changeset 11857:3aef4d88fbb9

simplify PEA block states by turning scalarAliases and objectAliases into one global NodeMap
author Lukas Stadler <lukas.stadler@jku.at>
date Wed, 02 Oct 2013 13:18:25 +0200
parents 7a5182bd2175
children cdff87c89c5f
files graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsBlockState.java graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationBlockState.java graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java
diffstat 9 files changed, 134 insertions(+), 149 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsBlockState.java	Wed Oct 02 10:19:43 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsBlockState.java	Wed Oct 02 13:18:25 2013 +0200
@@ -24,48 +24,14 @@
 
 import java.util.*;
 
-import com.oracle.graal.nodes.*;
-
 public abstract class EffectsBlockState<T extends EffectsBlockState<T>> {
 
-    protected final IdentityHashMap<ValueNode, ValueNode> scalarAliases;
-
-    protected EffectsBlockState() {
-        scalarAliases = new IdentityHashMap<>();
-    }
-
-    protected EffectsBlockState(EffectsBlockState<T> other) {
-        scalarAliases = new IdentityHashMap<>(other.scalarAliases);
-    }
-
-    public void addScalarAlias(ValueNode alias, ValueNode value) {
-        scalarAliases.put(alias, value);
-    }
-
-    public ValueNode getScalarAlias(ValueNode alias) {
-        ValueNode result = scalarAliases.get(alias);
-        return result == null ? alias : result;
-    }
-
     @Override
     public String toString() {
-        return "Scalar Aliases: " + scalarAliases.toString();
+        return "";
     }
 
-    public void meetAliases(List<T> states) {
-        scalarAliases.putAll(states.get(0).scalarAliases);
-        for (int i = 1; i < states.size(); i++) {
-            EffectsBlockState<T> state = states.get(i);
-            meetMaps(scalarAliases, state.scalarAliases);
-        }
-    }
-
-    public boolean equivalentTo(T other) {
-        if (this == other) {
-            return true;
-        }
-        return scalarAliases.equals(other.scalarAliases);
-    }
+    protected abstract boolean equivalentTo(T other);
 
     protected static <K, V> boolean compareMaps(Map<K, V> left, Map<K, V> right) {
         if (left.size() != right.size()) {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java	Wed Oct 02 10:19:43 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java	Wed Oct 02 13:18:25 2013 +0200
@@ -30,6 +30,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.graph.*;
 import com.oracle.graal.phases.graph.ReentrantBlockIterator.BlockIteratorClosure;
 import com.oracle.graal.phases.graph.ReentrantBlockIterator.LoopInfo;
@@ -40,6 +41,7 @@
 
     private final SchedulePhase schedule;
 
+    protected final NodeMap<ValueNode> aliases;
     protected final BlockMap<GraphEffectList> blockEffects;
     private final IdentityHashMap<Loop, GraphEffectList> loopMergeEffects = new IdentityHashMap<>();
 
@@ -47,6 +49,7 @@
 
     public EffectsClosure(SchedulePhase schedule) {
         this.schedule = schedule;
+        this.aliases = schedule.getCFG().graph.createNodeMap();
         this.blockEffects = new BlockMap<>(schedule.getCFG());
         for (Block block : schedule.getCFG().getBlocks()) {
             blockEffects.put(block, new GraphEffectList());
@@ -118,6 +121,7 @@
         GraphEffectList effects = blockEffects.get(block);
         FixedWithNextNode lastFixedNode = null;
         for (Node node : schedule.getBlockToNodesMap().get(block)) {
+            aliases.set(node, null);
             changed |= processNode(node, state, effects, lastFixedNode);
             if (node instanceof FixedWithNextNode) {
                 lastFixedNode = (FixedWithNextNode) node;
@@ -202,9 +206,11 @@
             this.afterMergeEffects = new GraphEffectList();
         }
 
+        /**
+         * @param states the states that should be merged.
+         */
         protected void merge(List<BlockT> states) {
             newState = getInitialState();
-            newState.meetAliases(states);
             mergeEffects.clear();
             afterMergeEffects.clear();
         }
@@ -213,4 +219,18 @@
         protected void commitEnds(List<BlockT> states) {
         }
     }
+
+    public void addScalarAlias(ValueNode node, ValueNode alias) {
+        assert !(alias instanceof VirtualObjectNode);
+        aliases.set(node, alias);
+    }
+
+    public ValueNode getScalarAlias(ValueNode node) {
+        assert !(node instanceof VirtualObjectNode);
+        if (node == null || !node.isAlive() || aliases.isNew(node)) {
+            return node;
+        }
+        ValueNode result = aliases.get(node);
+        return (result == null || result instanceof VirtualObjectNode) ? node : result;
+    }
 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java	Wed Oct 02 10:19:43 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java	Wed Oct 02 13:18:25 2013 +0200
@@ -92,9 +92,9 @@
         return super.equivalentTo(other);
     }
 
-    public void addReadCache(ValueNode object, ResolvedJavaField identity, ValueNode value) {
+    public void addReadCache(ValueNode object, ResolvedJavaField identity, ValueNode value, PartialEscapeClosure<?> closure) {
         ValueNode cacheObject;
-        ObjectState obj = getObjectState(object);
+        ObjectState obj = closure.getObjectState(this, object);
         if (obj != null) {
             assert !obj.isVirtual();
             cacheObject = obj.getMaterializedValue();
@@ -104,9 +104,9 @@
         readCache.put(new ReadCacheEntry(identity, cacheObject), value);
     }
 
-    public ValueNode getReadCache(ValueNode object, ResolvedJavaField identity) {
+    public ValueNode getReadCache(ValueNode object, ResolvedJavaField identity, PartialEscapeClosure<?> closure) {
         ValueNode cacheObject;
-        ObjectState obj = getObjectState(object);
+        ObjectState obj = closure.getObjectState(this, object);
         if (obj != null) {
             assert !obj.isVirtual();
             cacheObject = obj.getMaterializedValue();
@@ -114,13 +114,13 @@
             cacheObject = object;
         }
         ValueNode cacheValue = readCache.get(new ReadCacheEntry(identity, cacheObject));
-        obj = getObjectState(cacheValue);
+        obj = closure.getObjectState(this, cacheValue);
         if (obj != null) {
             assert !obj.isVirtual();
             cacheValue = obj.getMaterializedValue();
         } else {
             // assert !scalarAliases.containsKey(cacheValue);
-            cacheValue = getScalarAlias(cacheValue);
+            cacheValue = closure.getScalarAlias(cacheValue);
         }
         return cacheValue;
     }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java	Wed Oct 02 10:19:43 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java	Wed Oct 02 13:18:25 2013 +0200
@@ -57,13 +57,13 @@
                 LoadFieldNode load = (LoadFieldNode) node;
                 if (!load.isVolatile()) {
                     ValueNode object = GraphUtil.unproxify(load.object());
-                    ValueNode cachedValue = state.getReadCache(object, load.field());
+                    ValueNode cachedValue = state.getReadCache(object, load.field(), this);
                     if (cachedValue != null) {
                         effects.replaceAtUsages(load, cachedValue);
-                        state.addScalarAlias(load, cachedValue);
+                        addScalarAlias(load, cachedValue);
                         deleted = true;
                     } else {
-                        state.addReadCache(object, load.field(), load);
+                        state.addReadCache(object, load.field(), load, this);
                     }
                 } else {
                     processIdentity(state, ANY_LOCATION);
@@ -72,15 +72,15 @@
                 StoreFieldNode store = (StoreFieldNode) node;
                 if (!store.isVolatile()) {
                     ValueNode object = GraphUtil.unproxify(store.object());
-                    ValueNode cachedValue = state.getReadCache(object, store.field());
+                    ValueNode cachedValue = state.getReadCache(object, store.field(), this);
 
-                    ValueNode value = state.getScalarAlias(store.value());
+                    ValueNode value = getScalarAlias(store.value());
                     if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) {
                         effects.deleteFixedNode(store);
                         deleted = true;
                     }
                     state.killReadCache(store.field());
-                    state.addReadCache(object, store.field(), value);
+                    state.addReadCache(object, store.field(), value, this);
                 } else {
                     processIdentity(state, ANY_LOCATION);
                 }
@@ -112,7 +112,7 @@
 
         for (Map.Entry<ReadCacheEntry, ValueNode> entry : exitState.getReadCache().entrySet()) {
             if (initialState.getReadCache().get(entry.getKey()) != entry.getValue()) {
-                ValueNode value = exitState.getReadCache(entry.getKey().object, entry.getKey().identity);
+                ValueNode value = exitState.getReadCache(entry.getKey().object, entry.getKey().identity, this);
                 if (!(value instanceof ProxyNode) || ((ProxyNode) value).proxyPoint() != exitNode) {
                     ProxyNode proxy = new ProxyNode(value, exitNode, PhiType.Value, null);
                     effects.addFloatingNode(proxy, "readCacheProxy");
@@ -165,7 +165,7 @@
                     PhiNode phiNode = getCachedPhi(entry, value.kind());
                     mergeEffects.addFloatingNode(phiNode, "mergeReadCache");
                     for (int i = 0; i < states.size(); i++) {
-                        afterMergeEffects.addPhiInput(phiNode, states.get(i).getReadCache(key.object, key.identity));
+                        afterMergeEffects.addPhiInput(phiNode, states.get(i).getReadCache(key.object, key.identity, PEReadEliminationClosure.this));
                     }
                     newState.readCache.put(key, phiNode);
                 } else if (value != null) {
@@ -187,7 +187,7 @@
         private void mergeReadCachePhi(PhiNode phi, ResolvedJavaField identity, List<PEReadEliminationBlockState> states) {
             ValueNode[] values = new ValueNode[phi.valueCount()];
             for (int i = 0; i < phi.valueCount(); i++) {
-                ValueNode value = states.get(i).getReadCache(phi.valueAt(i), identity);
+                ValueNode value = states.get(i).getReadCache(phi.valueAt(i), identity, PEReadEliminationClosure.this);
                 if (value == null) {
                     return;
                 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java	Wed Oct 02 10:19:43 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java	Wed Oct 02 13:18:25 2013 +0200
@@ -24,7 +24,6 @@
 
 import java.util.*;
 
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.Virtualizable.EscapeState;
 import com.oracle.graal.nodes.virtual.*;
@@ -32,7 +31,6 @@
 public abstract class PartialEscapeBlockState<T extends PartialEscapeBlockState<T>> extends EffectsBlockState<T> {
 
     protected final IdentityHashMap<VirtualObjectNode, ObjectState> objectStates = new IdentityHashMap<>();
-    protected final IdentityHashMap<ValueNode, VirtualObjectNode> objectAliases;
 
     /**
      * Final subclass of PartialEscapeBlockState, for performance and to make everything behave
@@ -49,15 +47,12 @@
     }
 
     protected PartialEscapeBlockState() {
-        objectAliases = new IdentityHashMap<>();
     }
 
     protected PartialEscapeBlockState(PartialEscapeBlockState<T> other) {
-        super(other);
         for (Map.Entry<VirtualObjectNode, ObjectState> entry : other.objectStates.entrySet()) {
             objectStates.put(entry.getKey(), entry.getValue().cloneState());
         }
-        objectAliases = new IdentityHashMap<>(other.objectAliases);
     }
 
     public ObjectState getObjectState(VirtualObjectNode object) {
@@ -69,11 +64,6 @@
         return objectStates.get(object);
     }
 
-    public ObjectState getObjectState(ValueNode value) {
-        VirtualObjectNode object = objectAliases.get(value);
-        return object == null ? null : getObjectState(object);
-    }
-
     public void materializeBefore(FixedNode fixed, VirtualObjectNode virtual, EscapeState state, GraphEffectList materializeEffects) {
         PartialEscapeClosure.METRIC_MATERIALIZATIONS.increment();
         List<AllocatedObjectNode> objects = new ArrayList<>(2);
@@ -100,8 +90,8 @@
                 values.add(null);
             }
             for (int i = 0; i < entries.length; i++) {
-                ObjectState entryObj = getObjectState(entries[i]);
-                if (entryObj != null) {
+                if (entries[i] instanceof VirtualObjectNode) {
+                    ObjectState entryObj = getObjectState((VirtualObjectNode) entries[i]);
                     if (entryObj.isVirtual()) {
                         materializeWithCommit(fixed, entryObj.getVirtualObject(), objects, locks, values, otherAllocations, state);
                     }
@@ -122,26 +112,6 @@
         VirtualUtil.trace("materialized %s as %s with values %s", virtual, representation, values);
     }
 
-    void addAndMarkAlias(VirtualObjectNode virtual, ValueNode node, NodeBitMap usages) {
-        objectAliases.put(node, virtual);
-        if (node.isAlive()) {
-            for (Node usage : node.usages()) {
-                markVirtualUsages(usage, usages);
-            }
-        }
-    }
-
-    private void markVirtualUsages(Node node, NodeBitMap usages) {
-        if (!usages.isNew(node)) {
-            usages.mark(node);
-        }
-        if (node instanceof VirtualState) {
-            for (Node usage : node.usages()) {
-                markVirtualUsages(usage, usages);
-            }
-        }
-    }
-
     public void addObject(VirtualObjectNode virtual, ObjectState state) {
         objectStates.put(virtual, state);
     }
@@ -150,30 +120,18 @@
         return objectStates.values();
     }
 
-    public Collection<VirtualObjectNode> getVirtualObjects() {
-        return objectAliases.values();
+    public Set<VirtualObjectNode> getVirtualObjects() {
+        return objectStates.keySet();
     }
 
     @Override
     public String toString() {
-        return super.toString() + ", Object Aliases: " + objectAliases + ", Object States: " + objectStates;
-    }
-
-    @Override
-    public void meetAliases(List<T> states) {
-        super.meetAliases(states);
-        objectAliases.putAll(states.get(0).objectAliases);
-        for (int i = 1; i < states.size(); i++) {
-            meetMaps(objectAliases, states.get(i).objectAliases);
-        }
+        return super.toString() + ", Object States: " + objectStates;
     }
 
     @Override
     public boolean equivalentTo(T other) {
-        if (!compareMaps(objectAliases, other.objectAliases) || !compareMaps(objectStates, other.objectStates)) {
-            return false;
-        }
-        return super.equivalentTo(other);
+        return compareMaps(objectStates, other.objectStates);
     }
 
     protected static <K, V> boolean compareMaps(Map<K, V> left, Map<K, V> right) {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Wed Oct 02 10:19:43 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Wed Oct 02 13:18:25 2013 +0200
@@ -79,7 +79,7 @@
     public PartialEscapeClosure(SchedulePhase schedule, MetaAccessProvider metaAccess, Assumptions assumptions) {
         super(schedule);
         this.usages = schedule.getCFG().graph.createNodeBitMap();
-        this.tool = new VirtualizerToolImpl(usages, metaAccess, assumptions);
+        this.tool = new VirtualizerToolImpl(metaAccess, assumptions, this);
     }
 
     public Map<Invoke, Double> getHints() {
@@ -129,7 +129,7 @@
 
                         @Override
                         public void apply(Node usage, ValueNode value) {
-                            ObjectState valueObj = state.getObjectState(value);
+                            ObjectState valueObj = getObjectState(state, value);
                             if (valueObj != null) {
                                 virtual.add(valueObj);
                                 effects.replaceFirstInput(usage, value, valueObj.virtual);
@@ -158,8 +158,8 @@
                         ObjectState obj = queue.removeLast();
                         if (obj.isVirtual()) {
                             for (ValueNode field : obj.getEntries()) {
-                                ObjectState fieldObj = state.getObjectState(field);
-                                if (fieldObj != null) {
+                                if (field instanceof VirtualObjectNode) {
+                                    ObjectState fieldObj = state.getObjectState((VirtualObjectNode) field);
                                     if (fieldObj.isVirtual() && !virtual.contains(fieldObj)) {
                                         virtual.add(fieldObj);
                                         queue.addLast(fieldObj);
@@ -173,7 +173,7 @@
                         if (obj.isVirtual()) {
                             ValueNode[] fieldState = obj.getEntries().clone();
                             for (int i = 0; i < fieldState.length; i++) {
-                                ObjectState valueObj = state.getObjectState(fieldState[i]);
+                                ObjectState valueObj = getObjectState(state, fieldState[i]);
                                 if (valueObj != null) {
                                     if (valueObj.isVirtual()) {
                                         fieldState[i] = valueObj.virtual;
@@ -191,7 +191,7 @@
                 }
             }
             for (ValueNode input : node.inputs().filter(ValueNode.class)) {
-                ObjectState obj = state.getObjectState(input);
+                ObjectState obj = getObjectState(state, input);
                 if (obj != null) {
                     if (obj.isVirtual() && node instanceof MethodCallTargetNode) {
                         Invoke invoke = ((MethodCallTargetNode) node).invoke();
@@ -205,7 +205,7 @@
         return false;
     }
 
-    private static void ensureMaterialized(PartialEscapeBlockState state, ObjectState obj, FixedNode materializeBefore, GraphEffectList effects, DebugMetric metric) {
+    private void ensureMaterialized(BlockT state, ObjectState obj, FixedNode materializeBefore, GraphEffectList effects, DebugMetric metric) {
         assert obj != null;
         if (obj.getState() == EscapeState.Virtual) {
             metric.increment();
@@ -216,7 +216,7 @@
         assert !obj.isVirtual();
     }
 
-    private static void replaceWithMaterialized(ValueNode value, Node usage, FixedNode materializeBefore, PartialEscapeBlockState state, ObjectState obj, GraphEffectList effects, DebugMetric metric) {
+    private void replaceWithMaterialized(ValueNode value, Node usage, FixedNode materializeBefore, BlockT state, ObjectState obj, GraphEffectList effects, DebugMetric metric) {
         ensureMaterialized(state, obj, materializeBefore, effects, metric);
         effects.replaceFirstInput(usage, value, obj.getMaterializedValue());
     }
@@ -226,7 +226,7 @@
         HashMap<VirtualObjectNode, ProxyNode> proxies = new HashMap<>();
 
         for (ProxyNode proxy : exitNode.proxies()) {
-            ObjectState obj = exitState.getObjectState(proxy.value());
+            ObjectState obj = getObjectState(exitState, proxy.value());
             if (obj != null) {
                 proxies.put(obj.virtual, proxy);
             }
@@ -236,8 +236,7 @@
             if (obj.isVirtual()) {
                 for (int i = 0; i < obj.getEntries().length; i++) {
                     ValueNode value = obj.getEntry(i);
-                    ObjectState valueObj = exitState.getObjectState(value);
-                    if (valueObj == null) {
+                    if (!(value instanceof VirtualObjectNode)) {
                         if (exitNode.loopBegin().isPhiAtMerge(value) || initialObj == null || !initialObj.isVirtual() || initialObj.getEntry(i) != value) {
                             ProxyNode proxy = new ProxyNode(value, exitNode, PhiType.Value, null);
                             obj.setEntry(i, proxy);
@@ -327,16 +326,21 @@
              * and so on.
              */
 
-            HashSet<VirtualObjectNode> virtualObjects = new HashSet<>(newState.getVirtualObjects());
+            HashSet<VirtualObjectNode> virtualObjTemp = new HashSet<>(states.get(0).getVirtualObjects());
+            for (int i = 1; i < states.size(); i++) {
+                virtualObjTemp.retainAll(states.get(i).getVirtualObjects());
+            }
+
             boolean materialized;
             do {
                 mergeEffects.clear();
                 afterMergeEffects.clear();
                 materialized = false;
-                for (VirtualObjectNode object : virtualObjects) {
+                for (VirtualObjectNode object : virtualObjTemp) {
                     ObjectState[] objStates = new ObjectState[states.size()];
                     for (int i = 0; i < states.size(); i++) {
-                        objStates[i] = states.get(i).getObjectState(object);
+                        objStates[i] = states.get(i).getObjectStateOptional(object);
+                        assert objStates[i] != null;
                     }
                     int virtual = 0;
                     ObjectState startObj = objStates[0];
@@ -359,7 +363,7 @@
                             PhiNode materializedValuePhi = getCachedPhi(object, Kind.Object);
                             mergeEffects.addFloatingNode(materializedValuePhi, "materializedPhi");
                             for (int i = 0; i < states.size(); i++) {
-                                PartialEscapeBlockState state = states.get(i);
+                                BlockT state = states.get(i);
                                 ObjectState obj = objStates[i];
                                 materialized |= obj.isVirtual();
                                 Block predecessor = mergeBlock.getPredecessors().get(i);
@@ -396,8 +400,8 @@
                                         break outer;
                                     }
                                     ValueNode[] fields = objStates[i].getEntries();
-                                    ObjectState obj = states.get(i).getObjectState(fields[index]);
-                                    if (obj != null) {
+                                    if (fields[index] instanceof VirtualObjectNode) {
+                                        ObjectState obj = states.get(i).getObjectState((VirtualObjectNode) fields[index]);
                                         materialized |= obj.isVirtual();
                                         Block predecessor = mergeBlock.getPredecessors().get(i);
                                         ensureMaterialized(states.get(i), obj, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE);
@@ -421,6 +425,7 @@
         }
 
         private boolean processPhi(PhiNode phi, List<BlockT> states) {
+            aliases.set(phi, null);
             assert states.size() == phi.valueCount();
             int virtualInputs = 0;
             boolean materialized = false;
@@ -430,7 +435,7 @@
             boolean hasIdentity = false;
             for (int i = 0; i < phi.valueCount(); i++) {
                 ValueNode value = phi.valueAt(i);
-                ObjectState obj = states.get(i).getObjectState(value);
+                ObjectState obj = getObjectState(states.get(i), value);
                 if (obj != null) {
                     if (obj.isVirtual()) {
                         virtualInputs++;
@@ -460,10 +465,10 @@
                 // nothing to do...
             } else if (virtualInputs == phi.valueCount()) {
                 if (sameObject != null) {
-                    newState.addAndMarkAlias(sameObject, phi, usages);
+                    addAndMarkAlias(sameObject, phi);
                 } else if (sameType != null && sameEntryCount != -1) {
                     if (!hasIdentity) {
-                        VirtualObjectNode virtual = getValueObjectVirtual(phi, states.get(0).getObjectState(phi.valueAt(0)).virtual);
+                        VirtualObjectNode virtual = getValueObjectVirtual(phi, getObjectState(states.get(0), phi.valueAt(0)).virtual);
 
                         PhiNode[] phis = getValueObjectMergePhis(phi, virtual.entryCount());
                         for (int i = 0; i < virtual.entryCount(); i++) {
@@ -473,13 +478,13 @@
                             }
                             mergeEffects.addFloatingNode(phis[i], "valueObjectPhi");
                             for (int i2 = 0; i2 < phi.valueCount(); i2++) {
-                                afterMergeEffects.addPhiInput(phis[i], states.get(i2).getObjectState(phi.valueAt(i2)).getEntry(i));
+                                afterMergeEffects.addPhiInput(phis[i], getObjectState(states.get(i2), phi.valueAt(i2)).getEntry(i));
                             }
                         }
                         mergeEffects.addFloatingNode(virtual, "valueObjectNode");
                         newState.addObject(virtual, new ObjectState(virtual, Arrays.copyOf(phis, phis.length, ValueNode[].class), EscapeState.Virtual, null));
-                        newState.addAndMarkAlias(virtual, virtual, usages);
-                        newState.addAndMarkAlias(virtual, phi, usages);
+                        addAndMarkAlias(virtual, virtual);
+                        addAndMarkAlias(virtual, phi);
                     } else {
                         materialize = true;
                     }
@@ -493,7 +498,7 @@
             if (materialize) {
                 for (int i = 0; i < phi.valueCount(); i++) {
                     ValueNode value = phi.valueAt(i);
-                    ObjectState obj = states.get(i).getObjectState(value);
+                    ObjectState obj = getObjectState(states.get(i), value);
                     if (obj != null) {
                         materialized |= obj.isVirtual();
                         Block predecessor = mergeBlock.getPredecessors().get(i);
@@ -504,4 +509,39 @@
             return materialized;
         }
     }
+
+    public ObjectState getObjectState(PartialEscapeBlockState<?> state, ValueNode value) {
+        if (value == null) {
+            return null;
+        }
+        if (value.isAlive() && !aliases.isNew(value)) {
+            ValueNode object = aliases.get(value);
+            return object instanceof VirtualObjectNode ? state.getObjectStateOptional((VirtualObjectNode) object) : null;
+        } else {
+            if (value instanceof VirtualObjectNode) {
+                return state.getObjectStateOptional((VirtualObjectNode) value);
+            }
+            return null;
+        }
+    }
+
+    void addAndMarkAlias(VirtualObjectNode virtual, ValueNode node) {
+        if (node.isAlive()) {
+            aliases.set(node, virtual);
+            for (Node usage : node.usages()) {
+                markVirtualUsages(usage);
+            }
+        }
+    }
+
+    private void markVirtualUsages(Node node) {
+        if (!usages.isNew(node)) {
+            usages.mark(node);
+        }
+        if (node instanceof VirtualState) {
+            for (Node usage : node.usages()) {
+                markVirtualUsages(usage);
+            }
+        }
+    }
 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationBlockState.java	Wed Oct 02 10:19:43 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationBlockState.java	Wed Oct 02 13:18:25 2013 +0200
@@ -103,7 +103,6 @@
     }
 
     public ReadEliminationBlockState(ReadEliminationBlockState other) {
-        super(other);
         readCache = new HashMap<>(other.readCache);
     }
 
@@ -114,10 +113,7 @@
 
     @Override
     public boolean equivalentTo(ReadEliminationBlockState other) {
-        if (!compareMapsNoSize(readCache, other.readCache)) {
-            return false;
-        }
-        return super.equivalentTo(other);
+        return compareMapsNoSize(readCache, other.readCache);
     }
 
     public void addCacheEntry(CacheEntry<?> identifier, ValueNode value) {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java	Wed Oct 02 10:19:43 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java	Wed Oct 02 13:18:25 2013 +0200
@@ -61,7 +61,7 @@
                 ValueNode cachedValue = state.getCacheEntry(identifier);
                 if (cachedValue != null) {
                     effects.replaceAtUsages(load, cachedValue);
-                    state.addScalarAlias(load, cachedValue);
+                    addScalarAlias(load, cachedValue);
                     deleted = true;
                 } else {
                     state.addCacheEntry(identifier, load);
@@ -76,7 +76,7 @@
                 LoadCacheEntry identifier = new LoadCacheEntry(object, store.field());
                 ValueNode cachedValue = state.getCacheEntry(identifier);
 
-                ValueNode value = state.getScalarAlias(store.value());
+                ValueNode value = getScalarAlias(store.value());
                 if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) {
                     effects.deleteFixedNode(store);
                     deleted = true;
@@ -94,7 +94,7 @@
                 ValueNode cachedValue = state.getCacheEntry(identifier);
                 if (cachedValue != null) {
                     effects.replaceAtUsages(read, cachedValue);
-                    state.addScalarAlias(read, cachedValue);
+                    addScalarAlias(read, cachedValue);
                     deleted = true;
                 } else {
                     state.addCacheEntry(identifier, read);
@@ -107,7 +107,7 @@
                 ReadCacheEntry identifier = new ReadCacheEntry(object, write.location());
                 ValueNode cachedValue = state.getCacheEntry(identifier);
 
-                ValueNode value = state.getScalarAlias(write.value());
+                ValueNode value = getScalarAlias(write.value());
                 if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) {
                     effects.deleteFixedNode(write);
                     deleted = true;
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Wed Oct 02 10:19:43 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Wed Oct 02 13:18:25 2013 +0200
@@ -36,18 +36,18 @@
 
 class VirtualizerToolImpl implements VirtualizerTool {
 
-    private final NodeBitMap usages;
     private final MetaAccessProvider metaAccess;
     private final Assumptions assumptions;
+    private final PartialEscapeClosure<?> closure;
 
-    VirtualizerToolImpl(NodeBitMap usages, MetaAccessProvider metaAccess, Assumptions assumptions) {
-        this.usages = usages;
+    VirtualizerToolImpl(MetaAccessProvider metaAccess, Assumptions assumptions, PartialEscapeClosure<?> closure) {
         this.metaAccess = metaAccess;
         this.assumptions = assumptions;
+        this.closure = closure;
     }
 
     private boolean deleted;
-    private PartialEscapeBlockState state;
+    private PartialEscapeBlockState<?> state;
     private ValueNode current;
     private FixedNode position;
     private GraphEffectList effects;
@@ -76,15 +76,15 @@
 
     @Override
     public State getObjectState(ValueNode value) {
-        return state.getObjectState(value);
+        return closure.getObjectState(state, value);
     }
 
     @Override
     public void setVirtualEntry(State objectState, int index, ValueNode value) {
         ObjectState obj = (ObjectState) objectState;
         assert obj != null && obj.isVirtual() : "not virtual: " + obj;
-        ObjectState valueState = state.getObjectState(value);
-        ValueNode newValue = value;
+        ObjectState valueState = closure.getObjectState(state, value);
+        ValueNode newValue;
         if (valueState == null) {
             newValue = getReplacedValue(value);
             assert obj.getEntry(index) == null || obj.getEntry(index).kind() == newValue.kind() || (isObjectEntry(obj.getEntry(index)) && isObjectEntry(newValue));
@@ -106,12 +106,12 @@
 
     @Override
     public ValueNode getReplacedValue(ValueNode original) {
-        return state.getScalarAlias(original);
+        return closure.getScalarAlias(original);
     }
 
     @Override
     public void replaceWithVirtual(VirtualObjectNode virtual) {
-        state.addAndMarkAlias(virtual, current, usages);
+        closure.addAndMarkAlias(virtual, current);
         if (current instanceof FixedWithNextNode) {
             effects.deleteFixedNode((FixedWithNextNode) current);
         }
@@ -120,8 +120,8 @@
 
     @Override
     public void replaceWithValue(ValueNode replacement) {
-        effects.replaceAtUsages(current, state.getScalarAlias(replacement));
-        state.addScalarAlias(current, replacement);
+        effects.replaceAtUsages(current, closure.getScalarAlias(replacement));
+        closure.addScalarAlias(current, replacement);
         deleted = true;
     }
 
@@ -148,16 +148,21 @@
     @Override
     public void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, int[] locks) {
         VirtualUtil.trace("{{%s}} ", current);
-        if (virtualObject.isAlive()) {
-            state.addAndMarkAlias(virtualObject, virtualObject, usages);
-        } else {
+        if (!virtualObject.isAlive()) {
             effects.addFloatingNode(virtualObject, "newVirtualObject");
         }
         for (int i = 0; i < entryState.length; i++) {
-            entryState[i] = state.getScalarAlias(entryState[i]);
+            if (!(entryState[i] instanceof VirtualObjectNode)) {
+                ObjectState v = closure.getObjectState(state, entryState[i]);
+                if (v != null) {
+                    entryState[i] = v.isVirtual() ? v.getVirtualObject() : v.getMaterializedValue();
+                } else {
+                    entryState[i] = closure.getScalarAlias(entryState[i]);
+                }
+            }
         }
         state.addObject(virtualObject, new ObjectState(virtualObject, entryState, EscapeState.Virtual, locks));
-        state.addAndMarkAlias(virtualObject, virtualObject, usages);
+        closure.addAndMarkAlias(virtualObject, virtualObject);
         PartialEscapeClosure.METRIC_ALLOCATION_REMOVED.increment();
     }