changeset 9944:eef9281ec13b

pull basic algorithm of PartialEscapeAnalysisPhase into new base class EffectsPhase
author Lukas Stadler <lukas.stadler@jku.at>
date Fri, 07 Jun 2013 16:43:35 +0200
parents 671bcaf13017
children abf8c6cc5f50
files graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/IterativeInliningTest.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MonitorTest.java graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java 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/EffectsPhase.java graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.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/PartialEscapePhase.java graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java
diffstat 24 files changed, 794 insertions(+), 1055 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Fri Jun 07 14:27:04 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Fri Jun 07 16:43:35 2013 +0200
@@ -309,7 +309,7 @@
         Assumptions assumptions = new Assumptions(false);
         HighTierContext context = new HighTierContext(runtime(), assumptions, replacements);
         new InliningPhase(runtime(), null, replacements, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph);
-        new PartialEscapeAnalysisPhase(false, false, new CanonicalizerPhase(true)).apply(graph, context);
+        new PartialEscapePhase(false, new CanonicalizerPhase(true)).apply(graph, context);
         new CullFrameStatesPhase().apply(graph);
     }
 
@@ -333,7 +333,7 @@
                 }
                 new DeadCodeEliminationPhase().apply(graph);
                 canonicalizer.apply(graph, context);
-                new PartialEscapeAnalysisPhase(false, false, canonicalizer).apply(graph, context);
+                new PartialEscapePhase(false, canonicalizer).apply(graph, context);
 
                 new CullFrameStatesPhase().apply(graph);
                 new DeadCodeEliminationPhase().apply(graph);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Fri Jun 07 14:27:04 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Fri Jun 07 16:43:35 2013 +0200
@@ -222,7 +222,7 @@
                 HighTierContext context = new HighTierContext(runtime(), assumptions, replacements);
                 new InliningPhase(runtime(), null, replacements, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph);
                 new DeadCodeEliminationPhase().apply(graph);
-                new PartialEscapeAnalysisPhase(iterativeEscapeAnalysis, false, new CanonicalizerPhase(true)).apply(graph, context);
+                new PartialEscapePhase(iterativeEscapeAnalysis, new CanonicalizerPhase(true)).apply(graph, context);
                 Assert.assertEquals(1, graph.getNodes(ReturnNode.class).count());
                 ReturnNode returnNode = graph.getNodes(ReturnNode.class).first();
                 if (expectedConstantResult != null) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/IterativeInliningTest.java	Fri Jun 07 14:27:04 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/IterativeInliningTest.java	Fri Jun 07 16:43:35 2013 +0200
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.compiler.test.ea;
 
-import static com.oracle.graal.phases.GraalOptions.*;
 import static org.junit.Assert.*;
 
 import java.util.concurrent.*;
@@ -81,19 +80,6 @@
         assertEquals(graph.getLocal(0), result);
     }
 
