changeset 9755:432b8405e056

small refactoring of early read elimination (move logic into "virtualize" methods)
author Lukas Stadler <lukas.stadler@jku.at>
date Fri, 17 May 2013 14:29:44 +0200
parents 98b004bf3985
children d51f6d7fa6c4 12fdb8fe0a35
files 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/VirtualizableAllocation.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizableRoot.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.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/PartialEscapeAnalysisPhase.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/VirtualizerToolImpl.java
diffstat 9 files changed, 183 insertions(+), 129 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java	Thu May 16 17:03:18 2013 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java	Fri May 17 14:29:44 2013 +0200
@@ -33,7 +33,7 @@
  * The {@code LoadFieldNode} represents a read of a static or instance field.
  */
 @NodeInfo(nameTemplate = "LoadField#{p#field/s}")
-public final class LoadFieldNode extends AccessFieldNode implements Canonicalizable, Node.IterableNodeType, Virtualizable {
+public final class LoadFieldNode extends AccessFieldNode implements Canonicalizable, Node.IterableNodeType, VirtualizableRoot {
 
     /**
      * Creates a new LoadFieldNode instance.
@@ -79,6 +79,13 @@
             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	Thu May 16 17:03:18 2013 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java	Fri May 17 14:29:44 2013 +0200
@@ -33,7 +33,7 @@
  * The {@code StoreFieldNode} represents a write to a static or instance field.
  */
 @NodeInfo(nameTemplate = "StoreField#{p#field/s}")
-public final class StoreFieldNode extends AccessFieldNode implements StateSplit, Virtualizable {
+public final class StoreFieldNode extends AccessFieldNode implements StateSplit, VirtualizableRoot {
 
     @Input private ValueNode value;
     @Input(notDataflow = true) private FrameState stateAfter;
@@ -77,6 +77,12 @@
                 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/VirtualizableAllocation.java	Thu May 16 17:03:18 2013 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizableAllocation.java	Fri May 17 14:29:44 2013 +0200
@@ -26,12 +26,9 @@
  * This interface allows a node to convey information about what its effect would be if some of its
  * inputs were virtualized.
  * 
- * The difference to {@link Virtualizable} is that the {@link #virtualize(VirtualizerTool)} method
- * will be called regardless of whether this node had any interaction with virtualized nodes. This
- * interface can therefore be used for object allocations, for which virtualization introduces new
- * virtualized objects.
- * 
+ * The difference to {@link VirtualizableRoot} is that removing {@link VirtualizableAllocation}
+ * nodes is not considered progress during the escape analysis iterations.
  */
-public interface VirtualizableAllocation extends Virtualizable {
+public interface VirtualizableAllocation extends VirtualizableRoot {
 
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizableRoot.java	Fri May 17 14:29:44 2013 +0200
@@ -0,0 +1,37 @@
+/*
+ * 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.nodes.spi;
+
+/**
+ * This interface allows a node to convey information about what its effect would be if some of its
+ * inputs were virtualized.
+ * 
+ * The difference to {@link Virtualizable} is that the {@link #virtualize(VirtualizerTool)} method
+ * will be called regardless of whether this node had any interaction with virtualized nodes. This
+ * interface can therefore be used for object allocations, for which virtualization introduces new
+ * virtualized objects.
+ * 
+ */
+public interface VirtualizableRoot extends Virtualizable {
+
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java	Thu May 16 17:03:18 2013 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java	Fri May 17 14:29:44 2013 +0200
@@ -152,4 +152,11 @@
      * @param value the replacement value
      */
     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.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java	Thu May 16 17:03:18 2013 -0700
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java	Fri May 17 14:29:44 2013 +0200
@@ -26,10 +26,9 @@
 
 import java.util.*;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity;
 import com.oracle.graal.nodes.spi.Virtualizable.EscapeState;
 import com.oracle.graal.nodes.virtual.*;
 
@@ -42,10 +41,10 @@
 
     static class ReadCacheEntry {
 
-        public final LocationIdentity identity;
+        public final ResolvedJavaField identity;
         public final ValueNode object;
 
-        public ReadCacheEntry(LocationIdentity identity, ValueNode object) {
+        public ReadCacheEntry(ResolvedJavaField identity, ValueNode object) {
             this.identity = identity;
             this.object = object;
         }
@@ -83,7 +82,7 @@
         readCache = new HashMap<>(other.readCache);
     }
 
-    public void addReadCache(ValueNode object, LocationIdentity identity, ValueNode value) {
+    public void addReadCache(ValueNode object, ResolvedJavaField identity, ValueNode value) {
         ValueNode cacheObject;
         ObjectState obj = getObjectState(object);
         if (obj != null) {
@@ -95,7 +94,7 @@
         readCache.put(new ReadCacheEntry(identity, cacheObject), value);
     }
 
-    public ValueNode getReadCache(ValueNode object, LocationIdentity identity) {
+    public ValueNode getReadCache(ValueNode object, ResolvedJavaField identity) {
         ValueNode cacheObject;
         ObjectState obj = getObjectState(object);
         if (obj != null) {
@@ -115,16 +114,16 @@
         return cacheValue;
     }
 
-    public void killReadCache(LocationIdentity identity) {
-        if (identity == LocationNode.ANY_LOCATION) {
-            readCache.clear();
-        } else {
-            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 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();
             }
         }
     }
@@ -187,7 +186,7 @@
             if (virtual instanceof VirtualInstanceNode) {
                 VirtualInstanceNode instance = (VirtualInstanceNode) virtual;
                 for (int i = 0; i < entries.length; i++) {
-                    readCache.put(new ReadCacheEntry((LocationIdentity) instance.field(i), representation), values.get(pos + i));
+                    readCache.put(new ReadCacheEntry(instance.field(i), representation), values.get(pos + i));
                 }
             }
         } else {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java	Thu May 16 17:03:18 2013 -0700
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java	Fri May 17 14:29:44 2013 +0200
@@ -75,7 +75,7 @@
         if (!readElimination) {
             boolean analyzableNodes = false;
             for (Node node : graph.getNodes()) {
-                if (node instanceof VirtualizableAllocation) {
+                if (node instanceof VirtualizableRoot) {
                     analyzableNodes = true;
                     break;
                 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Thu May 16 17:03:18 2013 -0700
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Fri May 17 14:29:44 2013 +0200
@@ -59,9 +59,6 @@
     public static final DebugMetric METRIC_MATERIALIZATIONS_LOOP_END = Debug.metric("MaterializationsLoopEnd");
     public static final DebugMetric METRIC_ALLOCATION_REMOVED = Debug.metric("AllocationsRemoved");
 
-    public static final DebugMetric METRIC_STOREFIELD_RECORDED = Debug.metric("StoreFieldRecorded");
-    public static final DebugMetric METRIC_LOADFIELD_ELIMINATED = Debug.metric("LoadFieldEliminated");
-    public static final DebugMetric METRIC_LOADFIELD_NOT_ELIMINATED = Debug.metric("LoadFieldNotEliminated");
     public static final DebugMetric METRIC_MEMORYCHECKOINT = Debug.metric("MemoryCheckpoint");
 
     private final NodeBitMap usages;
@@ -148,44 +145,24 @@
         FixedWithNextNode lastFixedNode = null;
         for (Node node : nodeList) {
             boolean deleted;
-            if (usages.isMarked(node) || node instanceof VirtualizableAllocation) {
+            boolean isMarked = usages.isMarked(node);
+            if (isMarked || node instanceof VirtualizableRoot) {
                 trace("[[%s]] ", node);
-                deleted = processNode((ValueNode) node, lastFixedNode == null ? null : lastFixedNode.next(), state, effects);
+                FixedNode nextFixedNode = lastFixedNode == null ? null : lastFixedNode.next();
+                deleted = processNode((ValueNode) node, nextFixedNode, state, effects, isMarked);
             } else {
                 trace("%s ", node);
                 deleted = false;
             }
             if (GraalOptions.OptEarlyReadElimination) {
-                if (!deleted) {
-                    if (node instanceof StoreFieldNode) {
-                        METRIC_STOREFIELD_RECORDED.increment();
-                        StoreFieldNode store = (StoreFieldNode) node;
-                        ValueNode cachedValue = state.getReadCache(store.object(), (LocationIdentity) store.field());
-                        state.killReadCache((LocationIdentity) store.field());
-
-                        if (cachedValue == store.value()) {
-                            effects.deleteFixedNode(store);
-                            changed = true;
-                        } else {
-                            state.addReadCache(store.object(), (LocationIdentity) store.field(), store.value());
-                        }
-                    } else if (node instanceof LoadFieldNode) {
-                        LoadFieldNode load = (LoadFieldNode) node;
-                        ValueNode cachedValue = state.getReadCache(load.object(), (LocationIdentity) load.field());
-                        if (cachedValue != null) {
-                            METRIC_LOADFIELD_ELIMINATED.increment();
-                            effects.replaceAtUsages(load, cachedValue);
-                            state.addScalarAlias(load, cachedValue);
-                            changed = true;
-                        } else {
-                            METRIC_LOADFIELD_NOT_ELIMINATED.increment();
-                            state.addReadCache(load.object(), (LocationIdentity) load.field(), load);
-                        }
-                    } else if (node instanceof MemoryCheckpoint) {
-                        METRIC_MEMORYCHECKOINT.increment();
-                        MemoryCheckpoint checkpoint = (MemoryCheckpoint) node;
-                        for (LocationIdentity identity : checkpoint.getLocationIdentities()) {
-                            state.killReadCache(identity);
+                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 == LocationNode.ANY_LOCATION) {
+                            state.killReadCache();
                         }
                     }
                 }
@@ -198,7 +175,7 @@
         return state;
     }
 
-    private boolean processNode(final ValueNode node, FixedNode insertBefore, final BlockState state, final GraphEffectList effects) {
+    private boolean processNode(final ValueNode node, FixedNode insertBefore, final BlockState state, final GraphEffectList effects, boolean isMarked) {
         tool.reset(state, node, insertBefore);
         if (node instanceof Virtualizable) {
             ((Virtualizable) node).virtualize(tool);
@@ -209,89 +186,91 @@
             }
             return true;
         }
-        if (node instanceof StateSplit) {
-            StateSplit split = (StateSplit) node;
-            FrameState stateAfter = split.stateAfter();
-            if (stateAfter != null) {
-                if (stateAfter.usages().count() > 1) {
-                    stateAfter = (FrameState) stateAfter.copyWithInputs();
-                    split.setStateAfter(stateAfter);
-                }
-                final HashSet<ObjectState> virtual = new HashSet<>();
-                stateAfter.applyToNonVirtual(new NodeClosure<ValueNode>() {
+        if (isMarked) {
+            if (node instanceof StateSplit) {
+                StateSplit split = (StateSplit) node;
+                FrameState stateAfter = split.stateAfter();
+                if (stateAfter != null) {
+                    if (stateAfter.usages().count() > 1) {
+                        stateAfter = (FrameState) stateAfter.copyWithInputs();
+                        split.setStateAfter(stateAfter);
+                    }
+                    final HashSet<ObjectState> virtual = new HashSet<>();
+                    stateAfter.applyToNonVirtual(new NodeClosure<ValueNode>() {
 
-                    @Override
-                    public void apply(Node usage, ValueNode value) {
-                        ObjectState valueObj = state.getObjectState(value);
-                        if (valueObj != null) {
-                            virtual.add(valueObj);
-                            effects.replaceFirstInput(usage, value, valueObj.virtual);
-                        } else if (value instanceof VirtualObjectNode) {
-                            ObjectState virtualObj = null;
-                            for (ObjectState obj : state.getStates()) {
-                                if (value == obj.virtual) {
-                                    virtualObj = obj;
-                                    break;
+                        @Override
+                        public void apply(Node usage, ValueNode value) {
+                            ObjectState valueObj = state.getObjectState(value);
+                            if (valueObj != null) {
+                                virtual.add(valueObj);
+                                effects.replaceFirstInput(usage, value, valueObj.virtual);
+                            } else if (value instanceof VirtualObjectNode) {
+                                ObjectState virtualObj = null;
+                                for (ObjectState obj : state.getStates()) {
+                                    if (value == obj.virtual) {
+                                        virtualObj = obj;
+                                        break;
+                                    }
+                                }
+                                if (virtualObj != null) {
+                                    virtual.add(virtualObj);
                                 }
                             }
-                            if (virtualObj != null) {
-                                virtual.add(virtualObj);
-                            }
+                        }
+                    });
+                    for (ObjectState obj : state.getStates()) {
+                        if (obj.isVirtual() && obj.hasLocks()) {
+                            virtual.add(obj);
                         }
                     }
-                });
-                for (ObjectState obj : state.getStates()) {
-                    if (obj.isVirtual() && obj.hasLocks()) {
-                        virtual.add(obj);
-                    }
-                }
 
-                ArrayDeque<ObjectState> queue = new ArrayDeque<>(virtual);
-                while (!queue.isEmpty()) {
-                    ObjectState obj = queue.removeLast();
-                    if (obj.isVirtual()) {
-                        for (ValueNode field : obj.getEntries()) {
-                            ObjectState fieldObj = state.getObjectState(field);
-                            if (fieldObj != null) {
-                                if (fieldObj.isVirtual() && !virtual.contains(fieldObj)) {
-                                    virtual.add(fieldObj);
-                                    queue.addLast(fieldObj);
+                    ArrayDeque<ObjectState> queue = new ArrayDeque<>(virtual);
+                    while (!queue.isEmpty()) {
+                        ObjectState obj = queue.removeLast();
+                        if (obj.isVirtual()) {
+                            for (ValueNode field : obj.getEntries()) {
+                                ObjectState fieldObj = state.getObjectState(field);
+                                if (fieldObj != null) {
+                                    if (fieldObj.isVirtual() && !virtual.contains(fieldObj)) {
+                                        virtual.add(fieldObj);
+                                        queue.addLast(fieldObj);
+                                    }
                                 }
                             }
                         }
                     }
-                }
-                for (ObjectState obj : virtual) {
-                    EscapeObjectState v;
-                    if (obj.isVirtual()) {
-                        ValueNode[] fieldState = obj.getEntries().clone();
-                        for (int i = 0; i < fieldState.length; i++) {
-                            ObjectState valueObj = state.getObjectState(fieldState[i]);
-                            if (valueObj != null) {
-                                if (valueObj.isVirtual()) {
-                                    fieldState[i] = valueObj.virtual;
-                                } else {
-                                    fieldState[i] = valueObj.getMaterializedValue();
+                    for (ObjectState obj : virtual) {
+                        EscapeObjectState v;
+                        if (obj.isVirtual()) {
+                            ValueNode[] fieldState = obj.getEntries().clone();
+                            for (int i = 0; i < fieldState.length; i++) {
+                                ObjectState valueObj = state.getObjectState(fieldState[i]);
+                                if (valueObj != null) {
+                                    if (valueObj.isVirtual()) {
+                                        fieldState[i] = valueObj.virtual;
+                                    } else {
+                                        fieldState[i] = valueObj.getMaterializedValue();
+                                    }
                                 }
                             }
+                            v = new VirtualObjectState(obj.virtual, fieldState);
+                        } else {
+                            v = new MaterializedObjectState(obj.virtual, obj.getMaterializedValue());
                         }
-                        v = new VirtualObjectState(obj.virtual, fieldState);
-                    } else {
-                        v = new MaterializedObjectState(obj.virtual, obj.getMaterializedValue());
+                        effects.addVirtualMapping(stateAfter, v);
                     }
-                    effects.addVirtualMapping(stateAfter, v);
                 }
             }
-        }
-        for (ValueNode input : node.inputs().filter(ValueNode.class)) {
-            ObjectState obj = state.getObjectState(input);
-            if (obj != null) {
-                if (obj.isVirtual() && node instanceof MethodCallTargetNode) {
-                    Invoke invoke = ((MethodCallTargetNode) node).invoke();
-                    hints.put(invoke, 5d);
+            for (ValueNode input : node.inputs().filter(ValueNode.class)) {
+                ObjectState obj = state.getObjectState(input);
+                if (obj != null) {
+                    if (obj.isVirtual() && node instanceof MethodCallTargetNode) {
+                        Invoke invoke = ((MethodCallTargetNode) node).invoke();
+                        hints.put(invoke, 5d);
+                    }
+                    trace("replacing input %s at %s: %s", input, node, obj);
+                    replaceWithMaterialized(input, node, insertBefore, state, obj, effects, METRIC_MATERIALIZATIONS_UNHANDLED);
                 }
-                trace("replacing input %s at %s: %s", input, node, obj);
-                replaceWithMaterialized(input, node, insertBefore, state, obj, effects, METRIC_MATERIALIZATIONS_UNHANDLED);
             }
         }
         return false;
@@ -703,7 +682,7 @@
             }
         }
 
-        private void mergeReadCachePhi(PhiNode phi, LocationIdentity identity, List<BlockState> states) {
+        private void mergeReadCachePhi(PhiNode phi, ResolvedJavaField identity, List<BlockState> 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);
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Thu May 16 17:03:18 2013 -0700
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Fri May 17 14:29:44 2013 +0200
@@ -181,4 +181,26 @@
             }
         }
     }
+
+    @Override
+    public void addReadCache(ValueNode object, ResolvedJavaField identity, ValueNode value) {
+        if (GraalOptions.OptEarlyReadElimination) {
+            state.addReadCache(object, identity, value);
+        }
+    }
+
+    @Override
+    public ValueNode getReadCache(ValueNode object, ResolvedJavaField identity) {
+        if (GraalOptions.OptEarlyReadElimination) {
+            return state.getReadCache(object, identity);
+        }
+        return null;
+    }
+
+    @Override
+    public void killReadCache(ResolvedJavaField identity) {
+        if (GraalOptions.OptEarlyReadElimination) {
+            state.killReadCache(identity);
+        }
+    }
 }