changeset 5612:cf630991cb1d

Merge
author Gilles Duboscq <duboscq@ssw.jku.at>
date Thu, 14 Jun 2012 17:10:49 +0200
parents a03ca01cfe62 (current diff) a9b615da0cba (diff)
children 4cd97b3be234
files graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopFragment.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectFieldNode.java graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippets.java
diffstat 36 files changed, 655 insertions(+), 763 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Thu Jun 14 17:10:17 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Thu Jun 14 17:10:49 2012 +0200
@@ -261,7 +261,7 @@
      * Only instructions in methods whose fully qualified name contains this option will be HIR lowered.
      */
     public static String HIRLowerCheckcast = "";
-    public static String HIRLowerNewInstance = null;
+    public static String HIRLowerNewInstance = "NewInstanceTest";
 
     /**
      * The profiling info cache directory.
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Thu Jun 14 17:10:17 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Thu Jun 14 17:10:49 2012 +0200
@@ -32,7 +32,6 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.PhiNode.PhiType;
 import com.oracle.graal.nodes.virtual.*;
 
 public class DebugInfoBuilder {
@@ -52,20 +51,13 @@
         VirtualObject[] virtualObjectsArray = null;
         if (virtualObjects.size() != 0) {
             // collect all VirtualObjectField instances:
-            IdentityHashMap<VirtualObjectNode, VirtualObjectFieldNode> objectStates = new IdentityHashMap<>();
+            IdentityHashMap<VirtualObjectNode, VirtualObjectState> objectStates = new IdentityHashMap<>();
             FrameState current = topState;
             do {
-                for (Node n : current.virtualObjectMappings()) {
-                    Node p = n;
-                    while (p instanceof PhiNode) {
-                        PhiNode phi = (PhiNode) p;
-                        assert phi.type() == PhiType.Virtual;
-                        p = phi.valueAt(0);
-                    }
-                    VirtualObjectFieldNode field = (VirtualObjectFieldNode) p;
+                for (VirtualObjectState state : current.virtualObjectMappings()) {
                     // null states occur for objects with 0 fields
-                    if (field != null && !objectStates.containsKey(field.object())) {
-                        objectStates.put(field.object(), field);
+                    if (!objectStates.containsKey(state.object())) {
+                        objectStates.put(state.object(), state);
                     }
                 }
                 current = current.outerFrameState();
@@ -87,20 +79,11 @@
                             entry.getValue().setValues(values);
                             if (values.length > 0) {
                                 changed = true;
-                                ValueNode currentField = objectStates.get(vobj);
+                                VirtualObjectState currentField = objectStates.get(vobj);
                                 assert currentField != null;
-                                do {
-                                    if (currentField instanceof VirtualObjectFieldNode) {
-                                        int index = ((VirtualObjectFieldNode) currentField).index();
-                                        if (values[index] == null) {
-                                            values[index] = toCiValue(((VirtualObjectFieldNode) currentField).input());
-                                        }
-                                        currentField = ((VirtualObjectFieldNode) currentField).lastState();
-                                    } else {
-                                        assert currentField instanceof PhiNode : currentField;
-                                        currentField = ((PhiNode) currentField).valueAt(0);
-                                    }
-                                } while (currentField != null);
+                                for (int i = 0; i < vobj.fieldsCount(); i++) {
+                                    values[i] = toCiValue(currentField.fields().get(i));
+                                }
                             }
                         }
                     }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Thu Jun 14 17:10:17 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Thu Jun 14 17:10:49 2012 +0200
@@ -381,7 +381,7 @@
             lastState = fs;
         }
 
-        List<Node> nodes = lir.nodesFor(block);
+        List<ScheduledNode> nodes = lir.nodesFor(block);
         for (int i = 0; i < nodes.size(); i++) {
             Node instr = nodes.get(i);
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopFragment.java	Thu Jun 14 17:10:17 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopFragment.java	Thu Jun 14 17:10:49 2012 +0200
@@ -30,7 +30,6 @@
 import com.oracle.graal.lir.cfg.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.PhiNode.PhiType;
-import com.oracle.graal.nodes.util.*;
 
 
 public abstract class LoopFragment {
@@ -245,14 +244,8 @@
                     PhiNode phi = graph.add(vpn.type() == PhiType.Value ? new PhiNode(vpn.kind(), merge) : new PhiNode(vpn.type(), merge));
                     phi.addInput(vpn);
                     phi.addInput(newVpn);
-                    if (vpn.type() == PhiType.Value) {
-                        replaceWith = phi;
-                    } else {
-                        assert vpn.type() == PhiType.Virtual;
-                        ValueNode vof = GraphUtil.unProxify(vpn);
-                        ValueNode newVof = GraphUtil.unProxify(newVpn);
-                        replaceWith = GraphUtil.mergeVirtualChain(graph, vof, newVof, phi, earlyExit, newEarlyExit, merge);
-                    }
+                    assert vpn.type() == PhiType.Value;
+                    replaceWith = phi;
                 } else {
                     replaceWith = vpn.value();
                 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopFragmentInside.java	Thu Jun 14 17:10:17 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopFragmentInside.java	Thu Jun 14 17:10:49 2012 +0200
@@ -246,9 +246,6 @@
                 if (duplicateState != null) {
                     duplicateState.replaceFirstInput(phi, firstPhi); // fix the merge's state after
                 }
-                if (phi.type() == PhiType.Virtual) {
-                    initializer = GraphUtil.mergeVirtualChain(graph, firstPhi, newExitMerge);
-                }
                 mergedInitializers.put(phi, initializer);
             }
         }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/BoxingEliminationPhase.java	Thu Jun 14 17:10:17 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/BoxingEliminationPhase.java	Thu Jun 14 17:10:49 2012 +0200
@@ -110,7 +110,7 @@
         assert boxNode.objectStamp().isExactType();
         virtualizeUsages(boxNode, boxNode.source(), boxNode.objectStamp().type());
 
-        if (boxNode.usages().filter(isNotA(FrameState.class).nor(VirtualObjectFieldNode.class)).isNotEmpty()) {
+        if (boxNode.usages().filter(isNotA(VirtualState.class)).isNotEmpty()) {
             // Elimination failed, because boxing object escapes.
             return;
         }
@@ -125,7 +125,7 @@
     private static void virtualizeUsages(ValueNode boxNode, ValueNode replacement, ResolvedJavaType exactType) {
         ValueNode virtualValueNode = null;
         VirtualObjectNode virtualObjectNode = null;
-        for (Node n : boxNode.usages().filter(NodePredicates.isA(FrameState.class).or(VirtualObjectFieldNode.class)).snapshot()) {
+        for (Node n : boxNode.usages().filter(NodePredicates.isA(VirtualState.class)).snapshot()) {
             if (virtualValueNode == null) {
                 virtualObjectNode = n.graph().unique(new BoxedVirtualObjectNode(exactType, replacement));
             }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java	Thu Jun 14 17:10:17 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java	Thu Jun 14 17:10:49 2012 +0200
@@ -24,7 +24,6 @@
 
 import java.util.*;
 
-import com.oracle.max.criutils.*;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.compiler.*;
 import com.oracle.graal.compiler.graph.*;
@@ -38,38 +37,34 @@
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.virtual.*;
+import com.oracle.max.criutils.*;
 
 
 public class EscapeAnalysisPhase extends Phase {
 
+    /**
+     * Encapsulates the state of the virtual object, which is updated while traversing the control flow graph.
+     */
     public static class BlockExitState implements MergeableState<BlockExitState> {
         public final ValueNode[] fieldState;
         public final VirtualObjectNode virtualObject;
-        public ValueNode virtualObjectField;
         public final Graph graph;
 
         public BlockExitState(EscapeField[] fields, VirtualObjectNode virtualObject) {
             this.fieldState = new ValueNode[fields.length];
             this.virtualObject = virtualObject;
-            this.virtualObjectField = null;
             this.graph = virtualObject.graph();
             for (int i = 0; i < fields.length; i++) {
                 fieldState[i] = ConstantNode.defaultForKind(fields[i].type().kind(), virtualObject.graph());
-                virtualObjectField = graph.add(new VirtualObjectFieldNode(virtualObject, virtualObjectField, fieldState[i], i));
             }
         }
 
         public BlockExitState(BlockExitState state) {
             this.fieldState = state.fieldState.clone();
             this.virtualObject = state.virtualObject;
-            this.virtualObjectField = state.virtualObjectField;
             this.graph = state.graph;
         }
 
-        public void updateField(int fieldIndex) {
-            virtualObjectField = graph.add(new VirtualObjectFieldNode(virtualObject, virtualObjectField, fieldState[fieldIndex], fieldIndex));
-        }
-
         @Override
         public BlockExitState clone() {
             return new BlockExitState(this);
@@ -77,14 +72,8 @@
 
         @Override
         public boolean merge(MergeNode merge, List<BlockExitState> withStates) {
-            PhiNode vobjPhi = null;
             PhiNode[] valuePhis = new PhiNode[fieldState.length];
             for (BlockExitState other : withStates) {
-                if (virtualObjectField != other.virtualObjectField && vobjPhi == null) {
-                    vobjPhi = graph.add(new PhiNode(PhiType.Virtual, merge));
-                    vobjPhi.addInput(virtualObjectField);
-                    virtualObjectField = vobjPhi;
-                }
                 for (int i2 = 0; i2 < fieldState.length; i2++) {
                     if (fieldState[i2] != other.fieldState[i2] && valuePhis[i2] == null) {
                         valuePhis[i2] = graph.add(new PhiNode(fieldState[i2].kind(), merge));
@@ -94,51 +83,27 @@
                 }
             }
             for (BlockExitState other : withStates) {
-                if (vobjPhi != null) {
-                    vobjPhi.addInput(other.virtualObjectField);
-                }
                 for (int i2 = 0; i2 < fieldState.length; i2++) {
                     if (valuePhis[i2] != null) {
                         valuePhis[i2].addInput(other.fieldState[i2]);
                     }
                 }
             }
-            assert vobjPhi == null || vobjPhi.valueCount() == withStates.size() + 1;
-            for (int i2 = 0; i2 < fieldState.length; i2++) {
-                if (valuePhis[i2] != null) {
-                    virtualObjectField = graph.add(new VirtualObjectFieldNode(virtualObject, virtualObjectField, valuePhis[i2], i2));
-                    assert valuePhis[i2].valueCount() == withStates.size() + 1;
-                }
-            }
             return true;
         }
 
         @Override
         public void loopBegin(LoopBeginNode loopBegin) {
-            assert virtualObjectField != null : "unexpected null virtualObjectField";
-            PhiNode vobjPhi = null;
-            vobjPhi = graph.add(new PhiNode(PhiType.Virtual, loopBegin));
-            vobjPhi.addInput(virtualObjectField);
-            virtualObjectField = vobjPhi;
             for (int i2 = 0; i2 < fieldState.length; i2++) {
                 PhiNode valuePhi = graph.add(new PhiNode(fieldState[i2].kind(), loopBegin));
                 valuePhi.addInput(fieldState[i2]);
                 fieldState[i2] = valuePhi;
-                updateField(i2);
             }
         }
 
         @Override
         public void loopEnds(LoopBeginNode loopBegin, List<BlockExitState> loopEndStates) {
-            while (!loopBegin.isPhiAtMerge(virtualObjectField)) {
-                if (virtualObjectField instanceof PhiNode) {
-                    virtualObjectField = ((PhiNode) virtualObjectField).valueAt(0);
-                } else {
-                    virtualObjectField = ((VirtualObjectFieldNode) virtualObjectField).lastState();
-                }
-            }
             for (BlockExitState loopEndState : loopEndStates) {
-                ((PhiNode) virtualObjectField).addInput(loopEndState.virtualObjectField);
                 for (int i2 = 0; i2 < fieldState.length; i2++) {
                     ((PhiNode) fieldState[i2]).addInput(loopEndState.fieldState[i2]);
                 }
@@ -175,6 +140,12 @@
             }
         }
 
+        private void process() {
+            for (Node usage : node.usages().snapshot()) {
+                op.beforeUpdate(node, usage);
+            }
+        }
+
         public void removeAllocation() {
             escapeFields = op.fields(node);
             for (int i = 0; i < escapeFields.length; i++) {
@@ -202,42 +173,21 @@
                 final PostOrderNodeIterator<?> iterator = new PostOrderNodeIterator<BlockExitState>(next, startState) {
                     @Override
                     protected void node(FixedNode curNode) {
-                        int changedField = op.updateState(virtual, curNode, fields, state.fieldState);
-                        if (changedField != -1) {
-                            state.updateField(changedField);
-                        }
+                        op.updateState(virtual, curNode, fields, state.fieldState);
                         if (curNode instanceof LoopExitNode) {
-                            state.virtualObjectField = graph.unique(new ValueProxyNode(state.virtualObjectField, (LoopExitNode) curNode, PhiType.Virtual));
                             for (int i = 0; i < state.fieldState.length; i++) {
                                 state.fieldState[i] = graph.unique(new ValueProxyNode(state.fieldState[i], (LoopExitNode) curNode, PhiType.Value));
                             }
                         }
                         if (!curNode.isDeleted() && curNode instanceof StateSplit && ((StateSplit) curNode).stateAfter() != null) {
-                            if (state.virtualObjectField != null) {
-                                ValueNode v = state.virtualObjectField;
-                                if (curNode instanceof LoopBeginNode) {
-                                    while (!((LoopBeginNode) curNode).isPhiAtMerge(v)) {
-                                        if (v instanceof PhiNode) {
-                                            v = ((PhiNode) v).valueAt(0);
-                                        } else {
-                                            v = ((VirtualObjectFieldNode) v).lastState();
-                                        }
-                                    }
-                                }
-                                ((StateSplit) curNode).stateAfter().addVirtualObjectMapping(v);
-                            }
+                            VirtualObjectState v = graph.add(new VirtualObjectState(virtual, state.fieldState));
+                            ((StateSplit) curNode).stateAfter().addVirtualObjectMapping(v);
                         }
                     }
                 };
                 iterator.apply();
             }
         }
-
-        private void process() {
-            for (Node usage : node.usages().snapshot()) {
-                op.beforeUpdate(node, usage);
-            }
-        }
     }
 
     private final TargetDescription target;
@@ -278,7 +228,7 @@
 
     private static Node escape(EscapeRecord record, Node usage) {
         final Node node = record.node;
-        if (usage instanceof FrameState) {
+        if (usage instanceof VirtualState) {
             assert usage.inputs().contains(node);
             return null;
         } else {
@@ -318,8 +268,6 @@
                     // in order to not escape, the access needs to have a valid constant index and either a store into node or be self-referencing
                     return EscapeOp.isValidConstantIndex(x) && x.value() != node ? null : x.array();
                 }
-            } else if (usage instanceof VirtualObjectFieldNode) {
-                return null;
             } else if (usage instanceof RegisterFinalizerNode) {
                 assert ((RegisterFinalizerNode) usage).object() == node;
                 return null;
@@ -467,7 +415,7 @@
         for (Node usage : node.usages().snapshot()) {
             boolean escapes = op.escape(node, usage);
             if (escapes) {
-                if (usage instanceof FrameState) {
+                if (usage instanceof VirtualState) {
                     // nothing to do...
                 } else if (usage instanceof MethodCallTargetNode) {
                     if (usage.usages().size() == 0) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/InsertStateAfterPlaceholderPhase.java	Thu Jun 14 17:10:17 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/InsertStateAfterPlaceholderPhase.java	Thu Jun 14 17:10:49 2012 +0200
@@ -49,7 +49,7 @@
     protected void run(StructuredGraph graph) {
         for (ReturnNode ret : graph.getNodes(ReturnNode.class)) {
             PlaceholderNode p = graph.add(new PlaceholderNode());
-            p.setStateAfter(graph.add(new FrameState(null, FrameState.AFTER_BCI, 0, 0, false, false)));
+            p.setStateAfter(graph.add(new FrameState(FrameState.AFTER_BCI)));
             graph.addBeforeFixed(ret, p);
         }
     }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/schedule/SchedulePhase.java	Thu Jun 14 17:10:17 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/schedule/SchedulePhase.java	Thu Jun 14 17:10:49 2012 +0200
@@ -41,7 +41,7 @@
     /**
      * Map from blocks to the nodes in each block.
      */
-    private BlockMap<List<Node>> blockToNodesMap;
+    private BlockMap<List<ScheduledNode>> blockToNodesMap;
 
     public SchedulePhase() {
         super("Schedule");
@@ -57,17 +57,20 @@
         sortNodesWithinBlocks(graph);
     }
 
+    /**
+     * Sets {@link ScheduledNode#scheduledNext} on all scheduled nodes in all blocks using the scheduling built by @link {@link #run(StructuredGraph)}.
+     * This method should thus only be called when run has been successfully executed.
+     */
     public void scheduleGraph() {
+        assert blockToNodesMap != null : "cannot set scheduledNext before run has been executed";
         for (Block block : cfg.getBlocks()) {
-            List<Node> nodeList = blockToNodesMap.get(block);
+            List<ScheduledNode> nodeList = blockToNodesMap.get(block);
             ScheduledNode last = null;
-            for (Node node : nodeList) {
-                if (!(node instanceof FrameState)) {
-                    if (last != null) {
-                        last.setScheduledNext((ScheduledNode) node);
-                    }
-                    last = (ScheduledNode) node;
+            for (ScheduledNode node : nodeList) {
+                if (last != null) {
+                    last.setScheduledNext(node);
                 }
+                last = node;
             }
         }
     }
@@ -79,79 +82,86 @@
     /**
      * Gets the map from each block to the nodes in the block.
      */
-    public BlockMap<List<Node>> getBlockToNodesMap() {
+    public BlockMap<List<ScheduledNode>> getBlockToNodesMap() {
         return blockToNodesMap;
     }
 
     /**
      * Gets the nodes in a given block.
      */
-    public List<Node> nodesFor(Block block) {
+    public List<ScheduledNode> nodesFor(Block block) {
         return blockToNodesMap.get(block);
     }
 
     private void assignBlockToNodes(StructuredGraph graph) {
         for (Block block : cfg.getBlocks()) {
-            List<Node> nodes = new ArrayList<>();
+            List<ScheduledNode> nodes = new ArrayList<>();
             assert blockToNodesMap.get(block) == null;
             blockToNodesMap.put(block, nodes);
-            for (Node node : block.getNodes()) {
+            for (FixedNode node : block.getNodes()) {
                 nodes.add(node);
             }
         }
 
         for (Node n : graph.getNodes()) {
-            assignBlockToNode(n);
+            if (n instanceof ScheduledNode) {
+                assignBlockToNode((ScheduledNode) n);
+            }
         }
     }
 
-    private void assignBlockToNode(Node n) {
-        if (n == null) {
-            return;
-        }
+    /**
+     * Assigns a block to the given node. This method expects that PhiNodes and FixedNodes are already assigned to a
+     * block, since they should already have been placed by {@link ControlFlowGraph#identifyBlocks()}.
+     * This method will also try to
+     */
+    private void assignBlockToNode(ScheduledNode node) {
+        assert !node.isDeleted();
 
-        assert !n.isDeleted();
-
-        Block prevBlock = cfg.getNodeToBlock().get(n);
+        Block prevBlock = cfg.getNodeToBlock().get(node);
         if (prevBlock != null) {
             return;
         }
-        assert !(n instanceof PhiNode) : n;
-        assert !(n instanceof MergeNode);
+        // PhiNodes and FixedNodes should already have been placed in blocks by ControlFlowGraph.identifyBlocks
+        assert !(node instanceof PhiNode) : node;
+        assert !(node instanceof FixedNode) : node;
         // if in CFG, schedule at the latest position possible in the outermost loop possible
-        Block latestBlock = latestBlock(n);
+        Block latestBlock = latestBlock(node);
         Block block;
         if (latestBlock == null) {
-            block = earliestBlock(n);
-        } else if (GraalOptions.ScheduleOutOfLoops && !(n instanceof VirtualObjectFieldNode) && !(n instanceof VirtualObjectNode)) {
-            Block earliestBlock = earliestBlock(n);
-            block = scheduleOutOfLoops(n, latestBlock, earliestBlock);
-            assert earliestBlock.dominates(block) : "Graph can not be scheduled : inconsistent for " + n;
+            block = earliestBlock(node);
+        } else if (GraalOptions.ScheduleOutOfLoops && !(node instanceof VirtualObjectNode)) {
+            Block earliestBlock = earliestBlock(node);
+            block = scheduleOutOfLoops(node, latestBlock, earliestBlock);
+            assert earliestBlock.dominates(block) : "Graph can not be scheduled : inconsistent for " + node + " (" + earliestBlock + " needs to dominate " + block + ")";
         } else {
             block = latestBlock;
         }
-        cfg.getNodeToBlock().set(n, block);
-        blockToNodesMap.get(block).add(n);
+        cfg.getNodeToBlock().set(node, block);
+        blockToNodesMap.get(block).add(node);
     }
 
-    private Block latestBlock(Node n) {
-        Block block = null;
-        for (Node succ : n.successors()) {
-            if (succ == null) {
-                continue;
-            }
-            assignBlockToNode(succ);
-            block = getCommonDominator(block, cfg.getNodeToBlock().get(succ));
+    /**
+     * Calculates the last block that the given node could be scheduled in, i.e., the common dominator of all usages.
+     * To do so all usages are also assigned to blocks.
+     */
+    private Block latestBlock(ScheduledNode node) {
+        CommonDominatorBlockClosure cdbc = new CommonDominatorBlockClosure(null);
+        for (Node succ : node.successors().nonNull()) {
+            assert cfg.getNodeToBlock().get(succ) != null;
+            cdbc.apply(cfg.getNodeToBlock().get(succ));
         }
-        ensureScheduledUsages(n);
-        CommonDominatorBlockClosure cdbc = new CommonDominatorBlockClosure(block);
-        for (Node usage : n.usages()) {
-            blocksForUsage(n, usage, cdbc);
+        ensureScheduledUsages(node);
+        for (Node usage : node.usages()) {
+            blocksForUsage(node, usage, cdbc);
         }
         return cdbc.block;
     }
 
-    private class CommonDominatorBlockClosure implements BlockClosure {
+    /**
+     * A closure that will calculate the common dominator of all blocks passed to its {@link #apply(Block)} method.
+     */
+    private static class CommonDominatorBlockClosure implements BlockClosure {
         public Block block;
         public CommonDominatorBlockClosure(Block block) {
             this.block = block;
@@ -162,42 +172,45 @@
         }
     }
 
-    private Block earliestBlock(Node n) {
-        Block earliest = cfg.getNodeToBlock().get(n);
+    /**
+     * Determines the earliest block in which the given node can be scheduled.
+     */
+    private Block earliestBlock(Node node) {
+        Block earliest = cfg.getNodeToBlock().get(node);
         if (earliest != null) {
             return earliest;
         }
-        earliest = earliestCache.get(n);
+        earliest = earliestCache.get(node);
         if (earliest != null) {
             return earliest;
         }
-        BitSet bits = new BitSet(cfg.getBlocks().length);
-        ArrayList<Node> before = new ArrayList<>();
-        if (n.predecessor() != null) {
-            before.add(n.predecessor());
-        }
-        for (Node input : n.inputs()) {
-            before.add(input);
-        }
-        for (Node pred : before) {
-            if (pred == null) {
-                continue;
-            }
-            Block b = earliestBlock(pred);
-            if (!bits.get(b.getId())) {
-                earliest = b;
+        /*
+         * All inputs must be in a dominating block, otherwise the graph cannot be scheduled. This implies that the
+         * inputs' blocks have a total ordering via their dominance relation. So in order to find the earliest block
+         * placement for this node we need to find the input block that is dominated by all other input blocks.
+         *
+         * While iterating over the inputs a set of dominator blocks of the current earliest placement is maintained.
+         * When the block of an input is not within this set, it becomes the current earliest placement and the list of
+         * dominator blocks is updated.
+         */
+        BitSet dominators = new BitSet(cfg.getBlocks().length);
+
+        assert node.predecessor() == null;
+        for (Node input : node.inputs().nonNull()) {
+            assert input instanceof ValueNode;
+            Block inputEarliest = earliestBlock(input);
+            if (!dominators.get(inputEarliest.getId())) {
+                earliest = inputEarliest;
                 do {
-                    bits.set(b.getId());
-                    b = b.getDominator();
-                } while(b != null && !bits.get(b.getId()));
+                    dominators.set(inputEarliest.getId());
+                    inputEarliest = inputEarliest.getDominator();
+                } while(inputEarliest != null && !dominators.get(inputEarliest.getId()));
             }
         }
         if (earliest == null) {
-            Block start = cfg.getNodeToBlock().get(((StructuredGraph) n.graph()).start());
-            assert start != null;
-            return start;
+            earliest = cfg.getStartBlock();
         }
-        earliestCache.set(n, earliest);
+        earliestCache.set(node, earliest);
         return earliest;
     }
 
@@ -216,8 +229,20 @@
         return result;
     }
 
-    private void blocksForUsage(Node node, Node usage, BlockClosure closure) {
+    /**
+     * Passes all blocks that a specific usage of a node is in to a given closure.
+     * This is more complex than just taking the usage's block because of of PhiNodes and FrameStates.
+     *
+     * @param node the node that needs to be scheduled
+     * @param usage the usage whose blocks need to be considered
+     * @param closure the closure that will be called for each block
+     */
+    private void blocksForUsage(ScheduledNode node, Node usage, BlockClosure closure) {
+        assert !(node instanceof PhiNode);
+
         if (usage instanceof PhiNode) {
+            // An input to a PhiNode is used at the end of the predecessor block that corresponds to the PhiNode input.
+            // One PhiNode can use an input multiple times, the closure will be called for each usage.
             PhiNode phi = (PhiNode) usage;
             MergeNode merge = phi.merge();
             Block mergeBlock = cfg.getNodeToBlock().get(merge);
@@ -235,22 +260,38 @@
                     closure.apply(mergeBlock.getPredecessors().get(i));
                 }
             }
-        } else if (usage instanceof FrameState && ((FrameState) usage).block() != null) {
-            MergeNode merge = ((FrameState) usage).block();
-            Block block = null;
-            for (Node pred : merge.cfgPredecessors()) {
-                block = getCommonDominator(block, cfg.getNodeToBlock().get(pred));
+        } else if (usage instanceof VirtualState) {
+            // The following logic does not work if node is a PhiNode, but this method is never called for PhiNodes.
+            for (Node unscheduledUsage : usage.usages()) {
+                if (unscheduledUsage instanceof VirtualState) {
+                    // If a FrameState is an outer FrameState this method behaves as if the inner FrameState was the actual usage, by recursing.
+                    blocksForUsage(node, unscheduledUsage, closure);
+                } else if (unscheduledUsage instanceof MergeNode) {
+                    // Only FrameStates can be connected to MergeNodes.
+                    assert usage instanceof FrameState;
+                    // If a FrameState belongs to a MergeNode then it's inputs will be placed at the common dominator of all EndNodes.
+                    for (Node pred : unscheduledUsage.cfgPredecessors()) {
+                        closure.apply(cfg.getNodeToBlock().get(pred));
+                    }
+                } else {
+                    // For the time being, only FrameStates can be connected to StateSplits.
+                    assert usage instanceof FrameState;
+                    assert unscheduledUsage instanceof StateSplit;
+                    // Otherwise: Put the input into the same block as the usage.
+                    assignBlockToNode((ScheduledNode) unscheduledUsage);
+                    closure.apply(cfg.getNodeToBlock().get(unscheduledUsage));
+                }
             }
-            closure.apply(block);
         } else {
-            assignBlockToNode(usage);
+            // All other types of usages: Put the input into the same block as the usage.
+            assignBlockToNode((ScheduledNode) usage);
             closure.apply(cfg.getNodeToBlock().get(usage));
         }
     }
 
     private void ensureScheduledUsages(Node node) {
-        for (Node usage : node.usages().snapshot()) {
-            assignBlockToNode(usage);
+        for (Node usage : node.usages().filter(ScheduledNode.class)) {
+            assignBlockToNode((ScheduledNode) usage);
         }
         // now true usages are ready
     }
@@ -266,21 +307,25 @@
     }
 
     private void sortNodesWithinBlocks(StructuredGraph graph) {
-        NodeBitMap map = graph.createNodeBitMap();
+        NodeBitMap visited = graph.createNodeBitMap();
         for (Block b : cfg.getBlocks()) {
-            sortNodesWithinBlocks(b, map);
+            sortNodesWithinBlock(b, visited);
         }
     }
 
-    private void sortNodesWithinBlocks(Block b, NodeBitMap map) {
-        List<Node> instructions = blockToNodesMap.get(b);
-        List<Node> sortedInstructions = new ArrayList<>(instructions.size() + 2);
+    /**
+     * Sorts the nodes within a block by adding the nodes to a list in a post-order iteration over all inputs.
+     * This means that a node is added to the list after all its inputs have been processed.
+     */
+    private void sortNodesWithinBlock(Block b, NodeBitMap visited) {
+        List<ScheduledNode> instructions = blockToNodesMap.get(b);
+        List<ScheduledNode> sortedInstructions = new ArrayList<>(instructions.size() + 2);
 
-        assert !map.isMarked(b.getBeginNode()) && cfg.blockFor(b.getBeginNode()) == b;
-        assert !map.isMarked(b.getEndNode()) && cfg.blockFor(b.getEndNode()) == b;
+        assert !visited.isMarked(b.getBeginNode()) && cfg.blockFor(b.getBeginNode()) == b;
+        assert !visited.isMarked(b.getEndNode()) && cfg.blockFor(b.getEndNode()) == b;
 
-        for (Node i : instructions) {
-            addToSorting(b, i, sortedInstructions, map);
+        for (ScheduledNode i : instructions) {
+            addToSorting(b, i, sortedInstructions, visited);
         }
 
         // Make sure that last node gets really last (i.e. when a frame state successor hangs off it).
@@ -310,32 +355,45 @@
         blockToNodesMap.put(b, sortedInstructions);
     }
 
-    private void addToSorting(Block b, Node i, List<Node> sortedInstructions, NodeBitMap map) {
-        if (i == null || map.isMarked(i) || cfg.getNodeToBlock().get(i) != b || i instanceof PhiNode || i instanceof LocalNode) {
+    private void addUnscheduledToSorting(Block b, VirtualState state, List<ScheduledNode> sortedInstructions, NodeBitMap visited) {
+        if (state != null) {
+            // UnscheduledNodes should never be marked as visited.
+            assert !visited.isMarked(state);
+
+            for (Node input : state.inputs()) {
+                if (input instanceof VirtualState) {
+                    addUnscheduledToSorting(b, (VirtualState) input, sortedInstructions, visited);
+                } else {
+                    addToSorting(b, (ScheduledNode) input, sortedInstructions, visited);
+                }
+            }
+        }
+    }
+
+    private void addToSorting(Block b, ScheduledNode i, List<ScheduledNode> sortedInstructions, NodeBitMap visited) {
+        if (i == null || visited.isMarked(i) || cfg.getNodeToBlock().get(i) != b || i instanceof PhiNode || i instanceof LocalNode) {
             return;
         }
 
         FrameState state = null;
-        WriteNode writeNode = null;
+        WriteNode write = null;
         for (Node input : i.inputs()) {
-            if (input instanceof WriteNode && !map.isMarked(input) && cfg.getNodeToBlock().get(input) == b) {
-                writeNode = (WriteNode) input;
+            if (input instanceof WriteNode && !visited.isMarked(input) && cfg.getNodeToBlock().get(input) == b) {
+                assert write == null;
+                write = (WriteNode) input;
             } else if (input instanceof FrameState) {
+                assert state == null;
                 state = (FrameState) input;
             } else {
-                addToSorting(b, input, sortedInstructions, map);
+                addToSorting(b, (ScheduledNode) input, sortedInstructions, visited);
             }
         }
 
-        if (i.predecessor() != null) {
-            addToSorting(b, i.predecessor(), sortedInstructions, map);
-        }
-
-        map.mark(i);
-
-        addToSorting(b, state, sortedInstructions, map);
-        assert writeNode == null || !map.isMarked(writeNode);
-        addToSorting(b, writeNode, sortedInstructions, map);
+        addToSorting(b, (ScheduledNode) i.predecessor(), sortedInstructions, visited);
+        visited.mark(i);
+        addUnscheduledToSorting(b, state, sortedInstructions, visited);
+        assert write == null || !visited.isMarked(write);
+        addToSorting(b, write, sortedInstructions, visited);
 
         // Now predecessors and inputs are scheduled => we can add this node.
         sortedInstructions.add(i);
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java	Thu Jun 14 17:10:17 2012 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java	Thu Jun 14 17:10:49 2012 +0200
@@ -55,6 +55,7 @@
             this.nodes = new Node[elements.length];
             for (int i = 0; i < elements.length; i++) {
                 this.nodes[i] = elements[i];
+                assert this.nodes[i] == null || !this.nodes[i].isDeleted();
             }
         }
     }
@@ -70,6 +71,7 @@
             this.nodes = new Node[elements.size()];
             for (int i = 0; i < elements.size(); i++) {
                 this.nodes[i] = elements.get(i);
+                assert this.nodes[i] == null || !this.nodes[i].isDeleted();
             }
         }
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Thu Jun 14 17:10:17 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Thu Jun 14 17:10:49 2012 +0200
@@ -112,8 +112,9 @@
                 @Override
                 public void run() {
                     VMToCompilerImpl.this.intrinsifyArrayCopy = new IntrinsifyArrayCopyPhase(runtime);
-                    GraalIntrinsics.installIntrinsics(runtime, runtime.getCompiler().getTarget());
-                    runtime.installSnippets();
+                    SnippetInstaller installer = new SnippetInstaller(runtime, runtime.getCompiler().getTarget());
+                    GraalIntrinsics.installIntrinsics(installer);
+                    runtime.installSnippets(installer);
                 }
             });
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Thu Jun 14 17:10:17 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Thu Jun 14 17:10:49 2012 +0200
@@ -68,12 +68,12 @@
         System.setProperty(Backend.BACKEND_CLASS_PROPERTY, HotSpotAMD64Backend.class.getName());
     }
 
-    public void installSnippets() {
-        Snippets.install(this, compiler.getTarget(), new SystemSnippets());
-        Snippets.install(this, compiler.getTarget(), new UnsafeSnippets());
-        Snippets.install(this, compiler.getTarget(), new ArrayCopySnippets());
-        Snippets.install(this, compiler.getTarget(), new CheckCastSnippets());
-        Snippets.install(this, compiler.getTarget(), new NewInstanceSnippets());
+    public void installSnippets(SnippetInstaller installer) {
+        installer.install(SystemSnippets.class);
+        installer.install(UnsafeSnippets.class);
+        installer.install(ArrayCopySnippets.class);
+        installer.install(CheckCastSnippets.class);
+        installer.install(NewInstanceSnippets.class);
         checkcastSnippets = new CheckCastSnippets.Templates(this);
         newInstanceSnippets = new NewInstanceSnippets.Templates(this);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewInstanceSnippets.java	Thu Jun 14 17:10:17 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewInstanceSnippets.java	Thu Jun 14 17:10:49 2012 +0200
@@ -55,16 +55,18 @@
  */
 public class NewInstanceSnippets implements SnippetsInterface {
 
+    private static final boolean LOG_ALLOCATION = Boolean.getBoolean("graal.traceAllocation");
+
     /**
      * Type test used when the type being tested against is a final type.
      */
     @Snippet
-    public static Object newInstance(@Parameter("hub") Object hub, @ConstantParameter("size") int size, @ConstantParameter("checkInit") boolean checkInit) {
+    public static Object newInstance(@Parameter("hub") Object hub, @ConstantParameter("size") int size, @ConstantParameter("checkInit") boolean checkInit, @ConstantParameter("logType") String logType) {
         if (checkInit) {
             int klassState = load(hub, 0, klassStateOffset(), Kind.Int);
             if (klassState != klassStateFullyInitialized()) {
                 Object instance = NewInstanceStubCall.call(hub);
-                return formatInstance(hub, size, instance);
+                return formatInstance(hub, size, instance, logType);
             }
         }
 
@@ -80,7 +82,7 @@
             instance = NewInstanceStubCall.call(hub);
         }
 
-        return formatInstance(hub, size, instance);
+        return formatInstance(hub, size, instance, logType);
     }
 
     private static Word asWord(Object object) {
@@ -94,7 +96,7 @@
     /**
      * Formats the header of a created instance and zeroes out its body.
      */
-    private static Object formatInstance(Object hub, int size, Object instance) {
+    private static Object formatInstance(Object hub, int size, Object instance, String logType) {
         Word headerPrototype = cast(load(hub, 0, instanceHeaderPrototypeOffset(), wordKind()), Word.class);
         store(instance, 0, 0, headerPrototype);
         store(instance, 0, hubOffset(), hub);
@@ -102,6 +104,12 @@
         for (int offset = 2 * wordSize(); offset < size; offset += wordSize()) {
             store(instance, 0, offset, 0);
         }
+        if (logType != null) {
+            Log.print("allocated instance of ");
+            Log.print(logType);
+            Log.print(" at ");
+            Log.printlnAddress(instance);
+        }
         return instance;
     }
 
@@ -155,7 +163,7 @@
             this.runtime = runtime;
             this.cache = new Cache(runtime);
             try {
-                newInstance = runtime.getResolvedJavaMethod(NewInstanceSnippets.class.getDeclaredMethod("newInstance", Object.class, int.class, boolean.class));
+                newInstance = runtime.getResolvedJavaMethod(NewInstanceSnippets.class.getDeclaredMethod("newInstance", Object.class, int.class, boolean.class, String.class));
             } catch (NoSuchMethodException e) {
                 throw new GraalInternalError(e);
             }
@@ -170,7 +178,7 @@
             HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) newInstanceNode.instanceClass();
             HotSpotKlassOop hub = type.klassOop();
             int instanceSize = type.instanceSize();
-            Key key = new Key(newInstance).add("size", instanceSize).add("checkInit", !type.isInitialized());
+            Key key = new Key(newInstance).add("size", instanceSize).add("checkInit", !type.isInitialized()).add("logType", LOG_ALLOCATION ? type.name() : null);
             Arguments arguments = arguments("hub", hub);
             SnippetTemplate template = cache.get(key);
             Debug.log("Lowering newInstance in %s: node=%s, template=%s, arguments=%s", graph, newInstanceNode, template, arguments);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java	Thu Jun 14 17:10:17 2012 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java	Thu Jun 14 17:10:49 2012 +0200
@@ -29,6 +29,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.cfg.*;
+import com.oracle.graal.nodes.*;
 
 /**
  * This class implements the overall container for the LIR graph
@@ -42,7 +43,7 @@
      * The nodes for the blocks.
      * TODO: This should go away, we want all nodes connected with a next-pointer.
      */
-    private final BlockMap<List<Node>> blockToNodesMap;
+    private final BlockMap<List<ScheduledNode>> blockToNodesMap;
 
     /**
      * The linear-scan ordered list of blocks.
@@ -87,7 +88,7 @@
      * @param numLoops number of loops
      * @param compilation the compilation
      */
-    public LIR(ControlFlowGraph cfg, BlockMap<List<Node>> blockToNodesMap, List<Block> linearScanOrder, List<Block> codeEmittingOrder) {
+    public LIR(ControlFlowGraph cfg, BlockMap<List<ScheduledNode>> blockToNodesMap, List<Block> linearScanOrder, List<Block> codeEmittingOrder) {
         this.cfg = cfg;
         this.blockToNodesMap = blockToNodesMap;
         this.codeEmittingOrder = codeEmittingOrder;
@@ -99,7 +100,7 @@
     /**
      * Gets the nodes in a given block.
      */
-    public List<Node> nodesFor(Block block) {
+    public List<ScheduledNode> nodesFor(Block block) {
         return blockToNodesMap.get(block);
     }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/Block.java	Thu Jun 14 17:10:17 2012 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/Block.java	Thu Jun 14 17:10:49 2012 +0200
@@ -24,7 +24,6 @@
 
 import java.util.*;
 
-import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
@@ -33,7 +32,7 @@
     protected int id;
 
     protected BeginNode beginNode;
-    protected Node endNode;
+    protected FixedNode endNode;
     protected Loop loop;
     protected double probability;
 
@@ -62,7 +61,7 @@
         return beginNode;
     }
 
-    public Node getEndNode() {
+    public FixedNode getEndNode() {
         return endNode;
     }
 
@@ -122,8 +121,8 @@
         return postdominator;
     }
 
-    private class NodeIterator implements Iterator<Node> {
-        private Node cur;
+    private class NodeIterator implements Iterator<FixedNode> {
+        private FixedNode cur;
 
         public NodeIterator() {
             cur = getBeginNode();
@@ -135,8 +134,8 @@
         }
 
         @Override
-        public Node next() {
-            Node result = cur;
+        public FixedNode next() {
+            FixedNode result = cur;
             if (cur == getEndNode()) {
                 cur = null;
             } else {
@@ -152,10 +151,10 @@
         }
     }
 
-    public Iterable<Node> getNodes() {
-        return new Iterable<Node>() {
+    public Iterable<FixedNode> getNodes() {
+        return new Iterable<FixedNode>() {
             @Override
-            public Iterator<Node> iterator() {
+            public Iterator<FixedNode> iterator() {
                 return new NodeIterator();
             }
         };
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/ControlFlowGraph.java	Thu Jun 14 17:10:17 2012 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/ControlFlowGraph.java	Thu Jun 14 17:10:49 2012 +0200
@@ -118,9 +118,9 @@
 
                 block.beginNode = (BeginNode) node;
                 Node cur = node;
+                Node last;
                 do {
                     assert !cur.isDeleted();
-                    block.endNode = cur;
 
                     assert nodeToBlock.get(cur) == null;
                     nodeToBlock.set(cur, block);
@@ -137,15 +137,11 @@
                         }
                     }
 
-                    Node next = null;
-                    for (Node sux : cur.successors()) {
-                        if (sux != null && !(sux instanceof BeginNode)) {
-                            assert next == null;
-                            next = sux;
-                        }
-                    }
-                    cur = next;
-                } while (cur != null);
+                    last = cur;
+                    cur = cur.successors().first();
+                } while (cur != null && !(cur instanceof BeginNode));
+
+                block.endNode = (FixedNode) last;
             }
         }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java	Thu Jun 14 17:10:17 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java	Thu Jun 14 17:10:49 2012 +0200
@@ -28,6 +28,7 @@
 import com.oracle.graal.nodes.type.*;
 
 public abstract class CallTargetNode extends ValueNode implements LIRLowerable {
+
     @Input protected final NodeInputList<ValueNode> arguments;
 
     public CallTargetNode(ValueNode[] arguments) {
@@ -45,6 +46,6 @@
 
     @Override
     public void generate(LIRGeneratorTool gen) {
-        //nop
+        // nop
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Thu Jun 14 17:10:17 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Thu Jun 14 17:10:49 2012 +0200
@@ -35,7 +35,7 @@
  * The {@code FrameState} class encapsulates the frame state (i.e. local variables and
  * operand stack) at a particular point in the abstract interpretation.
  */
-public final class FrameState extends Node implements Node.IterableNodeType, LIRLowerable {
+public final class FrameState extends VirtualState implements Node.IterableNodeType, LIRLowerable {
 
     protected final int localsSize;
 
@@ -74,11 +74,10 @@
 
     @Input private final NodeInputList<ValueNode> values;
 
-    @Input private final NodeInputList<Node> virtualObjectMappings;
+    @Input private final NodeInputList<VirtualObjectState> virtualObjectMappings;
 
     /**
-     * The bytecode index to which this frame state applies. This will be {@code -1}
-     * iff this state is mutable.
+     * The bytecode index to which this frame state applies.
      */
     public final int bci;
 
@@ -93,19 +92,28 @@
      * @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
      */
-    public FrameState(ResolvedJavaMethod method, int bci, int localsSize, int stackSize, boolean rethrowException, boolean duringCall) {
+    public FrameState(ResolvedJavaMethod method, int bci, List<ValueNode> values, int stackSize, boolean rethrowException, boolean duringCall, List<VirtualObjectState> virtualObjectMappings) {
         assert stackSize >= 0;
+        assert (bci >= 0 && method != null) || (bci < 0 && method == null && values.isEmpty());
         this.method = method;
         this.bci = bci;
-        this.localsSize = localsSize;
+        this.localsSize = values.size() - stackSize;
         this.stackSize = stackSize;
-        this.values = new NodeInputList<>(this, localsSize + stackSize);
-        this.virtualObjectMappings = new NodeInputList<>(this);
+        this.values = new NodeInputList<>(this, values);
+        this.virtualObjectMappings = new NodeInputList<>(this, virtualObjectMappings);
         this.rethrowException = rethrowException;
         this.duringCall = duringCall;
         assert !rethrowException || stackSize == 1 : "must have exception on top of the stack";
     }
 
+    /**
+     * Simple constructor used to create marker FrameStates.
+     * @param bci marker bci, needs to be < 0
+     */
+    public FrameState(int bci) {
+        this(null, bci, Collections.<ValueNode>emptyList(), 0, false, false, Collections.<VirtualObjectState>emptyList());
+    }
+
     public FrameState(ResolvedJavaMethod method, int bci, ValueNode[] locals, ValueNode[] stack, int stackSize, boolean rethrowException, boolean duringCall) {
         this.method = method;
         this.bci = bci;
@@ -140,10 +148,6 @@
         this.outerFrameState = x;
     }
 
-    private void setValueAt(int i, ValueNode x) {
-        values.set(i, x);
-    }
-
     public boolean rethrowException() {
         return rethrowException;
     }
@@ -160,8 +164,7 @@
         return method;
     }
 
-    public void addVirtualObjectMapping(Node virtualObject) {
-        assert virtualObject instanceof VirtualObjectFieldNode || virtualObject instanceof PhiNode || virtualObject instanceof ValueProxyNode : virtualObject;
+    public void addVirtualObjectMapping(VirtualObjectState virtualObject) {
         virtualObjectMappings.add(virtualObject);
     }
 
@@ -173,7 +176,7 @@
         return virtualObjectMappings.get(i);
     }
 
-    public Iterable<Node> virtualObjectMappings() {
+    public Iterable<VirtualObjectState> virtualObjectMappings() {
         return virtualObjectMappings;
     }
 
@@ -192,9 +195,7 @@
     }
 
     public FrameState duplicate(int newBci, boolean duplicateOuter) {
-        FrameState other = graph().add(new FrameState(method, newBci, localsSize, stackSize, rethrowException, duringCall));
-        other.values.setAll(values);
-        other.virtualObjectMappings.setAll(virtualObjectMappings);
+        FrameState other = graph().add(new FrameState(method, newBci, values, stackSize, rethrowException, duringCall, virtualObjectMappings));
         FrameState newOuterFrameState = outerFrameState();
         if (duplicateOuter && newOuterFrameState != null) {
             newOuterFrameState = newOuterFrameState.duplicate(newOuterFrameState.bci, duplicateOuter);
@@ -209,30 +210,18 @@
      * or double is followed by a null slot.
      */
     public FrameState duplicateModified(int newBci, boolean newRethrowException, Kind popKind, ValueNode... pushedValues) {
-        int popSlots = 0;
+        ArrayList<ValueNode> copy = new ArrayList<>(values);
         if (popKind != Kind.Void) {
             if (stackAt(stackSize() - 1) == null) {
-                popSlots = 2;
-            } else {
-                popSlots = 1;
+                copy.remove(copy.size() - 1);
             }
-            assert stackAt(stackSize() - popSlots).kind().stackKind() == popKind.stackKind() || (stackAt(stackSize() - popSlots) instanceof BoxedVirtualObjectNode && popKind.isObject());
+            ValueNode lastSlot = copy.get(copy.size() - 1);
+            assert lastSlot.kind().stackKind() == popKind.stackKind() || (lastSlot instanceof BoxedVirtualObjectNode && popKind.isObject());
+            copy.remove(copy.size() - 1);
         }
+        Collections.addAll(copy, pushedValues);
 
-        int pushSlots = pushedValues.length;
-        FrameState other = graph().add(new FrameState(method, newBci, localsSize, stackSize - popSlots + pushSlots, newRethrowException, false));
-        for (int i = 0; i < localsSize; i++) {
-            other.setValueAt(i, localAt(i));
-        }
-        for (int i = 0; i < stackSize - popSlots; i++) {
-            other.setValueAt(localsSize + i, stackAt(i));
-        }
-        int slot = localsSize + stackSize - popSlots;
-        for (int i = 0; i < pushSlots; i++) {
-            assert pushedValues[i] == null || !pushedValues[i].kind().isVoid();
-            other.setValueAt(slot++, pushedValues[i]);
-        }
-        other.virtualObjectMappings.setAll(virtualObjectMappings);
+        FrameState other = graph().add(new FrameState(method, newBci, copy, copy.size() - localsSize, newRethrowException, false, virtualObjectMappings));
         other.setOuterFrameState(outerFrameState());
         return other;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Thu Jun 14 17:10:17 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Thu Jun 14 17:10:49 2012 +0200
@@ -36,8 +36,7 @@
 
     public static enum PhiType {
         Value(null), // normal value phis
-        Memory(StampFactory.dependency()), // memory phis
-        Virtual(StampFactory.virtual()); // phis used for VirtualObjectField merges
+        Memory(StampFactory.dependency());
 
         public final Stamp stamp;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ScheduledNode.java	Thu Jun 14 17:10:17 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ScheduledNode.java	Thu Jun 14 17:10:49 2012 +0200
@@ -26,7 +26,7 @@
 
 import com.oracle.graal.graph.*;
 
-public class ScheduledNode extends Node {
+public abstract class ScheduledNode extends Node {
 
     @Successor private ScheduledNode scheduledNext; // the immediate successor of the current node
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/VirtualState.java	Thu Jun 14 17:10:49 2012 +0200
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes;
+
+import com.oracle.graal.graph.*;
+
+/**
+ * Base class for nodes that contain "virtual" state, like FrameState and VirtualObjectState.
+ * Subclasses of this class will be treated in a special way by the scheduler.
+ */
+public abstract class VirtualState extends Node {
+
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java	Thu Jun 14 17:10:17 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java	Thu Jun 14 17:10:49 2012 +0200
@@ -34,11 +34,10 @@
 /**
  * The ValueAnchor instruction keeps non-CFG (floating) nodes above a certain point in the graph.
  */
-
 public final class ValueAnchorNode extends FixedWithNextNode implements Canonicalizable, LIRLowerable, Node.IterableNodeType {
 
     public ValueAnchorNode(ValueNode... values) {
-        super(StampFactory.dependency(), values);
+        super(StampFactory.forVoid(), values);
     }
 
     @Override
@@ -53,6 +52,12 @@
     }
 
     @Override
+    public boolean verify() {
+        assertTrue(usages().isEmpty(), "upwards dependencies should target BeginNodes only");
+        return super.verify();
+    }
+
+    @Override
     public ValueNode canonical(CanonicalizerTool tool) {
         if (this.predecessor() instanceof ValueAnchorNode) {
             // transfer values and remove
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeOp.java	Thu Jun 14 17:10:17 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeOp.java	Thu Jun 14 17:10:49 2012 +0200
@@ -29,8 +29,6 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.virtual.*;
-
 
 public abstract class EscapeOp {
 
@@ -43,7 +41,7 @@
         } else if (usage instanceof IsTypeNode) {
             assert ((IsTypeNode) usage).objectClass() == node;
             return false;
-        } else if (usage instanceof FrameState) {
+        } else if (usage instanceof VirtualState) {
             assert usage.inputs().contains(node);
             return true;
         } else if (usage instanceof AccessMonitorNode) {
@@ -73,8 +71,6 @@
                 // in order to not escape the access needs to have a valid constant index and either a store into node or self-referencing
                 return !isValidConstantIndex(x) || x.value() == node && x.array() != node;
             }
-        } else if (usage instanceof VirtualObjectFieldNode) {
-            return false;
         } else if (usage instanceof RegisterFinalizerNode) {
             assert ((RegisterFinalizerNode) usage).object() == node;
             return false;
@@ -112,8 +108,8 @@
             ((StructuredGraph) x.graph()).replaceFloating(x, ConstantNode.forBoolean(false, node.graph()));
         } else if (usage instanceof IsTypeNode) {
             IsTypeNode x = (IsTypeNode) usage;
-            assert x.type() == ((ValueNode) node).objectStamp().type();
-            ((StructuredGraph) x.graph()).replaceFloating(x, ConstantNode.forBoolean(true, node.graph()));
+            boolean result = ((ValueNode) node).objectStamp().type() == x.type();
+            ((StructuredGraph) x.graph()).replaceFloating(x, ConstantNode.forBoolean(result, node.graph()));
         } else if (usage instanceof AccessMonitorNode) {
             ((AccessMonitorNode) usage).eliminate();
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Thu Jun 14 17:10:17 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Thu Jun 14 17:10:49 2012 +0200
@@ -31,14 +31,12 @@
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.graph.iterators.NodePredicates.PositiveTypePredicate;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.PhiNode.PhiType;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.virtual.*;
 
 public class GraphUtil {
 
-    private static final PositiveTypePredicate FLOATING = isA(FloatingNode.class).or(CallTargetNode.class).or(FrameState.class).or(VirtualObjectFieldNode.class).or(VirtualObjectNode.class);
+    private static final PositiveTypePredicate FLOATING = isA(FloatingNode.class).or(VirtualState.class).or(CallTargetNode.class);
 
     public static void killCFG(FixedNode node) {
         assert node.isAlive();
@@ -61,30 +59,32 @@
 
     private static void killEnd(EndNode end) {
         MergeNode merge = end.merge();
-        merge.removeEnd(end);
-        StructuredGraph graph = (StructuredGraph) end.graph();
-        if (merge instanceof LoopBeginNode && merge.forwardEndCount() == 0) { //dead loop
-            for (PhiNode phi : merge.phis().snapshot()) {
-                propagateKill(phi);
-            }
-            LoopBeginNode begin = (LoopBeginNode) merge;
-            // disconnect and delete loop ends & loop exits
-            for (LoopEndNode loopend : begin.loopEnds().snapshot()) {
-                loopend.predecessor().replaceFirstSuccessor(loopend, null);
-                loopend.safeDelete();
+        if (merge != null) {
+            merge.removeEnd(end);
+            StructuredGraph graph = (StructuredGraph) end.graph();
+            if (merge instanceof LoopBeginNode && merge.forwardEndCount() == 0) { //dead loop
+                for (PhiNode phi : merge.phis().snapshot()) {
+                    propagateKill(phi);
+                }
+                LoopBeginNode begin = (LoopBeginNode) merge;
+                // disconnect and delete loop ends & loop exits
+                for (LoopEndNode loopend : begin.loopEnds().snapshot()) {
+                    loopend.predecessor().replaceFirstSuccessor(loopend, null);
+                    loopend.safeDelete();
+                }
+                for (LoopExitNode loopexit : begin.loopExits().snapshot()) {
+                    for (ValueProxyNode vpn : loopexit.proxies().snapshot()) {
+                        graph.replaceFloating(vpn, vpn.value());
+                    }
+                    graph.replaceFixedWithFixed(loopexit, graph.add(new BeginNode()));
+                }
+                killCFG(begin.next());
+                begin.safeDelete();
+            } else if (merge instanceof LoopBeginNode && ((LoopBeginNode) merge).loopEnds().isEmpty()) { // not a loop anymore
+                graph.reduceDegenerateLoopBegin((LoopBeginNode) merge);
+            } else if (merge.phiPredecessorCount() == 1) { // not a merge anymore
+                graph.reduceTrivialMerge(merge);
             }
-            for (LoopExitNode loopexit : begin.loopExits().snapshot()) {
-                for (ValueProxyNode vpn : loopexit.proxies().snapshot()) {
-                    graph.replaceFloating(vpn, vpn.value());
-                }
-                graph.replaceFixedWithFixed(loopexit, graph.add(new BeginNode()));
-            }
-            killCFG(begin.next());
-            begin.safeDelete();
-        } else if (merge instanceof LoopBeginNode && ((LoopBeginNode) merge).loopEnds().isEmpty()) { // not a loop anymore
-            graph.reduceDegenerateLoopBegin((LoopBeginNode) merge);
-        } else if (merge.phiPredecessorCount() == 1) { // not a merge anymore
-            graph.reduceTrivialMerge(merge);
         }
     }
 
@@ -219,144 +219,4 @@
         }
         return v;
     }
-
-    private static ValueProxyNode findProxy(ValueNode value, BeginNode proxyPoint) {
-        for (ValueProxyNode vpn : proxyPoint.proxies()) {
-            ValueNode v = vpn;
-            while (v instanceof ValueProxyNode) {
-                v = ((ValueProxyNode) v).value();
-                if (v == value) {
-                    return vpn;
-                }
-            }
-        }
-        return null;
-    }
-
-    public static ValueNode mergeVirtualChain(
-                    StructuredGraph graph,
-                    ValueNode vof,
-                    ValueNode newVof,
-                    PhiNode vPhi,
-                    BeginNode earlyExit,
-                    BeginNode newEarlyExit,
-                    MergeNode merge) {
-        VirtualObjectNode vObject = virtualObject(vof);
-        assert virtualObject(newVof) == vObject;
-        ValueNode[] virtualState = virtualState(vof);
-        ValueNode[] newVirtualState = virtualState(newVof);
-        ValueNode chain = vPhi;
-        for (int i = 0; i < virtualState.length; i++) {
-            ValueNode value = virtualState[i];
-            ValueNode newValue = newVirtualState[i];
-            assert value.kind() == newValue.kind();
-            if (value != newValue) {
-                PhiNode valuePhi = graph.add(new PhiNode(value.kind(), merge));
-                ValueProxyNode inputProxy = findProxy(value, earlyExit);
-                if (inputProxy != null) {
-                    ValueProxyNode newInputProxy = findProxy(newValue, newEarlyExit);
-                    assert newInputProxy != null : "no proxy for " + newValue + " at " + newEarlyExit;
-                    valuePhi.addInput(inputProxy);
-                    valuePhi.addInput(newInputProxy);
-                } else {
-                    valuePhi.addInput(graph.unique(new ValueProxyNode(value, earlyExit, PhiType.Value)));
-                    valuePhi.addInput(newValue);
-                }
-                chain = graph.add(new VirtualObjectFieldNode(vObject, chain, valuePhi, i));
-            }
-        }
-        return chain;
-    }
-
-    public static ValueNode mergeVirtualChain(
-                    StructuredGraph graph,
-                    PhiNode vPhi,
-                    MergeNode merge) {
-        NodeInputList<ValueNode> virtuals = vPhi.values();
-        VirtualObjectNode vObject = virtualObject(unProxify(virtuals.first()));
-        List<ValueNode[]> virtualStates = new ArrayList<>(virtuals.size());
-        for (ValueNode virtual : virtuals) {
-            virtualStates.add(virtualState(unProxify(virtual)));
-        }
-        ValueNode chain = vPhi;
-        int stateLength = virtualStates.get(0).length;
-        for (int i = 0; i < stateLength; i++) {
-            ValueNode v = null;
-            boolean reconcile = false;
-            for (ValueNode[] state : virtualStates) {
-                if (v == null) {
-                    v = state[i];
-                } else if (v != state[i]) {
-                    reconcile = true;
-                    break;
-                }
-                assert v.kind() == state[i].kind();
-            }
-            if (reconcile) {
-                PhiNode valuePhi = graph.add(new PhiNode(v.kind(), merge));
-                for (ValueNode[] state : virtualStates) {
-                    valuePhi.addInput(state[i]);
-                }
-                chain = graph.add(new VirtualObjectFieldNode(vObject, chain, valuePhi, i));
-            }
-        }
-        return chain;
-    }
-
-    /**
-     * Returns the VirtualObjectNode associated with the virtual chain of the provided virtual node.
-     * @param vof a virtual ValueNode (a VirtualObjectFieldNode or a Virtual Phi)
-     * @return the VirtualObjectNode associated with the virtual chain of the provided virtual node.
-     */
-    public static VirtualObjectNode virtualObject(ValueNode vof) {
-        assert vof instanceof VirtualObjectFieldNode || (vof instanceof PhiNode && ((PhiNode) vof).type() == PhiType.Virtual) : vof;
-        ValueNode currentField = vof;
-        do {
-            if (currentField instanceof VirtualObjectFieldNode) {
-               return ((VirtualObjectFieldNode) currentField).object();
-            } else {
-                assert currentField instanceof PhiNode && ((PhiNode) currentField).type() == PhiType.Virtual : currentField;
-                currentField = ((PhiNode) currentField).valueAt(0);
-            }
-        } while (currentField != null);
-        throw new GraalInternalError("Invalid virtual chain : cound not find virtual object from %s", vof);
-    }
-
-    /**
-     * Builds the state of the virtual object at the provided point into a virtual chain.
-     * @param vof a virtual ValueNode (a VirtualObjectFieldNode or a Virtual Phi)
-     * @return the state of the virtual object at the provided point into a virtual chain.
-     */
-    public static ValueNode[] virtualState(ValueNode vof) {
-        return virtualState(vof, virtualObject(vof));
-    }
-
-    /**
-     * Builds the state of the virtual object at the provided point into a virtual chain.
-     * @param vof a virtual ValueNode (a VirtualObjectFieldNode or a Virtual Phi)
-     * @param vObj the virtual object
-     * @return the state of the virtual object at the provided point into a virtual chain.
-     */
-    public static ValueNode[] virtualState(ValueNode vof, VirtualObjectNode vObj) {
-        int fieldsCount = vObj.fieldsCount();
-        int dicovered = 0;
-        ValueNode[] state = new ValueNode[fieldsCount];
-        ValueNode currentField = vof;
-        do {
-            if (currentField instanceof VirtualObjectFieldNode) {
-                int index = ((VirtualObjectFieldNode) currentField).index();
-                if (state[index] == null) {
-                    dicovered++;
-                    state[index] = ((VirtualObjectFieldNode) currentField).input();
-                }
-                currentField = ((VirtualObjectFieldNode) currentField).lastState();
-            } else if (currentField instanceof ValueProxyNode) {
-                currentField = ((ValueProxyNode) currentField).value();
-            } else {
-                assert currentField instanceof PhiNode && ((PhiNode) currentField).type() == PhiType.Virtual : currentField;
-                currentField = ((PhiNode) currentField).valueAt(0);
-            }
-        } while (currentField != null && dicovered < fieldsCount);
-        return state;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectFieldNode.java	Thu Jun 14 17:10:17 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,90 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.virtual;
-
-import java.util.*;
-
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-
-public class VirtualObjectFieldNode extends ValueNode implements LIRLowerable {
-
-    @Input private VirtualObjectNode object;
-    @Input private ValueNode lastState;
-    @Input private ValueNode input;
-
-    private int index;
-
-    public VirtualObjectNode object() {
-        return object;
-    }
-
-    public ValueNode lastState() {
-        return lastState;
-    }
-
-    public ValueNode input() {
-        return input;
-    }
-
-    public VirtualObjectFieldNode(VirtualObjectNode object, ValueNode lastState, ValueNode input, int index) {
-        super(StampFactory.virtual());
-        this.index = index;
-        this.object = object;
-        this.lastState = lastState;
-        this.input = input;
-    }
-
-    public int index() {
-        return index;
-    }
-
-    @Override
-    public void generate(LIRGeneratorTool gen) {
-        // nothing to do...
-    }
-
-    @Override
-    public boolean verify() {
-        assertTrue(object != null, "No object");
-        assertTrue(input != null, "No input");
-        return super.verify();
-    }
-
-    @Override
-    public Map<Object, Object> getDebugProperties() {
-        Map<Object, Object> properties = super.getDebugProperties();
-        properties.put("index", index);
-        return properties;
-    }
-
-    @Override
-    public String toString(Verbosity verbosity) {
-        if (verbosity == Verbosity.Name && object() != null && object().fields() != null) {
-            return super.toString(Verbosity.Name) + " " + object().fields()[index].name();
-        } else {
-            return super.toString(verbosity);
-        }
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java	Thu Jun 14 17:10:17 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java	Thu Jun 14 17:10:49 2012 +0200
@@ -23,12 +23,11 @@
 package com.oracle.graal.nodes.virtual;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
-
-public class VirtualObjectNode extends ValueNode implements LIRLowerable {
+public class VirtualObjectNode extends FloatingNode implements LIRLowerable {
 
     private ResolvedJavaType type;
     private EscapeField[] fields;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectState.java	Thu Jun 14 17:10:49 2012 +0200
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2009, 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.virtual;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+
+/**
+ * This class encapsulated the virtual state of an escape analyzed object.
+ */
+public final class VirtualObjectState extends VirtualState implements Node.IterableNodeType, LIRLowerable {
+
+    @Input private VirtualObjectNode object;
+    @Input private NodeInputList<ValueNode> fields;
+
+    public VirtualObjectNode object() {
+        return object;
+    }
+
+    public NodeInputList<ValueNode> fields() {
+        return fields;
+    }
+
+    public VirtualObjectState(VirtualObjectNode object, ValueNode[] fields) {
+        this.object = object;
+        assert object.fields().length == fields.length;
+        this.fields = new NodeInputList<>(this, fields);
+    }
+
+    @Override
+    public void generate(LIRGeneratorTool generator) {
+        // Nothing to do, virtual object states are processed as part of the handling of StateSplit nodes.
+    }
+}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/GraalIntrinsics.java	Thu Jun 14 17:10:17 2012 +0200
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/GraalIntrinsics.java	Thu Jun 14 17:10:49 2012 +0200
@@ -22,20 +22,18 @@
  */
 package com.oracle.graal.snippets;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.compiler.*;
-import com.oracle.graal.cri.*;
 
 /**
  * Definition of the snippets that are VM-independent and can be intrinsified by Graal in any VM.
  */
 public class GraalIntrinsics {
-    public static void installIntrinsics(ExtendedRiRuntime runtime, TargetDescription target) {
+    public static void installIntrinsics(SnippetInstaller installer) {
         if (GraalOptions.Intrinsify) {
-            Snippets.install(runtime, target, new MathSnippetsX86());
-            Snippets.install(runtime, target, new DoubleSnippets());
-            Snippets.install(runtime, target, new FloatSnippets());
-            Snippets.install(runtime, target, new NodeClassSnippets());
+            installer.install(MathSnippetsX86.class);
+            installer.install(DoubleSnippets.class);
+            installer.install(FloatSnippets.class);
+            installer.install(NodeClassSnippets.class);
         }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java	Thu Jun 14 17:10:49 2012 +0200
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.snippets;
+
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.concurrent.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.*;
+import com.oracle.graal.compiler.phases.*;
+import com.oracle.graal.compiler.util.*;
+import com.oracle.graal.cri.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.java.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.snippets.Snippet.InliningPolicy;
+
+/**
+ * Utility for snippet {@linkplain #install(Class) installation}.
+ */
+public class SnippetInstaller {
+
+    private final ExtendedRiRuntime runtime;
+    private final TargetDescription target;
+    private final BoxingMethodPool pool;
+
+    /**
+     * A graph cache used by this installer to avoid using the compiler
+     * storage for each method processed during snippet installation.
+     * Without this, all processed methods are to be determined as
+     * {@linkplain IntrinsificationPhase#canIntrinsify intrinsifiable}.
+     */
+    private final Map<ResolvedJavaMethod, StructuredGraph> graphCache;
+
+    public SnippetInstaller(ExtendedRiRuntime runtime, TargetDescription target) {
+        this.runtime = runtime;
+        this.target = target;
+        this.pool = new BoxingMethodPool(runtime);
+        this.graphCache = new HashMap<>();
+    }
+
+    /**
+     * Finds all the snippet methods in a given class, builds a graph for them and
+     * installs the graph with the key value of {@code Graph.class} in the
+     * {@linkplain ResolvedJavaMethod#compilerStorage() compiler storage} of each method.
+     * <p>
+     * If {@code snippetsHolder} is annotated with {@link ClassSubstitution}, then all
+     * methods in the class are snippets. Otherwise, the snippets are those methods
+     * annotated with {@link Snippet}.
+     */
+    public void install(Class<? extends SnippetsInterface> snippetsHolder) {
+        if (snippetsHolder.isAnnotationPresent(ClassSubstitution.class)) {
+            installSubstitutions(snippetsHolder, snippetsHolder.getAnnotation(ClassSubstitution.class).value());
+        } else {
+            installSnippets(snippetsHolder);
+        }
+    }
+
+    private void installSnippets(Class< ? extends SnippetsInterface> clazz) {
+        for (Method method : clazz.getDeclaredMethods()) {
+            if (method.getAnnotation(Snippet.class) != null) {
+                int modifiers = method.getModifiers();
+                if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) {
+                    throw new RuntimeException("Snippet must not be abstract or native");
+                }
+                ResolvedJavaMethod snippet = runtime.getResolvedJavaMethod(method);
+                assert snippet.compilerStorage().get(Graph.class) == null;
+                StructuredGraph graph = makeGraph(snippet, inliningPolicy(snippet));
+                //System.out.println("snippet: " + graph);
+                snippet.compilerStorage().put(Graph.class, graph);
+            }
+        }
+    }
+
+    private void installSubstitutions(Class< ? extends SnippetsInterface> clazz, Class<?> originalClazz) {
+        for (Method method : clazz.getDeclaredMethods()) {
+            try {
+                Method originalMethod = originalClazz.getDeclaredMethod(method.getName(), method.getParameterTypes());
+                if (!originalMethod.getReturnType().isAssignableFrom(method.getReturnType())) {
+                    throw new RuntimeException("Snippet has incompatible return type");
+                }
+                int modifiers = method.getModifiers();
+                if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) {
+                    throw new RuntimeException("Snippet must not be abstract or native");
+                }
+                ResolvedJavaMethod snippet = runtime.getResolvedJavaMethod(method);
+                StructuredGraph graph = makeGraph(snippet, inliningPolicy(snippet));
+                //System.out.println("snippet: " + graph);
+                runtime.getResolvedJavaMethod(originalMethod).compilerStorage().put(Graph.class, graph);
+            } catch (NoSuchMethodException e) {
+                throw new GraalInternalError("Could not resolve method in " + originalClazz + " to substitute with " + method, e);
+            }
+        }
+    }
+
+    private static InliningPolicy inliningPolicy(ResolvedJavaMethod method) {
+        Class<? extends InliningPolicy> policyClass = InliningPolicy.class;
+        Snippet snippet = method.getAnnotation(Snippet.class);
+        if (snippet != null) {
+            policyClass = snippet.inlining();
+        }
+        if (policyClass == InliningPolicy.class) {
+            return InliningPolicy.Default;
+        }
+        try {
+            return policyClass.getConstructor().newInstance();
+        } catch (Exception e) {
+            throw new GraalInternalError(e);
+        }
+    }
+
+    private StructuredGraph makeGraph(final ResolvedJavaMethod method, final InliningPolicy policy) {
+        StructuredGraph graph = graphCache.get(method);
+        if (graph == null) {
+            graph = buildGraph(method, policy);
+            //System.out.println("built " + graph);
+            graphCache.put(method, graph);
+        }
+        return graph;
+    }
+
+    private StructuredGraph buildGraph(final ResolvedJavaMethod method, final InliningPolicy policy) {
+        final StructuredGraph graph = new StructuredGraph(method);
+        return Debug.scope("BuildSnippetGraph", new Object[] {method, graph}, new Callable<StructuredGraph>() {
+            @Override
+            public StructuredGraph call() throws Exception {
+                GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault();
+                GraphBuilderPhase graphBuilder = new GraphBuilderPhase(runtime, config, OptimisticOptimizations.NONE);
+                graphBuilder.apply(graph);
+
+                Debug.dump(graph, "%s: %s", method.name(), GraphBuilderPhase.class.getSimpleName());
+
+                new SnippetIntrinsificationPhase(runtime, pool).apply(graph);
+
+                for (Invoke invoke : graph.getInvokes()) {
+                    MethodCallTargetNode callTarget = invoke.callTarget();
+                    ResolvedJavaMethod callee = callTarget.targetMethod();
+                    if (policy.shouldInline(callee, method)) {
+                        StructuredGraph targetGraph = makeGraph(callee, policy);
+                        InliningUtil.inline(invoke, targetGraph, true);
+                        Debug.dump(graph, "after inlining %s", callee);
+                        if (GraalOptions.OptCanonicalizer) {
+                            new WordTypeRewriterPhase(target).apply(graph);
+                            new CanonicalizerPhase(target, runtime, null).apply(graph);
+                        }
+                    }
+                }
+
+                new SnippetIntrinsificationPhase(runtime, pool).apply(graph);
+
+                new WordTypeRewriterPhase(target).apply(graph);
+
+                new DeadCodeEliminationPhase().apply(graph);
+                if (GraalOptions.OptCanonicalizer) {
+                    new CanonicalizerPhase(target, runtime, null).apply(graph);
+                }
+
+                for (LoopEndNode end : graph.getNodes(LoopEndNode.class)) {
+                    end.disableSafepoint();
+                }
+
+                new InsertStateAfterPlaceholderPhase().apply(graph);
+
+                Debug.dump(graph, "%s: Final", method.name());
+
+                return graph;
+            }
+        });
+    }
+}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippets.java	Thu Jun 14 17:10:17 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,164 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.snippets;
-
-import java.lang.reflect.*;
-import java.util.concurrent.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.*;
-import com.oracle.graal.compiler.phases.*;
-import com.oracle.graal.compiler.util.*;
-import com.oracle.graal.cri.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.java.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.snippets.Snippet.InliningPolicy;
-
-/**
- * Utilities for snippet installation and management.
- */
-public class Snippets {
-
-    public static void install(ExtendedRiRuntime runtime, TargetDescription target, SnippetsInterface obj) {
-        Class<? extends SnippetsInterface> clazz = obj.getClass();
-        BoxingMethodPool pool = new BoxingMethodPool(runtime);
-        if (clazz.isAnnotationPresent(ClassSubstitution.class)) {
-            installSubstitution(runtime, target, clazz, pool, clazz.getAnnotation(ClassSubstitution.class).value());
-        } else {
-            installSnippets(runtime, target, clazz, pool);
-        }
-    }
-
-    private static void installSnippets(ExtendedRiRuntime runtime, TargetDescription target, Class< ? extends SnippetsInterface> clazz, BoxingMethodPool pool) {
-        for (Method method : clazz.getDeclaredMethods()) {
-            if (method.getAnnotation(Snippet.class) != null) {
-                Method snippet = method;
-                int modifiers = snippet.getModifiers();
-                if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) {
-                    throw new RuntimeException("Snippet must not be abstract or native");
-                }
-                ResolvedJavaMethod snippetRiMethod = runtime.getResolvedJavaMethod(snippet);
-                if (snippetRiMethod.compilerStorage().get(Graph.class) == null) {
-                    buildSnippetGraph(snippetRiMethod, runtime, target, pool, inliningPolicy(snippetRiMethod));
-                }
-            }
-        }
-    }
-
-    private static InliningPolicy inliningPolicy(ResolvedJavaMethod method) {
-        Class<? extends InliningPolicy> policyClass = InliningPolicy.class;
-        Snippet snippet = method.getAnnotation(Snippet.class);
-        if (snippet != null) {
-            policyClass = snippet.inlining();
-        }
-        if (policyClass == InliningPolicy.class) {
-            return InliningPolicy.Default;
-        }
-        try {
-            return policyClass.getConstructor().newInstance();
-        } catch (Exception e) {
-            throw new GraalInternalError(e);
-        }
-    }
-
-    private static void installSubstitution(ExtendedRiRuntime runtime, TargetDescription target, Class< ? extends SnippetsInterface> clazz,
-                    BoxingMethodPool pool, Class<?> original) throws GraalInternalError {
-        for (Method snippet : clazz.getDeclaredMethods()) {
-            try {
-                Method method = original.getDeclaredMethod(snippet.getName(), snippet.getParameterTypes());
-                if (!method.getReturnType().isAssignableFrom(snippet.getReturnType())) {
-                    throw new RuntimeException("Snippet has incompatible return type");
-                }
-                int modifiers = snippet.getModifiers();
-                if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) {
-                    throw new RuntimeException("Snippet must not be abstract or native");
-                }
-                ResolvedJavaMethod snippetRiMethod = runtime.getResolvedJavaMethod(snippet);
-                StructuredGraph graph = buildSnippetGraph(snippetRiMethod, runtime, target, pool, inliningPolicy(snippetRiMethod));
-                runtime.getResolvedJavaMethod(method).compilerStorage().put(Graph.class, graph);
-            } catch (NoSuchMethodException e) {
-                throw new RuntimeException("Could not resolve method to substitute with: " + snippet.getName(), e);
-            }
-        }
-    }
-
-    private static StructuredGraph buildSnippetGraph(final ResolvedJavaMethod snippetRiMethod, final ExtendedRiRuntime runtime, final TargetDescription target, final BoxingMethodPool pool, final InliningPolicy policy) {
-        final StructuredGraph graph = new StructuredGraph(snippetRiMethod);
-        return Debug.scope("BuildSnippetGraph", new Object[] {snippetRiMethod, graph}, new Callable<StructuredGraph>() {
-            @Override
-            public StructuredGraph call() throws Exception {
-                GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault();
-                GraphBuilderPhase graphBuilder = new GraphBuilderPhase(runtime, config, OptimisticOptimizations.NONE);
-                graphBuilder.apply(graph);
-
-                Debug.dump(graph, "%s: %s", snippetRiMethod.name(), GraphBuilderPhase.class.getSimpleName());
-
-                new SnippetIntrinsificationPhase(runtime, pool).apply(graph);
-
-                for (Invoke invoke : graph.getInvokes()) {
-                    MethodCallTargetNode callTarget = invoke.callTarget();
-                    ResolvedJavaMethod method = callTarget.targetMethod();
-                    if (policy.shouldInline(method, snippetRiMethod)) {
-                        StructuredGraph targetGraph = (StructuredGraph) method.compilerStorage().get(Graph.class);
-                        if (targetGraph == null) {
-                            targetGraph = buildSnippetGraph(method, runtime, target, pool, policy);
-                        }
-                        InliningUtil.inline(invoke, targetGraph, true);
-                        Debug.dump(graph, "after inlining %s", method);
-                        if (GraalOptions.OptCanonicalizer) {
-                            new WordTypeRewriterPhase(target).apply(graph);
-                            new CanonicalizerPhase(target, runtime, null).apply(graph);
-                        }
-                    }
-                }
-
-                new SnippetIntrinsificationPhase(runtime, pool).apply(graph);
-
-                new WordTypeRewriterPhase(target).apply(graph);
-
-                new DeadCodeEliminationPhase().apply(graph);
-                if (GraalOptions.OptCanonicalizer) {
-                    new CanonicalizerPhase(target, runtime, null).apply(graph);
-                }
-
-                for (LoopEndNode end : graph.getNodes(LoopEndNode.class)) {
-                    end.disableSafepoint();
-                }
-
-                new InsertStateAfterPlaceholderPhase().apply(graph);
-
-                Debug.dump(graph, "%s: Final", snippetRiMethod.name());
-
-                snippetRiMethod.compilerStorage().put(Graph.class, graph);
-
-                return graph;
-            }
-        });
-
-    }
-}
--- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphScheduleTest.java	Thu Jun 14 17:10:17 2012 +0200
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphScheduleTest.java	Thu Jun 14 17:10:49 2012 +0200
@@ -40,7 +40,7 @@
         Block aBlock = nodeToBlock.get(a);
 
         if (bBlock == aBlock) {
-            List<Node> instructions = ibp.nodesFor(bBlock);
+            List<ScheduledNode> instructions = ibp.nodesFor(bBlock);
             Assert.assertTrue(instructions.indexOf(b) > instructions.indexOf(a));
         } else {
             Block block = bBlock;
--- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/ScalarTypeSystemTest.java	Thu Jun 14 17:10:17 2012 +0200
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/ScalarTypeSystemTest.java	Thu Jun 14 17:10:49 2012 +0200
@@ -160,17 +160,14 @@
     }
 
     private void test(final String snippet, final String referenceSnippet) {
-        Debug.scope("ScalarTypeSystemTest", new DebugDumpScope(snippet), new Runnable() {
-            public void run() {
-                StructuredGraph graph = parse(snippet);
-                Debug.dump(graph, "Graph");
-//                TypeSystemTest.outputGraph(graph);
-                new CanonicalizerPhase(null, runtime(), null).apply(graph);
-                new CheckCastEliminationPhase().apply(graph);
-                new CanonicalizerPhase(null, runtime(), null).apply(graph);
-                StructuredGraph referenceGraph = parse(referenceSnippet);
-                assertEquals(referenceGraph, graph);
-            }
-        });
+        // No debug scope to reduce console noise for @Test(expected = ...) tests
+        StructuredGraph graph = parse(snippet);
+        Debug.dump(graph, "Graph");
+//        TypeSystemTest.outputGraph(graph);
+        new CanonicalizerPhase(null, runtime(), null).apply(graph);
+        new CheckCastEliminationPhase().apply(graph);
+        new CanonicalizerPhase(null, runtime(), null).apply(graph);
+        StructuredGraph referenceGraph = parse(referenceSnippet);
+        assertEquals(referenceGraph, graph);
     }
 }
--- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/StraighteningTest.java	Thu Jun 14 17:10:17 2012 +0200
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/StraighteningTest.java	Thu Jun 14 17:10:49 2012 +0200
@@ -85,14 +85,11 @@
     }
 
     private void test(final String snippet) {
-        Debug.scope("StraighteningTest", new DebugDumpScope(snippet), new Runnable() {
-            public void run() {
-                StructuredGraph graph = parse(snippet);
-                Debug.dump(graph, "Graph");
-                new CanonicalizerPhase(null, runtime(), null).apply(graph);
-                StructuredGraph referenceGraph = parse(REFERENCE_SNIPPET);
-                assertEquals(referenceGraph, graph);
-            }
-        });
+        // No debug scope to reduce console noise for @Test(expected = ...) tests
+        StructuredGraph graph = parse(snippet);
+        Debug.dump(graph, "Graph");
+        new CanonicalizerPhase(null, runtime(), null).apply(graph);
+        StructuredGraph referenceGraph = parse(REFERENCE_SNIPPET);
+        assertEquals(referenceGraph, graph);
     }
 }
--- a/mx/commands.py	Thu Jun 14 17:10:17 2012 +0200
+++ b/mx/commands.py	Thu Jun 14 17:10:49 2012 +0200
@@ -338,6 +338,11 @@
                 for line in lines:
                     f.write(line)
                     
+            # Install a copy of the disassembler library
+            try:
+                hsdis([], copyToDir=_vmLibDirInJdk(jdk))
+            except SystemExit:
+                pass
     else:
         if not exists(jdk):
             mx.abort('The ' + build + ' VM has not been created - run \'mx clean; mx build ' + build + '\'')
@@ -553,11 +558,12 @@
         vm = _vm
         
     build = vmbuild if vmbuild is not None else _vmbuild if _vmSourcesAvailable else 'product'
+    jdk = _jdk(build)
     mx.expand_project_in_args(args)
     if _make_eclipse_launch:
         mx.make_eclipse_launch(args, 'graal-' + build, name=None, deps=mx.project('com.oracle.graal.hotspot').all_deps([], True))
     if len([a for a in args if 'PrintAssembly' in a]) != 0:
-        hsdis([])
+        hsdis([], copyToDir=_vmLibDirInJdk(jdk))
     if mx.java().debug_port is not None:
         args = ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(mx.java().debug_port)] + args
     if _jacoco == 'on' or _jacoco == 'append':
@@ -573,7 +579,7 @@
                         'excludes' : ':'.join(excludes)
         }
         args = ['-javaagent:' + jacocoagent.get_path(True) + '=' + ','.join([k + '=' + v for k, v in agentOptions.items()])] + args
-    exe = join(_jdk(build), 'bin', mx.exe_suffix('java'))
+    exe = join(jdk, 'bin', mx.exe_suffix('java'))
     return mx.run([exe, '-' + vm] + args, nonZeroIsFatal=nonZeroIsFatal, out=out, err=err, cwd=cwd, timeout=timeout)
 
 def _find_classes_with_annotations(classes, p, pkgRoot, annotations, includeInnerClasses=False):
@@ -967,19 +973,20 @@
     vm = _vm;
     sanitycheck.getSPECjvm2008(benchArgs, skipValid, wt, it).bench(vm, opts=vmArgs)
     
-def hsdis(args):
-    """install the hsdis library
+def hsdis(args, copyToDir=None):
+    """downloads the hsdis library
 
     This is needed to support HotSpot's assembly dumping features.
-    By default it installs the Intel syntax version, use the 'att' argument to install AT&T syntax."""
+    By default it downloads the Intel syntax version, use the 'att' argument to install AT&T syntax."""
     flavor = 'intel'
     if 'att' in args:
         flavor = 'att'
-    build = _vmbuild if _vmSourcesAvailable else 'product'
     lib = mx.lib_suffix('hsdis-amd64')
-    path = join(_vmLibDirInJdk(_jdk(build)), lib)
+    path = join(_graal_home, 'lib', lib)
     if not exists(path):
         mx.download(path, ['http://lafo.ssw.uni-linz.ac.at/hsdis/' + flavor + "/" + lib])
+    if copyToDir is not None and exists(copyToDir):
+        shutil.copy(path, copyToDir)
     
 def hcfdis(args):
     """disassembles HexCodeFiles embedded in text files
--- a/src/cpu/x86/vm/c1_Runtime1_x86.cpp	Thu Jun 14 17:10:17 2012 +0200
+++ b/src/cpu/x86/vm/c1_Runtime1_x86.cpp	Thu Jun 14 17:10:49 2012 +0200
@@ -1885,6 +1885,30 @@
       break;
     }
 
+    case graal_log_primitive_id: {
+      __ enter();
+      oop_maps = new OopMapSet();
+      OopMap* oop_map = save_live_registers(sasm, 0);
+      int call_offset = __ call_RT(noreg, noreg, (address)graal_log_primitive, j_rarg0, j_rarg1, j_rarg2);
+      oop_maps->add_gc_map(call_offset, oop_map);
+      restore_live_registers(sasm);
+      __ leave();
+      __ ret(0);
+      break;
+    }
+
+    case graal_log_object_id: {
+      __ enter();
+      oop_maps = new OopMapSet();
+      OopMap* oop_map = save_live_registers(sasm, 0);
+      int call_offset = __ call_RT(noreg, noreg, (address)graal_log_object, j_rarg0, j_rarg1, j_rarg2);
+      oop_maps->add_gc_map(call_offset, oop_map);
+      restore_live_registers(sasm);
+      __ leave();
+      __ ret(0);
+      break;
+    }
+
     case graal_generic_callback_id: {
     __ enter();
     oop_maps = new OopMapSet();
--- a/src/share/vm/c1/c1_Runtime1.cpp	Thu Jun 14 17:10:17 2012 +0200
+++ b/src/share/vm/c1/c1_Runtime1.cpp	Thu Jun 14 17:10:49 2012 +0200
@@ -212,8 +212,6 @@
     case graal_arithmetic_frem_id:
     case graal_arithmetic_drem_id:
     case graal_set_deopt_info_id:
-    case graal_log_primitive_id:
-    case graal_log_object_id:
 #endif
       break;
 
@@ -751,22 +749,29 @@
     int          length = java_lang_String::length(obj);
 
     if (length != 0) {
+      int printLength = MIN2(length, 1024);
       if (value == NULL) {
         // This can happen if, e.g., printing a String
         // object before its initializer has been called
         tty->print("null");
-      } else if (length < 256 - 1) {
+      } else if (printLength < 256 - 1) {
         // Use an intermediate buffer to try and prevent interlacing of multi-threaded output
         char buf[256];
-        for (int index = 0; index < length; index++) {
+        for (int index = 0; index < printLength; index++) {
           buf[index] = value->char_at(index + offset);
         }
-        buf[length] = 0;
+        buf[printLength] = 0;
         tty->print("%s", buf);
+        if (printLength < length) {
+          tty->print("... (%d more)", length - printLength);
+        }
       } else {
-        for (int index = 0; index < length; index++) {
+        for (int index = 0; index < printLength; index++) {
           tty->print("%c", value->char_at(index + offset));
         }
+        if (printLength < length) {
+          tty->print("... (%d more)", length - printLength);
+        }
       }
     }
   }