-    @SuppressWarnings("all")
-    public static int testSimpleReadSnippet(TestObject a, int b) throws Exception {
-        a.callable = new TestInt(b, 9);
-        return a.callable.call();
-    }
-
-    @Test
-    public void testSimpleRead() {
-        ValueNode result = getReturn("testSimpleReadSnippet").result();
-        assertTrue(graph.getNodes(LoadFieldNode.class).isEmpty());
-        assertEquals(graph.getLocal(1), result);
-    }
-
     final ReturnNode getReturn(String snippet) {
         processMethod(snippet);
         assertEquals(1, graph.getNodes(ReturnNode.class).count());
@@ -102,8 +88,7 @@
 
     private void processMethod(final String snippet) {
         graph = parse(snippet);
-        OptEarlyReadElimination.setValue(true);
         HighTierContext context = new HighTierContext(runtime(), new Assumptions(false), replacements);
-        new IterativeInliningPhase(replacements, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL, false, new CanonicalizerPhase(true)).apply(graph, context);
+        new IterativeInliningPhase(replacements, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL, new CanonicalizerPhase(true)).apply(graph, context);
     }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java	Fri Jun 07 14:27:04 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,229 +0,0 @@
-/*
- * Copyright (c) 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 static org.junit.Assert.*;
-
-import java.util.concurrent.*;
-
-import org.junit.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.compiler.test.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.*;
-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 PEAReadEliminationTest extends GraalCompilerTest {
-
-    private StructuredGraph graph;
-
-    public static Object staticField;
-
-    public static class TestObject implements Callable<Integer> {
-
-        public int x;
-        public int y;
-
-        public TestObject(int x, int y) {
-            this.x = x;
-            this.y = y;
-        }
-
-        @Override
-        public Integer call() throws Exception {
-            return x;
-        }
-    }
-
-    public static class TestObject2 {
-
-        public Object x;
-        public Object y;
-
-        public TestObject2(Object x, Object y) {
-            this.x = x;
-            this.y = y;
-        }
-    }
-
-    @SuppressWarnings("all")
-    public static int testSimpleSnippet(TestObject a) {
-        a.x = 2;
-        staticField = a;
-        return a.x;
-    }
-
-    @Test
-    public void testSimple() {
-        ValueNode result = getReturn("testSimpleSnippet").result();
-        assertTrue(graph.getNodes(LoadFieldNode.class).isEmpty());
-        assertTrue(result.isConstant());
-        assertEquals(2, result.asConstant().asInt());
-    }
-
-    @SuppressWarnings("all")
-    public static int testSimpleConflictSnippet(TestObject a, TestObject b) {
-        a.x = 2;
-        b.x = 3;
-        staticField = a;
-        return a.x;
-    }
-
-    @Test
-    public void testSimpleConflict() {
-        ValueNode result = getReturn("testSimpleConflictSnippet").result();
-        assertFalse(result.isConstant());
-        assertTrue(result instanceof LoadFieldNode);
-    }
-
-    @SuppressWarnings("all")
-    public static int testParamSnippet(TestObject a, int b) {
-        a.x = b;
-        return a.x;
-    }
-
-    @Test
-    public void testParam() {
-        ValueNode result = getReturn("testParamSnippet").result();
-        assertTrue(graph.getNodes(LoadFieldNode.class).isEmpty());
-        assertEquals(graph.getLocal(1), result);
-    }
-
-    @SuppressWarnings("all")
-    public static int testMaterializedSnippet(int a) {
-        TestObject obj = new TestObject(a, 0);
-        staticField = obj;
-        return obj.x;
-    }
-
-    @Test
-    public void testMaterialized() {
-        ValueNode result = getReturn("testMaterializedSnippet").result();
-        assertTrue(graph.getNodes(LoadFieldNode.class).isEmpty());
-        assertEquals(graph.getLocal(0), result);
-    }
-
-    @SuppressWarnings("all")
-    public static int testSimpleLoopSnippet(TestObject obj, int a, int b) {
-        obj.x = a;
-        for (int i = 0; i < 10; i++) {
-            staticField = obj;
-        }
-        return obj.x;
-    }
-
-    @Test
-    public void testSimpleLoop() {
-        ValueNode result = getReturn("testSimpleLoopSnippet").result();
-        assertTrue(graph.getNodes(LoadFieldNode.class).isEmpty());
-        assertEquals(graph.getLocal(1), result);
-    }
-
-    @SuppressWarnings("all")
-    public static int testBadLoopSnippet(TestObject obj, TestObject obj2, int a, int b) {
-        obj.x = a;
-        for (int i = 0; i < 10; i++) {
-            staticField = obj;
-            obj2.x = 10;
-            obj.x = 0;
-        }
-        return obj.x;
-    }
-
-    @Test
-    public void testBadLoop() {
-        ValueNode result = getReturn("testBadLoopSnippet").result();
-        assertEquals(0, graph.getNodes(LoadFieldNode.class).count());
-        assertTrue(result instanceof ProxyNode);
-        assertTrue(((ProxyNode) result).value() instanceof PhiNode);
-    }
-
-    @SuppressWarnings("all")
-    public static int testBadLoop2Snippet(TestObject obj, TestObject obj2, int a, int b) {
-        obj.x = a;
-        for (int i = 0; i < 10; i++) {
-            obj.x = 0;
-            obj2.x = 10;
-        }
-        return obj.x;
-    }
-
-    @Test
-    public void testBadLoop2() {
-        ValueNode result = getReturn("testBadLoop2Snippet").result();
-        assertEquals(1, graph.getNodes(LoadFieldNode.class).count());
-        assertTrue(result instanceof LoadFieldNode);
-    }
-
-    @SuppressWarnings("all")
-    public static int testPhiSnippet(TestObject a, int b) {
-        if (b < 0) {
-            a.x = 1;
-        } else {
-            a.x = 2;
-        }
-        return a.x;
-    }
-
-    @Test
-    public void testPhi() {
-        ValueNode result = getReturn("testPhiSnippet").result();
-        assertTrue(graph.getNodes(LoadFieldNode.class).isEmpty());
-        assertTrue(result instanceof PhiNode);
-        PhiNode phi = (PhiNode) result;
-        assertTrue(phi.valueAt(0).isConstant());
-        assertTrue(phi.valueAt(1).isConstant());
-        assertEquals(1, phi.valueAt(0).asConstant().asInt());
-        assertEquals(2, phi.valueAt(1).asConstant().asInt());
-    }
-
-    @SuppressWarnings("all")
-    public static void testSimpleStoreSnippet(TestObject a, int b) {
-        a.x = b;
-        a.x = b;
-    }
-
-    @Test
-    public void testSimpleStore() {
-        processMethod("testSimpleStoreSnippet");
-        assertEquals(1, graph.getNodes().filter(StoreFieldNode.class).count());
-    }
-
-    final ReturnNode getReturn(String snippet) {
-        processMethod(snippet);
-        assertEquals(1, graph.getNodes(ReturnNode.class).count());
-        return graph.getNodes(ReturnNode.class).first();
-    }
-
-    private 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);
-        new PartialEscapeAnalysisPhase(false, true, new CanonicalizerPhase(true)).apply(graph, context);
-    }
-}
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java	Fri Jun 07 14:27:04 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java	Fri Jun 07 16:43:35 2013 +0200
@@ -166,7 +166,7 @@
                 new DeadCodeEliminationPhase().apply(graph);
                 CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
                 canonicalizer.apply(graph, context);
-                new PartialEscapeAnalysisPhase(false, false, canonicalizer).apply(graph, context);
+                new PartialEscapePhase(false, canonicalizer).apply(graph, context);
 
                 new CullFrameStatesPhase().apply(graph);
                 new DeadCodeEliminationPhase().apply(graph);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Fri Jun 07 14:27:04 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Fri Jun 07 16:43:35 2013 +0200
@@ -149,7 +149,7 @@
 
         if (Inline.getValue() && !plan.isPhaseDisabled(InliningPhase.class)) {
             if (IterativeInlining.getValue()) {
-                new IterativeInliningPhase(replacements, cache, plan, optimisticOpts, OptEarlyReadElimination.getValue(), canonicalizer).apply(graph, highTierContext);
+                new IterativeInliningPhase(replacements, cache, plan, optimisticOpts, canonicalizer).apply(graph, highTierContext);
             } else {
                 new InliningPhase(runtime, null, replacements, assumptions, cache, plan, optimisticOpts).apply(graph);
                 new DeadCodeEliminationPhase().apply(graph);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Fri Jun 07 14:27:04 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Fri Jun 07 16:43:35 2013 +0200
@@ -45,7 +45,7 @@
         }
 
         if (PartialEscapeAnalysis.getValue()) {
-            addPhase(new PartialEscapeAnalysisPhase(true, OptEarlyReadElimination.getValue(), canonicalizer));
+            addPhase(new PartialEscapePhase(true, canonicalizer));
         }
 
         if (OptConvertDeoptsToGuards.getValue()) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java	Fri Jun 07 14:27:04 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java	Fri Jun 07 16:43:35 2013 +0200
@@ -79,13 +79,6 @@
             if (fieldIndex != -1) {
                 tool.replaceWith(state.getEntry(fieldIndex));
             }
-        } else {
-            ValueNode cachedValue = tool.getReadCache(object(), field());
-            if (cachedValue != null) {
-                tool.replaceWithValue(cachedValue);
-            } else {
-                tool.addReadCache(object(), field(), this);
-            }
         }
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java	Fri Jun 07 14:27:04 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java	Fri Jun 07 16:43:35 2013 +0200
@@ -77,12 +77,6 @@
                 tool.setVirtualEntry(state, fieldIndex, value());
                 tool.delete();
             }
-        } else {
-            if (value() == tool.getReadCache(object(), field())) {
-                tool.delete();
-            }
-            tool.killReadCache(field());
-            tool.addReadCache(object(), field(), value());
         }
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java	Fri Jun 07 14:27:04 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java	Fri Jun 07 16:43:35 2013 +0200
@@ -153,10 +153,4 @@
      */
     void replaceWith(ValueNode value);
 
-    void addReadCache(ValueNode object, ResolvedJavaField identity, ValueNode value);
-
-    ValueNode getReadCache(ValueNode object, ResolvedJavaField identity);
-
-    void killReadCache(ResolvedJavaField identity);
-
 }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Fri Jun 07 14:27:04 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Fri Jun 07 16:43:35 2013 +0200
@@ -261,8 +261,6 @@
     @Option(help = "")
     public static final OptionValue<Boolean> OptReadElimination = new OptionValue<>(true);
     @Option(help = "")
