src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/IntegerSwitchNode.java
branchdatagramsocketimpl-branch
changeset 58678 9cf78a70fa4f
parent 52910 583fd71c47d6
child 58679 9c3209ff7550
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/IntegerSwitchNode.java	Thu Oct 17 20:27:44 2019 +0100
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/IntegerSwitchNode.java	Thu Oct 17 20:53:35 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -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
@@ -220,7 +297,7 @@
             return false;
         }
         LoadIndexedNode loadIndexed = (LoadIndexedNode) value();
-        if (loadIndexed.usages().count() > 1) {
+        if (loadIndexed.hasMoreThanOneUsage()) {
             /*
              * The array load is necessary for other reasons too, so there is no benefit optimizing
              * the switch.
@@ -352,11 +429,14 @@
         }
 
         /*
-         * Collect dead successors. Successors have to be cleaned before adding the new node to the
-         * graph.
+         * Surviving successors have to be cleaned before adding the new node to the graph. Keep the
+         * dead ones attached to the old node for later cleanup.
          */
-        List<AbstractBeginNode> deadSuccessors = successors.filter(s -> !newSuccessors.contains(s)).snapshot();
-        successors.clear();
+        for (int i = 0; i < successors.size(); i++) {
+            if (newSuccessors.contains(successors.get(i))) {
+                successors.set(i, null);
+            }
+        }
 
         /*
          * Create the new switch node. This is done before removing dead successors as `killCFG`
@@ -366,14 +446,11 @@
         AbstractBeginNode[] successorsArray = newSuccessors.toArray(new AbstractBeginNode[newSuccessors.size()]);
         SwitchNode newSwitch = graph().add(new IntegerSwitchNode(newValue, successorsArray, newKeys, newKeyProbabilities, newKeySuccessors));
 
-        /* Remove dead successors. */
-        for (AbstractBeginNode successor : deadSuccessors) {
-            GraphUtil.killCFG(successor);
-        }
-
         /* Replace ourselves with the new switch */
         ((FixedWithNextNode) predecessor()).setNext(newSwitch);
-        GraphUtil.killWithUnusedFloatingInputs(this);
+
+        // Remove the old switch and the dead successors.
+        GraphUtil.killCFG(this);
     }
 
     @Override