# HG changeset patch # User Lukas Stadler # Date 1427716971 -7200 # Node ID a8b979f7dcef71f8dd02f3f6f098b5001030f482 # Parent 126ab00f859cd64fcfabb9aa4e5ef43317e66225 handle indexed loads and unboxing in PEA read elimination diff -r 126ab00f859c -r a8b979f7dcef graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java Mon Mar 30 14:02:08 2015 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java Mon Mar 30 14:02:51 2015 +0200 @@ -33,20 +33,23 @@ final HashMap readCache; - static class ReadCacheEntry { + static final class ReadCacheEntry { public final LocationIdentity identity; public final ValueNode object; + public final int index; - public ReadCacheEntry(LocationIdentity identity, ValueNode object) { + public ReadCacheEntry(LocationIdentity identity, ValueNode object, int index) { this.identity = identity; this.object = object; + this.index = index; } @Override public int hashCode() { int result = 31 + ((identity == null) ? 0 : identity.hashCode()); - return 31 * result + ((object == null) ? 0 : object.hashCode()); + result = 31 * result + ((object == null) ? 0 : object.hashCode()); + return result * 31 + index; } @Override @@ -60,7 +63,7 @@ @Override public String toString() { - return object + ":" + identity; + return index == -1 ? (object + ":" + identity) : (object + "[" + index + "]:" + identity); } } @@ -83,7 +86,7 @@ if (virtual instanceof VirtualInstanceNode) { VirtualInstanceNode instance = (VirtualInstanceNode) virtual; for (int i = 0; i < instance.entryCount(); i++) { - readCache.put(new ReadCacheEntry(instance.field(i).getLocationIdentity(), representation), values.get(i)); + readCache.put(new ReadCacheEntry(instance.field(i).getLocationIdentity(), representation, -1), values.get(i)); } } } @@ -96,7 +99,7 @@ return super.equivalentTo(other); } - public void addReadCache(ValueNode object, LocationIdentity identity, ValueNode value, PartialEscapeClosure closure) { + public void addReadCache(ValueNode object, LocationIdentity identity, int index, ValueNode value, PartialEscapeClosure closure) { ValueNode cacheObject; ObjectState obj = closure.getObjectState(this, object); if (obj != null) { @@ -105,10 +108,10 @@ } else { cacheObject = object; } - readCache.put(new ReadCacheEntry(identity, cacheObject), value); + readCache.put(new ReadCacheEntry(identity, cacheObject, index), value); } - public ValueNode getReadCache(ValueNode object, LocationIdentity identity, PartialEscapeClosure closure) { + public ValueNode getReadCache(ValueNode object, LocationIdentity identity, int index, PartialEscapeClosure closure) { ValueNode cacheObject; ObjectState obj = closure.getObjectState(this, object); if (obj != null) { @@ -117,7 +120,7 @@ } else { cacheObject = object; } - ValueNode cacheValue = readCache.get(new ReadCacheEntry(identity, cacheObject)); + ValueNode cacheValue = readCache.get(new ReadCacheEntry(identity, cacheObject, index)); obj = closure.getObjectState(this, cacheValue); if (obj != null) { assert !obj.isVirtual(); @@ -133,11 +136,11 @@ readCache.clear(); } - public void killReadCache(LocationIdentity identity) { + public void killReadCache(LocationIdentity identity, int index) { Iterator> iter = readCache.entrySet().iterator(); while (iter.hasNext()) { - Map.Entry entry = iter.next(); - if (entry.getKey().identity.equals(identity)) { + ReadCacheEntry entry = iter.next().getKey(); + if (entry.identity.equals(identity) && (index == -1 || entry.index == -1 || index == entry.index)) { iter.remove(); } } diff -r 126ab00f859c -r a8b979f7dcef graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java Mon Mar 30 14:02:08 2015 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java Mon Mar 30 14:02:51 2015 +0200 @@ -38,6 +38,14 @@ public class PEReadEliminationClosure extends PartialEscapeClosure { + private static final EnumMap UNBOX_LOCATIONS; + static { + UNBOX_LOCATIONS = new EnumMap<>(Kind.class); + for (Kind kind : Kind.values()) { + UNBOX_LOCATIONS.put(kind, NamedLocationIdentity.immutable("PEA unbox " + kind.getJavaName())); + } + } + public PEReadEliminationClosure(SchedulePhase schedule, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) { super(schedule, metaAccess, constantReflection); } @@ -57,8 +65,14 @@ return processLoadField((LoadFieldNode) node, state, effects); } else if (node instanceof StoreFieldNode) { return processStoreField((StoreFieldNode) node, state, effects); + } else if (node instanceof LoadIndexedNode) { + return processLoadIndexed((LoadIndexedNode) node, state, effects); + } else if (node instanceof StoreIndexedNode) { + return processStoreIndexed((StoreIndexedNode) node, state, effects); } else if (node instanceof ArrayLengthNode) { return processArrayLength((ArrayLengthNode) node, state, effects); + } else if (node instanceof UnboxNode) { + return processUnbox((UnboxNode) node, state, effects); } else if (node instanceof MemoryCheckpoint.Single) { METRIC_MEMORYCHECKPOINT.increment(); LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity(); @@ -75,13 +89,13 @@ private boolean processArrayLength(ArrayLengthNode length, PEReadEliminationBlockState state, GraphEffectList effects) { ValueNode array = GraphUtil.unproxify(length.array()); - ValueNode cachedValue = state.getReadCache(array, ARRAY_LENGTH_LOCATION, this); + ValueNode cachedValue = state.getReadCache(array, ARRAY_LENGTH_LOCATION, -1, this); if (cachedValue != null) { effects.replaceAtUsages(length, cachedValue); addScalarAlias(length, cachedValue); return true; } else { - state.addReadCache(array, ARRAY_LENGTH_LOCATION, length, this); + state.addReadCache(array, ARRAY_LENGTH_LOCATION, -1, length, this); } return false; } @@ -89,7 +103,7 @@ private boolean processStoreField(StoreFieldNode store, PEReadEliminationBlockState state, GraphEffectList effects) { if (!store.isVolatile()) { ValueNode object = GraphUtil.unproxify(store.object()); - ValueNode cachedValue = state.getReadCache(object, store.field().getLocationIdentity(), this); + ValueNode cachedValue = state.getReadCache(object, store.field().getLocationIdentity(), -1, this); ValueNode value = getScalarAlias(store.value()); boolean result = false; @@ -97,8 +111,8 @@ effects.deleteNode(store); result = true; } - state.killReadCache(store.field().getLocationIdentity()); - state.addReadCache(object, store.field().getLocationIdentity(), value, this); + state.killReadCache(store.field().getLocationIdentity(), -1); + state.addReadCache(object, store.field().getLocationIdentity(), -1, value, this); return result; } else { processIdentity(state, any()); @@ -111,14 +125,67 @@ processIdentity(state, any()); } else { ValueNode object = GraphUtil.unproxify(load.object()); - ValueNode cachedValue = state.getReadCache(object, load.field().getLocationIdentity(), this); + ValueNode cachedValue = state.getReadCache(object, load.field().getLocationIdentity(), -1, this); if (cachedValue != null) { effects.replaceAtUsages(load, cachedValue); addScalarAlias(load, cachedValue); return true; } else { - state.addReadCache(object, load.field().getLocationIdentity(), load, this); + state.addReadCache(object, load.field().getLocationIdentity(), -1, load, this); + } + } + return false; + } + + private boolean processStoreIndexed(StoreIndexedNode store, PEReadEliminationBlockState state, GraphEffectList effects) { + LocationIdentity arrayLocation = NamedLocationIdentity.getArrayLocation(store.elementKind()); + if (store.index().isConstant()) { + int index = ((JavaConstant) store.index().asConstant()).asInt(); + ValueNode object = GraphUtil.unproxify(store.array()); + ValueNode cachedValue = state.getReadCache(object, arrayLocation, index, this); + + ValueNode value = getScalarAlias(store.value()); + boolean result = false; + if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) { + effects.deleteNode(store); + result = true; } + state.killReadCache(arrayLocation, index); + state.addReadCache(object, arrayLocation, index, value, this); + return result; + } else { + state.killReadCache(arrayLocation, -1); + } + return false; + } + + private boolean processLoadIndexed(LoadIndexedNode load, PEReadEliminationBlockState state, GraphEffectList effects) { + if (load.index().isConstant()) { + int index = ((JavaConstant) load.index().asConstant()).asInt(); + LocationIdentity arrayLocation = NamedLocationIdentity.getArrayLocation(load.elementKind()); + ValueNode object = GraphUtil.unproxify(load.array()); + ValueNode cachedValue = state.getReadCache(object, arrayLocation, index, this); + if (cachedValue != null) { + effects.replaceAtUsages(load, cachedValue); + addScalarAlias(load, cachedValue); + return true; + } else { + state.addReadCache(object, arrayLocation, index, load, this); + } + } + return false; + } + + private boolean processUnbox(UnboxNode unbox, PEReadEliminationBlockState state, GraphEffectList effects) { + ValueNode object = GraphUtil.unproxify(unbox.getValue()); + LocationIdentity identity = UNBOX_LOCATIONS.get(unbox.getBoxingKind()); + ValueNode cachedValue = state.getReadCache(object, identity, -1, this); + if (cachedValue != null) { + effects.replaceAtUsages(unbox, cachedValue); + addScalarAlias(unbox, cachedValue); + return true; + } else { + state.addReadCache(object, identity, -1, unbox, this); } return false; } @@ -127,7 +194,7 @@ if (identity.isAny()) { state.killReadCache(); } else { - state.killReadCache(identity); + state.killReadCache(identity, -1); } } @@ -138,7 +205,7 @@ if (exitNode.graph().hasValueProxies()) { for (Map.Entry entry : exitState.getReadCache().entrySet()) { if (initialState.getReadCache().get(entry.getKey()) != entry.getValue()) { - ValueNode value = exitState.getReadCache(entry.getKey().object, entry.getKey().identity, this); + ValueNode value = exitState.getReadCache(entry.getKey().object, entry.getKey().identity, entry.getKey().index, this); if (!(value instanceof ProxyNode) || ((ProxyNode) value).proxyPoint() != exitNode) { ProxyNode proxy = new ValueProxyNode(value, exitNode); effects.addFloatingNode(proxy, "readCacheProxy"); @@ -192,7 +259,7 @@ PhiNode phiNode = getPhi(entry, value.stamp().unrestricted()); mergeEffects.addFloatingNode(phiNode, "mergeReadCache"); for (int i = 0; i < states.size(); i++) { - afterMergeEffects.addPhiInput(phiNode, states.get(i).getReadCache(key.object, key.identity, PEReadEliminationClosure.this)); + afterMergeEffects.addPhiInput(phiNode, states.get(i).getReadCache(key.object, key.identity, key.index, PEReadEliminationClosure.this)); } newState.readCache.put(key, phiNode); } else if (value != null) { @@ -203,7 +270,7 @@ if (phi.getKind() == Kind.Object) { for (Map.Entry entry : states.get(0).readCache.entrySet()) { if (entry.getKey().object == phi.valueAt(0)) { - mergeReadCachePhi(phi, entry.getKey().identity, states); + mergeReadCachePhi(phi, entry.getKey().identity, entry.getKey().index, states); } } @@ -211,22 +278,22 @@ } } - private void mergeReadCachePhi(PhiNode phi, LocationIdentity identity, List states) { + private void mergeReadCachePhi(PhiNode phi, LocationIdentity identity, int index, 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, PEReadEliminationClosure.this); + ValueNode value = states.get(i).getReadCache(phi.valueAt(i), identity, index, PEReadEliminationClosure.this); if (value == null) { return; } values[i] = value; } - PhiNode phiNode = getPhi(new ReadCacheEntry(identity, phi), values[0].stamp().unrestricted()); + PhiNode phiNode = getPhi(new ReadCacheEntry(identity, phi, index), values[0].stamp().unrestricted()); 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); + newState.readCache.put(new ReadCacheEntry(identity, phi, index), phiNode); } } }