-    public static final OptionValue<Boolean> OptEarlyReadElimination = new OptionValue<>(true);
-    @Option(help = "")
     public static final OptionValue<Boolean> OptCanonicalizer = new OptionValue<>(true);
     @Option(help = "")
     public static final OptionValue<Boolean> OptCanonicalizeReads = new OptionValue<>(true);
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MonitorTest.java	Fri Jun 07 14:27:04 2013 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MonitorTest.java	Fri Jun 07 16:43:35 2013 +0200
@@ -63,7 +63,7 @@
     }
 
     /**
-     * Tests monitor operations on {@link PartialEscapeAnalysisPhase virtual objects}.
+     * Tests monitor operations on {@link PartialEscapePhase virtual objects}.
      */
     @Test
     public void test3() {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java	Fri Jun 07 14:27:04 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,306 +0,0 @@
-/*
- * 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 java.util.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.Virtualizable.EscapeState;
-import com.oracle.graal.nodes.virtual.*;
-
-public class BlockState {
-
-    protected final IdentityHashMap<VirtualObjectNode, ObjectState> objectStates = new IdentityHashMap<>();
-    protected final IdentityHashMap<ValueNode, VirtualObjectNode> objectAliases;
-    protected final IdentityHashMap<ValueNode, ValueNode> scalarAliases;
-    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 BlockState() {
-        objectAliases = new IdentityHashMap<>();
-        scalarAliases = new IdentityHashMap<>();
-        readCache = new HashMap<>();
-    }
-
-    public BlockState(BlockState other) {
-        for (Map.Entry<VirtualObjectNode, ObjectState> entry : other.objectStates.entrySet()) {
-            objectStates.put(entry.getKey(), entry.getValue().cloneState());
-        }
-        objectAliases = new IdentityHashMap<>(other.objectAliases);
-        scalarAliases = new IdentityHashMap<>(other.scalarAliases);
-        readCache = new HashMap<>(other.readCache);
-    }
-
-    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 {
-            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 ObjectState getObjectState(VirtualObjectNode object) {
-        assert objectStates.containsKey(object);
-        return objectStates.get(object);
-    }
-
-    public ObjectState getObjectStateOptional(VirtualObjectNode object) {
-        return objectStates.get(object);
-    }
-
-    public ObjectState getObjectState(ValueNode value) {
-        VirtualObjectNode object = objectAliases.get(value);
-        return object == null ? null : getObjectState(object);
-    }
-
-    public BlockState cloneState() {
-        return new BlockState(this);
-    }
-
-    public BlockState cloneEmptyState() {
-        return new BlockState();
-    }
-
-    public void materializeBefore(FixedNode fixed, VirtualObjectNode virtual, EscapeState state, GraphEffectList materializeEffects) {
-        PartialEscapeClosure.METRIC_MATERIALIZATIONS.increment();
-        List<AllocatedObjectNode> objects = new ArrayList<>(2);
-        List<ValueNode> values = new ArrayList<>(8);
-        List<int[]> locks = new ArrayList<>(2);
-        List<ValueNode> otherAllocations = new ArrayList<>(2);
-        materializeWithCommit(fixed, virtual, objects, locks, values, otherAllocations, state);
-
-        materializeEffects.addMaterializationBefore(fixed, objects, locks, values, otherAllocations);
-    }
-
-    private void materializeWithCommit(FixedNode fixed, VirtualObjectNode virtual, List<AllocatedObjectNode> objects, List<int[]> locks, List<ValueNode> values, List<ValueNode> otherAllocations,
-                    EscapeState state) {
-        VirtualUtil.trace("materializing %s", virtual);
-        ObjectState obj = getObjectState(virtual);
-
-        ValueNode[] entries = obj.getEntries();
-        ValueNode representation = virtual.getMaterializedRepresentation(fixed, entries, obj.getLocks());
-        obj.escape(representation, state);
-        if (representation instanceof AllocatedObjectNode) {
-            objects.add((AllocatedObjectNode) representation);
-            locks.add(obj.getLocks());
-            int pos = values.size();
-            while (values.size() < pos + entries.length) {
-                values.add(null);
-            }
-            for (int i = 0; i < entries.length; i++) {
-                ObjectState entryObj = getObjectState(entries[i]);
-                if (entryObj != null) {
-                    if (entryObj.isVirtual()) {
-                        materializeWithCommit(fixed, entryObj.getVirtualObject(), objects, locks, values, otherAllocations, state);
-                    }
-                    values.set(pos + i, entryObj.getMaterializedValue());
-                } else {
-                    values.set(pos + i, entries[i]);
-                }
-            }
-            if (virtual instanceof VirtualInstanceNode) {
-                VirtualInstanceNode instance = (VirtualInstanceNode) virtual;
-                for (int i = 0; i < entries.length; i++) {
-                    readCache.put(new ReadCacheEntry(instance.field(i), representation), values.get(pos + i));
-                }
-            }
-        } else {
-            otherAllocations.add(representation);
-            assert obj.getLocks().length == 0;
-        }
-    }
-
-    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);
-    }
-
-    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;
-    }
-
-    public Iterable<ObjectState> getStates() {
-        return objectStates.values();
-    }
-
-    public Collection<VirtualObjectNode> getVirtualObjects() {
-        return objectAliases.values();
-    }
-
-    @Override
-    public String toString() {
-        return objectStates + " " + readCache;
-    }
-
-    public void meetAliases(List<? extends BlockState> states) {
-        objectAliases.putAll(states.get(0).objectAliases);
-        scalarAliases.putAll(states.get(0).scalarAliases);
-        for (int i = 1; i < states.size(); i++) {
-            BlockState state = states.get(i);
-            meetMaps(objectAliases, state.objectAliases);
-            meetMaps(scalarAliases, state.scalarAliases);
-        }
-    }
-
-    public Map<ReadCacheEntry, ValueNode> getReadCache() {
-        return readCache;
-    }
-
-    public boolean equivalentTo(BlockState other) {
-        if (this == other) {
-            return true;
-        }
-        boolean objectAliasesEqual = compareMaps(objectAliases, other.objectAliases);
-        boolean objectStatesEqual = compareMaps(objectStates, other.objectStates);
-        boolean readCacheEqual = compareMapsNoSize(readCache, other.readCache);
-        boolean scalarAliasesEqual = scalarAliases.equals(other.scalarAliases);
-        return objectAliasesEqual && objectStatesEqual && readCacheEqual && scalarAliasesEqual;
-    }
-
-    protected static <K, V> boolean compareMaps(Map<K, V> left, Map<K, V> right) {
-        if (left.size() != right.size()) {
-            return false;
-        }
-        return compareMapsNoSize(left, right);
-    }
-
-    protected static <K, V> boolean compareMapsNoSize(Map<K, V> left, Map<K, V> right) {
-        if (left == right) {
-            return true;
-        }
-        for (Map.Entry<K, V> entry : right.entrySet()) {
-            K key = entry.getKey();
-            V value = entry.getValue();
-            assert value != null;
-            V otherValue = left.get(key);
-            if (otherValue != value && !value.equals(otherValue)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    protected static <U, V> void meetMaps(Map<U, V> target, Map<U, V> source) {
-        Iterator<Map.Entry<U, V>> iter = target.entrySet().iterator();
-        while (iter.hasNext()) {
-            Map.Entry<U, V> entry = iter.next();
-            if (source.containsKey(entry.getKey())) {
-                assert source.get(entry.getKey()) == entry.getValue();
-            } else {
-                iter.remove();
-            }
-        }
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsBlockState.java	Fri Jun 07 16:43:35 2013 +0200
@@ -0,0 +1,105 @@
+/*
+ * 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 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();
+    }
+
+    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 static <K, V> boolean compareMaps(Map<K, V> left, Map<K, V> right) {
+        if (left.size() != right.size()) {
+            return false;
+        }
+        return compareMapsNoSize(left, right);
+    }
+
+    protected static <K, V> boolean compareMapsNoSize(Map<K, V> left, Map<K, V> right) {
+        if (left == right) {
+            return true;
+        }
+        for (Map.Entry<K, V> entry : right.entrySet()) {
+            K key = entry.getKey();
+            V value = entry.getValue();
+            assert value != null;
+            V otherValue = left.get(key);
+            if (otherValue != value && !value.equals(otherValue)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    protected static <U, V> void meetMaps(Map<U, V> target, Map<U, V> source) {
+        Iterator<Map.Entry<U, V>> iter = target.entrySet().iterator();
+        while (iter.hasNext()) {
+            Map.Entry<U, V> entry = iter.next();
+            if (source.containsKey(entry.getKey())) {
+                assert source.get(entry.getKey()) == entry.getValue();
+            } else {
+                iter.remove();
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java	Fri Jun 07 16:43:35 2013 +0200
@@ -0,0 +1,203 @@
+/*
+ * 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 java.util.*;
+
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.phases.graph.*;
+import com.oracle.graal.phases.graph.ReentrantBlockIterator.BlockIteratorClosure;
+import com.oracle.graal.phases.graph.ReentrantBlockIterator.LoopInfo;
+import com.oracle.graal.phases.schedule.*;
+import com.oracle.graal.virtual.phases.ea.EffectList.Effect;
+
+public abstract class EffectsClosure<BlockT extends EffectsBlockState<BlockT>> extends EffectsPhase.Closure<BlockT> {
+
+    private final SchedulePhase schedule;
+
+    protected final BlockMap<GraphEffectList> blockEffects;
+    private final IdentityHashMap<Loop, GraphEffectList> loopMergeEffects = new IdentityHashMap<>();
+
+    private boolean changed;
+
+    public EffectsClosure(SchedulePhase schedule) {
+        this.schedule = schedule;
+        this.blockEffects = new BlockMap<>(schedule.getCFG());
+        for (Block block : schedule.getCFG().getBlocks()) {
+            blockEffects.put(block, new GraphEffectList());
+        }
+    }
+
+    @Override
+    public boolean hasChanged() {
+        return changed;
+    }
+
+    @Override
+    public void applyEffects() {
+        final StructuredGraph graph = schedule.getCFG().graph;
+        final ArrayList<Node> obsoleteNodes = new ArrayList<>(0);
+        BlockIteratorClosure<Void> closure = new BlockIteratorClosure<Void>() {
+
+            @Override
+            protected Void getInitialState() {
+                return null;
+            }
+
+            private void apply(GraphEffectList effects, Object context) {
+                if (!effects.isEmpty()) {
+                    Debug.log(" ==== effects for %s", context);
+                    for (Effect effect : effects) {
+                        effect.apply(graph, obsoleteNodes);
+                        if (effect.isVisible()) {
+                            Debug.log("    %s", effect);
+                        }
+                    }
+                }
+            }
+
+            @Override
+            protected Void processBlock(Block block, Void currentState) {
+                apply(blockEffects.get(block), block);
+                Debug.dump(graph, "after processing block %s", block);
+                return currentState;
+            }
+
+            @Override
+            protected Void merge(Block merge, List<Void> states) {
+                return null;
+            }
+
+            @Override
+            protected Void cloneState(Void oldState) {
+                return oldState;
+            }
+
+            @Override
+            protected List<Void> processLoop(Loop loop, Void initialState) {
+                LoopInfo<Void> info = ReentrantBlockIterator.processLoop(this, loop, initialState);
+                apply(loopMergeEffects.get(loop), loop);
+                return info.exitStates;
+            }
+        };
+        ReentrantBlockIterator.apply(closure, schedule.getCFG().getStartBlock());
+        assert VirtualUtil.assertNonReachable(graph, obsoleteNodes);
+    }
+
+    @Override
+    protected BlockT processBlock(Block block, BlockT state) {
+        VirtualUtil.trace("\nBlock: %s (", block);
+
+        GraphEffectList effects = blockEffects.get(block);
+        FixedWithNextNode lastFixedNode = null;
+        for (Node node : schedule.getBlockToNodesMap().get(block)) {
+            changed |= processNode(node, state, effects, lastFixedNode);
+            if (node instanceof FixedWithNextNode) {
+                lastFixedNode = (FixedWithNextNode) node;
+            }
+        }
+        VirtualUtil.trace(")\n    end state: %s\n", state);
+        return state;
+    }
+
+    protected abstract boolean processNode(Node node, BlockT state, GraphEffectList effects, FixedWithNextNode lastFixedNode);
+
+    @Override
+    protected BlockT merge(Block merge, List<BlockT> states) {
+        assert blockEffects.get(merge).isEmpty();
+        MergeProcessor processor = createMergeProcessor(merge);
+        processor.merge(states);
+        blockEffects.get(merge).addAll(processor.mergeEffects);
+        blockEffects.get(merge).addAll(processor.afterMergeEffects);
+        return processor.newState;
+    }
+
+    @Override
+    protected final List<BlockT> processLoop(Loop loop, BlockT initialState) {
+        BlockT loopEntryState = initialState;
+        BlockT lastMergedState = initialState;
+        MergeProcessor mergeProcessor = createMergeProcessor(loop.header);
+        for (int iteration = 0; iteration < 10; iteration++) {
+            LoopInfo<BlockT> info = ReentrantBlockIterator.processLoop(this, loop, cloneState(lastMergedState));
+
+            List<BlockT> states = new ArrayList<>();
+            states.add(initialState);
+            states.addAll(info.endStates);
+            mergeProcessor.merge(states);
+
+            Debug.log("================== %s", loop.header);
+            Debug.log("%s", mergeProcessor.newState);
+            Debug.log("===== vs.");
+            Debug.log("%s", lastMergedState);
+
+            if (mergeProcessor.newState.equivalentTo(lastMergedState)) {
+                blockEffects.get(loop.header).insertAll(mergeProcessor.mergeEffects, 0);
+                loopMergeEffects.put(loop, mergeProcessor.afterMergeEffects);
+
+                assert info.exitStates.size() == loop.exits.size();
+                for (int i = 0; i < loop.exits.size(); i++) {
+                    BlockT exitState = info.exitStates.get(i);
+                    assert exitState != null : "no loop exit state at " + loop.exits.get(i) + " / " + loop.header;
+                    processLoopExit((LoopExitNode) loop.exits.get(i).getBeginNode(), loopEntryState, exitState, blockEffects.get(loop.exits.get(i)));
+                }
+
+                return info.exitStates;
+            } else {
+                lastMergedState = mergeProcessor.newState;
+                for (Block block : loop.blocks) {
+                    blockEffects.get(block).clear();
+                }
+            }
+        }
+        throw new GraalInternalError("too many iterations at %s", loop);
+    }
+
+    protected abstract void processLoopExit(LoopExitNode exitNode, BlockT initialState, BlockT exitState, GraphEffectList effects);
+
+    protected abstract MergeProcessor createMergeProcessor(Block merge);
+
+    protected class MergeProcessor {
+
+        protected final Block mergeBlock;
+        protected final MergeNode merge;
+
+        protected final GraphEffectList mergeEffects;
+        protected final GraphEffectList afterMergeEffects;
+        protected final BlockT newState;
+
+        public MergeProcessor(Block mergeBlock) {
+            this.mergeBlock = mergeBlock;
+            this.newState = getInitialState();
+            this.merge = (MergeNode) mergeBlock.getBeginNode();
+            this.mergeEffects = new GraphEffectList();
+            this.afterMergeEffects = new GraphEffectList();
+        }
+
+        protected void merge(List<BlockT> states) {
+            newState.meetAliases(states);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java	Fri Jun 07 16:43:35 2013 +0200
@@ -0,0 +1,98 @@
+/*
+ * 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 java.util.concurrent.*;
+
+import com.oracle.graal.debug.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.graph.*;
+import com.oracle.graal.phases.schedule.*;
+import com.oracle.graal.phases.tiers.*;
+
+public abstract class EffectsPhase<PhaseContextT extends PhaseContext> extends BasePhase<PhaseContextT> {
+
+    public abstract static class Closure<T> extends ReentrantBlockIterator.BlockIteratorClosure<T> {
+
+        public abstract boolean hasChanged();
+
+        public abstract void applyEffects();
+    }
+
+    private final int maxIterations;
+    private CanonicalizerPhase canonicalizer;
+
+    public EffectsPhase(int maxIterations, CanonicalizerPhase canonicalizer) {
+        this.maxIterations = maxIterations;
+        this.canonicalizer = canonicalizer;
+    }
+
+    @Override
+    protected void run(StructuredGraph graph, PhaseContextT context) {
+        runAnalysis(graph, context);
+    }
+
+    public boolean runAnalysis(final StructuredGraph graph, final PhaseContextT context) {
+        boolean changed = false;
+        for (int iteration = 0; iteration < maxIterations; iteration++) {
+            boolean currentChanged = Debug.scope("iteration " + iteration, new Callable<Boolean>() {
+
+                @Override
+                public Boolean call() {
+                    SchedulePhase schedule = new SchedulePhase();
+                    schedule.apply(graph, false);
+                    Closure<?> closure = createEffectsClosure(context, schedule);
+                    ReentrantBlockIterator.apply(closure, schedule.getCFG().getStartBlock());
+
+                    if (!closure.hasChanged()) {
+                        return false;
+                    }
+
+                    // apply the effects collected during this iteration
+                    closure.applyEffects();
+
+                    Debug.dump(graph, "after " + getName() + " iteration");
+
+                    new DeadCodeEliminationPhase().apply(graph);
+
+                    if (OptCanonicalizer.getValue()) {
+                        canonicalizer.apply(graph, context);
+                    }
+
+                    return true;
+                }
+            });
+            if (!currentChanged) {
+                break;
+            }
+            changed |= currentChanged;
+        }
+        return changed;
+    }
+
+    protected abstract Closure<?> createEffectsClosure(PhaseContextT context, SchedulePhase schedule);
+}
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java	Fri Jun 07 14:27:04 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java	Fri Jun 07 16:43:35 2013 +0200
@@ -41,15 +41,13 @@
     private final Replacements replacements;
     private final GraphCache cache;
     private final OptimisticOptimizations optimisticOpts;
-    private final boolean readElimination;
     private final CanonicalizerPhase canonicalizer;
 
-    public IterativeInliningPhase(Replacements replacements, GraphCache cache, PhasePlan plan, OptimisticOptimizations optimisticOpts, boolean readElimination, CanonicalizerPhase canonicalizer) {
+    public IterativeInliningPhase(Replacements replacements, GraphCache cache, PhasePlan plan, OptimisticOptimizations optimisticOpts, CanonicalizerPhase canonicalizer) {
         this.replacements = replacements;
         this.cache = cache;
         this.plan = plan;
         this.optimisticOpts = optimisticOpts;
-        this.readElimination = readElimination;
         this.canonicalizer = canonicalizer;
     }
 
@@ -73,11 +71,11 @@
                 @Override
                 public Boolean call() {
                     boolean progress = false;
-                    PartialEscapeAnalysisPhase ea = new PartialEscapeAnalysisPhase(false, readElimination, canonicalizer);
+                    PartialEscapePhase ea = new PartialEscapePhase(false, canonicalizer);
                     boolean eaResult = ea.runAnalysis(graph, context);
                     progress |= eaResult;
 
-                    Map<Invoke, Double> hints = PEAInliningHints.getValue() ? PartialEscapeAnalysisPhase.getHints(graph) : null;
+                    Map<Invoke, Double> hints = PEAInliningHints.getValue() ? PartialEscapePhase.getHints(graph) : null;
 
                     InliningPhase inlining = new InliningPhase(context.getRuntime(), hints, replacements, context.getAssumptions(), cache, plan, optimisticOpts);
                     inlining.setMaxMethodsPerInlining(simple ? 1 : Integer.MAX_VALUE);
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java	Fri Jun 07 14:27:04 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java	Fri Jun 07 16:43:35 2013 +0200
@@ -34,7 +34,7 @@
  * the fields or array elements (called "entries") and the lock count if the object is still
  * virtual. If the object was materialized, it contains the current materialized value.
  */
-class ObjectState extends Virtualizable.State {
+public class ObjectState extends Virtualizable.State {
 
     private static final int[] EMPTY_INT_ARRAY = new int[0];
 
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java	Fri Jun 07 14:27:04 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,166 +0,0 @@
-/*
- * 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 java.util.*;
-import java.util.concurrent.*;
-
-import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.nodes.virtual.*;
-import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.common.*;
-import com.oracle.graal.phases.graph.*;
-import com.oracle.graal.phases.schedule.*;
-import com.oracle.graal.phases.tiers.*;
-
-public class PartialEscapeAnalysisPhase extends BasePhase<PhaseContext> {
-
-    public abstract static class Closure<T> extends ReentrantBlockIterator.BlockIteratorClosure<T> {
-
-        public abstract boolean hasChanged();
-
-        public abstract void applyEffects();
-    }
-
-    private final boolean iterative;
-    private final boolean readElimination;
-    private final CanonicalizerPhase canonicalizer;
-
-    public PartialEscapeAnalysisPhase(boolean iterative, boolean readElimination, CanonicalizerPhase canonicalizer) {
-        this.iterative = iterative;
-        this.readElimination = readElimination;
-        this.canonicalizer = canonicalizer;
-    }
-
-    @Override
-    protected void run(StructuredGraph graph, PhaseContext context) {
-        runAnalysis(graph, context);
-    }
-
-    public boolean runAnalysis(final StructuredGraph graph, final PhaseContext context) {
-        if (!VirtualUtil.matches(graph, EscapeAnalyzeOnly.getValue())) {
-            return false;
-        }
-
-        if (!readElimination) {
-            boolean analyzableNodes = false;
-            for (Node node : graph.getNodes()) {
-                if (node instanceof VirtualizableAllocation) {
-                    analyzableNodes = true;
-                    break;
-                }
-            }
-            if (!analyzableNodes) {
-                return false;
-            }
-        }
-
-        boolean continueIteration = true;
-        boolean changed = false;
-        for (int iteration = 0; iteration < EscapeAnalysisIterations.getValue() && continueIteration; iteration++) {
-            boolean currentChanged = Debug.scope("iteration " + iteration, new Callable<Boolean>() {
-
-                @Override
-                public Boolean call() {
-
-                    SchedulePhase schedule = new SchedulePhase();
-                    schedule.apply(graph, false);
-                    Closure<?> closure = createAnalysisClosure(context, schedule);
-                    ReentrantBlockIterator.apply(closure, schedule.getCFG().getStartBlock());
-
-                    if (!closure.hasChanged()) {
-                        return false;
-                    }
-
-                    // apply the effects collected during the escape analysis iteration
-                    closure.applyEffects();
-
-                    Debug.dump(graph, "after PartialEscapeAnalysis iteration");
-
-                    new DeadCodeEliminationPhase().apply(graph);
-
-                    if (OptCanonicalizer.getValue()) {
-                        canonicalizer.apply(graph, context);
-                    }
-
-                    return true;
-                }
-            });
-            continueIteration = currentChanged && iterative;
-            changed |= currentChanged;
-        }
-
-        return changed;
-    }
-
-    protected Closure<?> createAnalysisClosure(PhaseContext context, SchedulePhase schedule) {
-        return new PartialEscapeClosure<>(schedule, context.getRuntime(), context.getAssumptions());
-    }
-
-    public static Map<Invoke, Double> getHints(StructuredGraph graph) {
-        NodesToDoubles probabilities = new ComputeProbabilityClosure(graph).apply();
-        Map<Invoke, Double> hints = null;
-        for (CommitAllocationNode commit : graph.getNodes(CommitAllocationNode.class)) {
-            double sum = 0;
-            double invokeSum = 0;
-            for (Node commitUsage : commit.usages()) {
-                for (Node usage : commitUsage.usages()) {
-                    if (usage instanceof FixedNode) {
-                        sum += probabilities.get((FixedNode) usage);
-                    } else {
-                        if (usage instanceof MethodCallTargetNode) {
-                            invokeSum += probabilities.get(((MethodCallTargetNode) usage).invoke().asNode());
-                        }
-                        for (Node secondLevelUage : usage.usages()) {
-                            if (secondLevelUage instanceof FixedNode) {
-                                sum += probabilities.get(((FixedNode) secondLevelUage));
-                            }
-                        }
-                    }
-                }
-            }
-            // TODO(lstadler) get rid of this magic number
-            if (sum > 100 && invokeSum > 0) {
-                for (Node commitUsage : commit.usages()) {
-                    for (Node usage : commitUsage.usages()) {
-                        if (usage instanceof MethodCallTargetNode) {
-                            if (hints == null) {
-                                hints = new HashMap<>();
-                            }
-                            Invoke invoke = ((MethodCallTargetNode) usage).invoke();
-                            hints.put(invoke, sum / invokeSum);
-                        }
-                    }
-                }
-            }
-        }
-        return hints;
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java	Fri Jun 07 16:43:35 2013 +0200
@@ -0,0 +1,214 @@
+/*
+ * 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 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.*;
+
+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
+     * nicely with generics.
+     */
+    public static final class Final extends PartialEscapeBlockState<Final> {
+
+        public Final() {
+        }
+
+        public Final(Final other) {
+            super(other);
+        }
+    }
+
+    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) {
+        assert objectStates.containsKey(object);
+        return objectStates.get(object);
+    }
+
+    public ObjectState getObjectStateOptional(VirtualObjectNode object) {
+        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);
+        List<ValueNode> values = new ArrayList<>(8);
+        List<int[]> locks = new ArrayList<>(2);
+        List<ValueNode> otherAllocations = new ArrayList<>(2);
+        materializeWithCommit(fixed, virtual, objects, locks, values, otherAllocations, state);
+
+        materializeEffects.addMaterializationBefore(fixed, objects, locks, values, otherAllocations);
+    }
+
+    private void materializeWithCommit(FixedNode fixed, VirtualObjectNode virtual, List<AllocatedObjectNode> objects, List<int[]> locks, List<ValueNode> values, List<ValueNode> otherAllocations,
+                    EscapeState state) {
+        ObjectState obj = getObjectState(virtual);
+
+        ValueNode[] entries = obj.getEntries();
+        ValueNode representation = virtual.getMaterializedRepresentation(fixed, entries, obj.getLocks());
+        obj.escape(representation, state);
+        if (representation instanceof AllocatedObjectNode) {
+            objects.add((AllocatedObjectNode) representation);
+            locks.add(obj.getLocks());
+            int pos = values.size();
+            while (values.size() < pos + entries.length) {
+                values.add(null);
+            }
+            for (int i = 0; i < entries.length; i++) {
+                ObjectState entryObj = getObjectState(entries[i]);
+                if (entryObj != null) {
+                    if (entryObj.isVirtual()) {
+                        materializeWithCommit(fixed, entryObj.getVirtualObject(), objects, locks, values, otherAllocations, state);
+                    }
+                    values.set(pos + i, entryObj.getMaterializedValue());
+                } else {
+                    values.set(pos + i, entries[i]);
+                }
+            }
+            objectMaterialized(virtual, (AllocatedObjectNode) representation, values.subList(pos, pos + entries.length));
+        } else {
+            VirtualUtil.trace("materialized %s as %s", virtual, representation);
+            otherAllocations.add(representation);
+            assert obj.getLocks().length == 0;
+        }
+    }
+
+    protected void objectMaterialized(VirtualObjectNode virtual, AllocatedObjectNode representation, List<ValueNode> values) {
+        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);
+    }
+
+    public Iterable<ObjectState> getStates() {
+        return objectStates.values();
+    }
+
+    public Collection<VirtualObjectNode> getVirtualObjects() {
+        return objectAliases.values();
+    }
+
+    @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);
+        }
+    }
+
+    @Override
+    public boolean equivalentTo(T other) {
+        if (!compareMaps(objectAliases, other.objectAliases) || !compareMaps(objectStates, other.objectStates)) {
+            return false;
+        }
+        return super.equivalentTo(other);
+    }
+
+    protected static <K, V> boolean compareMaps(Map<K, V> left, Map<K, V> right) {
+        if (left.size() != right.size()) {
+            return false;
+        }
+        return compareMapsNoSize(left, right);
+    }
+
+    protected static <K, V> boolean compareMapsNoSize(Map<K, V> left, Map<K, V> right) {
+        if (left == right) {
+            return true;
+        }
+        for (Map.Entry<K, V> entry : right.entrySet()) {
+            K key = entry.getKey();
+            V value = entry.getValue();
+            assert value != null;
+            V otherValue = left.get(key);
+            if (otherValue != value && !value.equals(otherValue)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    protected static <U, V> void meetMaps(Map<U, V> target, Map<U, V> source) {
+        Iterator<Map.Entry<U, V>> iter = target.entrySet().iterator();
+        while (iter.hasNext()) {
+            Map.Entry<U, V> entry = iter.next();
+            if (source.containsKey(entry.getKey())) {
+                assert source.get(entry.getKey()) == entry.getValue();
+            } else {
+                iter.remove();
+            }
+        }
+    }
+
+}
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Fri Jun 07 14:27:04 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Fri Jun 07 16:43:35 2013 +0200
@@ -22,9 +22,6 @@
  */
 package com.oracle.graal.virtual.phases.ea;
 
-import static com.oracle.graal.api.meta.LocationIdentity.*;
-import static com.oracle.graal.phases.GraalOptions.*;
-
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
@@ -35,20 +32,14 @@
 import com.oracle.graal.nodes.PhiNode.PhiType;
 import com.oracle.graal.nodes.VirtualState.NodeClosure;
 import com.oracle.graal.nodes.cfg.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.spi.Virtualizable.EscapeState;
 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;
 import com.oracle.graal.phases.schedule.*;
 import com.oracle.graal.virtual.nodes.*;
-import com.oracle.graal.virtual.phases.ea.BlockState.ReadCacheEntry;
-import com.oracle.graal.virtual.phases.ea.EffectList.Effect;
 
-public class PartialEscapeClosure<BlockT extends BlockState> extends PartialEscapeAnalysisPhase.Closure<BlockT> {
+public abstract class PartialEscapeClosure<BlockT extends PartialEscapeBlockState<BlockT>> extends EffectsClosure<BlockT> {
 
     public static final DebugMetric METRIC_MATERIALIZATIONS = Debug.metric("Materializations");
     public static final DebugMetric METRIC_MATERIALIZATIONS_PHI = Debug.metric("MaterializationsPhi");
@@ -61,143 +52,63 @@
     public static final DebugMetric METRIC_MEMORYCHECKOINT = Debug.metric("MemoryCheckpoint");
 
     private final NodeBitMap usages;
-    private final SchedulePhase schedule;
-
-    private final BlockMap<GraphEffectList> blockEffects;
-    private final IdentityHashMap<Loop, GraphEffectList> loopMergeEffects = new IdentityHashMap<>();
-
     private final VirtualizerToolImpl tool;
-
     private final Map<Invoke, Double> hints = new IdentityHashMap<>();
 
-    private boolean changed;
+    /**
+     * Final subclass of PartialEscapeClosure, for performance and to make everything behave nicely
+     * with generics.
+     */
+    public static final class Final extends PartialEscapeClosure<PartialEscapeBlockState.Final> {
 
-    public PartialEscapeClosure(SchedulePhase schedule, MetaAccessProvider metaAccess, Assumptions assumptions) {
-        this.usages = schedule.getCFG().graph.createNodeBitMap();
-        this.schedule = schedule;
-        this.tool = new VirtualizerToolImpl(usages, metaAccess, assumptions);
-        this.blockEffects = new BlockMap<>(schedule.getCFG());
-        for (Block block : schedule.getCFG().getBlocks()) {
-            blockEffects.put(block, new GraphEffectList());
+        public Final(SchedulePhase schedule, MetaAccessProvider metaAccess, Assumptions assumptions) {
+            super(schedule, metaAccess, assumptions);
+        }
+
+        @Override
+        protected PartialEscapeBlockState.Final getInitialState() {
+            return new PartialEscapeBlockState.Final();
+        }
+
+        @Override
+        protected PartialEscapeBlockState.Final cloneState(PartialEscapeBlockState.Final oldState) {
+            return new PartialEscapeBlockState.Final(oldState);
         }
     }
 
-    @SuppressWarnings("unchecked")
-    @Override
-    protected BlockT getInitialState() {
-        return (BlockT) new BlockState();
-    }
-
-    @Override
-    public boolean hasChanged() {
-        return changed;
-    }
-
-    @Override
-    public void applyEffects() {
-        final StructuredGraph graph = schedule.getCFG().graph;
-        final ArrayList<Node> obsoleteNodes = new ArrayList<>(0);
-        BlockIteratorClosure<Void> closure = new BlockIteratorClosure<Void>() {
-
-            @Override
-            protected Void getInitialState() {
-                return null;
-            }
-
-            private void apply(GraphEffectList effects, Object context) {
-                if (!effects.isEmpty()) {
-                    Debug.log(" ==== effects for %s", context);
-                    for (Effect effect : effects) {
-                        effect.apply(graph, obsoleteNodes);
-                        if (effect.isVisible()) {
-                            Debug.log("    %s", effect);
-                        }
-                    }
-                }
-            }
-
-            @Override
-            protected Void processBlock(Block block, Void currentState) {
-                apply(blockEffects.get(block), block);
-                return currentState;
-            }
-
-            @Override
-            protected Void merge(Block merge, List<Void> states) {
-                return null;
-            }
-
-            @Override
-            protected Void cloneState(Void oldState) {
-                return oldState;
-            }
-
-            @Override
-            protected List<Void> processLoop(Loop loop, Void initialState) {
-                LoopInfo<Void> info = ReentrantBlockIterator.processLoop(this, loop, initialState);
-                apply(loopMergeEffects.get(loop), loop);
-                return info.exitStates;
-            }
-        };
-        ReentrantBlockIterator.apply(closure, schedule.getCFG().getStartBlock());
-        assert VirtualUtil.assertNonReachable(graph, obsoleteNodes);
+    public PartialEscapeClosure(SchedulePhase schedule, MetaAccessProvider metaAccess, Assumptions assumptions) {
+        super(schedule);
+        this.usages = schedule.getCFG().graph.createNodeBitMap();
+        this.tool = new VirtualizerToolImpl(usages, metaAccess, assumptions);
     }
 
     public Map<Invoke, Double> getHints() {
         return hints;
     }
 
+    /**
+     * @return true if the node was deleted, false otherwise
+     */
     @Override
-    protected BlockT processBlock(Block block, BlockT state) {
-        GraphEffectList effects = blockEffects.get(block);
-        tool.setEffects(effects);
-
-        VirtualUtil.trace("\nBlock: %s (", block);
-        List<ScheduledNode> nodeList = schedule.getBlockToNodesMap().get(block);
-
-        FixedWithNextNode lastFixedNode = null;
-        for (Node node : nodeList) {
-            boolean deleted;
-            boolean isMarked = usages.isMarked(node);
-            if (isMarked || node instanceof VirtualizableRoot) {
-                VirtualUtil.trace("[[%s]] ", node);
-                FixedNode nextFixedNode = lastFixedNode == null ? null : lastFixedNode.next();
-                deleted = processNode((ValueNode) node, nextFixedNode, state, effects, isMarked);
-            } else {
-                VirtualUtil.trace("%s ", node);
-                deleted = false;
-            }
-            if (OptEarlyReadElimination.getValue()) {
-                if (!deleted && node instanceof MemoryCheckpoint) {
-                    METRIC_MEMORYCHECKOINT.increment();
-                    MemoryCheckpoint checkpoint = (MemoryCheckpoint) node;
-                    for (LocationIdentity identity : checkpoint.getLocationIdentities()) {
-                        if (identity instanceof ResolvedJavaField) {
-                            state.killReadCache((ResolvedJavaField) identity);
-                        } else if (identity == ANY_LOCATION) {
-                            state.killReadCache();
-                        }
-                    }
-                }
-            }
-            if (node instanceof FixedWithNextNode) {
-                lastFixedNode = (FixedWithNextNode) node;
-            }
+    protected boolean processNode(Node node, BlockT state, GraphEffectList effects, FixedWithNextNode lastFixedNode) {
+        boolean isMarked = usages.isMarked(node);
+        if (isMarked || node instanceof VirtualizableRoot) {
+            VirtualUtil.trace("[[%s]] ", node);
+            FixedNode nextFixedNode = lastFixedNode == null ? null : lastFixedNode.next();
+            return processNode((ValueNode) node, nextFixedNode, state, effects, isMarked);
+        } else {
+            VirtualUtil.trace("%s ", node);
+            return false;
         }
-        VirtualUtil.trace(")\n    end state: %s\n", state);
-        return state;
     }
 
     private boolean processNode(final ValueNode node, FixedNode insertBefore, final BlockT state, final GraphEffectList effects, boolean isMarked) {
-        tool.reset(state, node, insertBefore);
+        tool.reset(state, node, insertBefore, effects);
         if (node instanceof Virtualizable) {
             ((Virtualizable) node).virtualize(tool);
         }
         if (tool.isDeleted()) {
-            if (!(node instanceof CommitAllocationNode || node instanceof AllocatedObjectNode)) {
-                changed = true;
-            }
-            return true;
+            return !(node instanceof CommitAllocationNode || node instanceof AllocatedObjectNode);
         }
         if (isMarked) {
             if (node instanceof StateSplit) {
@@ -289,7 +200,7 @@
         return false;
     }
 
-    private static void ensureMaterialized(BlockState state, ObjectState obj, FixedNode materializeBefore, GraphEffectList effects, DebugMetric metric) {
+    private static void ensureMaterialized(PartialEscapeBlockState state, ObjectState obj, FixedNode materializeBefore, GraphEffectList effects, DebugMetric metric) {
         assert obj != null;
         if (obj.getState() == EscapeState.Virtual) {
             metric.increment();
@@ -300,70 +211,13 @@
         assert !obj.isVirtual();
     }
 
-    private static void replaceWithMaterialized(ValueNode value, Node usage, FixedNode materializeBefore, BlockState state, ObjectState obj, GraphEffectList effects, DebugMetric metric) {
+    private static void replaceWithMaterialized(ValueNode value, Node usage, FixedNode materializeBefore, PartialEscapeBlockState state, ObjectState obj, GraphEffectList effects, DebugMetric metric) {
         ensureMaterialized(state, obj, materializeBefore, effects, metric);
         effects.replaceFirstInput(usage, value, obj.getMaterializedValue());
     }
 
     @Override
-    protected BlockT merge(Block merge, List<BlockT> states) {
-        assert blockEffects.get(merge).isEmpty();
-        MergeProcessor<BlockT> processor = new MergeProcessor<>(merge, usages, blockEffects);
-        processor.merge(states);
-        blockEffects.get(merge).addAll(processor.mergeEffects);
-        blockEffects.get(merge).addAll(processor.afterMergeEffects);
-        return processor.newState;
-
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    protected BlockT cloneState(BlockState oldState) {
-        return (BlockT) oldState.cloneState();
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    protected List<BlockT> processLoop(Loop loop, BlockT initialState) {
-        BlockState loopEntryState = initialState;
-        BlockState lastMergedState = initialState;
-        MergeProcessor<BlockT> mergeProcessor = new MergeProcessor<>(loop.header, usages, blockEffects);
-        for (int iteration = 0; iteration < 10; iteration++) {
-            LoopInfo<BlockT> info = ReentrantBlockIterator.processLoop(this, loop, (BlockT) lastMergedState.cloneState());
-
-            List<BlockT> states = new ArrayList<>();
-            states.add(initialState);
-            states.addAll(info.endStates);
-            mergeProcessor.merge(states);
-
-            Debug.log("================== %s", loop.header);
-            Debug.log("%s", mergeProcessor.newState);
-            Debug.log("===== vs.");
-            Debug.log("%s", lastMergedState);
-
-            if (mergeProcessor.newState.equivalentTo(lastMergedState)) {
-                blockEffects.get(loop.header).insertAll(mergeProcessor.mergeEffects, 0);
-                loopMergeEffects.put(loop, mergeProcessor.afterMergeEffects);
-
-                assert info.exitStates.size() == loop.exits.size();
-                for (int i = 0; i < loop.exits.size(); i++) {
-                    BlockState exitState = info.exitStates.get(i);
-                    assert exitState != null : "no loop exit state at " + loop.exits.get(i) + " / " + loop.header;
-                    processLoopExit((LoopExitNode) loop.exits.get(i).getBeginNode(), loopEntryState, exitState, blockEffects.get(loop.exits.get(i)));
-                }
-
-                return info.exitStates;
-            } else {
-                lastMergedState = mergeProcessor.newState;
-                for (Block block : loop.blocks) {
-                    blockEffects.get(block).clear();
-                }
-            }
-        }
-        throw new GraalInternalError("too many iterations at %s", loop);
-    }
-
-    private static void processLoopExit(LoopExitNode exitNode, BlockState initialState, BlockState exitState, GraphEffectList effects) {
+    protected void processLoopExit(LoopExitNode exitNode, BlockT initialState, BlockT exitState, GraphEffectList effects) {
         HashMap<VirtualObjectNode, ProxyNode> proxies = new HashMap<>();
 
         for (ProxyNode proxy : exitNode.proxies()) {
@@ -404,41 +258,25 @@
                 }
             }
         }
-
-        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);
-            }
-        }
     }
 
-    private static class MergeProcessor<BlockT extends BlockState> {
+    @Override
+    protected MergeProcessor createMergeProcessor(Block merge) {
+        return new MergeProcessor(merge);
+    }
 
-        private final Block mergeBlock;
-        private final MergeNode merge;
-        private final NodeBitMap usages;
-        private final BlockMap<GraphEffectList> blockEffects;
-        private final GraphEffectList mergeEffects;
-        private final GraphEffectList afterMergeEffects;
+    protected class MergeProcessor extends EffectsClosure<BlockT>.MergeProcessor {
 
         private final HashMap<Object, PhiNode> materializedPhis = new HashMap<>();
         private final IdentityHashMap<VirtualObjectNode, PhiNode[]> valuePhis = new IdentityHashMap<>();
         private final IdentityHashMap<PhiNode, PhiNode[]> valueObjectMergePhis = new IdentityHashMap<>();
         private final IdentityHashMap<PhiNode, VirtualObjectNode> valueObjectVirtuals = new IdentityHashMap<>();
-        private BlockT newState;
 
-        public MergeProcessor(Block mergeBlock, NodeBitMap usages, BlockMap<GraphEffectList> blockEffects) {
-            this.usages = usages;
-            this.mergeBlock = mergeBlock;
-            this.blockEffects = blockEffects;
-            this.merge = (MergeNode) mergeBlock.getBeginNode();
-            this.mergeEffects = new GraphEffectList();
-            this.afterMergeEffects = new GraphEffectList();
+        public MergeProcessor(Block mergeBlock) {
+            super(mergeBlock);
         }
 
-        private <T> PhiNode getCachedPhi(T virtual, Kind kind) {
+        protected <T> PhiNode getCachedPhi(T virtual, Kind kind) {
             PhiNode result = materializedPhis.get(virtual);
             if (result == null) {
                 result = new PhiNode(kind, merge);
@@ -474,10 +312,9 @@
             return result;
         }
 
-        @SuppressWarnings("unchecked")
-        private void merge(List<BlockT> states) {
-            newState = (BlockT) states.get(0).cloneEmptyState();
-            newState.meetAliases(states);
+        @Override
+        protected void merge(List<BlockT> states) {
+            super.merge(states);
 
             /*
              * Iterative processing: Merging the materialized/virtual state of virtual objects can
@@ -519,7 +356,7 @@
                             PhiNode materializedValuePhi = getCachedPhi(object, Kind.Object);
                             mergeEffects.addFloatingNode(materializedValuePhi, "materializedPhi");
                             for (int i = 0; i < states.size(); i++) {
-                                BlockState state = states.get(i);
+                                PartialEscapeBlockState state = states.get(i);
                                 ObjectState obj = objStates[i];
                                 materialized |= obj.isVirtual();
                                 Block predecessor = mergeBlock.getPredecessors().get(i);
@@ -578,8 +415,6 @@
                     }
                 }
             } while (materialized);
-
-            mergeReadCache(states);
         }
 
         private boolean processPhi(PhiNode phi, List<BlockT> states) {
@@ -665,62 +500,5 @@
             }
             return materialized;
         }
-
-        private void mergeReadCache(List<BlockT> 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<BlockT> 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);
-        }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapePhase.java	Fri Jun 07 16:43:35 2013 +0200
@@ -0,0 +1,106 @@
+/*
+ * 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 java.util.*;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.nodes.virtual.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.graph.*;
+import com.oracle.graal.phases.schedule.*;
+import com.oracle.graal.phases.tiers.*;
+
+public class PartialEscapePhase extends EffectsPhase<PhaseContext> {
+
+    public PartialEscapePhase(boolean iterative, CanonicalizerPhase canonicalizer) {
+        super(iterative ? EscapeAnalysisIterations.getValue() : 1, canonicalizer);
+    }
+
+    @Override
+    protected void run(StructuredGraph graph, PhaseContext context) {
+        if (VirtualUtil.matches(graph, EscapeAnalyzeOnly.getValue())) {
+            boolean analyzableNodes = false;
+            for (Node node : graph.getNodes()) {
+                if (node instanceof VirtualizableAllocation) {
+                    analyzableNodes = true;
+                    break;
+                }
+            }
+            if (analyzableNodes) {
+                runAnalysis(graph, context);
+            }
+        }
+    }
+
+    @Override
+    protected Closure<?> createEffectsClosure(PhaseContext context, SchedulePhase schedule) {
+        return new PartialEscapeClosure.Final(schedule, context.getRuntime(), context.getAssumptions());
+    }
+
+    public static Map<Invoke, Double> getHints(StructuredGraph graph) {
+        NodesToDoubles probabilities = new ComputeProbabilityClosure(graph).apply();
+        Map<Invoke, Double> hints = null;
+        for (CommitAllocationNode commit : graph.getNodes(CommitAllocationNode.class)) {
+            double sum = 0;
+            double invokeSum = 0;
+            for (Node commitUsage : commit.usages()) {
+                for (Node usage : commitUsage.usages()) {
+                    if (usage instanceof FixedNode) {
+                        sum += probabilities.get((FixedNode) usage);
+                    } else {
+                        if (usage instanceof MethodCallTargetNode) {
+                            invokeSum += probabilities.get(((MethodCallTargetNode) usage).invoke().asNode());
+                        }
+                        for (Node secondLevelUage : usage.usages()) {
+                            if (secondLevelUage instanceof FixedNode) {
+                                sum += probabilities.get(((FixedNode) secondLevelUage));
+                            }
+                        }
+                    }
+                }
+            }
+            // TODO(lstadler) get rid of this magic number
+            if (sum > 100 && invokeSum > 0) {
+                for (Node commitUsage : commit.usages()) {
+                    for (Node usage : commitUsage.usages()) {
+                        if (usage instanceof MethodCallTargetNode) {
+                            if (hints == null) {
+                                hints = new HashMap<>();
+                            }
+                            Invoke invoke = ((MethodCallTargetNode) usage).invoke();
+                            hints.put(invoke, sum / invokeSum);
+                        }
+                    }
+                }
+            }
+        }
+        return hints;
+    }
+}
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java	Fri Jun 07 14:27:04 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java	Fri Jun 07 16:43:35 2013 +0200
@@ -111,7 +111,7 @@
         }
     }
 
-    static boolean matches(StructuredGraph graph, String filter) {
+    public static boolean matches(StructuredGraph graph, String filter) {
         if (filter != null) {
             if (filter.startsWith("~")) {
                 ResolvedJavaMethod method = graph.method();
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Fri Jun 07 14:27:04 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Fri Jun 07 16:43:35 2013 +0200
@@ -39,7 +39,6 @@
     private final NodeBitMap usages;
     private final MetaAccessProvider metaAccess;
     private final Assumptions assumptions;
-    private GraphEffectList effects;
 
     VirtualizerToolImpl(NodeBitMap usages, MetaAccessProvider metaAccess, Assumptions assumptions) {
         this.usages = usages;
@@ -48,9 +47,10 @@
     }
 
     private boolean deleted;
-    private BlockState state;
+    private PartialEscapeBlockState state;
     private ValueNode current;
     private FixedNode position;
+    private GraphEffectList effects;
 
     @Override
     public MetaAccessProvider getMetaAccessProvider() {
@@ -62,15 +62,12 @@
         return assumptions;
     }
 
-    public void setEffects(GraphEffectList effects) {
-        this.effects = effects;
-    }
-
-    public void reset(BlockState newState, ValueNode newCurrent, FixedNode newPosition) {
+    public void reset(PartialEscapeBlockState newState, ValueNode newCurrent, FixedNode newPosition, GraphEffectList newEffects) {
         deleted = false;
         state = newState;
         current = newCurrent;
         position = newPosition;
+        effects = newEffects;
     }
 
     public boolean isDeleted() {
@@ -136,7 +133,6 @@
 
     @Override
     public void delete() {
-        assert current instanceof FixedWithNextNode;
         effects.deleteFixedNode((FixedWithNextNode) current);
         deleted = true;
     }
@@ -189,26 +185,4 @@
             }
         }
     }
-
-    @Override
-    public void addReadCache(ValueNode object, ResolvedJavaField identity, ValueNode value) {
-        if (OptEarlyReadElimination.getValue()) {
-            state.addReadCache(object, identity, value);
-        }
-    }
-
-    @Override
-    public ValueNode getReadCache(ValueNode object, ResolvedJavaField identity) {
-        if (OptEarlyReadElimination.getValue()) {
-            return state.getReadCache(object, identity);
-        }
-        return null;
-    }
-
-    @Override
-    public void killReadCache(ResolvedJavaField identity) {
-        if (OptEarlyReadElimination.getValue()) {
-            state.killReadCache(identity);
-        }
-    }
 }