src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/IntegerSwitchNode.java
changeset 57537 ecc6e394475f
parent 55509 d58442b8abc1
child 58299 6df94ce3ab2f
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/IntegerSwitchNode.java	Thu Jul 25 11:44:37 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/IntegerSwitchNode.java	Thu Jul 25 17:35:58 2019 -0400
@@ -36,6 +36,7 @@
 import org.graalvm.compiler.core.common.type.PrimitiveStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.spi.Simplifiable;
 import org.graalvm.compiler.graph.spi.SimplifierTool;
@@ -51,6 +52,7 @@
 import org.graalvm.compiler.nodes.java.LoadIndexedNode;
 import org.graalvm.compiler.nodes.spi.LIRLowerable;
 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.spi.SwitchFoldable;
 import org.graalvm.compiler.nodes.util.GraphUtil;
 
 import jdk.vm.ci.meta.DeoptimizationAction;
@@ -63,7 +65,7 @@
  * values. The actual implementation of the switch will be decided by the backend.
  */
 @NodeInfo
-public final class IntegerSwitchNode extends SwitchNode implements LIRLowerable, Simplifiable {
+public final class IntegerSwitchNode extends SwitchNode implements LIRLowerable, Simplifiable, SwitchFoldable {
     public static final NodeClass<IntegerSwitchNode> TYPE = NodeClass.create(IntegerSwitchNode.class);
 
     protected final int[] keys;
@@ -75,6 +77,7 @@
         this.keys = keys;
         assert value.stamp(NodeView.DEFAULT) instanceof PrimitiveStamp && value.stamp(NodeView.DEFAULT).getStackKind().isNumericInteger();
         assert assertSorted();
+        assert assertNoUntargettedSuccessor();
     }
 
     private boolean assertSorted() {
@@ -84,6 +87,18 @@
         return true;
     }
 
+    private boolean assertNoUntargettedSuccessor() {
+        boolean[] checker = new boolean[successors.size()];
+        for (int successorIndex : keySuccessors) {
+            checker[successorIndex] = true;
+        }
+        checker[defaultSuccessorIndex()] = true;
+        for (boolean b : checker) {
+            assert b;
+        }
+        return true;
+    }
+
     public IntegerSwitchNode(ValueNode value, int successorCount, int[] keys, double[] keyProbabilities, int[] keySuccessors) {
         this(value, new AbstractBeginNode[successorCount], keys, keyProbabilities, keySuccessors);
     }
@@ -104,6 +119,14 @@
         return JavaConstant.forInt(keys[i]);
     }
 
+    /**
+     * Gets the key at the specified index, as a java int.
+     */
+    @Override
+    public int intKeyAt(int i) {
+        return keys[i];
+    }
+
     @Override
     public int keyCount() {
         return keys.length;
@@ -148,9 +171,63 @@
             return;
         } else if (tryRemoveUnreachableKeys(tool, value().stamp(view))) {
             return;
+        } else if (switchTransformationOptimization(tool)) {
+            return;
         }
     }
 
+    private void addSuccessorForDeletion(AbstractBeginNode defaultNode) {
+        successors.add(defaultNode);
+    }
+
+    @Override
+    public Node getNextSwitchFoldableBranch() {
+        return defaultSuccessor();
+    }
+
+    @Override
+    public boolean isInSwitch(ValueNode switchValue) {
+        return value == switchValue;
+    }
+
+    @Override
+    public void cutOffCascadeNode() {
+        AbstractBeginNode toKill = defaultSuccessor();
+        clearSuccessors();
+        addSuccessorForDeletion(toKill);
+    }
+
+    @Override
+    public void cutOffLowestCascadeNode() {
+        clearSuccessors();
+    }
+
+    @Override
+    public AbstractBeginNode getDefault() {
+        return defaultSuccessor();
+    }
+
+    @Override
+    public ValueNode switchValue() {
+        return value();
+    }
+
+    @Override
+    public boolean isNonInitializedProfile() {
+        int nbSuccessors = getSuccessorCount();
+        double prob = 0.0d;
+        for (int i = 0; i < nbSuccessors; i++) {
+            if (keyProbabilities[i] > 0.0d) {
+                if (prob == 0.0d) {
+                    prob = keyProbabilities[i];
+                } else if (keyProbabilities[i] != prob) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
     static final class KeyData {
         final int key;
         final double keyProbability;
@@ -208,7 +285,7 @@
      * because {@link Enum#ordinal()} can change when recompiling an enum, it cannot be used
      * directly as the value that is switched on. An intermediate int[] array, which is initialized
      * once at run time based on the actual {@link Enum#ordinal()} values, is used.
-     *
+     * <p>
      * The {@link ConstantFieldProvider} of Graal already detects the int[] arrays and marks them as
      * {@link ConstantNode#isDefaultStable() stable}, i.e., the array elements are constant. The
      * code in this method detects array loads from such a stable array and re-wires the switch to