src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java
changeset 47667 390896759aa2
parent 47216 71c04702a3d5
child 48190 25cfedf27edc
--- 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);
             }
         }
     }