changeset 10791:e2786e2c491a

Merge.
author Doug Simon <doug.simon@oracle.com>
date Tue, 16 Jul 2013 18:30:45 +0200
parents 6d176112d162 (current diff) 0a306985c262 (diff)
children 7a8d6ba83a04
files graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationPEBlockState.java graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationPEClosure.java
diffstat 11 files changed, 746 insertions(+), 342 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EarlyReadEliminationTest.java	Tue Jul 16 18:30:45 2013 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2011, 2013, 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.compiler.test.ea;
+
+import org.junit.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
+import com.oracle.graal.virtual.phases.ea.*;
+
+public class EarlyReadEliminationTest extends PEAReadEliminationTest {
+
+    @Test
+    public void dummy() {
+        // dummy test to make the harness recognize this class as a JUnit test
+    }
+
+    @Override
+    protected void processMethod(final String snippet) {
+        graph = parse(snippet);
+        Assumptions assumptions = new Assumptions(false);
+        HighTierContext context = new HighTierContext(runtime(), assumptions, replacements);
+        new InliningPhase(runtime(), null, replacements, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph);
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
+        new EarlyReadEliminationPhase(canonicalizer).apply(graph, context);
+    }
+}
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java	Tue Jul 16 18:13:36 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java	Tue Jul 16 18:30:45 2013 +0200
@@ -37,7 +37,7 @@
 
 public class PEAReadEliminationTest extends GraalCompilerTest {
 
-    private StructuredGraph graph;
+    protected StructuredGraph graph;
 
     public static Object staticField;
 
@@ -240,7 +240,7 @@
         return graph.getNodes(ReturnNode.class).first();
     }
 
