changeset 6399:6ad5bf2efb5e

cleanups, merge EscapeRecord and VirtualObjectNode
author Lukas Stadler <lukas.stadler@jku.at>
date Fri, 14 Sep 2012 15:26:57 +0200
parents bced4f3a4174
children e7b50827698e
files graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ea/PartialEscapeAnalysisPhase.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeBitMap.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MaterializeObjectNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeField.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeOp.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/BoxedVirtualObjectNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectState.java
diffstat 14 files changed, 412 insertions(+), 525 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Fri Sep 14 15:16:50 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Fri Sep 14 15:26:57 2012 +0200
@@ -82,13 +82,13 @@
                             BoxedVirtualObjectNode boxedVirtualObjectNode = (BoxedVirtualObjectNode) vobj;
                             entry.getValue().setValues(new Value[]{toValue(boxedVirtualObjectNode.getUnboxedValue())});
                         } else {
-                            Value[] values = new Value[vobj.fields().length];
+                            Value[] values = new Value[vobj.entryCount()];
                             entry.getValue().setValues(values);
                             if (values.length > 0) {
                                 changed = true;
                                 VirtualObjectState currentField = (VirtualObjectState) objectStates.get(vobj);
                                 assert currentField != null;
-                                for (int i = 0; i < vobj.fields().length; i++) {
+                                for (int i = 0; i < vobj.entryCount(); i++) {
                                     values[i] = toValue(currentField.fieldValues().get(i));
                                 }
                             }
@@ -147,14 +147,14 @@
         if (value instanceof VirtualObjectNode) {
             VirtualObjectNode obj = (VirtualObjectNode) value;
             EscapeObjectState state = objectStates.get(obj);
-            if (state == null && obj.fields().length > 0) {
+            if (state == null && obj.entryCount() > 0) {
                 // null states occur for objects with 0 fields
                 throw new GraalInternalError("no mapping found for virtual object %s", obj);
             }
             if (state instanceof MaterializedObjectState) {
                 return toValue(((MaterializedObjectState) state).materializedValue());
             } else {
-                assert obj.fields().length == 0 || state instanceof VirtualObjectState;
+                assert obj.entryCount() == 0 || state instanceof VirtualObjectState;
                 VirtualObject ciObj = virtualObjects.get(value);
                 if (ciObj == null) {
                     ciObj = VirtualObject.get(obj.type(), null, virtualObjects.size());
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ea/PartialEscapeAnalysisPhase.java	Fri Sep 14 15:16:50 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ea/PartialEscapeAnalysisPhase.java	Fri Sep 14 15:26:57 2012 +0200
@@ -42,77 +42,6 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.virtual.*;
 
-abstract class EscapeRecord {
-
-    public final int id;
-    public final ResolvedJavaType type;
-    public final VirtualObjectNode virtualObject;
-
-    public EscapeRecord(int id, ResolvedJavaType type, VirtualObjectNode virtualObject) {
-        this.id = id;
-        this.type = type;
-        this.virtualObject = virtualObject;
-    }
-
-    public abstract String fieldName(int index);
-
-    public abstract int fieldCount();
-}
-
-class InstanceEscapeRecord extends EscapeRecord {
-
-    public final EscapeField[] fields;
-    public final HashMap<Object, Integer> fieldMap = new HashMap<>();
-
-    public InstanceEscapeRecord(int id, ResolvedJavaType type, VirtualObjectNode virtualObject, EscapeField[] fields) {
-        super(id, type, virtualObject);
-        this.fields = fields;
-        for (int i = 0; i < fields.length; i++) {
-            fieldMap.put(fields[i].representation(), i);
-        }
-    }
-
-    @Override
-    public String toString() {
-        return MetaUtil.toJavaName(type, false) + "@" + id;
-    }
-
-    @Override
-    public String fieldName(int index) {
-        return fields[index].name();
-    }
-
-    @Override
-    public int fieldCount() {
-        return fields.length;
-    }
-}
-
-class ArrayEscapeRecord extends EscapeRecord {
-
-    public final int length;
-
-    public ArrayEscapeRecord(int id, ResolvedJavaType type, VirtualObjectNode virtualObject, int length) {
-        super(id, type, virtualObject);
-        this.length = length;
-    }
-
-    @Override
-    public String toString() {
-        return MetaUtil.toJavaName(type.componentType(), false) + "[" + length + "]@" + id;
-    }
-
-    @Override
-    public String fieldName(int index) {
-        return "[" + index + "]";
-    }
-
-    @Override
-    public int fieldCount() {
-        return length;
-    }
-}
-
 class EscapeAnalysisIteration {
 
     // Metrics
@@ -145,11 +74,11 @@
     private final MetaAccessProvider runtime;
     private final SchedulePhase schedule;
     private final NodeBitMap usages;
-    private final NodeBitMap visitedNodes;
     boolean changed = false;
 
     private final boolean changeGraph;
 
+    private final HashSet<VirtualObjectNode> reusedVirtualObjects = new HashSet<>();
     private final HashSet<ValueNode> allocations;
     private final ArrayList<ValueNode> obsoleteNodes = new ArrayList<>();
     private int virtualIds = 0;
@@ -160,7 +89,6 @@
         this.runtime = runtime;
         this.allocations = allocations;
         this.changeGraph = changeGraph;
-        this.visitedNodes = graph.createNodeBitMap();
         this.usages = graph.createNodeBitMap();
     }
 
@@ -183,41 +111,33 @@
             if (changed) {
                 Debug.log("escape analysis on %s\n", graph.method());
             }
-
-            if (GraalOptions.TraceEscapeAnalysis) {
-                for (Node node : graph.getNodes()) {
-                    if (!visitedNodes.isMarked(node) && !(node instanceof VirtualState) && !(node instanceof VirtualObjectNode)) {
-                        trace("unvisited node: %s", node);
-                    }
-                }
-            }
         }
     }
 
     private static class ObjectState {
 
-        public final EscapeRecord record;
+        public final VirtualObjectNode virtual;
         public ValueNode[] fieldState;
         public ValueNode materializedValue;
         public int lockCount;
         public boolean initialized;
 
-        public ObjectState(EscapeRecord record, ValueNode[] fieldState, int lockCount) {
-            this.record = record;
+        public ObjectState(VirtualObjectNode virtual, ValueNode[] fieldState, int lockCount) {
+            this.virtual = virtual;
             this.fieldState = fieldState;
             this.lockCount = lockCount;
             this.initialized = false;
         }
 
-        public ObjectState(EscapeRecord record, ValueNode materializedValue, int lockCount) {
-            this.record = record;
+        public ObjectState(VirtualObjectNode virtual, ValueNode materializedValue, int lockCount) {
+            this.virtual = virtual;
             this.materializedValue = materializedValue;
             this.lockCount = lockCount;
             this.initialized = true;
         }
 
         private ObjectState(ObjectState other) {
-            record = other.record;
+            virtual = other.virtual;
             fieldState = other.fieldState == null ? null : other.fieldState.clone();
             materializedValue = other.materializedValue;
             lockCount = other.lockCount;
@@ -237,7 +157,7 @@
             }
             if (fieldState != null) {
                 for (int i = 0; i < fieldState.length; i++) {
-                    str.append(record.fieldName(i)).append('=').append(fieldState[i]).append(' ');
+                    str.append(virtual.fieldName(i)).append('=').append(fieldState[i]).append(' ');
                 }
             }
             if (materializedValue != null) {
@@ -250,29 +170,29 @@
 
     private class BlockState implements MergeableBlockState<BlockState> {
 
-        private final HashMap<EscapeRecord, ObjectState> recordStates = new HashMap<>();
-        private final HashMap<ValueNode, EscapeRecord> recordAliases = new HashMap<>();
+        private final HashMap<VirtualObjectNode, ObjectState> objectStates = new HashMap<>();
+        private final HashMap<ValueNode, VirtualObjectNode> objectAliases = new HashMap<>();
 
         public BlockState() {
         }
 
         public BlockState(BlockState other) {
-            for (Map.Entry<EscapeRecord, ObjectState> entry : other.recordStates.entrySet()) {
-                recordStates.put(entry.getKey(), entry.getValue().clone());
+            for (Map.Entry<VirtualObjectNode, ObjectState> entry : other.objectStates.entrySet()) {
+                objectStates.put(entry.getKey(), entry.getValue().clone());
             }
-            for (Map.Entry<ValueNode, EscapeRecord> entry : other.recordAliases.entrySet()) {
-                recordAliases.put(entry.getKey(), entry.getValue());
+            for (Map.Entry<ValueNode, VirtualObjectNode> entry : other.objectAliases.entrySet()) {
+                objectAliases.put(entry.getKey(), entry.getValue());
             }
         }
 
-        public ObjectState objectState(EscapeRecord record) {
-            assert recordStates.containsKey(record);
-            return recordStates.get(record);
+        public ObjectState objectState(VirtualObjectNode object) {
+            assert objectStates.containsKey(object);
+            return objectStates.get(object);
         }
 
         public ObjectState objectState(ValueNode value) {
-            EscapeRecord record = recordAliases.get(value);
-            return record == null ? null : objectState(record);
+            VirtualObjectNode object = objectAliases.get(value);
+            return object == null ? null : objectState(object);
         }
 
         @Override
@@ -280,26 +200,26 @@
             return new BlockState(this);
         }
 
-        public void materializeBefore(FixedNode fixed, EscapeRecord record) {
+        public void materializeBefore(FixedNode fixed, VirtualObjectNode virtual) {
             if (changeGraph) {
-                HashSet<EscapeRecord> deferred = new HashSet<>();
+                HashSet<VirtualObjectNode> deferred = new HashSet<>();
                 ArrayList<FixedWithNextNode> deferredStores = new ArrayList<>();
-                materializeChangedBefore(fixed, record, deferred, deferredStores);
+                materializeChangedBefore(fixed, virtual, deferred, deferredStores);
                 for (FixedWithNextNode write : deferredStores) {
                     write.setProbability(fixed.probability());
                     graph.addBeforeFixed(fixed, write);
                 }
             } else {
-                materializeUnchangedBefore(record);
+                materializeUnchangedBefore(virtual);
             }
         }
 
-        private void materializeUnchangedBefore(EscapeRecord record) {
-            trace("materializing %s", record);
-            ObjectState obj = objectState(record);
+        private void materializeUnchangedBefore(VirtualObjectNode virtual) {
+            trace("materializing %s", virtual);
+            ObjectState obj = objectState(virtual);
             if (obj.lockCount > 0) {
                 if (changeGraph) {
-                    error("object materialized with lock: %s\n", record);
+                    error("object materialized with lock: %s\n", virtual);
                 }
                 metricMonitorBailouts.increment();
                 throw new BailoutException("object materialized with lock");
@@ -312,75 +232,75 @@
                 ObjectState valueObj = objectState(fieldState[i]);
                 if (valueObj != null) {
                     if (valueObj.materializedValue == null) {
-                        materializeUnchangedBefore(valueObj.record);
+                        materializeUnchangedBefore(valueObj.virtual);
                     }
                 }
             }
             obj.initialized = true;
         }
 
-        private void materializeChangedBefore(FixedNode fixed, EscapeRecord record, HashSet<EscapeRecord> deferred, ArrayList<FixedWithNextNode> deferredStores) {
-            trace("materializing %s at %s", record, fixed);
-            ObjectState obj = objectState(record);
+        private void materializeChangedBefore(FixedNode fixed, VirtualObjectNode virtual, HashSet<VirtualObjectNode> deferred, ArrayList<FixedWithNextNode> deferredStores) {
+            trace("materializing %s at %s", virtual, fixed);
+            ObjectState obj = objectState(virtual);
             if (obj.lockCount > 0) {
-                error("object materialized with lock: %s\n", record);
+                error("object materialized with lock: %s\n", virtual);
                 metricMonitorBailouts.increment();
                 throw new BailoutException("object materialized with lock");
             }
 
-            MaterializeObjectNode materialize = graph.add(new MaterializeObjectNode(record.type, record.virtualObject));
+            MaterializeObjectNode materialize = graph.add(new MaterializeObjectNode(virtual));
             materialize.setProbability(fixed.probability());
             ValueNode[] fieldState = obj.fieldState;
             metricMaterializations.increment();
             metricMaterializationFields.add(fieldState.length);
             obj.fieldState = null;
             obj.materializedValue = materialize;
-            deferred.add(record);
+            deferred.add(virtual);
             for (int i = 0; i < fieldState.length; i++) {
                 ObjectState valueObj = objectState(fieldState[i]);
                 if (valueObj != null) {
                     if (valueObj.materializedValue == null) {
-                        materializeChangedBefore(fixed, valueObj.record, deferred, deferredStores);
+                        materializeChangedBefore(fixed, valueObj.virtual, deferred, deferredStores);
                     }
-                    if (deferred.contains(valueObj.record)) {
+                    if (deferred.contains(valueObj.virtual)) {
                         Kind fieldKind;
-                        if (record.type.isArrayClass()) {
+                        if (virtual instanceof VirtualArrayNode) {
                             deferredStores.add(graph.add(new CyclicMaterializeStoreNode(materialize, valueObj.materializedValue, i)));
-                            fieldKind = record.type.componentType().kind();
+                            fieldKind = ((VirtualArrayNode) virtual).componentType().kind();
                         } else {
-                            InstanceEscapeRecord instanceRecord = (InstanceEscapeRecord) record;
-                            deferredStores.add(graph.add(new CyclicMaterializeStoreNode(materialize, valueObj.materializedValue, (ResolvedJavaField) instanceRecord.fields[i].representation())));
-                            fieldKind = instanceRecord.fields[i].type().kind();
+                            VirtualInstanceNode instanceObject = (VirtualInstanceNode) virtual;
+                            deferredStores.add(graph.add(new CyclicMaterializeStoreNode(materialize, valueObj.materializedValue, instanceObject.field(i))));
+                            fieldKind = instanceObject.field(i).type().kind();
                         }
                         materialize.values().set(i, ConstantNode.defaultForKind(fieldKind, graph));
                     } else {
-                        assert valueObj.initialized : "should be initialized: " + record + " at " + fixed;
+                        assert valueObj.initialized : "should be initialized: " + virtual + " at " + fixed;
                         materialize.values().set(i, valueObj.materializedValue);
                     }
                 } else {
                     materialize.values().set(i, fieldState[i]);
                 }
             }
-            deferred.remove(record);
+            deferred.remove(virtual);
 
             obj.initialized = true;
             graph.addBeforeFixed(fixed, materialize);
         }
 
-        private void addAndMarkAlias(EscapeRecord record, ValueNode node) {
-            addAlias(record, node);
+        private void addAndMarkAlias(VirtualObjectNode virtual, ValueNode node, boolean remove) {
+            objectAliases.put(node, virtual);
             for (Node usage : node.usages()) {
-                assert !visitedNodes.isMarked(usage) : "used by already visited node: " + node + " -> " + usage;
-                usages.mark(usage);
-                if (usage instanceof VirtualState) {
-                    markVirtualUsages(usage);
-                }
+                markVirtualUsages(usage);
             }
-            obsoleteNodes.add(node);
+            if (remove) {
+                obsoleteNodes.add(node);
+            }
         }
 
         private void markVirtualUsages(Node node) {
-            usages.mark(node);
+            if (!usages.isNew(node)) {
+                usages.mark(node);
+            }
             if (node instanceof VirtualState) {
                 for (Node usage : node.usages()) {
                     markVirtualUsages(usage);
@@ -388,21 +308,17 @@
             }
         }
 
-        public void addAlias(EscapeRecord record, ValueNode alias) {
-            recordAliases.put(alias, record);
-        }
-
-        public void addRecord(EscapeRecord record, ObjectState state) {
-            recordStates.put(record, state);
+        public void addObject(VirtualObjectNode virtual, ObjectState state) {
+            objectStates.put(virtual, state);
         }
 
         public Iterable<ObjectState> states() {
-            return recordStates.values();
+            return objectStates.values();
         }
 
         @Override
         public String toString() {
-            return recordStates.toString();
+            return objectStates.toString();
         }
     }
 
@@ -432,23 +348,26 @@
 
                 if (op != null) {
                     trace("{{%s}} ", node);
-                    ResolvedJavaType type = op.type();
-                    EscapeField[] fields = op.fields();
-                    VirtualObjectNode virtualObject = changeGraph ? graph.add(new VirtualObjectNode(virtualIds, type, fields)) : null;
-                    EscapeRecord record = type.isArrayClass() ? new ArrayEscapeRecord(virtualIds, type, virtualObject, fields.length) : new InstanceEscapeRecord(virtualIds, type, virtualObject, fields);
-                    ValueNode[] fieldState = changeGraph ? op.fieldState() : new ValueNode[fields.length];
+                    VirtualObjectNode virtualObject = op.virtualObject(virtualIds);
+                    if (virtualObject.isAlive()) {
+                        reusedVirtualObjects.add(virtualObject);
+                        state.addAndMarkAlias(virtualObject, virtualObject, false);
+                    } else {
+                        if (changeGraph) {
+                            virtualObject = graph.add(virtualObject);
+                        }
+                    }
+                    ValueNode[] fieldState = changeGraph ? op.fieldState() : new ValueNode[virtualObject.entryCount()];
                     if (changeGraph) {
                         metricAllocationRemoved.increment();
                         metricAllocationFieldsRemoved.add(fieldState.length);
                     } else {
                         allocations.add((ValueNode) node);
                     }
-                    state.addRecord(record, new ObjectState(record, fieldState, 0));
-                    state.addAndMarkAlias(record, (ValueNode) node);
+                    state.addObject(virtualObject, new ObjectState(virtualObject, fieldState, 0));
+                    state.addAndMarkAlias(virtualObject, (ValueNode) node, true);
                     virtualIds++;
                 } else {
-                    visitedNodes.mark(node);
-
                     if (changeGraph && node instanceof LoopExitNode) {
                         for (ObjectState obj : state.states()) {
                             if (obj.fieldState != null) {
@@ -487,7 +406,7 @@
                 ObjectState obj = state.objectState(value);
                 assert obj != null : node;
                 if (obj.materializedValue == null) {
-                    state.addAndMarkAlias(obj.record, node);
+                    state.addAndMarkAlias(obj.virtual, node, true);
                 } else {
                     if (changeGraph) {
                         node.replaceFirstInput(value, obj.materializedValue);
@@ -499,9 +418,9 @@
                 ObjectState obj = state.objectState(x.object());
                 assert obj != null : x;
                 if (obj.materializedValue == null) {
-                    if (x.targetClass() != null && obj.record.type.isSubtypeOf(x.targetClass())) {
+                    if (x.targetClass() != null && obj.virtual.type().isSubtypeOf(x.targetClass())) {
                         metricOtherRemoved.increment();
-                        state.addAndMarkAlias(obj.record, x);
+                        state.addAndMarkAlias(obj.virtual, x, true);
                         // throw new UnsupportedOperationException("probably incorrect - losing dependency");
                     } else {
                         replaceWithMaterialized(x.object(), x, state, obj);
@@ -527,7 +446,7 @@
                 AccessMonitorNode x = (AccessMonitorNode) node;
                 ObjectState obj = state.objectState(x.object());
                 if (obj != null) {
-                    Debug.log("monitor operation %s on %s\n", x, obj.record);
+                    Debug.log("monitor operation %s on %s\n", x, obj.virtual);
                     if (node instanceof MonitorEnterNode) {
                         obj.lockCount++;
                     } else {
@@ -538,7 +457,7 @@
                         changed = true;
                         if (obj.materializedValue == null) {
                             metricLockRemoved.increment();
-                            node.replaceFirstInput(x.object(), obj.record.virtualObject);
+                            node.replaceFirstInput(x.object(), obj.virtual);
                             x.eliminate();
                         } else {
                             node.replaceFirstInput(x.object(), obj.materializedValue);
@@ -550,11 +469,11 @@
                 CyclicMaterializeStoreNode x = (CyclicMaterializeStoreNode) node;
                 ObjectState obj = state.objectState(x.object());
                 assert obj != null : x;
-                if (obj.record.type.isArrayClass()) {
+                if (obj.virtual instanceof VirtualArrayNode) {
                     obj.fieldState[x.targetIndex()] = x.value();
                 } else {
-                    InstanceEscapeRecord record = (InstanceEscapeRecord) obj.record;
-                    int index = record.fieldMap.get(x.targetField());
+                    VirtualInstanceNode instance = (VirtualInstanceNode) obj.virtual;
+                    int index = instance.fieldIndex(x.targetField());
                     obj.fieldState[index] = x.value();
                 }
                 if (changeGraph) {
@@ -565,17 +484,17 @@
                 LoadFieldNode x = (LoadFieldNode) node;
                 ObjectState obj = state.objectState(x.object());
                 assert obj != null : x;
-                InstanceEscapeRecord record = (InstanceEscapeRecord) obj.record;
-                if (!record.fieldMap.containsKey(x.field())) {
+                VirtualInstanceNode virtual = (VirtualInstanceNode) obj.virtual;
+                int fieldIndex = virtual.fieldIndex(x.field());
+                if (fieldIndex == -1) {
                     // the field does not exist in the virtual object
                     ensureMaterialized(state, obj, x);
                 }
                 if (obj.materializedValue == null) {
-                    int index = record.fieldMap.get(x.field());
-                    ValueNode result = obj.fieldState[index];
+                    ValueNode result = obj.fieldState[fieldIndex];
                     ObjectState resultObj = state.objectState(result);
                     if (resultObj != null) {
-                        state.addAndMarkAlias(resultObj.record, x);
+                        state.addAndMarkAlias(resultObj.virtual, x, true);
                     } else {
                         if (changeGraph) {
                             x.replaceAtUsages(result);
@@ -598,14 +517,14 @@
                 ValueNode value = x.value();
                 ObjectState obj = state.objectState(object);
                 if (obj != null) {
-                    InstanceEscapeRecord record = (InstanceEscapeRecord) obj.record;
-                    if (!record.fieldMap.containsKey(x.field())) {
+                    VirtualInstanceNode virtual = (VirtualInstanceNode) obj.virtual;
+                    int fieldIndex = virtual.fieldIndex(x.field());
+                    if (fieldIndex == -1) {
                         // the field does not exist in the virtual object
                         ensureMaterialized(state, obj, x);
                     }
                     if (obj.materializedValue == null) {
-                        int index = record.fieldMap.get(x.field());
-                        obj.fieldState[index] = value;
+                        obj.fieldState[fieldIndex] = value;
                         if (changeGraph) {
                             graph.removeFixed(x);
                             metricStoreRemoved.increment();
@@ -642,7 +561,7 @@
                             ValueNode result = arrayObj.fieldState[index];
                             ObjectState resultObj = state.objectState(result);
                             if (resultObj != null) {
-                                state.addAndMarkAlias(resultObj.record, x);
+                                state.addAndMarkAlias(resultObj.virtual, x, true);
                             } else {
                                 if (changeGraph) {
                                     x.replaceAtUsages(result);
@@ -710,7 +629,7 @@
                 ObjectState obj = state.objectState(x.array());
                 assert obj != null : x;
                 if (changeGraph) {
-                    graph.replaceFixedWithFloating(x, ConstantNode.forInt(((ArrayEscapeRecord) obj.record).length, graph));
+                    graph.replaceFixedWithFloating(x, ConstantNode.forInt(((VirtualArrayNode) obj.virtual).entryCount(), graph));
                     metricOtherRemoved.increment();
                 }
                 changed = true;
@@ -720,7 +639,7 @@
                 ObjectState obj = state.objectState(x.object());
                 assert obj != null : x;
                 if (changeGraph) {
-                    ConstantNode hub = ConstantNode.forConstant(obj.record.type.getEncoding(Representation.ObjectHub), runtime, graph);
+                    ConstantNode hub = ConstantNode.forConstant(obj.virtual.type().getEncoding(Representation.ObjectHub), runtime, graph);
                     graph.replaceFixedWithFloating(x, hub);
                     metricOtherRemoved.increment();
                 }
@@ -800,11 +719,11 @@
                                 ObjectState valueObj = state.objectState(value);
                                 if (valueObj != null) {
                                     virtual.add(valueObj);
-                                    usage.replaceFirstInput(value, valueObj.record.virtualObject);
+                                    usage.replaceFirstInput(value, valueObj.virtual);
                                 } else if (value instanceof VirtualObjectNode) {
                                     ObjectState virtualObj = null;
                                     for (ObjectState obj : state.states()) {
-                                        if (value == obj.record.virtualObject) {
+                                        if (value == obj.virtual) {
                                             virtualObj = obj;
                                             break;
                                         }
@@ -844,19 +763,23 @@
                                     ObjectState valueObj = state.objectState(fieldState[i]);
                                     if (valueObj != null) {
                                         if (valueObj.materializedValue == null) {
-                                            fieldState[i] = valueObj.record.virtualObject;
+                                            fieldState[i] = valueObj.virtual;
                                         } else {
                                             fieldState[i] = valueObj.materializedValue;
                                         }
                                     }
                                 }
-                                v = graph.add(new VirtualObjectState(obj.record.virtualObject, fieldState));
+                                v = graph.add(new VirtualObjectState(obj.virtual, fieldState));
                             } else {
-                                v = graph.add(new MaterializedObjectState(obj.record.virtualObject, obj.materializedValue));
+                                v = graph.add(new MaterializedObjectState(obj.virtual, obj.materializedValue));
                             }
-                            for (EscapeObjectState s : stateAfter.virtualObjectMappings()) {
-                                if (s.object() == v.object()) {
-                                    throw new GraalInternalError("unexpected duplicate virtual state at: %s for %s", node, v.object());
+                            for (int i = 0; i < stateAfter.virtualObjectMappingCount(); i++) {
+                                if (stateAfter.virtualObjectMappingAt(i).object() == v.object()) {
+                                    if (reusedVirtualObjects.contains(v.object())) {
+                                        stateAfter.virtualObjectMappings().remove(i);
+                                    } else {
+                                        throw new GraalInternalError("unexpected duplicate virtual state at: %s for %s", node, v.object());
+                                    }
                                 }
                             }
                             stateAfter.addVirtualObjectMapping(v);
@@ -880,7 +803,7 @@
         private void ensureMaterialized(BlockState state, ObjectState obj, FixedNode materializeBefore) {
             assert obj != null;
             if (obj.materializedValue == null) {
-                state.materializeBefore(materializeBefore, obj.record);
+                state.materializeBefore(materializeBefore, obj.virtual);
             }
             assert obj.materializedValue != null;
         }
@@ -903,14 +826,14 @@
         protected BlockState merge(MergeNode merge, List<BlockState> states) {
             BlockState newState = new BlockState();
 
-            newState.recordAliases.putAll(states.get(0).recordAliases);
+            newState.objectAliases.putAll(states.get(0).objectAliases);
             for (int i = 1; i < states.size(); i++) {
                 BlockState state = states.get(i);
-                for (Map.Entry<ValueNode, EscapeRecord> entry : states.get(0).recordAliases.entrySet()) {
-                    if (state.recordAliases.containsKey(entry.getKey())) {
-                        assert state.recordAliases.get(entry.getKey()) == entry.getValue();
+                for (Map.Entry<ValueNode, VirtualObjectNode> entry : states.get(0).objectAliases.entrySet()) {
+                    if (state.objectAliases.containsKey(entry.getKey())) {
+                        assert state.objectAliases.get(entry.getKey()) == entry.getValue();
                     } else {
-                        newState.recordAliases.remove(entry.getKey());
+                        newState.objectAliases.remove(entry.getKey());
                     }
                 }
             }
@@ -923,13 +846,13 @@
             do {
                 materialized = false;
                 // use a hash set to make the values distinct...
-                for (EscapeRecord record : new HashSet<>(newState.recordAliases.values())) {
-                    ObjectState resultState = newState.recordStates.get(record);
+                for (VirtualObjectNode object : new HashSet<>(newState.objectAliases.values())) {
+                    ObjectState resultState = newState.objectStates.get(object);
                     if (resultState == null || resultState.materializedValue == null) {
                         int virtual = 0;
-                        int lockCount = states.get(0).objectState(record).lockCount;
+                        int lockCount = states.get(0).objectState(object).lockCount;
                         for (BlockState state : states) {
-                            ObjectState obj = state.objectState(record);
+                            ObjectState obj = state.objectState(object);
                             if (obj.materializedValue == null) {
                                 virtual++;
                             }
@@ -940,23 +863,23 @@
                             ValueNode materializedValuePhi = changeGraph ? graph.add(new PhiNode(Kind.Object, merge)) : DUMMY_NODE;
                             for (int i = 0; i < states.size(); i++) {
                                 BlockState state = states.get(i);
-                                ObjectState obj = state.objectState(record);
+                                ObjectState obj = state.objectState(object);
                                 materialized |= obj.materializedValue == null;
                                 ensureMaterialized(state, obj, merge.forwardEndAt(i));
                                 if (changeGraph) {
                                     ((PhiNode) materializedValuePhi).addInput(obj.materializedValue);
                                 }
                             }
-                            newState.addRecord(record, new ObjectState(record, materializedValuePhi, lockCount));
+                            newState.addObject(object, new ObjectState(object, materializedValuePhi, lockCount));
                         } else {
                             assert virtual == states.size();
-                            ValueNode[] values = states.get(0).objectState(record).fieldState.clone();
+                            ValueNode[] values = states.get(0).objectState(object).fieldState.clone();
                             PhiNode[] phis = new PhiNode[values.length];
                             boolean[] phiCreated = new boolean[values.length];
                             int mismatch = 0;
                             for (int i = 1; i < states.size(); i++) {
                                 BlockState state = states.get(i);
-                                ValueNode[] fields = state.objectState(record).fieldState;
+                                ValueNode[] fields = state.objectState(object).fieldState;
                                 for (int index = 0; index < values.length; index++) {
                                     if (!phiCreated[index] && values[index] != fields[index]) {
                                         mismatch++;
@@ -970,7 +893,7 @@
                             if (mismatch > 0) {
                                 for (int i = 0; i < states.size(); i++) {
                                     BlockState state = states.get(i);
-                                    ValueNode[] fields = state.objectState(record).fieldState;
+                                    ValueNode[] fields = state.objectState(object).fieldState;
                                     for (int index = 0; index < values.length; index++) {
                                         if (phiCreated[index]) {
                                             ObjectState obj = state.objectState(fields[index]);
@@ -991,14 +914,13 @@
                                     }
                                 }
                             }
-                            newState.addRecord(record, new ObjectState(record, values, lockCount));
+                            newState.addObject(object, new ObjectState(object, values, lockCount));
                         }
                     }
                 }
 
                 for (PhiNode phi : merge.phis().snapshot()) {
                     if (usages.isMarked(phi) && phi.type() == PhiType.Value) {
-                        visitedNodes.mark(phi);
                         materialized |= processPhi(newState, merge, phi, states);
                     }
                 }
@@ -1011,9 +933,9 @@
             assert states.size() == phi.valueCount();
             int virtualInputs = 0;
             boolean materialized = false;
-            EscapeRecord sameRecord = null;
+            VirtualObjectNode sameObject = null;
             ResolvedJavaType sameType = null;
-            int sameFieldCount = -1;
+            int sameEntryCount = -1;
             for (int i = 0; i < phi.valueCount(); i++) {
                 ValueNode value = phi.valueAt(i);
                 ObjectState obj = states.get(i).objectState(value);
@@ -1021,18 +943,18 @@
                     if (obj.materializedValue == null) {
                         virtualInputs++;
                         if (i == 0) {
-                            sameRecord = obj.record;
-                            sameType = obj.record.type;
-                            sameFieldCount = obj.record.fieldCount();
+                            sameObject = obj.virtual;
+                            sameType = obj.virtual.type();
+                            sameEntryCount = obj.virtual.entryCount();
                         } else {
-                            if (sameRecord != obj.record) {
-                                sameRecord = null;
+                            if (sameObject != obj.virtual) {
+                                sameObject = null;
                             }
-                            if (sameType != obj.record.type) {
+                            if (sameType != obj.virtual.type()) {
                                 sameType = null;
                             }
-                            if (sameFieldCount != obj.record.fieldCount()) {
-                                sameFieldCount = -1;
+                            if (sameEntryCount != obj.virtual.entryCount()) {
+                                sameEntryCount = -1;
                             }
                         }
                     } else {
@@ -1046,9 +968,9 @@
             if (virtualInputs == 0) {
                 // nothing to do...
             } else if (virtualInputs == phi.valueCount()) {
-                if (sameRecord != null) {
-                    newState.addAndMarkAlias(sameRecord, phi);
-                } else if (sameType != null && sameFieldCount != -1) {
+                if (sameObject != null) {
+                    newState.addAndMarkAlias(sameObject, phi, true);
+                } else if (sameType != null && sameEntryCount != -1) {
                     materialize = true;
                     // throw new GraalInternalError("merge required for %s", sameType);
                 } else {
@@ -1124,10 +1046,10 @@
                     Iterator<LoopEndNode> iter = loopEnds.iterator();
                     for (BlockState loopEndState : loopEndStates) {
                         LoopEndNode loopEnd = iter.next();
-                        ObjectState endObj = loopEndState.objectState(obj.record);
+                        ObjectState endObj = loopEndState.objectState(obj.virtual);
                         if (endObj.fieldState == null) {
                             if (changeGraph) {
-                                error("object materialized within loop: %s\n", obj.record);
+                                error("object materialized within loop: %s\n", obj.virtual);
                             }
                             metricLoopBailouts.increment();
                             throw new BailoutException("object materialized within loop");
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeBitMap.java	Fri Sep 14 15:16:50 2012 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeBitMap.java	Fri Sep 14 15:26:57 2012 +0200
@@ -111,7 +111,7 @@
 
     private boolean check(Node node) {
         assert node.graph() == graph : "this node is not part of the graph";
-        assert !isNew(node) : "node was added to the graph after creating the node bitmap";
+        assert !isNew(node) : "node was added to the graph after creating the node bitmap: " + node;
         assert node.isAlive() : "node is deleted!";
         return true;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Fri Sep 14 15:16:50 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Fri Sep 14 15:26:57 2012 +0200
@@ -211,7 +211,7 @@
         return virtualObjectMappings.size();
     }
 
-    public Node virtualObjectMappingAt(int i) {
+    public EscapeObjectState virtualObjectMappingAt(int i) {
         return virtualObjectMappings.get(i);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MaterializeObjectNode.java	Fri Sep 14 15:16:50 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MaterializeObjectNode.java	Fri Sep 14 15:26:57 2012 +0200
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.nodes.java;
 
-import java.util.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
@@ -31,22 +29,16 @@
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.virtual.*;
 
-@NodeInfo(nameTemplate = "Materialize {p#type/s}")
+@NodeInfo(nameTemplate = "Materialize {i#virtualObject}")
 public final class MaterializeObjectNode extends FixedWithNextNode implements EscapeAnalyzable, Lowerable, Node.IterableNodeType, Canonicalizable {
 
     @Input private final NodeInputList<ValueNode> values;
     @Input private final VirtualObjectNode virtualObject;
-    private final ResolvedJavaType type;
 
-    public MaterializeObjectNode(ResolvedJavaType type, VirtualObjectNode virtualObject) {
-        super(StampFactory.exactNonNull(type));
-        this.type = type;
+    public MaterializeObjectNode(VirtualObjectNode virtualObject) {
+        super(StampFactory.exactNonNull(virtualObject.type()));
         this.virtualObject = virtualObject;
-        this.values = new NodeInputList<>(this, virtualObject.fields().length);
-    }
-
-    public ResolvedJavaType type() {
-        return type;
+        this.values = new NodeInputList<>(this, virtualObject.entryCount());
     }
 
     public NodeInputList<ValueNode> values() {
@@ -56,34 +48,38 @@
     @Override
     public void lower(LoweringTool tool) {
         StructuredGraph graph = (StructuredGraph) graph();
-        EscapeField[] fields = virtualObject.fields();
-        if (type.isArrayClass()) {
-            ResolvedJavaType element = type.componentType();
-            NewArrayNode newArray;
-            if (element.kind() == Kind.Object) {
-                newArray = graph.add(new NewObjectArrayNode(element, ConstantNode.forInt(fields.length, graph), false));
-            } else {
-                newArray = graph.add(new NewPrimitiveArrayNode(element, ConstantNode.forInt(fields.length, graph), false));
-            }
-            this.replaceAtUsages(newArray);
-            graph.addAfterFixed(this, newArray);
+        if (virtualObject instanceof VirtualInstanceNode) {
+            VirtualInstanceNode virtual = (VirtualInstanceNode) virtualObject;
 
-            FixedWithNextNode position = newArray;
-            for (int i = 0; i < fields.length; i++) {
-                StoreIndexedNode store = graph.add(new StoreIndexedNode(newArray, ConstantNode.forInt(i, graph), element.kind(), values.get(i), -1));
+            NewInstanceNode newInstance = graph.add(new NewInstanceNode(virtual.type(), false));
+            this.replaceAtUsages(newInstance);
+            graph.addAfterFixed(this, newInstance);
+
+            FixedWithNextNode position = newInstance;
+            for (int i = 0; i < virtual.entryCount(); i++) {
+                StoreFieldNode store = graph.add(new StoreFieldNode(newInstance, virtual.field(i), values.get(i), -1));
                 graph.addAfterFixed(position, store);
                 position = store;
             }
 
             graph.removeFixed(this);
         } else {
-            NewInstanceNode newInstance = graph.add(new NewInstanceNode(type, false));
-            this.replaceAtUsages(newInstance);
-            graph.addAfterFixed(this, newInstance);
+            assert virtualObject instanceof VirtualArrayNode;
+            VirtualArrayNode virtual = (VirtualArrayNode) virtualObject;
 
-            FixedWithNextNode position = newInstance;
-            for (int i = 0; i < fields.length; i++) {
-                StoreFieldNode store = graph.add(new StoreFieldNode(newInstance, (ResolvedJavaField) fields[i].representation(), values.get(i), -1));
+            ResolvedJavaType element = virtual.componentType();
+            NewArrayNode newArray;
+            if (element.kind() == Kind.Object) {
+                newArray = graph.add(new NewObjectArrayNode(element, ConstantNode.forInt(virtual.entryCount(), graph), false));
+            } else {
+                newArray = graph.add(new NewPrimitiveArrayNode(element, ConstantNode.forInt(virtual.entryCount(), graph), false));
+            }
+            this.replaceAtUsages(newArray);
+            graph.addAfterFixed(this, newArray);
+
+            FixedWithNextNode position = newArray;
+            for (int i = 0; i < virtual.entryCount(); i++) {
+                StoreIndexedNode store = graph.add(new StoreIndexedNode(newArray, ConstantNode.forInt(i, graph), element.kind(), values.get(i), -1));
                 graph.addAfterFixed(position, store);
                 position = store;
             }
@@ -103,34 +99,17 @@
 
     @Override
     public EscapeOp getEscapeOp() {
-        return new EscapeOpImpl();
-    }
-
-    private final class EscapeOpImpl extends EscapeOp {
-
-        @Override
-        public ResolvedJavaType type() {
-            return type;
-        }
-
-        @Override
-        public EscapeField[] fields() {
-            return virtualObject.fields();
-        }
+        return new EscapeOp() {
 
-        @Override
-        public ValueNode[] fieldState() {
-            return values.toArray(new ValueNode[values.size()]);
-        }
+            @Override
+            public ValueNode[] fieldState() {
+                return values.toArray(new ValueNode[values.size()]);
+            }
 
-        @Override
-        public void beforeUpdate(Node usage) {
-            throw new UnsupportedOperationException("MaterializeNode can only be escape analyzed using partial escape analysis");
-        }
-
-        @Override
-        public int updateState(VirtualObjectNode node, Node current, Map<Object, Integer> fieldIndex, ValueNode[] fieldState) {
-            throw new UnsupportedOperationException("MaterializeNode can only be escape analyzed using partial escape analysis");
-        }
+            @Override
+            public VirtualObjectNode virtualObject(int virtualId) {
+                return virtualObject;
+            }
+        };
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Fri Sep 14 15:16:50 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Fri Sep 14 15:26:57 2012 +0200
@@ -22,14 +22,10 @@
  */
 package com.oracle.graal.nodes.java;
 
-import java.util.*;
-
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.nodes.virtual.*;
 
 /**
@@ -50,6 +46,7 @@
 
     /**
      * Constructs a new NewArrayNode.
+     *
      * @param length the node that produces the length for this allocation
      */
     protected NewArrayNode(ResolvedJavaType elementType, ValueNode length, boolean fillContents) {
@@ -73,6 +70,7 @@
 
     /**
      * Gets the element type of the array.
+     *
      * @return the element type of the array
      */
     public ResolvedJavaType elementType() {
@@ -93,72 +91,27 @@
 
     @Override
     public EscapeOp getEscapeOp() {
-        Constant constantLength = length().asConstant();
-        if (constantLength != null && constantLength.asInt() >= 0 && constantLength.asInt() < MaximumEscapeAnalysisArrayLength) {
-            return new EscapeOpImpl();
-        } else {
-            return null;
-        }
-    }
-
-    private final class EscapeOpImpl extends EscapeOp {
-
-        @Override
-        public ResolvedJavaType type() {
-            return elementType.arrayOf();
-        }
+        if (length().asConstant() != null) {
+            final int constantLength = length().asConstant().asInt();
+            if (constantLength >= 0 && constantLength < MaximumEscapeAnalysisArrayLength) {
+                return new EscapeOp() {
 
-        @Override
-        public EscapeField[] fields() {
-            int constantLength = dimension(0).asConstant().asInt();
-            EscapeField[] fields = new EscapeField[constantLength];
-            for (int i = 0; i < constantLength; i++) {
-                Integer representation = i;
-                fields[i] = new EscapeField(Integer.toString(i), representation, elementType());
-            }
-            return fields;
-        }
+                    @Override
+                    public ValueNode[] fieldState() {
+                        ValueNode[] state = new ValueNode[constantLength];
+                        for (int i = 0; i < constantLength; i++) {
+                            state[i] = ConstantNode.defaultForKind(elementType().kind(), graph());
+                        }
+                        return state;
+                    }
 
-        @Override
-        public ValueNode[] fieldState() {
-            ValueNode[] state = new ValueNode[dimension(0).asConstant().asInt()];
-            for (int i = 0; i < state.length; i++) {
-                state[i] = ConstantNode.defaultForKind(elementType().kind(), graph());
-            }
-            return state;
-        }
-
-        @Override
-        public void beforeUpdate(Node usage) {
-            if (usage instanceof ArrayLengthNode) {
-                ArrayLengthNode x = (ArrayLengthNode) usage;
-                StructuredGraph graph = (StructuredGraph) graph();
-                x.replaceAtUsages(dimension(0));
-                graph.removeFixed(x);
-            } else {
-                beforeUpdate(NewArrayNode.this, usage);
+                    @Override
+                    public VirtualObjectNode virtualObject(int virtualId) {
+                        return new VirtualArrayNode(virtualId, elementType, constantLength);
+                    }
+                };
             }
         }
-
-        @Override
-        public int updateState(VirtualObjectNode virtualObject, Node current, Map<Object, Integer> fieldIndex, ValueNode[] fieldState) {
-            if (current instanceof AccessIndexedNode) {
-                AccessIndexedNode x = (AccessIndexedNode) current;
-                if (GraphUtil.unProxify(x.array()) == virtualObject) {
-                    int index = ((AccessIndexedNode) current).index().asConstant().asInt();
-                    StructuredGraph graph = (StructuredGraph) x.graph();
-                    if (current instanceof LoadIndexedNode) {
-                        x.replaceAtUsages(fieldState[index]);
-                        graph.removeFixed(x);
-                    } else if (current instanceof StoreIndexedNode) {
-                        fieldState[index] = ((StoreIndexedNode) x).value();
-                        graph.removeFixed(x);
-                        return index;
-                    }
-                }
-            }
-            return -1;
-        }
-
+        return null;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Fri Sep 14 15:16:50 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Fri Sep 14 15:26:57 2012 +0200
@@ -29,7 +29,6 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.nodes.virtual.*;
 
 /**
@@ -43,6 +42,7 @@
 
     /**
      * Constructs a NewInstanceNode.
+     *
      * @param type the class being allocated
      */
     public NewInstanceNode(ResolvedJavaType type, boolean fillContents) {
@@ -53,6 +53,7 @@
 
     /**
      * Gets the instance class being allocated by this node.
+     *
      * @return the instance class allocated
      */
     public ResolvedJavaType instanceClass() {
@@ -73,76 +74,39 @@
         gen.visitNewInstance(this);
     }
 
-    @Override
-    public EscapeOp getEscapeOp() {
-        return instanceClass == null ? null : new EscapeOpImpl();
-    }
-
-    private final class EscapeOpImpl extends EscapeOp {
-
-        @Override
-        public ResolvedJavaType type() {
-            return instanceClass();
-        }
-
-        private void fillEscapeFields(ResolvedJavaType type, List<EscapeField> escapeFields) {
-            if (type != null) {
-                fillEscapeFields(type.superType(), escapeFields);
-                JavaField[] declaredFields = type.declaredFields();
-                assert declaredFields != null : "the runtime must specify the declared fields of that type";
-                for (JavaField field : declaredFields) {
-                    escapeFields.add(new EscapeField(field.name(), field, field.type()));
-                }
+    private void fillEscapeFields(ResolvedJavaType type, List<ResolvedJavaField> escapeFields) {
+        if (type != null) {
+            fillEscapeFields(type.superType(), escapeFields);
+            for (ResolvedJavaField field : type.declaredFields()) {
+                escapeFields.add(field);
             }
         }
-
-        @Override
-        public EscapeField[] fields() {
-            assert !instanceClass().isArrayClass();
-            List<EscapeField> escapeFields = new ArrayList<>();
-            fillEscapeFields(instanceClass(), escapeFields);
-            return escapeFields.toArray(new EscapeField[escapeFields.size()]);
-        }
+    }
 
-        @Override
-        public ValueNode[] fieldState() {
-            EscapeField[] fields = fields();
-            ValueNode[] state = new ValueNode[fields.length];
-            for (int i = 0; i < state.length; i++) {
-                state[i] = ConstantNode.defaultForKind(fields[i].type().kind(), graph());
-            }
-            return state;
-        }
+    @Override
+    public EscapeOp getEscapeOp() {
+        if (instanceClass != null) {
+            assert !instanceClass().isArrayClass();
+            List<ResolvedJavaField> escapeFields = new ArrayList<>();
+            fillEscapeFields(instanceClass(), escapeFields);
+            final ResolvedJavaField[] fields = escapeFields.toArray(new ResolvedJavaField[escapeFields.size()]);
+            return new EscapeOp() {
 
-        @Override
-        public void beforeUpdate(Node usage) {
-            if (usage instanceof RegisterFinalizerNode) {
-                RegisterFinalizerNode x = (RegisterFinalizerNode) usage;
-                ((StructuredGraph) x.graph()).removeFixed(x);
-            } else {
-                super.beforeUpdate(NewInstanceNode.this, usage);
-            }
-        }
+                @Override
+                public ValueNode[] fieldState() {
+                    ValueNode[] state = new ValueNode[fields.length];
+                    for (int i = 0; i < state.length; i++) {
+                        state[i] = ConstantNode.defaultForKind(fields[i].type().kind(), graph());
+                    }
+                    return state;
+                }
 
-        @Override
-        public int updateState(VirtualObjectNode node, Node current, Map<Object, Integer> fieldIndex, ValueNode[] fieldState) {
-            if (current instanceof AccessFieldNode) {
-                AccessFieldNode x = (AccessFieldNode) current;
-                if (GraphUtil.unProxify(x.object()) == node) {
-                    int field = fieldIndex.get(x.field());
-                    StructuredGraph graph = (StructuredGraph) x.graph();
-                    if (current instanceof LoadFieldNode) {
-                        assert fieldState[field] != null : field + ", " + x.field();
-                        x.replaceAtUsages(fieldState[field]);
-                        graph.removeFixed(x);
-                    } else if (current instanceof StoreFieldNode) {
-                        fieldState[field] = ((StoreFieldNode) x).value();
-                        graph.removeFixed(x);
-                        return field;
-                    }
+                @Override
+                public VirtualObjectNode virtualObject(int virtualId) {
+                    return new VirtualInstanceNode(virtualId, instanceClass(), fields);
                 }
-            }
-            return -1;
+            };
         }
+        return null;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeField.java	Fri Sep 14 15:16:50 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.spi;
-
-import com.oracle.graal.api.meta.*;
-
-public class EscapeField {
-
-    private final String name;
-    private final Object representation;
-    private final JavaType type;
-
-    public EscapeField(String name, Object representation, JavaType type) {
-        this.name = name;
-        this.representation = representation;
-        this.type = type;
-    }
-
-    public String name() {
-        return name;
-    }
-
-    public Object representation() {
-        return representation;
-    }
-
-    public JavaType type() {
-        return type;
-    }
-
-    @Override
-    public String toString() {
-        return name();
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeOp.java	Fri Sep 14 15:16:50 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeOp.java	Fri Sep 14 15:26:57 2012 +0200
@@ -22,48 +22,16 @@
  */
 package com.oracle.graal.nodes.spi;
 
-import java.util.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.virtual.*;
 
 public abstract class EscapeOp {
 
     /**
-     * Returns the type of object that is created by the associated node.
-     */
-    public abstract ResolvedJavaType type();
-
-    /**
-     * Returns all the fields that the objects create by the associated node have.
-     */
-    public abstract EscapeField[] fields();
-
-    /**
-     * Returns the initial value of all fields, in the same order as {@link #fields()}.
+     * Returns the initial value of all fields.
      */
     public abstract ValueNode[] fieldState();
 
-    public abstract void beforeUpdate(Node usage);
-
-    protected static void beforeUpdate(Node node, Node usage) {
-        // IsNullNode and IsTypeNode should have been eliminated by the CanonicalizerPhase, but we can't rely on this
-        if (usage instanceof IsNullNode) {
-            IsNullNode x = (IsNullNode) usage;
-            ((StructuredGraph) x.graph()).replaceFloating(x, ConstantNode.forBoolean(false, node.graph()));
-        } else if (usage instanceof IsTypeNode) {
-            IsTypeNode x = (IsTypeNode) usage;
-            boolean result = ((ValueNode) node).objectStamp().type() == x.type();
-            ((StructuredGraph) x.graph()).replaceFloating(x, ConstantNode.forBoolean(result, node.graph()));
-        } else if (usage instanceof AccessMonitorNode) {
-            ((AccessMonitorNode) usage).eliminate();
-        }
-    }
-
-    public abstract int updateState(VirtualObjectNode virtualObject, Node current, Map<Object, Integer> fieldIndex, ValueNode[] fieldState);
+    public abstract VirtualObjectNode virtualObject(int virtualId);
 
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/BoxedVirtualObjectNode.java	Fri Sep 14 15:16:50 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/BoxedVirtualObjectNode.java	Fri Sep 14 15:26:57 2012 +0200
@@ -31,14 +31,31 @@
 public class BoxedVirtualObjectNode extends VirtualObjectNode implements LIRLowerable, Node.ValueNumberable {
 
     @Input ValueNode unboxedValue;
+    private final ResolvedJavaType type;
 
-    public BoxedVirtualObjectNode(int id, ResolvedJavaType type, ValueNode unboxedValue) {
-        super(id, type, new EscapeField[1]);
+    public BoxedVirtualObjectNode(int virtualId, ResolvedJavaType type, ValueNode unboxedValue) {
+        super(virtualId);
+        this.type = type;
         this.unboxedValue = unboxedValue;
     }
 
-
     public ValueNode getUnboxedValue() {
         return unboxedValue;
     }
+
+    @Override
+    public ResolvedJavaType type() {
+        return type;
+    }
+
+    @Override
+    public int entryCount() {
+        return 1;
+    }
+
+    @Override
+    public Object fieldName(int index) {
+        assert index == 0;
+        return "value";
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java	Fri Sep 14 15:26:57 2012 +0200
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.virtual;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.spi.*;
+
+@NodeInfo(nameTemplate = "VirtualArray {p#componentType/s}[{p#length}]")
+public class VirtualArrayNode extends VirtualObjectNode {
+
+    private final ResolvedJavaType componentType;
+    private final int length;
+
+    public VirtualArrayNode(int virtualId, ResolvedJavaType componentType, int length) {
+        super(virtualId);
+        this.componentType = componentType;
+        this.length = length;
+    }
+
+    @Override
+    public ResolvedJavaType type() {
+        return componentType.arrayOf();
+    }
+
+    public ResolvedJavaType componentType() {
+        return componentType;
+    }
+
+    @Override
+    public int entryCount() {
+        return length;
+    }
+
+    @Override
+    public void generate(LIRGeneratorTool gen) {
+        // nothing to do...
+    }
+
+    @Override
+    public String toString(Verbosity verbosity) {
+        if (verbosity == Verbosity.Name) {
+            return super.toString(Verbosity.Name) + " " + componentType.name() + "[" + length + "]";
+        } else {
+            return super.toString(verbosity);
+        }
+    }
+
+    @Override
+    public Object fieldName(int index) {
+        return "[" + index + "]";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java	Fri Sep 14 15:26:57 2012 +0200
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.virtual;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+
+@NodeInfo(nameTemplate = "VirtualInstance {p#type}")
+public class VirtualInstanceNode extends VirtualObjectNode {
+
+    private final ResolvedJavaType type;
+    private final ResolvedJavaField[] fields;
+    private final HashMap<ResolvedJavaField, Integer> fieldMap = new HashMap<>();
+
+    public VirtualInstanceNode(int virtualId, ResolvedJavaType type, ResolvedJavaField[] fields) {
+        super(virtualId);
+        this.type = type;
+        this.fields = fields;
+        for (int i = 0; i < fields.length; i++) {
+            fieldMap.put(fields[i], i);
+        }
+    }
+
+    @Override
+    public ResolvedJavaType type() {
+        return type;
+    }
+
+    @Override
+    public int entryCount() {
+        return fields.length;
+    }
+
+    public ResolvedJavaField field(int index) {
+        return fields[index];
+    }
+
+    @Override
+    public String toString(Verbosity verbosity) {
+        if (verbosity == Verbosity.Name) {
+            return super.toString(Verbosity.Name) + " " + type.name();
+        } else {
+            return super.toString(verbosity);
+        }
+    }
+
+    @Override
+    public Object fieldName(int index) {
+        return fields[index].name();
+    }
+
+    public int fieldIndex(ResolvedJavaField field) {
+        Integer index = fieldMap.get(field);
+        return index == null ? -1 : index;
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java	Fri Sep 14 15:16:50 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java	Fri Sep 14 15:26:57 2012 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,22 +29,21 @@
 import com.oracle.graal.nodes.type.*;
 
 @NodeInfo(nameTemplate = "VirtualObject {p#type}")
-public class VirtualObjectNode extends FloatingNode implements LIRLowerable {
+public abstract class VirtualObjectNode extends FloatingNode implements LIRLowerable {
+
+    private final int virtualId;
 
-    @SuppressWarnings("unused")
-    private final int id;
-    private final ResolvedJavaType type;
-    private final EscapeField[] fields;
-
-    public VirtualObjectNode(int id, ResolvedJavaType type, EscapeField[] fields) {
+    public VirtualObjectNode(int virtualId) {
         super(StampFactory.virtual());
-        this.id = id;
-        this.type = type;
-        this.fields = fields;
+        this.virtualId = virtualId;
     }
 
-    public ResolvedJavaType type() {
-        return type;
+    public abstract ResolvedJavaType type();
+
+    public abstract int entryCount();
+
+    public int virtualId() {
+        return virtualId;
     }
 
     @Override
@@ -52,16 +51,5 @@
         // nothing to do...
     }
 
-    @Override
-    public String toString(Verbosity verbosity) {
-        if (verbosity == Verbosity.Name) {
-            return super.toString(Verbosity.Name) + " " + type.name();
-        } else {
-            return super.toString(verbosity);
-        }
-    }
-
-    public EscapeField[] fields() {
-        return fields;
-    }
+    public abstract Object fieldName(int i);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectState.java	Fri Sep 14 15:16:50 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectState.java	Fri Sep 14 15:26:57 2012 +0200
@@ -41,13 +41,13 @@
 
     public VirtualObjectState(VirtualObjectNode object, ValueNode[] fieldValues) {
         super(object);
-        assert object.fields().length == fieldValues.length;
+        assert object.entryCount() == fieldValues.length;
         this.fieldValues = new NodeInputList<>(this, fieldValues);
     }
 
     private VirtualObjectState(VirtualObjectNode object, List<ValueNode> fieldValues) {
         super(object);
-        assert object.fields().length == fieldValues.size();
+        assert object.entryCount() == fieldValues.size();
         this.fieldValues = new NodeInputList<>(this, fieldValues);
     }