src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java
changeset 50330 2cbc42a5764b
parent 49873 26ebfe8ce852
child 50858 2d3e99a72541
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java	Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java	Thu May 31 10:38:05 2018 -0700
@@ -28,6 +28,7 @@
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Objects;
 import java.util.function.BiFunction;
 
 import jdk.internal.vm.compiler.collections.EconomicMap;
@@ -66,10 +67,13 @@
 import org.graalvm.compiler.nodes.StateSplit;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValuePhiNode;
+import org.graalvm.compiler.nodes.ValueProxyNode;
 import org.graalvm.compiler.nodes.java.LoadIndexedNode;
 import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
 import org.graalvm.compiler.nodes.java.MonitorIdNode;
 import org.graalvm.compiler.nodes.spi.ArrayLengthProvider;
+import org.graalvm.compiler.nodes.spi.ArrayLengthProvider.FindLengthMode;
 import org.graalvm.compiler.nodes.spi.LimitedValueProxy;
 import org.graalvm.compiler.nodes.spi.LoweringProvider;
 import org.graalvm.compiler.nodes.spi.ValueProxy;
@@ -664,28 +668,71 @@
     }
 
     /**
-     * Looks for an {@link ArrayLengthProvider} while iterating through all {@link ValueProxy
-     * ValueProxies}.
+     * Returns the length of the array described by the value parameter, or null if it is not
+     * available. Details of the different modes are documented in {@link FindLengthMode}.
      *
      * @param value The start value.
+     * @param mode The mode as documented in {@link FindLengthMode}.
      * @return The array length if one was found, or null otherwise.
      */
-    public static ValueNode arrayLength(ValueNode value) {
+    public static ValueNode arrayLength(ValueNode value, ArrayLengthProvider.FindLengthMode mode) {
+        Objects.requireNonNull(mode);
+
         ValueNode current = value;
         do {
+            /*
+             * PiArrayNode implements ArrayLengthProvider and ValueProxy. We want to treat it as an
+             * ArrayLengthProvider, therefore we check this case first.
+             */
             if (current instanceof ArrayLengthProvider) {
-                ValueNode length = ((ArrayLengthProvider) current).length();
-                if (length != null) {
-                    return length;
+                return ((ArrayLengthProvider) current).findLength(mode);
+
+            } else if (current instanceof ValuePhiNode) {
+                return phiArrayLength((ValuePhiNode) current, mode);
+
+            } else if (current instanceof ValueProxyNode) {
+                ValueProxyNode proxy = (ValueProxyNode) current;
+                ValueNode length = arrayLength(proxy.getOriginalNode(), mode);
+                if (mode == ArrayLengthProvider.FindLengthMode.CANONICALIZE_READ && length != null && !length.isConstant()) {
+                    length = new ValueProxyNode(length, proxy.proxyPoint());
                 }
-            }
-            if (current instanceof ValueProxy) {
+                return length;
+
+            } else if (current instanceof ValueProxy) {
+                /* Written as a loop instead of a recursive call to reduce recursion depth. */
                 current = ((ValueProxy) current).getOriginalNode();
+
             } else {
-                break;
+                return null;
             }
         } while (true);
-        return null;
+    }
+
+    private static ValueNode phiArrayLength(ValuePhiNode phi, ArrayLengthProvider.FindLengthMode mode) {
+        if (phi.merge() instanceof LoopBeginNode) {
+            /* Avoid cycle detection by not processing phi functions that could introduce cycles. */
+            return null;
+        }
+
+        ValueNode singleLength = null;
+        for (int i = 0; i < phi.values().count(); i++) {
+            ValueNode input = phi.values().get(i);
+            ValueNode length = arrayLength(input, mode);
+            if (length == null) {
+                return null;
+            }
+            assert length.stamp(NodeView.DEFAULT).getStackKind() == JavaKind.Int;
+
+            if (i == 0) {
+                assert singleLength == null;
+                singleLength = length;
+            } else if (singleLength == length) {
+                /* Nothing to do, still having a single length. */
+            } else {
+                return null;
+            }
+        }
+        return singleLength;
     }
 
     /**
@@ -1006,7 +1053,7 @@
         } else {
             /* The source array is not virtualized, emit index loads. */
             for (int i = 0; i < readLength; i++) {
-                LoadIndexedNode load = new LoadIndexedNode(null, sourceAlias, ConstantNode.forInt(i + fromInt, graph), elementKind);
+                LoadIndexedNode load = new LoadIndexedNode(null, sourceAlias, ConstantNode.forInt(i + fromInt, graph), null, elementKind);
                 tool.addNode(load);
                 newEntryState[i] = load;
             }