-    private void processMethod(final String snippet) {
+    protected void processMethod(final String snippet) {
         graph = parse(snippet);
         Assumptions assumptions = new Assumptions(false);
         HighTierContext context = new HighTierContext(runtime(), assumptions, replacements);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectSubstitutions.java	Tue Jul 16 18:13:36 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectSubstitutions.java	Tue Jul 16 18:30:45 2013 +0200
@@ -53,6 +53,6 @@
         RegisterFinalizerNode.register(thisObj);
     }
 
-    @MacroSubstitution(macro = ObjectCloneNode.class, isStatic = false)
+    @MacroSubstitution(macro = ObjectCloneNode.class, isStatic = false, forced = true)
     public static native Object clone(Object obj);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EarlyReadEliminationPhase.java	Tue Jul 16 18:30:45 2013 +0200
@@ -0,0 +1,49 @@
+/*
+ * 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.virtual.phases.ea;
+
+import static com.oracle.graal.phases.GraalOptions.*;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.schedule.*;
+import com.oracle.graal.phases.tiers.*;
+
+public class EarlyReadEliminationPhase extends EffectsPhase<PhaseContext> {
+
+    public EarlyReadEliminationPhase(CanonicalizerPhase canonicalizer) {
+        super(1, canonicalizer);
+    }
+
+    @Override
+    protected void run(StructuredGraph graph, PhaseContext context) {
+        if (VirtualUtil.matches(graph, EscapeAnalyzeOnly.getValue())) {
+            runAnalysis(graph, context);
+        }
+    }
+
+    @Override
+    protected Closure<?> createEffectsClosure(PhaseContext context, SchedulePhase schedule) {
+        return new ReadEliminationClosure(schedule);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java	Tue Jul 16 18:30:45 2013 +0200
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2011, 2013, 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.virtual.phases.ea;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.virtual.*;
+
+public class PEReadEliminationBlockState extends PartialEscapeBlockState<PEReadEliminationBlockState> {
+
+    final HashMap<ReadCacheEntry, ValueNode> readCache;
+
+    static class ReadCacheEntry {
+
+        public final ResolvedJavaField identity;
+        public final ValueNode object;
+
+        public ReadCacheEntry(ResolvedJavaField identity, ValueNode object) {
+            this.identity = identity;
+            this.object = object;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = 31 + ((identity == null) ? 0 : identity.hashCode());
+            return 31 * result + ((object == null) ? 0 : object.hashCode());
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            ReadCacheEntry other = (ReadCacheEntry) obj;
+            return identity == other.identity && object == other.object;
+        }
+
+        @Override
+        public String toString() {
+            return object + ":" + identity;
+        }
+    }
+
+    public PEReadEliminationBlockState() {
+        readCache = new HashMap<>();
+    }
+
+    public PEReadEliminationBlockState(PEReadEliminationBlockState other) {
+        super(other);
+        readCache = new HashMap<>(other.readCache);
+    }
+
+    @Override
+    public String toString() {
+        return super.toString() + " " + readCache;
+    }
+
+    @Override
+    protected void objectMaterialized(VirtualObjectNode virtual, AllocatedObjectNode representation, List<ValueNode> values) {
+        if (virtual instanceof VirtualInstanceNode) {
+            VirtualInstanceNode instance = (VirtualInstanceNode) virtual;
+            for (int i = 0; i < instance.entryCount(); i++) {
+                readCache.put(new ReadCacheEntry(instance.field(i), representation), values.get(i));
+            }
+        }
+    }
+
+    @Override
+    public boolean equivalentTo(PEReadEliminationBlockState other) {
+        if (!compareMapsNoSize(readCache, other.readCache)) {
+            return false;
+        }
+        return super.equivalentTo(other);
+    }
+
+    public void addReadCache(ValueNode object, ResolvedJavaField identity, ValueNode value) {
+        ValueNode cacheObject;
+        ObjectState obj = getObjectState(object);
+        if (obj != null) {
+            assert !obj.isVirtual();
+            cacheObject = obj.getMaterializedValue();
+        } else {
+            cacheObject = object;
+        }
+        readCache.put(new ReadCacheEntry(identity, cacheObject), value);
+    }
+
+    public ValueNode getReadCache(ValueNode object, ResolvedJavaField identity) {
+        ValueNode cacheObject;
+        ObjectState obj = getObjectState(object);
+        if (obj != null) {
+            assert !obj.isVirtual();
+            cacheObject = obj.getMaterializedValue();
+        } else {
+            cacheObject = object;
+        }
+        ValueNode cacheValue = readCache.get(new ReadCacheEntry(identity, cacheObject));
+        obj = getObjectState(cacheValue);
+        if (obj != null) {
+            assert !obj.isVirtual();
+            cacheValue = obj.getMaterializedValue();
+        } else {
+            // assert !scalarAliases.containsKey(cacheValue);
+            cacheValue = getScalarAlias(cacheValue);
+        }
+        return cacheValue;
+    }
+
+    public void killReadCache() {
+        readCache.clear();
+    }
+
+    public void killReadCache(ResolvedJavaField identity) {
+        Iterator<Map.Entry<ReadCacheEntry, ValueNode>> iter = readCache.entrySet().iterator();
+        while (iter.hasNext()) {
+            Map.Entry<ReadCacheEntry, ValueNode> entry = iter.next();
+            if (entry.getKey().identity == identity) {
+                iter.remove();
+            }
+        }
+    }
+
+    public Map<ReadCacheEntry, ValueNode> getReadCache() {
+        return readCache;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java	Tue Jul 16 18:30:45 2013 +0200
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2011, 2013, 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.virtual.phases.ea;
+
+import static com.oracle.graal.api.meta.LocationIdentity.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.PhiNode.PhiType;
+import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.phases.schedule.*;
+import com.oracle.graal.virtual.phases.ea.PEReadEliminationBlockState.ReadCacheEntry;
+
+public class PEReadEliminationClosure extends PartialEscapeClosure<PEReadEliminationBlockState> {
+
+    public PEReadEliminationClosure(SchedulePhase schedule, MetaAccessProvider metaAccess, Assumptions assumptions) {
+        super(schedule, metaAccess, assumptions);
+    }
+
+    @Override
+    protected PEReadEliminationBlockState getInitialState() {
+        return new PEReadEliminationBlockState();
+    }
+
+    @Override
+    protected boolean processNode(Node node, PEReadEliminationBlockState state, GraphEffectList effects, FixedWithNextNode lastFixedNode) {
+        boolean deleted = super.processNode(node, state, effects, lastFixedNode);
+        if (!deleted) {
+            if (node instanceof LoadFieldNode) {
+                LoadFieldNode load = (LoadFieldNode) node;
+                ValueNode object = GraphUtil.unproxify(load.object());
+                ValueNode cachedValue = state.getReadCache(object, load.field());
+                if (cachedValue != null) {
+                    effects.replaceAtUsages(load, cachedValue);
+                    state.addScalarAlias(load, cachedValue);
+                    deleted = true;
+                } else {
+                    state.addReadCache(object, load.field(), load);
+                }
+            } else if (node instanceof StoreFieldNode) {
+                StoreFieldNode store = (StoreFieldNode) node;
+                ValueNode object = GraphUtil.unproxify(store.object());
+                ValueNode cachedValue = state.getReadCache(object, store.field());
+
+                if (state.getScalarAlias(store.value()) == cachedValue) {
+                    effects.deleteFixedNode(store);
+                    deleted = true;
+                }
+                state.killReadCache(store.field());
+                state.addReadCache(object, store.field(), store.value());
+            } else if (node instanceof MemoryCheckpoint.Single) {
+                METRIC_MEMORYCHECKOINT.increment();
+                LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity();
+                processIdentity(state, identity);
+            } else if (node instanceof MemoryCheckpoint.Multi) {
+                METRIC_MEMORYCHECKOINT.increment();
+                for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getLocationIdentities()) {
+                    processIdentity(state, identity);
+                }
+            }
+        }
+        return deleted;
+    }
+
+    private static void processIdentity(PEReadEliminationBlockState state, LocationIdentity identity) {
+        if (identity instanceof ResolvedJavaField) {
+            state.killReadCache((ResolvedJavaField) identity);
+        } else if (identity == ANY_LOCATION) {
+            state.killReadCache();
+        }
+    }
+
+    @Override
+    protected void processLoopExit(LoopExitNode exitNode, PEReadEliminationBlockState initialState, PEReadEliminationBlockState exitState, GraphEffectList effects) {
+        super.processLoopExit(exitNode, initialState, exitState, effects);
+
+        for (Map.Entry<ReadCacheEntry, ValueNode> entry : exitState.getReadCache().entrySet()) {
+            if (initialState.getReadCache().get(entry.getKey()) != entry.getValue()) {
+                ProxyNode proxy = new ProxyNode(exitState.getReadCache(entry.getKey().object, entry.getKey().identity), exitNode, PhiType.Value, null);
+                effects.addFloatingNode(proxy, "readCacheProxy");
+                entry.setValue(proxy);
+            }
+        }
+    }
+
+    @Override
+    protected PEReadEliminationBlockState cloneState(PEReadEliminationBlockState other) {
+        return new PEReadEliminationBlockState(other);
+    }
+
+    @Override
+    protected MergeProcessor createMergeProcessor(Block merge) {
+        return new ReadEliminationMergeProcessor(merge);
+    }
+
+    private class ReadEliminationMergeProcessor extends MergeProcessor {
+
+        public ReadEliminationMergeProcessor(Block mergeBlock) {
+            super(mergeBlock);
+        }
+
+        @Override
+        protected void merge(List<PEReadEliminationBlockState> states) {
+            super.merge(states);
+
+            mergeReadCache(states);
+        }
+
+        private void mergeReadCache(List<PEReadEliminationBlockState> states) {
+            for (Map.Entry<ReadCacheEntry, ValueNode> entry : states.get(0).readCache.entrySet()) {
+                ReadCacheEntry key = entry.getKey();
+                ValueNode value = entry.getValue();
+                boolean phi = false;
+                for (int i = 1; i < states.size(); i++) {
+                    ValueNode otherValue = states.get(i).readCache.get(key);
+                    if (otherValue == null) {
+                        value = null;
+                        phi = false;
+                        break;
+                    }
+                    if (!phi && otherValue != value) {
+                        phi = true;
+                    }
+                }
+                if (phi) {
+                    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));
+                    }
+                    newState.readCache.put(key, phiNode);
+                } else if (value != null) {
+                    newState.readCache.put(key, value);
+                }
+            }
+            for (PhiNode phi : merge.phis()) {
+                if (phi.kind() == Kind.Object) {
+                    for (Map.Entry<ReadCacheEntry, ValueNode> entry : states.get(0).readCache.entrySet()) {
+                        if (entry.getKey().object == phi.valueAt(0)) {
+                            mergeReadCachePhi(phi, entry.getKey().identity, states);
+                        }
+                    }
+
+                }
+            }
+        }
+
+        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);
+                if (value == null) {
+                    return;
+                }
+                values[i] = value;
+            }
+
+            PhiNode phiNode = getCachedPhi(new ReadCacheEntry(identity, phi), values[0].kind());
+            mergeEffects.addFloatingNode(phiNode, "mergeReadCachePhi");
+            for (int i = 0; i < values.length; i++) {
+                afterMergeEffects.addPhiInput(phiNode, values[i]);
+            }
+            newState.readCache.put(new ReadCacheEntry(identity, phi), phiNode);
+        }
+    }
+}
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapePhase.java	Tue Jul 16 18:13:36 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapePhase.java	Tue Jul 16 18:30:45 2013 +0200
@@ -68,7 +68,7 @@
     @Override
     protected Closure<?> createEffectsClosure(PhaseContext context, SchedulePhase schedule) {
         if (readElimination) {
-            return new ReadEliminationPEClosure(schedule, context.getRuntime(), context.getAssumptions());
+            return new PEReadEliminationClosure(schedule, context.getRuntime(), context.getAssumptions());
         } else {
             return new PartialEscapeClosure.Final(schedule, context.getRuntime(), context.getAssumptions());
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationBlockState.java	Tue Jul 16 18:30:45 2013 +0200
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2011, 2013, 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.virtual.phases.ea;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+
+public class ReadEliminationBlockState extends EffectsBlockState<ReadEliminationBlockState> {
+
+    final HashMap<ReadCacheEntry, ValueNode> readCache;
+
+    static class ReadCacheEntry {
+
+        public final ResolvedJavaField identity;
+        public final ValueNode object;
+
+        public ReadCacheEntry(ResolvedJavaField identity, ValueNode object) {
+            this.identity = identity;
+            this.object = object;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = 31 + ((identity == null) ? 0 : identity.hashCode());
+            return 31 * result + ((object == null) ? 0 : object.hashCode());
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            ReadCacheEntry other = (ReadCacheEntry) obj;
+            return identity == other.identity && object == other.object;
+        }
+
+        @Override
+        public String toString() {
+            return object + ":" + identity;
+        }
+    }
+
+    public ReadEliminationBlockState() {
+        readCache = new HashMap<>();
+    }
+
+    public ReadEliminationBlockState(ReadEliminationBlockState other) {
+        super(other);
+        readCache = new HashMap<>(other.readCache);
+    }
+
+    @Override
+    public String toString() {
+        return super.toString() + " " + readCache;
+    }
+
+    @Override
+    public boolean equivalentTo(ReadEliminationBlockState other) {
+        if (!compareMapsNoSize(readCache, other.readCache)) {
+            return false;
+        }
+        return super.equivalentTo(other);
+    }
+
+    public void addReadCache(ValueNode object, ResolvedJavaField identity, ValueNode value) {
+        readCache.put(new ReadCacheEntry(identity, object), value);
+    }
+
+    public ValueNode getReadCache(ValueNode object, ResolvedJavaField identity) {
+        return readCache.get(new ReadCacheEntry(identity, object));
+    }
+
+    public void killReadCache() {
+        readCache.clear();
+    }
+
+    public void killReadCache(ResolvedJavaField identity) {
+        Iterator<Map.Entry<ReadCacheEntry, ValueNode>> iter = readCache.entrySet().iterator();
+        while (iter.hasNext()) {
+            Map.Entry<ReadCacheEntry, ValueNode> entry = iter.next();
+            if (entry.getKey().identity == identity) {
+                iter.remove();
+            }
+        }
+    }
+
+    public Map<ReadCacheEntry, ValueNode> getReadCache() {
+        return readCache;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java	Tue Jul 16 18:30:45 2013 +0200
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2011, 2013, 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.virtual.phases.ea;
+
+import static com.oracle.graal.api.meta.LocationIdentity.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.PhiNode.PhiType;
+import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.phases.schedule.*;
+import com.oracle.graal.virtual.phases.ea.ReadEliminationBlockState.ReadCacheEntry;
+
+public class ReadEliminationClosure extends EffectsClosure<ReadEliminationBlockState> {
+
+    public ReadEliminationClosure(SchedulePhase schedule) {
+        super(schedule);
+    }
+
+    @Override
+    protected ReadEliminationBlockState getInitialState() {
+        return new ReadEliminationBlockState();
+    }
+
+    @Override
+    protected boolean processNode(Node node, ReadEliminationBlockState state, GraphEffectList effects, FixedWithNextNode lastFixedNode) {
+        boolean deleted = false;
+        if (node instanceof LoadFieldNode) {
+            LoadFieldNode load = (LoadFieldNode) node;
+            ValueNode object = GraphUtil.unproxify(load.object());
+            ValueNode cachedValue = state.getReadCache(object, load.field());
+            if (cachedValue != null) {
+                effects.replaceAtUsages(load, cachedValue);
+                state.addScalarAlias(load, cachedValue);
+                deleted = true;
+            } else {
+                state.addReadCache(object, load.field(), load);
+            }
+        } else if (node instanceof StoreFieldNode) {
+            StoreFieldNode store = (StoreFieldNode) node;
+            ValueNode object = GraphUtil.unproxify(store.object());
+            ValueNode cachedValue = state.getReadCache(object, store.field());
+
+            if (state.getScalarAlias(store.value()) == cachedValue) {
+                effects.deleteFixedNode(store);
+                deleted = true;
+            }
+            state.killReadCache(store.field());
+            state.addReadCache(object, store.field(), store.value());
+        } else if (node instanceof MemoryCheckpoint.Single) {
+            LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity();
+            processIdentity(state, identity);
+        } else if (node instanceof MemoryCheckpoint.Multi) {
+            for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getLocationIdentities()) {
+                processIdentity(state, identity);
+            }
+        }
+        return deleted;
+    }
+
+    private static void processIdentity(ReadEliminationBlockState state, LocationIdentity identity) {
+        if (identity instanceof ResolvedJavaField) {
+            state.killReadCache((ResolvedJavaField) identity);
+        } else if (identity == ANY_LOCATION) {
+            state.killReadCache();
+        }
+    }
+
+    @Override
+    protected void processLoopExit(LoopExitNode exitNode, ReadEliminationBlockState initialState, ReadEliminationBlockState exitState, GraphEffectList effects) {
+        for (Map.Entry<ReadCacheEntry, ValueNode> entry : exitState.getReadCache().entrySet()) {
+            if (initialState.getReadCache().get(entry.getKey()) != entry.getValue()) {
+                ProxyNode proxy = new ProxyNode(exitState.getReadCache(entry.getKey().object, entry.getKey().identity), exitNode, PhiType.Value, null);
+                effects.addFloatingNode(proxy, "readCacheProxy");
+                entry.setValue(proxy);
+            }
+        }
+    }
+
+    @Override
+    protected ReadEliminationBlockState cloneState(ReadEliminationBlockState other) {
+        return new ReadEliminationBlockState(other);
+    }
+
+    @Override
+    protected MergeProcessor createMergeProcessor(Block merge) {
+        return new ReadEliminationMergeProcessor(merge);
+    }
+
+    private class ReadEliminationMergeProcessor extends EffectsClosure<ReadEliminationBlockState>.MergeProcessor {
+
+        private final HashMap<Object, PhiNode> materializedPhis = new HashMap<>();
+
+        public ReadEliminationMergeProcessor(Block mergeBlock) {
+            super(mergeBlock);
+        }
+
+        protected <T> PhiNode getCachedPhi(T virtual, Kind kind) {
+            PhiNode result = materializedPhis.get(virtual);
+            if (result == null) {
+                result = new PhiNode(kind, merge);
+                materializedPhis.put(virtual, result);
+            }
+            return result;
+        }
+
+        @Override
+        protected void merge(List<ReadEliminationBlockState> states) {
+            super.merge(states);
+
+            mergeReadCache(states);
+        }
+
+        private void mergeReadCache(List<ReadEliminationBlockState> states) {
+            for (Map.Entry<ReadCacheEntry, ValueNode> entry : states.get(0).readCache.entrySet()) {
+                ReadCacheEntry key = entry.getKey();
+                ValueNode value = entry.getValue();
+                boolean phi = false;
+                for (int i = 1; i < states.size(); i++) {
+                    ValueNode otherValue = states.get(i).readCache.get(key);
+                    if (otherValue == null) {
+                        value = null;
+                        phi = false;
+                        break;
+                    }
+                    if (!phi && otherValue != value) {
+                        phi = true;
+                    }
+                }
+                if (phi) {
+                    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));
+                    }
+                    newState.readCache.put(key, phiNode);
+                } else if (value != null) {
+                    newState.readCache.put(key, value);
+                }
+            }
+            for (PhiNode phi : merge.phis()) {
+                if (phi.kind() == Kind.Object) {
+                    for (Map.Entry<ReadCacheEntry, ValueNode> entry : states.get(0).readCache.entrySet()) {
+                        if (entry.getKey().object == phi.valueAt(0)) {
+                            mergeReadCachePhi(phi, entry.getKey().identity, states);
+                        }
+                    }
+
+                }
+            }
+        }
+
+        private void mergeReadCachePhi(PhiNode phi, ResolvedJavaField identity, List<ReadEliminationBlockState> 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);
+                if (value == null) {
+                    return;
+                }
+                values[i] = value;
+            }
+
+            PhiNode phiNode = getCachedPhi(new ReadCacheEntry(identity, phi), values[0].kind());
+            mergeEffects.addFloatingNode(phiNode, "mergeReadCachePhi");
+            for (int i = 0; i < values.length; i++) {
+                afterMergeEffects.addPhiInput(phiNode, values[i]);
+            }
+            newState.readCache.put(new ReadCacheEntry(identity, phi), phiNode);
+        }
+    }
+}
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationPEBlockState.java	Tue Jul 16 18:13:36 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,145 +0,0 @@
-/*
- * Copyright (c) 2011, 2013, 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.virtual.phases.ea;
-
-import java.util.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.virtual.*;
-
-public class ReadEliminationPEBlockState extends PartialEscapeBlockState<ReadEliminationPEBlockState> {
-
-    final HashMap<ReadCacheEntry, ValueNode> readCache;
-
-    static class ReadCacheEntry {
-
-        public final ResolvedJavaField identity;
-        public final ValueNode object;
-
-        public ReadCacheEntry(ResolvedJavaField identity, ValueNode object) {
-            this.identity = identity;
-            this.object = object;
-        }
-
-        @Override
-        public int hashCode() {
-            int result = 31 + ((identity == null) ? 0 : identity.hashCode());
-            return 31 * result + ((object == null) ? 0 : object.hashCode());
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            ReadCacheEntry other = (ReadCacheEntry) obj;
-            return identity == other.identity && object == other.object;
-        }
-
-        @Override
-        public String toString() {
-            return object + ":" + identity;
-        }
-    }
-
-    public ReadEliminationPEBlockState() {
-        readCache = new HashMap<>();
-    }
-
-    public ReadEliminationPEBlockState(ReadEliminationPEBlockState other) {
-        super(other);
-        readCache = new HashMap<>(other.readCache);
-    }
-
-    @Override
-    public String toString() {
-        return super.toString() + " " + readCache;
-    }
-
-    @Override
-    protected void objectMaterialized(VirtualObjectNode virtual, AllocatedObjectNode representation, List<ValueNode> values) {
-        if (virtual instanceof VirtualInstanceNode) {
-            VirtualInstanceNode instance = (VirtualInstanceNode) virtual;
-            for (int i = 0; i < instance.entryCount(); i++) {
-                readCache.put(new ReadCacheEntry(instance.field(i), representation), values.get(i));
-            }
-        }
-    }
-
-    @Override
-    public boolean equivalentTo(ReadEliminationPEBlockState other) {
-        if (!compareMapsNoSize(readCache, other.readCache)) {
-            return false;
-        }
-        return super.equivalentTo(other);
-    }
-
-    public void addReadCache(ValueNode object, ResolvedJavaField identity, ValueNode value) {
-        ValueNode cacheObject;
-        ObjectState obj = getObjectState(object);
-        if (obj != null) {
-            assert !obj.isVirtual();
-            cacheObject = obj.getMaterializedValue();
-        } else {
-            cacheObject = object;
-        }
-        readCache.put(new ReadCacheEntry(identity, cacheObject), value);
-    }
-
-    public ValueNode getReadCache(ValueNode object, ResolvedJavaField identity) {
-        ValueNode cacheObject;
-        ObjectState obj = getObjectState(object);
-        if (obj != null) {
-            assert !obj.isVirtual();
-            cacheObject = obj.getMaterializedValue();
-        } else {
-            cacheObject = object;
-        }
-        ValueNode cacheValue = readCache.get(new ReadCacheEntry(identity, cacheObject));
-        obj = getObjectState(cacheValue);
-        if (obj != null) {
-            assert !obj.isVirtual();
-            cacheValue = obj.getMaterializedValue();
-        } else {
-            // assert !scalarAliases.containsKey(cacheValue);
-            cacheValue = getScalarAlias(cacheValue);
-        }
-        return cacheValue;
-    }
-
-    public void killReadCache() {
-        readCache.clear();
-    }
-
-    public void killReadCache(ResolvedJavaField identity) {
-        Iterator<Map.Entry<ReadCacheEntry, ValueNode>> iter = readCache.entrySet().iterator();
-        while (iter.hasNext()) {
-            Map.Entry<ReadCacheEntry, ValueNode> entry = iter.next();
-            if (entry.getKey().identity == identity) {
-                iter.remove();
-            }
-        }
-    }
-
-    public Map<ReadCacheEntry, ValueNode> getReadCache() {
-        return readCache;
-    }
-}
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationPEClosure.java	Tue Jul 16 18:13:36 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,193 +0,0 @@
-/*
- * Copyright (c) 2011, 2013, 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.virtual.phases.ea;
-
-import static com.oracle.graal.api.meta.LocationIdentity.*;
-
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.PhiNode.PhiType;
-import com.oracle.graal.nodes.cfg.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.phases.schedule.*;
-import com.oracle.graal.virtual.phases.ea.ReadEliminationPEBlockState.ReadCacheEntry;
-
-public class ReadEliminationPEClosure extends PartialEscapeClosure<ReadEliminationPEBlockState> {
-
-    public ReadEliminationPEClosure(SchedulePhase schedule, MetaAccessProvider metaAccess, Assumptions assumptions) {
-        super(schedule, metaAccess, assumptions);
-    }
-
-    @Override
-    protected ReadEliminationPEBlockState getInitialState() {
-        return new ReadEliminationPEBlockState();
-    }
-
-    @Override
-    protected boolean processNode(Node node, ReadEliminationPEBlockState state, GraphEffectList effects, FixedWithNextNode lastFixedNode) {
-        boolean deleted = super.processNode(node, state, effects, lastFixedNode);
-        if (!deleted) {
-            if (node instanceof LoadFieldNode) {
-                LoadFieldNode load = (LoadFieldNode) node;
-                ValueNode object = GraphUtil.unproxify(load.object());
-                ValueNode cachedValue = state.getReadCache(object, load.field());
-                if (cachedValue != null) {
-                    effects.replaceAtUsages(load, cachedValue);
-                    state.addScalarAlias(load, cachedValue);
-                    deleted = true;
-                } else {
-                    state.addReadCache(object, load.field(), load);
-                }
-            } else if (node instanceof StoreFieldNode) {
-                StoreFieldNode store = (StoreFieldNode) node;
-                ValueNode object = GraphUtil.unproxify(store.object());
-                ValueNode cachedValue = state.getReadCache(object, store.field());
-
-                if (state.getScalarAlias(store.value()) == cachedValue) {
-                    effects.deleteFixedNode(store);
-                    deleted = true;
-                }
-                state.killReadCache(store.field());
-                state.addReadCache(object, store.field(), store.value());
-            } else if (node instanceof MemoryCheckpoint.Single) {
-                METRIC_MEMORYCHECKOINT.increment();
-                LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity();
-                processIdentity(state, identity);
-            } else if (node instanceof MemoryCheckpoint.Multi) {
-                METRIC_MEMORYCHECKOINT.increment();
-                for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getLocationIdentities()) {
-                    processIdentity(state, identity);
-                }
-            }
-        }
-        return deleted;
-    }
-
-    private static void processIdentity(ReadEliminationPEBlockState state, LocationIdentity identity) {
-        if (identity instanceof ResolvedJavaField) {
-            state.killReadCache((ResolvedJavaField) identity);
-        } else if (identity == ANY_LOCATION) {
-            state.killReadCache();
-        }
-    }
-
-    @Override
-    protected void processLoopExit(LoopExitNode exitNode, ReadEliminationPEBlockState initialState, ReadEliminationPEBlockState exitState, GraphEffectList effects) {
-        super.processLoopExit(exitNode, initialState, exitState, effects);
-
-        for (Map.Entry<ReadCacheEntry, ValueNode> entry : exitState.getReadCache().entrySet()) {
-            if (initialState.getReadCache().get(entry.getKey()) != entry.getValue()) {
-                ProxyNode proxy = new ProxyNode(exitState.getReadCache(entry.getKey().object, entry.getKey().identity), exitNode, PhiType.Value, null);
-                effects.addFloatingNode(proxy, "readCacheProxy");
-                entry.setValue(proxy);
-            }
-        }
-    }
-
-    @Override
-    protected ReadEliminationPEBlockState cloneState(ReadEliminationPEBlockState other) {
-        return new ReadEliminationPEBlockState(other);
-    }
-
-    @Override
-    protected MergeProcessor createMergeProcessor(Block merge) {
-        return new ReadEliminationMergeProcessor(merge);
-    }
-
-    private class ReadEliminationMergeProcessor extends MergeProcessor {
-
-        public ReadEliminationMergeProcessor(Block mergeBlock) {
-            super(mergeBlock);
-        }
-
-        @Override
-        protected void merge(List<ReadEliminationPEBlockState> states) {
-            super.merge(states);
-
-            mergeReadCache(states);
-        }
-
-        private void mergeReadCache(List<ReadEliminationPEBlockState> states) {
-            for (Map.Entry<ReadCacheEntry, ValueNode> entry : states.get(0).readCache.entrySet()) {
-                ReadCacheEntry key = entry.getKey();
-                ValueNode value = entry.getValue();
-                boolean phi = false;
-                for (int i = 1; i < states.size(); i++) {
-                    ValueNode otherValue = states.get(i).readCache.get(key);
-                    if (otherValue == null) {
-                        value = null;
-                        phi = false;
-                        break;
-                    }
-                    if (!phi && otherValue != value) {
-                        phi = true;
-                    }
-                }
-                if (phi) {
-                    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));
-                    }
-                    newState.readCache.put(key, phiNode);
-                } else if (value != null) {
-                    newState.readCache.put(key, value);
-                }
-            }
-            for (PhiNode phi : merge.phis()) {
-                if (phi.kind() == Kind.Object) {
-                    for (Map.Entry<ReadCacheEntry, ValueNode> entry : states.get(0).readCache.entrySet()) {
-                        if (entry.getKey().object == phi.valueAt(0)) {
-                            mergeReadCachePhi(phi, entry.getKey().identity, states);
-                        }
-                    }
-
-                }
-            }
-        }
-
-        private void mergeReadCachePhi(PhiNode phi, ResolvedJavaField identity, List<ReadEliminationPEBlockState> 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);
-                if (value == null) {
-                    return;
-                }
-                values[i] = value;
-            }
-
-            PhiNode phiNode = getCachedPhi(new ReadCacheEntry(identity, phi), values[0].kind());
-            mergeEffects.addFloatingNode(phiNode, "mergeReadCachePhi");
-            for (int i = 0; i < values.length; i++) {
-                afterMergeEffects.addPhiInput(phiNode, values[i]);
-            }
-            newState.readCache.put(new ReadCacheEntry(identity, phi), phiNode);
-        }
-    }
-}