changeset 5604:46f8a4c46b6a

Merge.
author Doug Simon <doug.simon@oracle.com>
date Thu, 14 Jun 2012 16:25:54 +0200
parents dbd82d1edce6 (current diff) a9b615da0cba (diff)
children f8eb2cb76a2f
files graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectFieldNode.java
diffstat 18 files changed, 174 insertions(+), 410 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Thu Jun 14 16:20:59 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Thu Jun 14 16:25:54 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/loop/LoopFragment.java	Thu Jun 14 16:20:59 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopFragment.java	Thu Jun 14 16:25:54 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 {
@@ -244,14 +243,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 16:20:59 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopFragmentInside.java	Thu Jun 14 16:25:54 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 16:20:59 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/BoxingEliminationPhase.java	Thu Jun 14 16:25:54 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 16:20:59 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java	Thu Jun 14 16:25:54 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 16:20:59 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/InsertStateAfterPlaceholderPhase.java	Thu Jun 14 16:25:54 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 16:20:59 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/schedule/SchedulePhase.java	Thu Jun 14 16:25:54 2012 +0200
@@ -130,7 +130,7 @@
         Block block;
         if (latestBlock == null) {
             block = earliestBlock(node);
-        } else if (GraalOptions.ScheduleOutOfLoops && !(node instanceof VirtualObjectFieldNode) && !(node instanceof VirtualObjectNode)) {
+        } 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 + ")";
@@ -260,22 +260,26 @@
                     closure.apply(mergeBlock.getPredecessors().get(i));
                 }
             }
-        } else if (usage instanceof FrameState) {
+        } 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 frameStateUsage : usage.usages()) {
-                if (frameStateUsage instanceof FrameState) {
+            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, frameStateUsage, closure);
-                } else if (frameStateUsage instanceof MergeNode) {
+                    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 : frameStateUsage.cfgPredecessors()) {
+                    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.
-                    assert frameStateUsage instanceof StateSplit;
-                    assignBlockToNode((ScheduledNode) frameStateUsage);
-                    closure.apply(cfg.getNodeToBlock().get(frameStateUsage));
+                    assignBlockToNode((ScheduledNode) unscheduledUsage);
+                    closure.apply(cfg.getNodeToBlock().get(unscheduledUsage));
                 }
             }
         } else {
@@ -351,13 +355,14 @@
         blockToNodesMap.put(b, sortedInstructions);
     }
 
-    private void addFrameStateToSorting(Block b, FrameState state, List<ScheduledNode> sortedInstructions, NodeBitMap visited) {
+    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 FrameState) {
-                    addFrameStateToSorting(b, (FrameState) input, sortedInstructions, visited);
+                if (input instanceof VirtualState) {
+                    addUnscheduledToSorting(b, (VirtualState) input, sortedInstructions, visited);
                 } else {
                     addToSorting(b, (ScheduledNode) input, sortedInstructions, visited);
                 }
@@ -386,7 +391,7 @@
 
         addToSorting(b, (ScheduledNode) i.predecessor(), sortedInstructions, visited);
         visited.mark(i);
-        addFrameStateToSorting(b, state, sortedInstructions, visited);
+        addUnscheduledToSorting(b, state, sortedInstructions, visited);
         assert write == null || !visited.isMarked(write);
         addToSorting(b, write, sortedInstructions, visited);
 
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java	Thu Jun 14 16:20:59 2012 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java	Thu Jun 14 16:25:54 2012 +0200
@@ -21,11 +21,7 @@
  * questions.
  */
 package com.oracle.graal.graph;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.ListIterator;
+import java.util.*;
 
 import com.oracle.graal.graph.iterators.*;
 
@@ -60,6 +56,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();
             }
         }
     }
@@ -75,6 +72,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.nodes/src/com/oracle/graal/nodes/CallTargetNode.java	Thu Jun 14 16:20:59 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java	Thu Jun 14 16:25:54 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 16:20:59 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Thu Jun 14 16:25:54 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 16:20:59 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Thu Jun 14 16:25:54 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 16:20:59 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ScheduledNode.java	Thu Jun 14 16:25:54 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 16:25:54 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/spi/EscapeOp.java	Thu Jun 14 16:20:59 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeOp.java	Thu Jun 14 16:25:54 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 16:20:59 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Thu Jun 14 16:25:54 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();
@@ -221,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 16:20:59 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 16:20:59 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java	Thu Jun 14 16:25:54 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 16:25:54 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.
+    }
+}