--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java Wed Sep 20 15:12:11 2017 +0200
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java Wed Oct 11 17:11:28 2017 -0700
@@ -31,7 +31,6 @@
import org.graalvm.compiler.core.common.cfg.Loop;
import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
-import org.graalvm.compiler.core.common.type.Stamp;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.nodes.AbstractBeginNode;
import org.graalvm.compiler.nodes.FieldLocationIdentity;
@@ -131,9 +130,10 @@
return false;
}
- private boolean processStore(FixedNode store, ValueNode object, LocationIdentity identity, int index, JavaKind kind, ValueNode value, PEReadEliminationBlockState state, GraphEffectList effects) {
+ private boolean processStore(FixedNode store, ValueNode object, LocationIdentity identity, int index, JavaKind accessKind, boolean overflowAccess, ValueNode value,
+ PEReadEliminationBlockState state, GraphEffectList effects) {
ValueNode unproxiedObject = GraphUtil.unproxify(object);
- ValueNode cachedValue = state.getReadCache(object, identity, index, kind, this);
+ ValueNode cachedValue = state.getReadCache(object, identity, index, accessKind, this);
ValueNode finalValue = getScalarAlias(value);
boolean result = false;
@@ -142,7 +142,7 @@
result = true;
}
state.killReadCache(identity, index);
- state.addReadCache(unproxiedObject, identity, index, kind, finalValue, this);
+ state.addReadCache(unproxiedObject, identity, index, accessKind, overflowAccess, finalValue, this);
return result;
}
@@ -150,43 +150,52 @@
ValueNode unproxiedObject = GraphUtil.unproxify(object);
ValueNode cachedValue = state.getReadCache(unproxiedObject, identity, index, kind, this);
if (cachedValue != null) {
- Stamp loadStamp = load.stamp();
- Stamp cachedValueStamp = cachedValue.stamp();
- if (!loadStamp.isCompatible(cachedValueStamp)) {
- /*
- * Can either be the first field of a two slot write to a one slot field which would
- * have a non compatible stamp or the second load which will see Illegal.
- */
- assert load.stamp().getStackKind() == JavaKind.Int && (cachedValue.stamp().getStackKind() == JavaKind.Long || cachedValue.getStackKind() == JavaKind.Double ||
- cachedValue.getStackKind() == JavaKind.Illegal) : "Can only allow different stack kind two slot marker writes on one slot fields.";
- return false;
- } else {
- // perform the read elimination
- effects.replaceAtUsages(load, cachedValue, load);
- addScalarAlias(load, cachedValue);
- return true;
- }
+ // perform the read elimination
+ effects.replaceAtUsages(load, cachedValue, load);
+ addScalarAlias(load, cachedValue);
+ return true;
} else {
- state.addReadCache(unproxiedObject, identity, index, kind, load, this);
+ state.addReadCache(unproxiedObject, identity, index, kind, false, load, this);
return false;
}
}
+ private static boolean isOverflowAccess(JavaKind accessKind, JavaKind declaredKind) {
+ if (accessKind == declaredKind) {
+ return false;
+ }
+ if (accessKind == JavaKind.Object) {
+ switch (declaredKind) {
+ case Object:
+ case Double:
+ case Long:
+ return false;
+ default:
+ return true;
+ }
+ }
+ assert accessKind.isPrimitive() : "Illegal access kind";
+ return declaredKind.isPrimitive() ? accessKind.getBitCount() > declaredKind.getBitCount() : true;
+ }
+
private boolean processUnsafeLoad(RawLoadNode load, PEReadEliminationBlockState state, GraphEffectList effects) {
if (load.offset().isConstant()) {
ResolvedJavaType type = StampTool.typeOrNull(load.object());
if (type != null && type.isArray()) {
+ JavaKind accessKind = load.accessKind();
+ JavaKind componentKind = type.getComponentType().getJavaKind();
long offset = load.offset().asJavaConstant().asLong();
- int index = VirtualArrayNode.entryIndexForOffset(offset, load.accessKind(), type.getComponentType(), Integer.MAX_VALUE);
+ int index = VirtualArrayNode.entryIndexForOffset(offset, accessKind, type.getComponentType(), Integer.MAX_VALUE);
ValueNode object = GraphUtil.unproxify(load.object());
- LocationIdentity location = NamedLocationIdentity.getArrayLocation(type.getComponentType().getJavaKind());
- ValueNode cachedValue = state.getReadCache(object, location, index, load.accessKind(), this);
- if (cachedValue != null && load.stamp().isCompatible(cachedValue.stamp())) {
+ LocationIdentity location = NamedLocationIdentity.getArrayLocation(componentKind);
+ ValueNode cachedValue = state.getReadCache(object, location, index, accessKind, this);
+ assert cachedValue == null || load.stamp().isCompatible(cachedValue.stamp()) : "The RawLoadNode's stamp is not compatible with the cached value.";
+ if (cachedValue != null) {
effects.replaceAtUsages(load, cachedValue, load);
addScalarAlias(load, cachedValue);
return true;
} else {
- state.addReadCache(object, location, index, load.accessKind(), load, this);
+ state.addReadCache(object, location, index, accessKind, isOverflowAccess(accessKind, componentKind), load, this);
}
}
}
@@ -196,11 +205,14 @@
private boolean processUnsafeStore(RawStoreNode store, PEReadEliminationBlockState state, GraphEffectList effects) {
ResolvedJavaType type = StampTool.typeOrNull(store.object());
if (type != null && type.isArray()) {
- LocationIdentity location = NamedLocationIdentity.getArrayLocation(type.getComponentType().getJavaKind());
+ JavaKind accessKind = store.accessKind();
+ JavaKind componentKind = type.getComponentType().getJavaKind();
+ LocationIdentity location = NamedLocationIdentity.getArrayLocation(componentKind);
if (store.offset().isConstant()) {
long offset = store.offset().asJavaConstant().asLong();
- int index = VirtualArrayNode.entryIndexForOffset(offset, store.accessKind(), type.getComponentType(), Integer.MAX_VALUE);
- return processStore(store, store.object(), location, index, store.accessKind(), store.value(), state, effects);
+ boolean overflowAccess = isOverflowAccess(accessKind, componentKind);
+ int index = overflowAccess ? -1 : VirtualArrayNode.entryIndexForOffset(offset, accessKind, type.getComponentType(), Integer.MAX_VALUE);
+ return processStore(store, store.object(), location, index, accessKind, overflowAccess, store.value(), state, effects);
} else {
processIdentity(state, location);
}
@@ -219,7 +231,8 @@
state.killReadCache();
return false;
}
- return processStore(store, store.object(), new FieldLocationIdentity(store.field()), -1, store.field().getJavaKind(), store.value(), state, effects);
+ JavaKind kind = store.field().getJavaKind();
+ return processStore(store, store.object(), new FieldLocationIdentity(store.field()), -1, kind, false, store.value(), state, effects);
}
private boolean processLoadField(LoadFieldNode load, PEReadEliminationBlockState state, GraphEffectList effects) {
@@ -230,11 +243,32 @@
return processLoad(load, load.object(), new FieldLocationIdentity(load.field()), -1, load.field().getJavaKind(), state, effects);
}
+ private static JavaKind getElementKindFromStamp(ValueNode array) {
+ ResolvedJavaType type = StampTool.typeOrNull(array);
+ if (type != null && type.isArray()) {
+ return type.getComponentType().getJavaKind();
+ } else {
+ // It is likely an OSRLocal without valid stamp
+ return JavaKind.Illegal;
+ }
+ }
+
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();
- return processStore(store, store.array(), arrayLocation, index, store.elementKind(), store.value(), state, effects);
+ int index = store.index().isConstant() ? ((JavaConstant) store.index().asConstant()).asInt() : -1;
+ // BASTORE (with elementKind being Byte) can be used to store values in boolean arrays.
+ JavaKind elementKind = store.elementKind();
+ if (elementKind == JavaKind.Byte) {
+ elementKind = getElementKindFromStamp(store.array());
+ if (elementKind == JavaKind.Illegal) {
+ // Could not determine the actual access kind from stamp. Hence kill both.
+ state.killReadCache(NamedLocationIdentity.getArrayLocation(JavaKind.Boolean), index);
+ state.killReadCache(NamedLocationIdentity.getArrayLocation(JavaKind.Byte), index);
+ return false;
+ }
+ }
+ LocationIdentity arrayLocation = NamedLocationIdentity.getArrayLocation(elementKind);
+ if (index != -1) {
+ return processStore(store, store.array(), arrayLocation, index, elementKind, false, store.value(), state, effects);
} else {
state.killReadCache(arrayLocation, -1);
}
@@ -244,8 +278,17 @@
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());
- return processLoad(load, load.array(), arrayLocation, index, load.elementKind(), state, effects);
+ // BALOAD (with elementKind being Byte) can be used to retrieve values from boolean
+ // arrays.
+ JavaKind elementKind = load.elementKind();
+ if (elementKind == JavaKind.Byte) {
+ elementKind = getElementKindFromStamp(load.array());
+ if (elementKind == JavaKind.Illegal) {
+ return false;
+ }
+ }
+ LocationIdentity arrayLocation = NamedLocationIdentity.getArrayLocation(elementKind);
+ return processLoad(load, load.array(), arrayLocation, index, elementKind, state, effects);
}
return false;
}
@@ -293,7 +336,7 @@
if (object != null) {
Pair<ValueNode, Object> pair = firstValueSet.get(object);
while (pair != null) {
- initialState.addReadCache(pair.getLeft(), entry.identity, entry.index, entry.kind, initialState.getReadCache().get(entry), this);
+ initialState.addReadCache(pair.getLeft(), entry.identity, entry.index, entry.kind, entry.overflowAccess, initialState.getReadCache().get(entry), this);
pair = (Pair<ValueNode, Object>) pair.getRight();
}
}
@@ -386,14 +429,14 @@
if (phi.getStackKind() == JavaKind.Object) {
for (ReadCacheEntry entry : states.get(0).readCache.getKeys()) {
if (entry.object == getPhiValueAt(phi, 0)) {
- mergeReadCachePhi(phi, entry.identity, entry.index, entry.kind, states);
+ mergeReadCachePhi(phi, entry.identity, entry.index, entry.kind, entry.overflowAccess, states);
}
}
}
}
}
- private void mergeReadCachePhi(PhiNode phi, LocationIdentity identity, int index, JavaKind kind, List<PEReadEliminationBlockState> states) {
+ private void mergeReadCachePhi(PhiNode phi, LocationIdentity identity, int index, JavaKind kind, boolean overflowAccess, List<PEReadEliminationBlockState> states) {
ValueNode[] values = new ValueNode[states.size()];
values[0] = states.get(0).getReadCache(getPhiValueAt(phi, 0), identity, index, kind, PEReadEliminationClosure.this);
if (values[0] != null) {
@@ -407,12 +450,12 @@
values[i] = value;
}
- PhiNode phiNode = getPhi(new ReadCacheEntry(identity, phi, index, kind), values[0].stamp().unrestricted());
+ PhiNode phiNode = getPhi(new ReadCacheEntry(identity, phi, index, kind, overflowAccess), values[0].stamp().unrestricted());
mergeEffects.addFloatingNode(phiNode, "mergeReadCachePhi");
for (int i = 0; i < values.length; i++) {
setPhiInput(phiNode, i, values[i]);
}
- newState.readCache.put(new ReadCacheEntry(identity, phi, index, kind), phiNode);
+ newState.readCache.put(new ReadCacheEntry(identity, phi, index, kind, overflowAccess), phiNode);
}
}
}