changeset 3168:adbb7bca84b7

Merge.
author Thomas Wuerthinger <thomas@wuerthinger.net>
date Wed, 06 Jul 2011 17:02:38 +0200
parents 132aa6f2bbc0 (current diff) ce7e5b3798f7 (diff)
children af4955a7ffc2
files graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameState.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameStateBuilder.java
diffstat 24 files changed, 900 insertions(+), 555 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScan.java	Wed Jul 06 17:02:15 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScan.java	Wed Jul 06 17:02:38 2011 +0200
@@ -26,6 +26,7 @@
 import static java.lang.reflect.Modifier.*;
 
 import java.util.*;
+import java.util.Map.Entry;
 
 import com.oracle.max.graal.compiler.*;
 import com.oracle.max.graal.compiler.alloc.Interval.*;
@@ -1837,117 +1838,162 @@
         }
     }
 
-    CiValue toCiValue(int opId, Value value) {
-        if (value instanceof VirtualObject) {
-            return toCiVirtualObject(opId, (VirtualObject) value);
-        } else if (value != null && value.operand() != CiValue.IllegalValue) {
-            CiValue operand = value.operand();
-            Constant con = null;
-            if (value instanceof Constant) {
-                con = (Constant) value;
-            }
+    private class DebugFrameBuilder {
+
+        private final FrameState topState;
+        private final int opId;
+        private final BitMap frameRefMap;
 
-            assert con == null || operand.isVariable() || operand.isConstant() || operand.isIllegal() : "Constant instructions have only constant operands (or illegal if constant is optimized away)";
+        private HashMap<VirtualObject, CiVirtualObject> virtualObjects;
+
+        public DebugFrameBuilder(FrameState topState, int opId, BitMap frameRefMap) {
+            this.topState = topState;
+            this.opId = opId;
+            this.frameRefMap = frameRefMap;
+        }
 
-            if (operand.isVariable()) {
-                OperandMode mode = OperandMode.Input;
-                LIRBlock block = blockForId(opId);
-                if (block.numberOfSux() == 1 && opId == block.lastLirInstructionId()) {
-                    // generating debug information for the last instruction of a block.
-                    // if this instruction is a branch, spill moves are inserted before this branch
-                    // and so the wrong operand would be returned (spill moves at block boundaries are not
-                    // considered in the live ranges of intervals)
-                    // Solution: use the first opId of the branch target block instead.
-                    final LIRInstruction instr = block.lir().instructionsList().get(block.lir().instructionsList().size() - 1);
-                    if (instr instanceof LIRBranch) {
-                        if (block.liveOut.get(operandNumber(operand))) {
-                            opId = block.suxAt(0).firstLirInstructionId();
-                            mode = OperandMode.Output;
-                        }
-                    }
+        private CiValue toCiValue(Value value) {
+            if (value instanceof VirtualObject) {
+                if (virtualObjects == null) {
+                    virtualObjects = new HashMap<VirtualObject, CiVirtualObject>();
+                }
+                VirtualObject obj = (VirtualObject) value;
+                CiVirtualObject ciObj = virtualObjects.get(value);
+                if (ciObj == null) {
+                    ciObj = CiVirtualObject.get(obj.type(), null, value.id());
+                    virtualObjects.put(obj, ciObj);
+                }
+                return ciObj;
+            } else if (value != null && value.operand() != CiValue.IllegalValue) {
+                CiValue operand = value.operand();
+                Constant con = null;
+                if (value instanceof Constant) {
+                    con = (Constant) value;
                 }
 
-                // Get current location of operand
-                // The operand must be live because debug information is considered when building the intervals
-                // if the interval is not live, colorLirOperand will cause an assert on failure
-                operand = colorLirOperand((CiVariable) operand, opId, mode);
-                assert !hasCall(opId) || operand.isStackSlot() || !isCallerSave(operand) : "cannot have caller-save register operands at calls";
-                return operand;
-            } else if (operand.isRegister()) {
-                assert false : "must not reach here";
-                return operand;
+                assert con == null || operand.isVariable() || operand.isConstant() || operand.isIllegal() : "Constant instructions have only constant operands (or illegal if constant is optimized away)";
+
+                int tempOpId = this.opId;
+                if (operand.isVariable()) {
+                    OperandMode mode = OperandMode.Input;
+                    LIRBlock block = blockForId(tempOpId);
+                    if (block.numberOfSux() == 1 && tempOpId == block.lastLirInstructionId()) {
+                        // generating debug information for the last instruction of a block.
+                        // if this instruction is a branch, spill moves are inserted before this branch
+                        // and so the wrong operand would be returned (spill moves at block boundaries are not
+                        // considered in the live ranges of intervals)
+                        // Solution: use the first opId of the branch target block instead.
+                        final LIRInstruction instr = block.lir().instructionsList().get(block.lir().instructionsList().size() - 1);
+                        if (instr instanceof LIRBranch) {
+                            if (block.liveOut.get(operandNumber(operand))) {
+                                tempOpId = block.suxAt(0).firstLirInstructionId();
+                                mode = OperandMode.Output;
+                            }
+                        }
+                    }
+
+                    // Get current location of operand
+                    // The operand must be live because debug information is considered when building the intervals
+                    // if the interval is not live, colorLirOperand will cause an assert on failure
+                    operand = colorLirOperand((CiVariable) operand, tempOpId, mode);
+                    assert !hasCall(tempOpId) || operand.isStackSlot() || !isCallerSave(operand) : "cannot have caller-save register operands at calls";
+                    return operand;
+                } else if (operand.isRegister()) {
+                    assert false : "must not reach here";
+                    return operand;
+                } else {
+                    assert value instanceof Constant;
+                    assert operand.isConstant() : "operand must be constant";
+                    return operand;
+                }
             } else {
-                assert value instanceof Constant;
-                assert operand.isConstant() : "operand must be constant";
-                return operand;
+                // return a dummy value because real value not needed
+                return CiValue.IllegalValue;
             }
-        } else {
-            // return a dummy value because real value not needed
-            return CiValue.IllegalValue;
         }
-    }
 
-    private CiVirtualObject toCiVirtualObject(int opId, VirtualObject obj) {
-        RiType type = obj.type();
-        EscapeField[] escapeFields = obj.fields();
-        CiValue[] values = new CiValue[escapeFields.length];
-        int valuesFilled = 0;
+        private CiFrame computeFrameForState(FrameState state) {
+            CiValue[] values = new CiValue[state.valuesSize() + state.locksSize()];
+            int valueIndex = 0;
+
+            for (int i = 0; i < state.valuesSize(); i++) {
+                values[valueIndex++] = toCiValue(state.valueAt(i));
+            }
 
-        VirtualObject current = obj;
-        do {
-            boolean found = false;
-            for (int i = 0; i < escapeFields.length; i++) {
-                if (escapeFields[i].representation() == current.field().representation()) {
-                    if (values[i] == null) {
-                        values[i] = toCiValue(opId, current.input());
-                        valuesFilled++;
+            for (int i = 0; i < state.locksSize(); i++) {
+                if (compilation.runtime.sizeOfBasicObjectLock() != 0) {
+                    CiStackSlot monitorAddress = frameMap.toMonitorBaseStackAddress(i);
+                    values[valueIndex++] = monitorAddress;
+                    CiStackSlot objectAddress = frameMap.toMonitorObjectStackAddress(i);
+                    frameRefMap.set(objectAddress.index());
+                } else {
+                    Value lock = state.lockAt(i);
+                    if (lock.isConstant() && compilation.runtime.asJavaClass(lock.asConstant()) != null) {
+                        // lock on class for synchronized static method
+                        values[valueIndex++] = lock.asConstant();
+                    } else {
+                        values[valueIndex++] = toCiValue(lock);
                     }
-                    found = true;
-                    break;
                 }
             }
-            assert found : type + "." + current.field() + " not found";
-            current = current.object();
-        } while (current != null && valuesFilled < values.length);
-
-        for (int i = 0; i < escapeFields.length; i++) {
-            assert values[i] != null : type + "." + escapeFields[i];
-        }
-
-        return CiVirtualObject.get(type, values, obj.id());
-    }
-
-    CiFrame computeFrameForState(FrameState state, int opId, BitMap frameRefMap) {
-        CiValue[] values = new CiValue[state.valuesSize() + state.locksSize()];
-        int valueIndex = 0;
-
-        for (int i = 0; i < state.valuesSize(); i++) {
-            values[valueIndex++] = toCiValue(opId, state.valueAt(i));
+            CiFrame caller = null;
+            if (state.outerFrameState() != null) {
+                caller = computeFrameForState(state.outerFrameState());
+            }
+            return new CiFrame(caller, state.method, state.bci, state.rethrowException(), values, state.localsSize(), state.stackSize(), state.locksSize());
         }
 
-        for (int i = 0; i < state.locksSize(); i++) {
-            if (compilation.runtime.sizeOfBasicObjectLock() != 0) {
-                CiStackSlot monitorAddress = frameMap.toMonitorBaseStackAddress(i);
-                values[valueIndex++] = monitorAddress;
-                assert frameRefMap != null;
-                CiStackSlot objectAddress = frameMap.toMonitorObjectStackAddress(i);
-//                LIRDebugInfo.setBit(frameRefMap, objectAddress.index());
-                frameRefMap.set(objectAddress.index());
-            } else {
-                Value lock = state.lockAt(i);
-                if (lock.isConstant() && compilation.runtime.asJavaClass(lock.asConstant()) != null) {
-                   // lock on class for synchronized static method
-                   values[valueIndex++] = lock.asConstant();
-                } else {
-                   values[valueIndex++] = toCiValue(opId, lock);
-                }
+        public CiFrame build() {
+            CiFrame frame = computeFrameForState(topState);
+
+            if (virtualObjects != null) {
+                // collect all VirtualObjectField instances:
+                HashMap<VirtualObject, VirtualObjectField> objectStates = new HashMap<VirtualObject, VirtualObjectField>();
+                FrameState current = topState;
+                do {
+                    for (Node n : current.inputs().variablePart()) {
+                        VirtualObjectField field = (VirtualObjectField) n;
+                        // null states occur for objects with 0 fields
+                        if (field != null && !objectStates.containsKey(field.object())) {
+                            objectStates.put(field.object(), field);
+                        }
+                    }
+                    current = current.outerFrameState();
+                } while (current != null);
+                // fill in the CiVirtualObject values:
+                // during this process new CiVirtualObjects might be discovered, so repeat until no more changes occur.
+                boolean changed;
+                do {
+                    changed = false;
+                    HashMap<VirtualObject, CiVirtualObject> virtualObjectsCopy = new HashMap<VirtualObject, CiVirtualObject>(virtualObjects);
+                    for (Entry<VirtualObject, CiVirtualObject> entry : virtualObjectsCopy.entrySet()) {
+                        if (entry.getValue().values() == null) {
+                            VirtualObject vobj = entry.getKey();
+                            CiValue[] values = new CiValue[vobj.fields().length];
+                            entry.getValue().setValues(values);
+                            if (vobj.fields().length > 0) {
+                                changed = true;
+                                FloatingNode currentField = objectStates.get(vobj);
+                                assert currentField != null;
+                                do {
+                                    if (currentField instanceof VirtualObjectField) {
+                                        int index = ((VirtualObjectField) currentField).index();
+                                        if (values[index] == null) {
+                                            values[index] = toCiValue(((VirtualObjectField) currentField).input());
+                                        }
+                                        currentField = ((VirtualObjectField) currentField).lastState();
+                                    } else {
+                                        assert currentField instanceof Phi : currentField;
+                                        currentField = (FloatingNode) ((Phi) currentField).valueAt(0);
+                                    }
+                                } while (currentField != null);
+                            }
+                        }
+                    }
+                } while (changed);
             }
+            return frame;
         }
-        CiFrame caller = null;
-        if (state.outerFrameState() != null) {
-            caller = computeFrameForState(state.outerFrameState(), opId, frameRefMap);
-        }
-        return new CiFrame(caller, state.method, state.bci, state.rethrowException(), values, state.localsSize(), state.stackSize(), state.locksSize());
     }
 
     private void computeDebugInfo(IntervalWalker iw, LIRInstruction op) {
@@ -1983,7 +2029,7 @@
         if (GraalOptions.TraceLinearScanLevel >= 3) {
             TTY.println("creating debug information at opId %d", opId);
         }
-        return computeFrameForState(state, opId, frameRefMap);
+        return new DebugFrameBuilder(state, opId, frameRefMap).build();
     }
 
     private void assignLocations(List<LIRInstruction> instructions, IntervalWalker iw) {
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/IdealGraphPrinterObserver.java	Wed Jul 06 17:02:15 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/IdealGraphPrinterObserver.java	Wed Jul 06 17:02:38 2011 +0200
@@ -109,7 +109,7 @@
                 return;
             }
 
-            printer = new IdealGraphPrinter(stream);
+            printer = new IdealGraphPrinter(new BufferedOutputStream(stream));
             if (GraalOptions.OmitDOTFrameStates) {
                 printer.addOmittedClass(FrameState.class);
             }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java	Wed Jul 06 17:02:15 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java	Wed Jul 06 17:02:38 2011 +0200
@@ -39,9 +39,11 @@
 import com.oracle.max.graal.compiler.graph.*;
 import com.oracle.max.graal.compiler.ir.*;
 import com.oracle.max.graal.compiler.ir.Deoptimize.DeoptAction;
+import com.oracle.max.graal.compiler.ir.Phi.PhiType;
 import com.oracle.max.graal.compiler.lir.*;
 import com.oracle.max.graal.compiler.util.*;
 import com.oracle.max.graal.compiler.value.*;
+import com.oracle.max.graal.compiler.value.FrameState.ValueProcedure;
 import com.oracle.max.graal.graph.*;
 import com.sun.cri.bytecode.Bytecodes.MemoryBarriers;
 import com.sun.cri.ci.*;
@@ -757,7 +759,7 @@
         for (Node n : fixedGuard.inputs()) {
             if (n != null) {
                 emitGuardComp((BooleanNode) n);
-            }
+    }
         }
     }
 
@@ -781,14 +783,14 @@
             if (comp instanceof Constant && comp.asConstant().asBoolean()) {
                 // Nothing to emit.
             } else {
-                if (deoptimizationStubs == null) {
-                    deoptimizationStubs = new ArrayList<DeoptimizationStub>();
-                }
+            if (deoptimizationStubs == null) {
+                deoptimizationStubs = new ArrayList<DeoptimizationStub>();
+            }
 
-                DeoptimizationStub stub = new DeoptimizationStub(DeoptAction.InvalidateReprofile, state);
-                deoptimizationStubs.add(stub);
-                emitBooleanBranch(comp, null, new LIRBlock(stub.label, stub.info), stub.info);
-            }
+            DeoptimizationStub stub = new DeoptimizationStub(DeoptAction.InvalidateReprofile, state);
+            deoptimizationStubs.add(stub);
+            emitBooleanBranch(comp, null, new LIRBlock(stub.label, stub.info), stub.info);
+        }
         }
     }
 
@@ -1093,7 +1095,7 @@
             lastState = fs;
         } else if (block.blockPredecessors().size() == 1) {
             FrameState fs = block.blockPredecessors().get(0).lastState();
-            //assert fs != null : "B" + block.blockID() + ", pred=B" + block.blockPredecessors().get(0).blockID();
+            assert fs != null;
             if (GraalOptions.TraceLIRGeneratorLevel >= 2) {
                 TTY.println("STATE CHANGE (singlePred)");
                 if (GraalOptions.TraceLIRGeneratorLevel >= 3) {
@@ -1513,7 +1515,7 @@
         int nextSuccIndex = merge.phiPredecessorIndex(pred);
         PhiResolver resolver = new PhiResolver(this);
         for (Phi phi : merge.phis()) {
-            if (!phi.isDead()) {
+            if (phi.type() == PhiType.Value) {
                 Value curVal = phi.valueAt(nextSuccIndex);
                 if (curVal != null && curVal != phi) {
                     if (curVal instanceof Phi) {
@@ -1575,7 +1577,7 @@
     }
 
     private CiValue operandForPhi(Phi phi) {
-        assert !phi.isDead() : "dead phi: " + phi.id();
+        assert phi.type() == PhiType.Value : "wrong phi type: " + phi.id();
         if (phi.operand().isIllegal()) {
             // allocate a variable for this phi
             createResultVariable(phi);
@@ -1631,57 +1633,25 @@
         }
     }
 
-    protected void walkState(Node x, FrameState state) {
+    protected void walkState(final Node x, FrameState state) {
         if (state == null) {
             return;
         }
 
-        walkState(x, state.outerFrameState());
-
-        for (int index = 0; index < state.stackSize(); index++) {
-            Value value = state.stackAt(index);
-            if (value != x) {
-                walkStateValue(value);
-            }
-        }
-        for (int index = 0; index < state.localsSize(); index++) {
-            final Value value = state.localAt(index);
-            if (value != null) {
-                if (!(value instanceof Phi && ((Phi) value).isDead())) {
-                    walkStateValue(value);
+        state.forEachLiveStateValue(new ValueProcedure() {
+            public void doValue(Value value) {
+                if (value == x) {
+                    // nothing to do, will be visited shortly
+                } else if (value instanceof Phi && ((Phi) value).type() == PhiType.Value) {
+                    // phi's are special
+                    operandForPhi((Phi) value);
+                } else if (value.operand().isIllegal()) {
+                    // instruction doesn't have an operand yet
+                    CiValue operand = makeOperand(value);
+                    assert operand.isLegal() : "must be evaluated now";
                 }
             }
-        }
-    }
-
-    private void walkStateValue(Value value) {
-        if (value != null) {
-            if (value instanceof VirtualObject) {
-                walkVirtualObject((VirtualObject) value);
-            } else if (value instanceof Phi && !((Phi) value).isDead()) {
-                // phi's are special
-                operandForPhi((Phi) value);
-            } else if (value.operand().isIllegal()) {
-                // instruction doesn't have an operand yet
-                CiValue operand = makeOperand(value);
-                assert operand.isLegal() : "must be evaluated now";
-            }
-        }
-    }
-
-    private void walkVirtualObject(VirtualObject value) {
-        if (value.input() instanceof Phi) {
-            assert !((Phi) value.input()).isDead();
-        }
-        HashSet<Object> fields = new HashSet<Object>();
-        VirtualObject obj = value;
-        do {
-            if (!fields.contains(obj.field().representation())) {
-                fields.add(obj.field().representation());
-                walkStateValue(obj.input());
-            }
-            obj = obj.object();
-        } while (obj != null);
+        });
     }
 
     protected LIRDebugInfo stateFor(Value x) {
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/PhiSimplifier.java	Wed Jul 06 17:02:15 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/PhiSimplifier.java	Wed Jul 06 17:02:38 2011 +0200
@@ -62,9 +62,6 @@
         } else if (visited.isMarked(phi)) {
             // break cycles in phis
             return phi;
-        } else if (phi.isDead()) {
-            // don't bother with illegals
-            return phi;
         } else {
             // attempt to simplify the phi by recursively simplifying its operands
             visited.mark(phi);
@@ -74,20 +71,20 @@
             for (int i = 0; i < max; i++) {
                 Value oldInstr = phi.valueAt(i);
 
-                if (oldInstr == null || (oldInstr instanceof Phi && ((Phi) oldInstr).isDead())) {
+                if (oldInstr == null) {
                     // if one operand is illegal, make the entire phi illegal
-                    phi.makeDead();
                     visited.clear(phi);
-                    return phi;
+                    phi.replaceAndDelete(null);
+                    return null;
                 }
 
                 Value newInstr = simplify(oldInstr);
 
-                if (newInstr == null || (newInstr instanceof Phi && ((Phi) newInstr).isDead())) {
+                if (newInstr == null) {
                     // if the subst instruction is illegal, make the entire phi illegal
-                    phi.makeDead();
                     visited.clear(phi);
-                    return phi;
+                    phi.replaceAndDelete(null);
+                    return null;
                 }
 
                 // attempt to simplify this operand
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/CheckCast.java	Wed Jul 06 17:02:15 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/CheckCast.java	Wed Jul 06 17:02:38 2011 +0200
@@ -23,6 +23,7 @@
 package com.oracle.max.graal.compiler.ir;
 
 import com.oracle.max.graal.compiler.debug.*;
+import com.oracle.max.graal.compiler.phases.CanonicalizerPhase.CanonicalizerOp;
 import com.oracle.max.graal.graph.*;
 import com.sun.cri.bytecode.*;
 import com.sun.cri.ci.*;
@@ -93,4 +94,27 @@
     public Node copy(Graph into) {
         return new CheckCast(null, null, into);
     }
+
+    private static CanonicalizerOp CANONICALIZER = new CanonicalizerOp() {
+        @Override
+        public Node canonical(Node node) {
+            CheckCast checkCast = (CheckCast) node;
+            Value object = checkCast.object();
+            RiType exactType = object.exactType();
+            if (exactType != null) {
+                return Constant.forBoolean(exactType.isSubtypeOf(checkCast.targetClass()), node.graph());
+            }
+            CiConstant constant = object.asConstant();
+            if (constant != null) {
+                assert constant.kind == CiKind.Object;
+                if (constant.isNull()) {
+                    return Constant.forBoolean(true, node.graph());
+                } else {
+                    // this should never happen - non-null constants are always expected to provide an exactType
+                    assert false;
+                }
+            }
+            return checkCast;
+        }
+    };
 }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/CreateVectorNode.java	Wed Jul 06 17:02:15 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/CreateVectorNode.java	Wed Jul 06 17:02:38 2011 +0200
@@ -26,6 +26,7 @@
 
 import com.oracle.max.graal.compiler.debug.*;
 import com.oracle.max.graal.compiler.gen.*;
+import com.oracle.max.graal.compiler.ir.Phi.PhiType;
 import com.oracle.max.graal.compiler.phases.LoweringPhase.*;
 import com.oracle.max.graal.graph.*;
 import com.sun.cri.ci.*;
@@ -98,7 +99,7 @@
         EndNode end = new EndNode(graph());
         LoopBegin loopBegin = new LoopBegin(graph());
         loopBegin.addEnd(end);
-        Phi loopVariable = new Phi(CiKind.Int, loopBegin, graph());
+        Phi loopVariable = new Phi(CiKind.Int, loopBegin, PhiType.Value, graph());
 
         if (reversed) {
             IntegerSub add = new IntegerSub(CiKind.Int, loopVariable, Constant.forInt(1, graph()), graph());
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/InstanceOf.java	Wed Jul 06 17:02:15 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/InstanceOf.java	Wed Jul 06 17:02:38 2011 +0200
@@ -23,10 +23,12 @@
 package com.oracle.max.graal.compiler.ir;
 
 import com.oracle.max.graal.compiler.debug.*;
+import com.oracle.max.graal.compiler.phases.CanonicalizerPhase.CanonicalizerOp;
 import com.oracle.max.graal.compiler.util.*;
 import com.oracle.max.graal.graph.*;
 import com.sun.cri.bytecode.*;
 import com.sun.cri.ci.*;
+import com.sun.cri.ri.*;
 
 /**
  * The {@code InstanceOf} instruction represents an instanceof test.
@@ -71,4 +73,36 @@
     public Node copy(Graph into) {
         return new InstanceOf(null, null, nullIsTrue, into);
     }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T extends Op> T lookup(Class<T> clazz) {
+        if (clazz == CanonicalizerOp.class) {
+            return (T) CANONICALIZER;
+        }
+        return super.lookup(clazz);
+    }
+
+    private static CanonicalizerOp CANONICALIZER = new CanonicalizerOp() {
+        @Override
+        public Node canonical(Node node) {
+            InstanceOf isInstance = (InstanceOf) node;
+            Value object = isInstance.object();
+            RiType exactType = object.exactType();
+            if (exactType != null) {
+                return Constant.forBoolean(exactType.isSubtypeOf(isInstance.targetClass()), node.graph());
+            }
+            CiConstant constant = object.asConstant();
+            if (constant != null) {
+                assert constant.kind == CiKind.Object;
+                if (constant.isNull()) {
+                    return Constant.forBoolean(false, node.graph());
+                } else {
+                    // this should never happen - non-null constants are always expected to provide an exactType
+                    assert false;
+                }
+            }
+            return isInstance;
+        }
+    };
 }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IsNonNull.java	Wed Jul 06 17:02:15 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IsNonNull.java	Wed Jul 06 17:02:38 2011 +0200
@@ -23,6 +23,7 @@
 package com.oracle.max.graal.compiler.ir;
 
 import com.oracle.max.graal.compiler.debug.*;
+import com.oracle.max.graal.compiler.phases.CanonicalizerPhase.CanonicalizerOp;
 import com.oracle.max.graal.compiler.util.*;
 import com.oracle.max.graal.graph.*;
 import com.sun.cri.bytecode.*;
@@ -67,7 +68,7 @@
      */
     public IsNonNull(Value object, Graph graph) {
         super(CiKind.Object, INPUT_COUNT, SUCCESSOR_COUNT, graph);
-        assert object == null || object.kind == CiKind.Object;
+        assert object == null || object.kind == CiKind.Object : object;
         setObject(object);
     }
 
@@ -107,4 +108,30 @@
     public Node copy(Graph into) {
         return new IsNonNull(null, into);
     }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T extends Op> T lookup(Class<T> clazz) {
+        if (clazz == CanonicalizerOp.class) {
+            return (T) CANONICALIZER;
+        }
+        return super.lookup(clazz);
+    }
+
+    private static CanonicalizerOp CANONICALIZER = new CanonicalizerOp() {
+        @Override
+        public Node canonical(Node node) {
+            IsNonNull isNonNull = (IsNonNull) node;
+            Value object = isNonNull.object();
+            if (object instanceof NewInstance || object instanceof NewArray) {
+                return Constant.forBoolean(true, node.graph());
+            }
+            CiConstant constant = object.asConstant();
+            if (constant != null) {
+                assert constant.kind == CiKind.Object;
+                return Constant.forBoolean(constant.isNonNull(), node.graph());
+            }
+            return isNonNull;
+        }
+    };
 }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IsType.java	Wed Jul 06 17:02:15 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IsType.java	Wed Jul 06 17:02:38 2011 +0200
@@ -25,6 +25,7 @@
 import java.util.*;
 
 import com.oracle.max.graal.compiler.debug.*;
+import com.oracle.max.graal.compiler.phases.CanonicalizerPhase.CanonicalizerOp;
 import com.oracle.max.graal.compiler.util.*;
 import com.oracle.max.graal.graph.*;
 import com.sun.cri.bytecode.*;
@@ -127,4 +128,27 @@
     public Node copy(Graph into) {
         return new IsType(null, type, into);
     }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T extends Op> T lookup(Class<T> clazz) {
+        if (clazz == CanonicalizerOp.class) {
+            return (T) CANONICALIZER;
+        }
+        return super.lookup(clazz);
+    }
+
+    private static CanonicalizerOp CANONICALIZER = new CanonicalizerOp() {
+        @Override
+        public Node canonical(Node node) {
+            IsType isType = (IsType) node;
+            Value object = isType.object();
+            RiType exactType = object.exactType();
+            if (exactType != null) {
+                return Constant.forBoolean(exactType == isType.type, node.graph());
+            }
+            // constants return the correct exactType, so they are handled by the code above
+            return isType;
+        }
+    };
 }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Merge.java	Wed Jul 06 17:02:15 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Merge.java	Wed Jul 06 17:02:38 2011 +0200
@@ -197,7 +197,7 @@
             while (!hasPhisOnStack && i < state.stackSize()) {
                 Value value = state.stackAt(i);
                 hasPhisOnStack = isPhiAtBlock(value);
-                if (value != null && !(value instanceof Phi && ((Phi) value).isDead())) {
+                if (value != null) {
                     i += value.kind.sizeInSlots();
                 } else {
                     i++;
@@ -208,7 +208,7 @@
                 Value value = state.localAt(i);
                 hasPhisInLocals = isPhiAtBlock(value);
                 // also ignore illegal HiWords
-                if (value != null && !(value instanceof Phi && ((Phi) value).isDead())) {
+                if (value != null) {
                     i += value.kind.sizeInSlots();
                 } else {
                     i++;
@@ -227,11 +227,7 @@
                 if (value != null) {
                     out.println(stateString(j, value));
                     // also ignore illegal HiWords
-                    if (value instanceof Phi && ((Phi) value).isDead()) {
-                        j +=  1;
-                    } else {
-                        j += value.kind.sizeInSlots();
-                    }
+                    j += value.kind.sizeInSlots();
                 } else {
                     j++;
                 }
@@ -320,10 +316,7 @@
 
         for (Node usage : usages()) {
             if (usage instanceof Phi) {
-                Phi phi = (Phi) usage;
-                if (!phi.isDead()) {
-                    phi.removeInput(predIndex);
-                }
+                ((Phi) usage).removeInput(predIndex);
             }
         }
     }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewArray.java	Wed Jul 06 17:02:15 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewArray.java	Wed Jul 06 17:02:38 2011 +0200
@@ -36,8 +36,6 @@
  */
 public abstract class NewArray extends FixedNodeWithNext {
 
-    private static final EscapeOp ESCAPE = new NewArrayEscapeOp();
-
     private static final int INPUT_COUNT = 1;
     private static final int INPUT_LENGTH = 0;
 
@@ -109,7 +107,7 @@
         return super.lookup(clazz);
     }
 
-    private static class NewArrayEscapeOp implements EscapeOp {
+    private static final EscapeOp ESCAPE = new EscapeOp() {
 
         @Override
         public boolean canAnalyze(Node node) {
@@ -207,31 +205,27 @@
         }
 
         @Override
-        public EscapeField updateState(Node node, Node current, Map<Object, EscapeField> fields, Map<EscapeField, Value> fieldState) {
+        public int updateState(Node node, Node current, Map<Object, Integer> fieldIndex, Value[] fieldState) {
             if (current instanceof AccessIndexed) {
                 int index = ((AccessIndexed) current).index().asConstant().asInt();
-                EscapeField field = fields.get(index);
                 if (current instanceof LoadIndexed) {
                     LoadIndexed x = (LoadIndexed) current;
                     if (x.array() == node) {
-                        x.replaceAtUsages(fieldState.get(field));
+                        x.replaceAtUsages(fieldState[index]);
                         assert x.usages().size() == 0;
                         x.replaceAndDelete(x.next());
                     }
                 } else if (current instanceof StoreIndexed) {
                     StoreIndexed x = (StoreIndexed) current;
                     if (x.array() == node) {
-                        fieldState.put(field, x.value());
+                        fieldState[index] = x.value();
                         assert x.usages().size() == 0;
-                        WriteMemoryCheckpointNode checkpoint = new WriteMemoryCheckpointNode(x.graph());
-                        checkpoint.setStateAfter(x.stateAfter());
-                        checkpoint.setNext(x.next());
-                        x.replaceAndDelete(checkpoint);
-                        return field;
+                        x.replaceAndDelete(x.next());
+                        return index;
                     }
                 }
             }
-            return null;
+            return -1;
         }
-    }
+    };
 }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewInstance.java	Wed Jul 06 17:02:15 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewInstance.java	Wed Jul 06 17:02:38 2011 +0200
@@ -36,7 +36,6 @@
  * The {@code NewInstance} instruction represents the allocation of an instance class object.
  */
 public final class NewInstance extends FixedNodeWithNext {
-    private static final EscapeOp ESCAPE = new NewInstanceEscapeOp();
 
     private static final int INPUT_COUNT = 0;
     private static final int SUCCESSOR_COUNT = 0;
@@ -109,7 +108,7 @@
         return super.lookup(clazz);
     }
 
-    private static class NewInstanceEscapeOp implements EscapeOp {
+    private static final EscapeOp ESCAPE = new EscapeOp() {
 
         @Override
         public boolean canAnalyze(Node node) {
@@ -195,31 +194,27 @@
         }
 
         @Override
-        public EscapeField updateState(Node node, Node current, Map<Object, EscapeField> fields, Map<EscapeField, Value> fieldState) {
+        public int updateState(Node node, Node current, Map<Object, Integer> fieldIndex, Value[] fieldState) {
             if (current instanceof AccessField) {
-                EscapeField field = fields.get(((AccessField) current).field());
-                if (current instanceof LoadField) {
-                    LoadField x = (LoadField) current;
-                    if (x.object() == node) {
-                        assert fieldState.get(field) != null : field + ", " + ((AccessField) current).field() + ((AccessField) current).field().hashCode();
-                        x.replaceAtUsages(fieldState.get(field));
+                if (((AccessField) current).object() == node) {
+                    Integer field = fieldIndex.get(((AccessField) current).field());
+                    assert field != null : ((AccessField) current).field() + " " + ((AccessField) current).field().hashCode();
+                    if (current instanceof LoadField) {
+                        LoadField x = (LoadField) current;
+                        assert fieldState[field] != null : field + ", " + ((AccessField) current).field() + ((AccessField) current).field().hashCode();
+                        x.replaceAtUsages(fieldState[field]);
                         assert x.usages().size() == 0;
                         x.replaceAndDelete(x.next());
-                    }
-                } else if (current instanceof StoreField) {
-                    StoreField x = (StoreField) current;
-                    if (x.object() == node) {
-                        fieldState.put(field, x.value());
+                    } else if (current instanceof StoreField) {
+                        StoreField x = (StoreField) current;
+                        fieldState[field] = x.value();
                         assert x.usages().size() == 0;
-                        WriteMemoryCheckpointNode checkpoint = new WriteMemoryCheckpointNode(x.graph());
-                        checkpoint.setStateAfter(x.stateAfter());
-                        checkpoint.setNext(x.next());
-                        x.replaceAndDelete(checkpoint);
+                        x.replaceAndDelete(x.next());
                         return field;
                     }
                 }
             }
-            return null;
+            return -1;
         }
-    }
+    };
 }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Phi.java	Wed Jul 06 17:02:15 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Phi.java	Wed Jul 06 17:02:38 2011 +0200
@@ -42,7 +42,7 @@
 
     private static final int SUCCESSOR_COUNT = 0;
 
-    private boolean isDead;
+    private final PhiType type;
 
     @Override
     protected int inputCount() {
@@ -66,21 +66,31 @@
         inputs().set(super.inputCount() + INPUT_MERGE, n);
     }
 
-    public Phi(CiKind kind, Merge merge, Graph graph) {
+    public static enum PhiType {
+        Value,          // normal value phis
+        Memory,         // memory phis
+        Virtual         // phis used for VirtualObjectField merges
+    }
+
+    public Phi(CiKind kind, Merge merge, PhiType type, Graph graph) {
         super(kind, INPUT_COUNT, SUCCESSOR_COUNT, graph);
+        this.type = type;
         setMerge(merge);
     }
 
-    Phi(CiKind kind, Graph graph) {
+    private Phi(CiKind kind, PhiType type, Graph graph) {
         super(kind, INPUT_COUNT, SUCCESSOR_COUNT, graph);
+        this.type = type;
+    }
+
+    public PhiType type() {
+        return type;
     }
 
     @Override
     public boolean verify() {
         assertTrue(merge() != null);
-        if (!isDead()) {
-            assertTrue(merge().phiPredecessorCount() == valueCount());
-        }
+        assertTrue(merge().phiPredecessorCount() == valueCount(), merge().phiPredecessorCount() + "==" + valueCount());
         return true;
     }
 
@@ -111,17 +121,6 @@
         v.visitPhi(this);
     }
 
-    /**
-     * Make this phi illegal if types were not merged correctly.
-     */
-    public void makeDead() {
-        isDead = true;
-    }
-
-    public boolean isDead() {
-        return isDead;
-    }
-
     @Override
     public void print(LogStream out) {
         out.print("phi function (");
@@ -143,10 +142,10 @@
             }
             str.append(valueAt(i) == null ? "-" : valueAt(i).id());
         }
-        if (isDead()) {
-            return "Phi: dead (" + str + ")";
+        if (type == PhiType.Value) {
+            return "Phi: (" + str + ")";
         } else {
-            return "Phi: (" + str + ")";
+            return type + "Phi: (" + str + ")";
         }
     }
 
@@ -160,8 +159,7 @@
 
     @Override
     public Node copy(Graph into) {
-        Phi x = new Phi(kind, into);
-        x.isDead = isDead;
+        Phi x = new Phi(kind, type, into);
         return x;
     }
 
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/VirtualObject.java	Wed Jul 06 17:02:15 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/VirtualObject.java	Wed Jul 06 17:02:38 2011 +0200
@@ -33,9 +33,7 @@
 
 public class VirtualObject extends FloatingNode {
 
-    private static final int INPUT_COUNT = 2;
-    private static final int INPUT_OBJECT = 0;
-    private static final int INPUT_INPUT = 1;
+    private static final int INPUT_COUNT = 0;
 
     private static final int SUCCESSOR_COUNT = 0;
 
@@ -49,48 +47,13 @@
         return super.successorCount() + SUCCESSOR_COUNT;
     }
 
-    /**
-     * The instruction that specifies the old state of the virtual object.
-     */
-     public VirtualObject object() {
-        return (VirtualObject) inputs().get(super.inputCount() + INPUT_OBJECT);
-    }
-
-    private VirtualObject setObject(VirtualObject n) {
-        return (VirtualObject) inputs().set(super.inputCount() + INPUT_OBJECT, n);
-    }
-
-    /**
-     * The instruction that contains the new state of the specified field.
-     */
-     public Value input() {
-        return (Value) inputs().get(super.inputCount() + INPUT_INPUT);
-    }
-
-    public Value setInput(Value n) {
-        return (Value) inputs().set(super.inputCount() + INPUT_INPUT, n);
-    }
-
-    private EscapeField field;
     private EscapeField[] fields;
     private RiType type;
 
-    /**
-     * Constructs a new ArrayLength instruction.
-     * @param array the instruction producing the array
-     * @param newFrameState the state after executing this instruction
-     */
-    public VirtualObject(VirtualObject object, Value input, EscapeField field, RiType type, EscapeField[] fields, Graph graph) {
+    public VirtualObject(RiType type, EscapeField[] fields, Graph graph) {
         super(CiKind.Int, INPUT_COUNT, SUCCESSOR_COUNT, graph);
-        this.field = field;
         this.type = type;
         this.fields = fields;
-        setObject(object);
-        setInput(input);
-    }
-
-    public EscapeField field() {
-        return field;
     }
 
     public RiType type() {
@@ -110,23 +73,22 @@
     public Map<Object, Object> getDebugProperties() {
         Map<Object, Object> properties = super.getDebugProperties();
         properties.put("type", type);
-        properties.put("field", field);
         return properties;
     }
 
     @Override
     public String shortName() {
-        return "VirtualObject " + field.name();
+        return "VirtualObject " + type.name();
     }
 
     @Override
     public void print(LogStream out) {
-        out.print(object()).print(".").print(field.name()).print("=").print(input());
+        out.print("virtualobject ").print(type.name());
     }
 
     @Override
     public Node copy(Graph into) {
-        VirtualObject x = new VirtualObject(null, null, field, type, fields, into);
+        VirtualObject x = new VirtualObject(type, fields, into);
         return x;
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/VirtualObjectField.java	Wed Jul 06 17:02:38 2011 +0200
@@ -0,0 +1,130 @@
+/*
+ * 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.max.graal.compiler.ir;
+
+import java.util.*;
+
+import com.oracle.max.graal.compiler.debug.*;
+import com.oracle.max.graal.graph.*;
+import com.sun.cri.ci.*;
+
+
+public class VirtualObjectField extends FloatingNode {
+
+    private static final int INPUT_COUNT = 3;
+    private static final int INPUT_OBJECT = 0;
+    private static final int INPUT_LAST_STATE = 1;
+    private static final int INPUT_INPUT = 2;
+
+    private static final int SUCCESSOR_COUNT = 0;
+
+    @Override
+    protected int inputCount() {
+        return super.inputCount() + INPUT_COUNT;
+    }
+
+    @Override
+    protected int successorCount() {
+        return super.successorCount() + SUCCESSOR_COUNT;
+    }
+
+    /**
+     * The instruction that specifies the virtual object instance.
+     */
+     public VirtualObject object() {
+        return (VirtualObject) inputs().get(super.inputCount() + INPUT_OBJECT);
+    }
+
+    private VirtualObject setObject(VirtualObject n) {
+        return (VirtualObject) inputs().set(super.inputCount() + INPUT_OBJECT, n);
+    }
+
+    /**
+     * The instruction that specifies the old state of the virtual object.
+     */
+     public FloatingNode lastState() {
+        return (FloatingNode) inputs().get(super.inputCount() + INPUT_LAST_STATE);
+    }
+
+    private FloatingNode setLastState(FloatingNode n) {
+        return (FloatingNode) inputs().set(super.inputCount() + INPUT_LAST_STATE, n);
+    }
+
+    /**
+     * The instruction that contains the new state of the specified field.
+     */
+     public Value input() {
+        return (Value) inputs().get(super.inputCount() + INPUT_INPUT);
+    }
+
+    public Value setInput(Value n) {
+        return (Value) inputs().set(super.inputCount() + INPUT_INPUT, n);
+    }
+
+    private int index;
+
+    /**
+     * Constructs a new ArrayLength instruction.
+     * @param array the instruction producing the array
+     * @param newFrameState the state after executing this instruction
+     */
+    public VirtualObjectField(VirtualObject object, FloatingNode lastState, Value input, int index, Graph graph) {
+        super(CiKind.Int, INPUT_COUNT, SUCCESSOR_COUNT, graph);
+        this.index = index;
+        setObject(object);
+        setLastState(lastState);
+        setInput(input);
+    }
+
+    public int index() {
+        return index;
+    }
+
+    @Override
+    public void accept(ValueVisitor v) {
+        // nothing to do...
+    }
+
+    @Override
+    public Map<Object, Object> getDebugProperties() {
+        Map<Object, Object> properties = super.getDebugProperties();
+        properties.put("index", index);
+        return properties;
+    }
+
+    @Override
+    public String shortName() {
+        return "VirtualObjectField " + object().fields()[index].name();
+    }
+
+    @Override
+    public void print(LogStream out) {
+        out.print(object()).print(".").print(object().fields()[index].name()).print("=").print(input());
+    }
+
+    @Override
+    public Node copy(Graph into) {
+        VirtualObjectField x = new VirtualObjectField(null, null, null, index, into);
+        return x;
+    }
+}
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/DeadCodeEliminationPhase.java	Wed Jul 06 17:02:15 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/DeadCodeEliminationPhase.java	Wed Jul 06 17:02:38 2011 +0200
@@ -77,8 +77,8 @@
             if (current instanceof AbstractVectorNode) {
                 for (Node usage : current.usages()) {
                     flood.add(usage);
-                }
-            }
+        }
+    }
         }
     }
 
@@ -105,29 +105,29 @@
                         endNode.replaceAndDelete(loop.next());
                         loop.delete();
                     }
-                } else if (node instanceof Merge) {
-                    for (Node n : node.usages()) {
-                        if (n instanceof Phi) {
-                            Phi phi = (Phi) n;
-                            if (phi.usages().size() == 1 && phi.usages().get(0) instanceof VirtualObject) {
-                                // (tw) This VirtualObject instance is implicitely dead, because the CFG to it (i.e. the store that produced it) is dead! => fix this in escape analysis
-                                VirtualObject virtualObject = (VirtualObject) phi.usages().get(0);
-                                virtualObject.replaceAndDelete(virtualObject.object());
-                            }
-                        }
-                    }
-                }
-
-
-                if (IdentifyBlocksPhase.isFixed(node)) {
-                    for (Node n : new ArrayList<Node>(node.usages())) {
-                        if (n instanceof VirtualObject) {
-                            // (tw) This VirtualObject instance is implicitely dead, because the CFG to it (i.e. the
-                            // store that produced it) is dead! => fix this in Escape analysis
-                            VirtualObject virtualObject = (VirtualObject) n;
-                            virtualObject.replaceAndDelete(virtualObject.object());
-                        }
-                    }
+//                } else if (node instanceof Merge) {
+//                    for (Node n : node.usages()) {
+//                        if (n instanceof Phi) {
+//                            Phi phi = (Phi) n;
+//                            if (phi.usages().size() == 1 && phi.usages().get(0) instanceof VirtualObject) {
+//                                // (tw) This VirtualObject instance is implicitely dead, because the CFG to it (i.e. the store that produced it) is dead! => fix this in escape analysis
+//                                VirtualObject virtualObject = (VirtualObject) phi.usages().get(0);
+//                                virtualObject.replaceAndDelete(virtualObject.object());
+//                            }
+//                        }
+//                    }
+//                }
+//
+//
+//                if (IdentifyBlocksPhase.isFixed(node)) {
+//                    for (Node n : new ArrayList<Node>(node.usages())) {
+//                        if (n instanceof VirtualObject) {
+//                            // (tw) This VirtualObject instance is implicitely dead, because the CFG to it (i.e. the
+//                            // store that produced it) is dead! => fix this in Escape analysis
+//                            VirtualObject virtualObject = (VirtualObject) n;
+//                            virtualObject.replaceAndDelete(virtualObject.object());
+//                        }
+//                    }
                 }
             }
         }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/EscapeAnalysisPhase.java	Wed Jul 06 17:02:15 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/EscapeAnalysisPhase.java	Wed Jul 06 17:02:38 2011 +0200
@@ -23,13 +23,13 @@
 package com.oracle.max.graal.compiler.phases;
 
 import java.util.*;
-import java.util.Map.Entry;
 
 import com.oracle.max.graal.compiler.*;
 import com.oracle.max.graal.compiler.debug.*;
 import com.oracle.max.graal.compiler.gen.*;
 import com.oracle.max.graal.compiler.graph.*;
 import com.oracle.max.graal.compiler.ir.*;
+import com.oracle.max.graal.compiler.ir.Phi.*;
 import com.oracle.max.graal.compiler.observer.*;
 import com.oracle.max.graal.compiler.schedule.*;
 import com.oracle.max.graal.compiler.value.*;
@@ -40,24 +40,277 @@
 
 public class EscapeAnalysisPhase extends Phase {
 
+    public interface MergeableState <T> {
+        T clone();
+        void merge(Merge merge, Collection<T> withStates);
+        void loopBegin(LoopBegin loopBegin);
+        void loopEnd(LoopEnd loopEnd, T loopEndState);
+    }
 
-    public static class BlockExitState {
-        public final Map<EscapeField, Value> fieldState;
-        public VirtualObject obj;
+    public abstract static class PostOrderNodeIterator<T extends MergeableState<T>> {
+
+        private final NodeBitMap visitedEnds;
+        private final Deque<FixedNode> nodeQueue;
+        private final HashMap<FixedNode, T> nodeStates;
+        private final FixedNode start;
+
+        protected T state;
+
+        public PostOrderNodeIterator(FixedNode start, T initialState) {
+            visitedEnds = start.graph().createNodeBitMap();
+            nodeQueue = new ArrayDeque<FixedNode>();
+            nodeStates = new HashMap<FixedNode, T>();
+            this.start = start;
+            this.state = initialState;
+        }
+
+        public void apply(FixedNode start) {
+            FixedNode current = start;
+
+            do {
+                if (current instanceof Invoke) {
+                    invoke((Invoke) current);
+                    queueSuccessors(current);
+                    current = nextQueuedNode();
+                } else if (current instanceof LoopBegin) {
+                    state.loopBegin((LoopBegin) current);
+                    nodeStates.put(current, state.clone());
+                    loopBegin((LoopBegin) current);
+                    current = ((LoopBegin) current).next();
+                    assert current != null;
+                } else if (current instanceof LoopEnd) {
+                    T loopBeginState = nodeStates.get(((LoopEnd) current).loopBegin());
+                    if (loopBeginState != null) {
+                        loopBeginState.loopEnd((LoopEnd) current, state);
+                    }
+                    loopEnd((LoopEnd) current);
+                    current = nextQueuedNode();
+                } else if (current instanceof Merge) {
+                    merge((Merge) current);
+                    current = ((Merge) current).next();
+                    assert current != null;
+                } else if (current instanceof FixedNodeWithNext) {
+                    FixedNode next = ((FixedNodeWithNext) current).next();
+                    node(current);
+                    current = next;
+                    assert current != null;
+                } else if (current instanceof EndNode) {
+                    end((EndNode) current);
+                    queueMerge((EndNode) current);
+                    current = nextQueuedNode();
+                } else if (current instanceof Deoptimize) {
+                    deoptimize((Deoptimize) current);
+                    current = nextQueuedNode();
+                } else if (current instanceof Return) {
+                    returnNode((Return) current);
+                    current = nextQueuedNode();
+                } else if (current instanceof Unwind) {
+                    unwind((Unwind) current);
+                    current = nextQueuedNode();
+                } else if (current instanceof ControlSplit) {
+                    controlSplit((ControlSplit) current);
+                    queueSuccessors(current);
+                    current = nextQueuedNode();
+                } else {
+                    assert false : current.shortName();
+                }
+            } while(current != null);
+        }
+
+        private void queueSuccessors(FixedNode x) {
+            nodeStates.put(x, state);
+            for (Node node : x.successors()) {
+                if (node != null) {
+                    nodeQueue.addFirst((FixedNode) node);
+                }
+            }
+        }
 
-        public BlockExitState() {
-            this.fieldState = new HashMap<EscapeField, Value>();
+        private FixedNode nextQueuedNode() {
+            int maxIterations = nodeQueue.size();
+            while (maxIterations-- > 0) {
+                FixedNode node = nodeQueue.removeFirst();
+                if (node instanceof Merge) {
+                    Merge merge = (Merge) node;
+                    state = nodeStates.get(merge.endAt(0)).clone();
+                    ArrayList<T> states = new ArrayList<T>(merge.endCount() - 1);
+                    for (int i = 1; i < merge.endCount(); i++) {
+                        T other = nodeStates.get(merge.endAt(i));
+                        assert other != null;
+                        states.add(other);
+                    }
+                    state.merge(merge, states);
+                    return merge;
+                } else {
+                    assert node.predecessors().size() == 1;
+                    state = nodeStates.get(node.predecessors().get(0)).clone();
+                    return node;
+                }
+            }
+            return null;
+        }
+
+        private void queueMerge(EndNode end) {
+            assert !visitedEnds.isMarked(end);
+            assert !nodeStates.containsKey(end);
+            nodeStates.put(end, state);
+            visitedEnds.mark(end);
+            Merge merge = end.merge();
+            boolean endsVisited = true;
+            for (int i = 0; i < merge.endCount(); i++) {
+                if (!visitedEnds.isMarked(merge.endAt(i))) {
+                    endsVisited = false;
+                    break;
+                }
+            }
+            if (endsVisited) {
+                nodeQueue.add(merge);
+            }
+        }
+
+        protected abstract void node(FixedNode node);
+
+        protected void end(EndNode endNode) {
+            node(endNode);
+        }
+
+        protected void merge(Merge merge) {
+            node(merge);
+        }
+
+        protected void loopBegin(LoopBegin loopBegin) {
+            node(loopBegin);
+        }
+
+        protected void loopEnd(LoopEnd loopEnd) {
+            node(loopEnd);
+        }
+
+        protected void deoptimize(Deoptimize deoptimize) {
+            node(deoptimize);
+        }
+
+        protected void controlSplit(ControlSplit controlSplit) {
+            node(controlSplit);
+        }
+
+        protected void returnNode(Return returnNode) {
+            node(returnNode);
+        }
+
+        protected void invoke(Invoke invoke) {
+            node(invoke);
+        }
+
+        protected void unwind(Unwind unwind) {
+            node(unwind);
         }
     }
 
+    public static class BlockExitState implements MergeableState<BlockExitState> {
+        public final Value[] fieldState;
+        public final VirtualObject virtualObject;
+        public FloatingNode virtualObjectField;
+
+        public BlockExitState(EscapeField[] fields, VirtualObject virtualObject) {
+            this.fieldState = new Value[fields.length];
+            this.virtualObject = virtualObject;
+            this.virtualObjectField = null;
+            for (int i = 0; i < fields.length; i++) {
+                fieldState[i] = Constant.defaultForKind(fields[i].kind(), virtualObject.graph());
+                virtualObjectField = new VirtualObjectField(virtualObject, virtualObjectField, fieldState[i], i, virtualObject.graph());
+            }
+        }
+
+        public BlockExitState(BlockExitState state) {
+            this.fieldState = state.fieldState.clone();
+            this.virtualObject = state.virtualObject;
+            this.virtualObjectField = state.virtualObjectField;
+        }
+
+        public void updateField(int fieldIndex) {
+            virtualObjectField = new VirtualObjectField(virtualObject, virtualObjectField, fieldState[fieldIndex], fieldIndex, virtualObject.graph());
+        }
+
+        @Override
+        public BlockExitState clone() {
+            return new BlockExitState(this);
+        }
+
+        @Override
+        public void merge(Merge merge, Collection<BlockExitState> withStates) {
+            Phi vobjPhi = null;
+            Phi[] valuePhis = new Phi[fieldState.length];
+            for (BlockExitState other : withStates) {
+                if (virtualObjectField != other.virtualObjectField && vobjPhi == null) {
+                    vobjPhi = new Phi(CiKind.Illegal, merge, PhiType.Virtual, virtualObject.graph());
+                    vobjPhi.addInput(virtualObjectField);
+                    virtualObjectField = vobjPhi;
+                }
+                for (int i2 = 0; i2 < fieldState.length; i2++) {
+                    if (fieldState[i2] != other.fieldState[i2] && valuePhis[i2] == null) {
+                        valuePhis[i2] = new Phi(fieldState[i2].kind, merge, PhiType.Value, virtualObject.graph());
+                        valuePhis[i2].addInput(fieldState[i2]);
+                        fieldState[i2] = valuePhis[i2];
+                    }
+                }
+            }
+            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 = new VirtualObjectField(virtualObject, virtualObjectField, valuePhis[i2], i2, virtualObject.graph());
+                    assert valuePhis[i2].valueCount() == withStates.size() + 1;
+                }
+            }
+        }
+
+        @Override
+        public void loopBegin(LoopBegin loopBegin) {
+            Phi vobjPhi = null;
+            vobjPhi = new Phi(CiKind.Illegal, loopBegin, PhiType.Virtual, virtualObject.graph());
+            vobjPhi.addInput(virtualObjectField);
+            virtualObjectField = vobjPhi;
+            for (int i2 = 0; i2 < fieldState.length; i2++) {
+                Phi valuePhi = new Phi(fieldState[i2].kind, loopBegin, PhiType.Value, virtualObject.graph());
+                valuePhi.addInput(fieldState[i2]);
+                fieldState[i2] = valuePhi;
+                updateField(i2);
+            }
+        }
+
+        @Override
+        public void loopEnd(LoopEnd x, BlockExitState loopEndState) {
+            while (!(virtualObjectField instanceof Phi)) {
+                virtualObjectField = ((VirtualObjectField) virtualObjectField).lastState();
+            }
+            ((Phi) virtualObjectField).addInput(loopEndState.virtualObjectField);
+            assert ((Phi) virtualObjectField).valueCount() == 2;
+            for (int i2 = 0; i2 < fieldState.length; i2++) {
+                ((Phi) fieldState[i2]).addInput(loopEndState.fieldState[i2]);
+                assert ((Phi) fieldState[i2]).valueCount() == 2;
+            }
+        }
+    }
+
+
     public class EscapementFixup {
 
         private List<Block> blocks;
-        private final Map<Object, EscapeField> fields = new HashMap<Object, EscapeField>();
+        private final Map<Object, Integer> fields = new HashMap<Object, Integer>();
         private final Map<Block, BlockExitState> exitStates = new HashMap<Block, BlockExitState>();
 
         private final EscapeOp op;
-        private Graph graph;
+        private final Graph graph;
         private final Node node;
         private RiType type;
         private EscapeField[] escapeFields;
@@ -74,217 +327,36 @@
         }
 
         public void removeAllocation() {
-            final IdentifyBlocksPhase identifyBlocksPhase = new IdentifyBlocksPhase(true);
-            identifyBlocksPhase.apply(graph);
-            blocks = identifyBlocksPhase.getBlocks();
+            assert node instanceof FixedNodeWithNext;
 
-            final HashMap<Phi, EscapeField> phis = new HashMap<Phi, EscapeField>();
-            final Block startBlock = identifyBlocksPhase.getNodeToBlock().get(node);
-            assert startBlock != null;
             type = ((Value) node).exactType();
             escapeFields = op.fields(node);
-            for (EscapeField field : escapeFields) {
-                fields.put(field.representation(), field);
+            for (int i = 0; i < escapeFields.length; i++) {
+                fields.put(escapeFields[i].representation(), i);
             }
-
-            Block.iteratePostOrder(blocks, new BlockClosure() {
-
-                public void apply(Block block) {
-                    if (GraalOptions.TraceEscapeAnalysis) {
-                        TTY.println("Block %d", block.blockID());
-                    }
-//                    for (Node n : block.getInstructions()) {
-//                        TTY.println("  %d %s", n.id(), n.shortName());
-//                    }
-//                    for (Block b : block.getSuccessors()) {
-//                        TTY.print(" %d", b.blockID());
-//                    }
-//                    TTY.println();
-
-                    BlockExitState state = new BlockExitState();
-                    if (/*block == startBlock ||*/ block.getPredecessors().size() == 0) {
-                        state.obj = null;
-                    } else {
-                        List<Block> predecessors = block.getPredecessors();
-                        Set<EscapeField> mergedFields = new HashSet<EscapeField>();
-
-                        BlockExitState predState = exitStates.get(predecessors.get(0));
-                        state.obj = predState == null ? null : predState.obj;
-
-                        for (int i = 0; i < predecessors.size(); i++) {
-                            BlockExitState exitState = exitStates.get(predecessors.get(i));
-                            if (exitState == null) {
-                                // (tw) What about an object that is allocated in a loop. We are merging in the values of the old allocation?; Now solved by "if" below.
-                                mergedFields.addAll(fields.values());
-                                state.obj = null;
-                                break;
-                            } else {
-                                for (EscapeField field : fields.values()) {
-                                    if (state.fieldState.get(field) == null) {
-                                        state.fieldState.put(field, exitState.fieldState.get(field));
-                                        if (i != 0) {
-                                            // We need to merge this field too!
-                                            mergedFields.add(field);
-                                        }
-                                    } else if (state.fieldState.get(field) != exitState.fieldState.get(field)) {
-                                        mergedFields.add(field);
-                                    }
-                                }
-                            }
-                        }
-                        if (block.firstNode() instanceof LoopBegin) {
-                            if (predState.obj == null) {
-                                state.obj = null;
-                                mergedFields.clear();
-                            }
-                        }
-
-                        if (!mergedFields.isEmpty()) {
-                            assert block.firstNode() instanceof Merge : "unexpected: " + block.firstNode().shortName() + " " + block.firstNode().id();
-                            for (EscapeField field : mergedFields) {
-                                Phi phi = new Phi(field.kind().stackKind(), (Merge) block.firstNode(), graph);
-                                state.fieldState.put(field, phi);
-                                phis.put(phi, field);
-                                state.obj = new VirtualObject(state.obj, phi, field, type, escapeFields, graph);
-                            }
-                        }
-                    }
+            final VirtualObject virtual = new VirtualObject(type, escapeFields, graph);
+            final BlockExitState startState = new BlockExitState(escapeFields, virtual);
+            if (GraalOptions.TraceEscapeAnalysis || GraalOptions.PrintEscapeAnalysis) {
+                TTY.println("new virtual object: " + virtual);
+            }
+            node.replaceAtUsages(virtual);
+            final FixedNode next = ((FixedNodeWithNext) node).next();
+            node.replaceAndDelete(next);
 
-                    Node current;
-                    if (block.firstNode() instanceof StartNode) {
-                        current = ((StartNode) block.firstNode()).next();
-                    } else {
-                        current = block.firstNode();
-                    }
-                    while (current != block.lastNode()) {
-                        Node next = ((FixedNodeWithNext) current).next();
-                        FrameState stateAfter = null;
-                        if (current instanceof StateSplit) {
-                            stateAfter = ((StateSplit) current).stateAfter();
-                        }
-                        if (current == node) {
-                            for (EscapeField field : fields.values()) {
-                                Constant value = Constant.defaultForKind(field.kind(), graph);
-                                state.fieldState.put(field, value);
-                                state.obj = new VirtualObject(state.obj, value, field, type, escapeFields, graph);
-                            }
-                        } else {
-                            EscapeField changedField = op.updateState(node, current, fields, state.fieldState);
-                            if (changedField != null) {
-                                state.obj = new VirtualObject(state.obj, state.fieldState.get(changedField), changedField, type, escapeFields, graph);
-                            }
-                        }
-                        if (stateAfter != null) {
-                            updateFrameState(stateAfter, state.obj);
-                        }
-                        current = next;
+            new PostOrderNodeIterator<BlockExitState>(next, startState) {
+                @Override
+                protected void node(FixedNode node) {
+                    int changedField = op.updateState(virtual, node, fields, state.fieldState);
+                    if (changedField != -1) {
+                        state.updateField(changedField);
                     }
-
-                    if (GraalOptions.TraceEscapeAnalysis) {
-                        TTY.print(" block end state: ");
-                        for (Entry<EscapeField, Value> entry : state.fieldState.entrySet()) {
-                            TTY.print("%s->%s ", entry.getKey().name(), entry.getValue());
-                        }
-                        TTY.println();
-                    }
-                    exitStates.put(block, state);
-                }
-            });
-
-            for (Entry<Phi, EscapeField> entry : phis.entrySet()) {
-                Phi phi = entry.getKey();
-                EscapeField field = entry.getValue();
-                Block block = identifyBlocksPhase.getNodeToBlock().get(entry.getKey().merge());
-
-                List<Block> predecessors = block.getPredecessors();
-                assert predecessors.size() > 0;
-                Node simple = exitStates.get(predecessors.get(0)).fieldState.get(field);
-                for (int i = 1; i < predecessors.size(); i++) {
-                    BlockExitState exitState = exitStates.get(predecessors.get(i));
-                    if (exitState.fieldState.get(field) != simple) {
-                        simple = null;
-                        break;
-                    }
-                }
-                if (simple != null) {
-                    // (tw) Should never be reached, because Phi verification fails here..
-                    phi.replaceAndDelete(simple);
-                } else {
-                    for (int i = 0; i < predecessors.size(); i++) {
-                        BlockExitState exitState = exitStates.get(predecessors.get(i));
-                        assert exitState != null;
-                        Node value = exitState.fieldState.get(field);
-                        if (GraalOptions.TraceEscapeAnalysis) {
-                            TTY.println("fixing phi %d with %s", phi.id(), value);
-                        }
-                        if (value == null) {
-                            phi.addInput(Constant.defaultForKind(field.kind(), graph));
-                        } else {
-                            phi.addInput(value);
+                    if (!node.isDeleted() && node instanceof StateSplit && ((StateSplit) node).stateAfter() != null) {
+                        if (state.virtualObjectField != null) {
+                            ((StateSplit) node).stateAfter().addVirtualObjectMapping(state.virtualObjectField);
                         }
                     }
                 }
-            }
-            // the rest of the usages should be dead frame states...
-            for (Node usage : new ArrayList<Node>(node.usages())) {
-                if (usage instanceof IsNonNull) {
-                    usage.replaceAndDelete(Constant.forBoolean(true, graph));
-                } else if (usage instanceof RegisterFinalizer) {
-                    usage.replaceAndDelete(((RegisterFinalizer) usage).next());
-                } else {
-                    assert usage instanceof FrameState || usage instanceof VirtualObject : "usage: " + usage;
-                    usage.inputs().replace(node, Node.Null);
-                }
-            }
-
-            if (node instanceof FixedNodeWithNext) {
-                node.replaceAndDelete(((FixedNodeWithNext) node).next());
-            } else {
-                node.delete();
-            }
-        }
-
-        private void updateFrameState(FrameState frameState, VirtualObject current) {
-            for (int i = 0; i < frameState.inputs().size(); i++) {
-                if (frameState.inputs().get(i) == node) {
-                    frameState.inputs().set(i, current);
-                } else if (frameState.inputs().get(i) instanceof VirtualObject) {
-                    VirtualObject obj = (VirtualObject) frameState.inputs().get(i);
-                    do {
-                        updateVirtualObject(obj, current);
-                        obj = obj.object();
-                    } while (obj != null);
-                }
-            }
-            FrameState outer = frameState.outerFrameState();
-            if (outer != null) {
-                boolean duplicate = false;
-                for (int i = 0; i < outer.inputs().size(); i++) {
-                    if (outer.inputs().get(i) == node) {
-                        duplicate = true;
-                    }
-                }
-                // (tw) need to fully duplicate also if there is a reference to "node" in an outer framestate?
-                duplicate = true;
-                if (duplicate) {
-                    outer = outer.duplicate(outer.bci);
-                    frameState.setOuterFrameState(outer);
-                }
-                updateFrameState(outer, current);
-            }
-        }
-
-        private void updateVirtualObject(VirtualObject obj, VirtualObject current) {
-            if (obj.input() == node) {
-                // (tw) don't we have similar issues here like in framestate dup? We are updating a shared data structure here..
-                obj.setInput(current);
-            } else if (obj.input() instanceof VirtualObject) {
-                VirtualObject obj2 = (VirtualObject) obj.input();
-                do {
-                    updateVirtualObject(obj2, current);
-                    obj2 = obj2.object();
-                } while (obj2 != null);
-            }
+            }.apply(next);
         }
 
         private void process() {
@@ -305,9 +377,6 @@
 
     @Override
     protected void run(Graph graph) {
-        if (compilation.method.name().contains("removeEnd") || compilation.method.name().contains("emitCode")) {
-            return;
-        }
         for (Node node : graph.getNodes()) {
             EscapeOp op = node.lookup(EscapeOp.class);
             if (op != null && op.canAnalyze(node)) {
@@ -344,10 +413,10 @@
                             TTY.println("%n!!!!!!!! non-escaping object: %d %s (%s) in %s", node.id(), node.shortName(), ((Value) node).exactType(), compilation.method);
                         }
                         new EscapementFixup(op, graph, node).apply();
+                        if (compilation.compiler.isObserved()) {
+                            compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, "After escape", graph, true, false));
+                        }
                         new PhiSimplifier(graph);
-                        if (compilation.compiler.isObserved()) {
-                            compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, "After escape " + node.id(), graph, true, false));
-                        }
                         break;
                     }
                     if (weight < minimumWeight) {
@@ -364,6 +433,12 @@
                     }
                     new InliningPhase(compilation, ir, invokes).apply(graph);
                     new DeadCodeEliminationPhase().apply(graph);
+                    if (node.isDeleted()) {
+                        if (GraalOptions.TraceEscapeAnalysis || GraalOptions.PrintEscapeAnalysis) {
+                            TTY.println("%n!!!!!!!! object died while performing escape analysis: %d %s (%s) in %s", node.id(), node.shortName(), ((Value) node).exactType(), compilation.method);
+                        }
+                        break;
+                    }
                     exits.clear();
                     invokes.clear();
                 } while (iterations++ < 3);
@@ -433,7 +508,7 @@
 
         void beforeUpdate(Node node, Node usage);
 
-        EscapeField updateState(Node node, Node current, Map<Object, EscapeField> fields, Map<EscapeField, Value> fieldState);
+        int updateState(Node node, Node current, Map<Object, Integer> fieldIndex, Value[] fieldState);
 
     }
 }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/LoopPhase.java	Wed Jul 06 17:02:15 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/LoopPhase.java	Wed Jul 06 17:02:38 2011 +0200
@@ -26,6 +26,7 @@
 
 import com.oracle.max.graal.compiler.*;
 import com.oracle.max.graal.compiler.ir.*;
+import com.oracle.max.graal.compiler.ir.Phi.PhiType;
 import com.oracle.max.graal.compiler.util.*;
 import com.oracle.max.graal.compiler.util.LoopUtil.Loop;
 import com.oracle.max.graal.compiler.value.*;
@@ -93,7 +94,7 @@
                         IntegerSub sub = new IntegerSub(kind, c2.init(), c1.init(), graph);
                         IntegerAdd addStride = new IntegerAdd(kind, sub, c1.stride(), graph);
                         IntegerAdd add = new IntegerAdd(kind, c1, addStride, graph);
-                        Phi phi = new Phi(kind, loopBegin, graph); // (gd) assumes order on loopBegin preds - works in collab with graph builder
+                        Phi phi = new Phi(kind, loopBegin, PhiType.Value, graph); // (gd) assumes order on loopBegin preds - works in collab with graph builder
                         phi.addInput(c2.init());
                         phi.addInput(add);
                         c2.replaceAndDelete(phi);
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/MemoryPhase.java	Wed Jul 06 17:02:15 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/MemoryPhase.java	Wed Jul 06 17:02:38 2011 +0200
@@ -28,6 +28,7 @@
 import com.oracle.max.graal.compiler.*;
 import com.oracle.max.graal.compiler.debug.*;
 import com.oracle.max.graal.compiler.ir.*;
+import com.oracle.max.graal.compiler.ir.Phi.*;
 import com.oracle.max.graal.compiler.schedule.*;
 import com.oracle.max.graal.graph.*;
 import com.sun.cri.ci.*;
@@ -155,8 +156,7 @@
                 assert phi.valueCount() <= phi.merge().endCount();
                 return original;
             } else {
-                Phi phi = new Phi(CiKind.Illegal, m, m.graph());
-                phi.makeDead(); // Phi does not produce a value, it is only a memory phi.
+                Phi phi = new Phi(CiKind.Illegal, m, PhiType.Memory, m.graph());
                 for (int i = 0; i < mergeOperationCount + 1; ++i) {
                     phi.addInput(original);
                 }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/IdentifyBlocksPhase.java	Wed Jul 06 17:02:15 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/IdentifyBlocksPhase.java	Wed Jul 06 17:02:38 2011 +0200
@@ -308,10 +308,11 @@
                 assert mergeBlock != null : "no block for merge " + merge.id();
                 for (int i = 0; i < phi.valueCount(); ++i) {
                     if (phi.valueAt(i) == n) {
-                        if (mergeBlock.getPredecessors().size() == 0) {
+                        if (mergeBlock.getPredecessors().size() <= i) {
                             TTY.println(merge.toString());
                             TTY.println(phi.toString());
                             TTY.println(merge.phiPredecessors().toString());
+                            TTY.println(phi.inputs().toString());
                             TTY.println("value count: " + phi.valueCount());
                         }
                         block = getCommonDominator(block, mergeBlock.getPredecessors().get(i));
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64LIRGenerator.java	Wed Jul 06 17:02:15 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64LIRGenerator.java	Wed Jul 06 17:02:38 2011 +0200
@@ -364,7 +364,7 @@
             return;
         }
 
-        assert Util.archKindsEqual(x.x().kind, x.kind) && Util.archKindsEqual(x.y().kind, x.kind) : "wrong parameter types: " + Bytecodes.nameOf(x.opcode);
+        assert Util.archKindsEqual(x.x().kind, x.kind) && Util.archKindsEqual(x.y().kind, x.kind) : "wrong parameter types: " + Bytecodes.nameOf(x.opcode) + ", x: " + x.x() + ", y: " + x.y() + ", kind: " + x.kind;
         switch (x.kind) {
             case Float:
             case Double:
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/LoopUtil.java	Wed Jul 06 17:02:15 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/LoopUtil.java	Wed Jul 06 17:02:38 2011 +0200
@@ -27,6 +27,7 @@
 
 import com.oracle.max.graal.compiler.*;
 import com.oracle.max.graal.compiler.ir.*;
+import com.oracle.max.graal.compiler.ir.Phi.*;
 import com.oracle.max.graal.compiler.observer.*;
 import com.oracle.max.graal.compiler.schedule.*;
 import com.oracle.max.graal.compiler.util.GraphUtil.ColorSplitingLambda;
@@ -153,7 +154,7 @@
             for (Node usage : n.dataUsages()) {
                 if (usage instanceof Phi) { // filter out data graph cycles
                     Phi phi = (Phi) usage;
-                    if (!phi.isDead()) {
+                    if (phi.type() == PhiType.Value) {
                         Merge merge = phi.merge();
                         if (merge instanceof LoopBegin) {
                             LoopBegin phiLoop = (LoopBegin) merge;
@@ -172,7 +173,7 @@
             markWithState(n, inOrBefore);
             if (n instanceof Phi) { // filter out data graph cycles
                 Phi phi = (Phi) n;
-                if (!phi.isDead()) {
+                if (phi.type() == PhiType.Value) {
                     int backIndex = -1;
                     Merge merge = phi.merge();
                     if (!loopNodes.isMarked(merge) && merge instanceof LoopBegin) {
@@ -489,7 +490,7 @@
                     values.add(valueAt);
                 }
                 if (createPhi) {
-                    Phi phi = new Phi(kind, merge, merge.graph());
+                    Phi phi = new Phi(kind, merge, PhiType.Value, merge.graph());
                     valueMap.set(point, phi);
                     for (EndNode end : merge.cfgPredecessors()) {
                         phi.addInput(getValueAt(colors.get(end), valueMap, kind));
@@ -642,7 +643,7 @@
             }
             if (n instanceof Phi) { // filter out data graph cycles
                 Phi phi = (Phi) n;
-                if (!phi.isDead()) {
+                if (phi.type() == PhiType.Value) {
                     int backIndex = -1;
                     Merge merge = phi.merge();
                     if (!loopNodes.isNew(merge) && !loopNodes.isMarked(merge) && merge instanceof LoopBegin) {
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameState.java	Wed Jul 06 17:02:15 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameState.java	Wed Jul 06 17:02:38 2011 +0200
@@ -29,6 +29,7 @@
 import com.oracle.max.graal.compiler.*;
 import com.oracle.max.graal.compiler.debug.*;
 import com.oracle.max.graal.compiler.ir.*;
+import com.oracle.max.graal.compiler.ir.Phi.*;
 import com.oracle.max.graal.graph.*;
 import com.sun.cri.ci.*;
 import com.sun.cri.ri.*;
@@ -128,12 +129,27 @@
         return method;
     }
 
+    public void addVirtualObjectMapping(Node virtualObject) {
+        assert virtualObject instanceof VirtualObjectField || virtualObject instanceof Phi : virtualObject;
+        inputs().variablePart().add(virtualObject);
+    }
+
+    public int virtualObjectMappingCount() {
+        return inputs().variablePart().size();
+    }
+
+    public Node virtualObjectMappingAt(int i) {
+        return inputs().variablePart().get(i);
+    }
+
+
     /**
      * Gets a copy of this frame state.
      */
     public FrameState duplicate(int bci) {
         FrameState other = new FrameState(method, bci, localsSize, stackSize, locksSize, rethrowException, graph());
         other.inputs().setAll(inputs());
+        other.inputs().variablePart().addAll(inputs().variablePart());
         other.setOuterFrameState(outerFrameState());
         return other;
     }
@@ -165,6 +181,7 @@
         for (int i = 0; i < locksSize; i++) {
             other.setValueAt(localsSize + other.stackSize + i, lockAt(i));
         }
+        other.inputs().variablePart().addAll(inputs().variablePart());
         other.setOuterFrameState(outerFrameState());
         return other;
     }
@@ -317,7 +334,7 @@
                     return phi;
                 }
             }
-            Phi phi = new Phi(p.kind, block, graph());
+            Phi phi = new Phi(p.kind, block, PhiType.Value, graph());
             setValueAt(localsSize + i, phi);
             return phi;
         }
@@ -337,7 +354,7 @@
                 return phi;
             }
         }
-        Phi phi = new Phi(p.kind, block, graph());
+        Phi phi = new Phi(p.kind, block, PhiType.Value, graph());
         storeLocal(i, phi);
         return phi;
     }
@@ -385,11 +402,9 @@
                 Value y = other.valueAt(i);
                 if (x != y || ((x instanceof Phi) && ((Phi) x).merge() == block)) {
                     if (typeMismatch(x, y)) {
-                        if (x instanceof Phi) {
-                            Phi phi = (Phi) x;
-                            if (phi.merge() == block) {
-                                phi.makeDead();
-                            }
+                        if ((x instanceof Phi) && ((Phi) x).merge() == block) {
+                            x.replaceAtUsages(null);
+                            x.delete();
                         }
                         setValueAt(i, null);
                         continue;
@@ -471,30 +486,83 @@
      * @param proc the call back called to process each live value traversed
      */
     public void forEachLiveStateValue(ValueProcedure proc) {
-        for (int i = 0; i < valuesSize(); i++) {
-            Value value = valueAt(i);
-            visitLiveStateValue(value, proc);
-        }
-        if (outerFrameState() != null) {
-            outerFrameState().forEachLiveStateValue(proc);
-        }
-    }
+        HashSet<VirtualObject> vobjs = null;
+        FrameState current = this;
+        do {
+            for (int i = 0; i < current.valuesSize(); i++) {
+                Value value = current.valueAt(i);
+                if (value instanceof VirtualObject) {
+                    if (vobjs == null) {
+                        vobjs = new HashSet<VirtualObject>();
+                    }
+                    vobjs.add((VirtualObject) value);
+                } else if (value != null) {
+                    proc.doValue(value);
+                }
+            }
+            current = current.outerFrameState();
+        } while (current != null);
+
+        if (vobjs != null) {
+            // collect all VirtualObjectField instances:
+            HashMap<VirtualObject, VirtualObjectField> objectStates = new HashMap<VirtualObject, VirtualObjectField>();
+            current = this;
+            do {
+                for (int i = 0; i < current.virtualObjectMappingCount(); i++) {
+                    VirtualObjectField field = (VirtualObjectField) current.virtualObjectMappingAt(i);
+                    // null states occur for objects with 0 fields
+                    if (field != null && !objectStates.containsKey(field.object())) {
+                        objectStates.put(field.object(), field);
+                    }
+                }
+                current = current.outerFrameState();
+            } while (current != null);
 
-    private void visitLiveStateValue(Value value, ValueProcedure proc) {
-        if (value != null) {
-            if (value instanceof VirtualObject) {
-                HashSet<Object> fields = new HashSet<Object>();
-                VirtualObject obj = (VirtualObject) value;
-                do {
-                    if (!fields.contains(obj.field().representation())) {
-                        fields.add(obj.field().representation());
-                        visitLiveStateValue(obj.input(), proc);
+            do {
+                HashSet<VirtualObject> vobjsCopy = new HashSet<VirtualObject>(vobjs);
+                for (VirtualObject vobj : vobjsCopy) {
+                    if (vobj.fields().length > 0) {
+                        boolean[] fieldState = new boolean[vobj.fields().length];
+                        FloatingNode currentField = objectStates.get(vobj);
+                        assert currentField != null : this;
+                        do {
+                            if (currentField instanceof VirtualObjectField) {
+                                int index = ((VirtualObjectField) currentField).index();
+                                Value value = ((VirtualObjectField) currentField).input();
+                                if (!fieldState[index]) {
+                                    fieldState[index] = true;
+                                    if (value instanceof VirtualObject) {
+                                        vobjs.add((VirtualObject) value);
+                                    } else {
+                                        proc.doValue(value);
+                                    }
+                                }
+                                currentField = ((VirtualObjectField) currentField).lastState();
+                            } else {
+                                assert currentField instanceof Phi : currentField;
+                                currentField = (FloatingNode) ((Phi) currentField).valueAt(0);
+                            }
+                        } while (currentField != null);
                     }
-                    obj = obj.object();
-                } while (obj != null);
-            } else {
-                proc.doValue(value);
+                    vobjs.remove(vobj);
+                }
+            } while (!vobjs.isEmpty());
+            if (!vobjs.isEmpty()) {
+                for (VirtualObject obj : vobjs) {
+                    TTY.println("+" + obj);
+                }
+                for (Node vobj : inputs().variablePart()) {
+                    if (vobj instanceof VirtualObjectField) {
+                        TTY.println("-" + ((VirtualObjectField) vobj).object());
+                    } else {
+                        TTY.println("-" + vobj);
+                    }
+                }
+                for (Node n : this.usages()) {
+                    TTY.println("usage: " + n);
+                }
             }
+            assert vobjs.isEmpty() : "at FrameState " + this;
         }
     }
 
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameStateBuilder.java	Wed Jul 06 17:02:15 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameStateBuilder.java	Wed Jul 06 17:02:38 2011 +0200
@@ -28,6 +28,7 @@
 import java.util.*;
 
 import com.oracle.max.graal.compiler.ir.*;
+import com.oracle.max.graal.compiler.ir.Phi.PhiType;
 import com.oracle.max.graal.graph.*;
 import com.sun.cri.ci.*;
 import com.sun.cri.ri.*;
@@ -334,8 +335,11 @@
     public Value loadLocal(int i) {
         Value x = locals[i];
         if (x != null) {
-            if (x instanceof Phi && ((Phi) x).isDead()) {
-                return null;
+            if (x instanceof Phi) {
+                assert ((Phi) x).type() == PhiType.Value;
+                if (x.isDeleted()) {
+                    return null;
+                }
             }
             assert x.kind.isSingleWord() || locals[i + 1] == null || locals[i + 1] instanceof Phi;
         }