# HG changeset patch # User Lukas Stadler # Date 1368793784 -7200 # Node ID 432b8405e05657d9a571c0f40607cdab61c5cbb0 # Parent 98b004bf3985883bea8bf90e0c34527a591fb8f1 small refactoring of early read elimination (move logic into "virtualize" methods) diff -r 98b004bf3985 -r 432b8405e056 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java --- 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); + } } } } diff -r 98b004bf3985 -r 432b8405e056 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java --- 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()); } } } diff -r 98b004bf3985 -r 432b8405e056 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizableAllocation.java --- 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 { } diff -r 98b004bf3985 -r 432b8405e056 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizableRoot.java --- /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 { + +} diff -r 98b004bf3985 -r 432b8405e056 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java --- 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); + } diff -r 98b004bf3985 -r 432b8405e056 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java --- 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> iter = readCache.entrySet().iterator(); - while (iter.hasNext()) { - Map.Entry entry = iter.next(); - if (entry.getKey().identity == identity) { - iter.remove(); - } + public void killReadCache() { + readCache.clear(); + } + + public void killReadCache(ResolvedJavaField identity) { + Iterator> iter = readCache.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry 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 { diff -r 98b004bf3985 -r 432b8405e056 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java --- 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; } diff -r 98b004bf3985 -r 432b8405e056 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java --- 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 virtual = new HashSet<>(); - stateAfter.applyToNonVirtual(new NodeClosure() { + 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 virtual = new HashSet<>(); + stateAfter.applyToNonVirtual(new NodeClosure() { - @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 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 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 states) { + private void mergeReadCachePhi(PhiNode phi, ResolvedJavaField identity, List 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); diff -r 98b004bf3985 -r 432b8405e056 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java --- 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); + } + } }