Introduce common super type for IntSwitch and StringSwitch

Change-Id: I877916417bc992882b4ac7b17f1818aa332db61d
diff --git a/src/main/java/com/android/tools/r8/ir/code/Goto.java b/src/main/java/com/android/tools/r8/ir/code/Goto.java
index a6f906c..826c75b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Goto.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Goto.java
@@ -14,7 +14,7 @@
 public class Goto extends JumpInstruction {
 
   public Goto() {
-    super(null);
+    super();
   }
 
   public Goto(BasicBlock block) {
diff --git a/src/main/java/com/android/tools/r8/ir/code/If.java b/src/main/java/com/android/tools/r8/ir/code/If.java
index 40d3c72..539ecdd 100644
--- a/src/main/java/com/android/tools/r8/ir/code/If.java
+++ b/src/main/java/com/android/tools/r8/ir/code/If.java
@@ -70,12 +70,12 @@
   private Type type;
 
   public If(Type type, Value value) {
-    super(null, value);
+    super(value);
     this.type = type;
   }
 
   public If(Type type, List<Value> values) {
-    super(null, values);
+    super(values);
     this.type = type;
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/Instruction.java b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
index 16f9a11..9c94730 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
@@ -780,6 +780,14 @@
     return null;
   }
 
+  public boolean isSwitch() {
+    return false;
+  }
+
+  public Switch asSwitch() {
+    return null;
+  }
+
   public boolean isIntSwitch() {
     return false;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/IntSwitch.java b/src/main/java/com/android/tools/r8/ir/code/IntSwitch.java
index 8ce8fde..8f1b7f4 100644
--- a/src/main/java/com/android/tools/r8/ir/code/IntSwitch.java
+++ b/src/main/java/com/android/tools/r8/ir/code/IntSwitch.java
@@ -24,17 +24,13 @@
 import java.util.ArrayList;
 import java.util.List;
 
-public class IntSwitch extends JumpInstruction {
+public class IntSwitch extends Switch {
 
   private final int[] keys;
-  private final int[] targetBlockIndices;
-  private int fallthroughBlockIndex;
 
   public IntSwitch(Value value, int[] keys, int[] targetBlockIndices, int fallthroughBlockIndex) {
-    super(null, value);
+    super(value, targetBlockIndices, fallthroughBlockIndex);
     this.keys = keys;
-    this.targetBlockIndices = targetBlockIndices;
-    this.fallthroughBlockIndex = fallthroughBlockIndex;
     assert valid();
   }
 
@@ -49,29 +45,25 @@
     }
   }
 
-  private boolean valid() {
+  @Override
+  public boolean valid() {
+    assert super.valid();
     assert keys.length >= 1;
     assert keys.length <= Constants.U16BIT_MAX;
     // Keys must be acceding, and cannot target the fallthrough.
-    assert keys.length == targetBlockIndices.length;
+    assert keys.length == numberOfKeys();
     for (int i = 1; i < keys.length - 1; i++) {
       assert keys[i - 1] < keys[i];
-      assert targetBlockIndices[i] != fallthroughBlockIndex;
     }
-    assert targetBlockIndices[keys.length - 1] != fallthroughBlockIndex;
     return true;
   }
 
-  public Value value() {
-    return inValues.get(0);
-  }
-
   // Number of targets if this switch is emitted as a packed switch.
-  private static long numberOfTargetsIfPacked(int keys[]) {
+  private static long numberOfTargetsIfPacked(int[] keys) {
     return ((long) keys[keys.length - 1]) - ((long) keys[0]) + 1;
   }
 
-  public static boolean canBePacked(InternalOutputMode mode, int keys[]) {
+  public static boolean canBePacked(InternalOutputMode mode, int[] keys) {
     // The size of a switch payload is stored in an ushort in the Dex file.
     return canBePacked(mode, numberOfTargetsIfPacked(keys));
   }
@@ -135,7 +127,7 @@
   }
 
   // Size of the switch payload if emitted as packed in code units (bytes in CF, 16-bit in Dex).
-  public static long packedPayloadSize(InternalOutputMode mode, int keys[]) {
+  public static long packedPayloadSize(InternalOutputMode mode, int[] keys) {
     assert canBePacked(mode, keys);
     long numberOfTargets = numberOfTargetsIfPacked(keys);
     return packedPayloadSize(mode, numberOfTargets);
@@ -205,27 +197,14 @@
     }
   }
 
-
-  public int numberOfKeys() {
-    return keys.length;
-  }
-
   public int getKey(int index) {
     return keys[index];
   }
 
-  public int getTargetBlockIndex(int index) {
-    return targetBlockIndices[index];
-  }
-
   public int[] getKeys() {
     return keys;
   }
 
-  public int[] targetBlockIndices() {
-    return targetBlockIndices;
-  }
-
   public Int2ReferenceSortedMap<BasicBlock> getKeyToTargetMap() {
     Int2ReferenceSortedMap<BasicBlock> result = new Int2ReferenceAVLTreeMap<>();
     for (int i = 0; i < keys.length; i++) {
@@ -234,28 +213,6 @@
     return result;
   }
 
-  @Override
-  public BasicBlock fallthroughBlock() {
-    return getBlock().getSuccessors().get(fallthroughBlockIndex);
-  }
-
-  public int getFallthroughBlockIndex() {
-    return fallthroughBlockIndex;
-  }
-
-  public void setFallthroughBlockIndex(int i) {
-    fallthroughBlockIndex = i;
-  }
-
-  public BasicBlock targetBlock(int index) {
-    return getBlock().getSuccessors().get(targetBlockIndices()[index]);
-  }
-
-  @Override
-  public void setFallthroughBlock(BasicBlock block) {
-    getBlock().getMutableSuccessors().set(fallthroughBlockIndex, block);
-  }
-
   public Nop buildPayload(int[] targets, int fallthroughTarget, InternalOutputMode mode) {
     assert keys.length == targets.length;
     assert mode.isGeneratingDex();
@@ -299,23 +256,22 @@
 
   @Override
   public String toString() {
-    StringBuilder builder = new StringBuilder(super.toString()+ "\n");
+    StringBuilder builder = new StringBuilder(super.toString()).append(System.lineSeparator());
     for (int i = 0; i < numberOfKeys(); i++) {
-      builder.append("          ");
-      builder.append(getKey(i));
-      builder.append(" -> ");
-      builder.append(targetBlock(i).getNumberAsString());
-      builder.append("\n");
+      builder
+          .append("          ")
+          .append(getKey(i))
+          .append(" -> ")
+          .append(targetBlock(i).getNumberAsString())
+          .append(System.lineSeparator());
     }
-    builder.append("          F -> ");
-    builder.append(fallthroughBlock().getNumber());
-    return builder.toString();
+    return builder.append("          F -> ").append(fallthroughBlock().getNumber()).toString();
   }
 
   @Override
   public void print(CfgPrinter printer) {
     super.print(printer);
-    for (int index : targetBlockIndices) {
+    for (int index : targetBlockIndices()) {
       BasicBlock target = getBlock().getSuccessors().get(index);
       printer.append(" B").append(target.getNumber());
     }
@@ -337,16 +293,16 @@
       int index = 0;
       for (long i = min; i <= max; i++) {
         if (i == keys[index]) {
-          labels.add(builder.getLabel(successors.get(targetBlockIndices[index])));
+          labels.add(builder.getLabel(successors.get(getTargetBlockIndex(index))));
           index++;
         } else {
           labels.add(fallthroughLabel);
         }
       }
-      assert index == targetBlockIndices.length;
-      builder.add(new CfSwitch(Kind.TABLE, fallthroughLabel, new int[] { min }, labels));
+      assert index == numberOfKeys();
+      builder.add(new CfSwitch(Kind.TABLE, fallthroughLabel, new int[] {min}, labels));
     } else {
-      for (int index : targetBlockIndices) {
+      for (int index : targetBlockIndices()) {
         labels.add(builder.getLabel(successors.get(index)));
       }
       builder.add(new CfSwitch(Kind.LOOKUP, fallthroughLabel, this.keys, labels));
diff --git a/src/main/java/com/android/tools/r8/ir/code/JumpInstruction.java b/src/main/java/com/android/tools/r8/ir/code/JumpInstruction.java
index 4fca114..cf049a4 100644
--- a/src/main/java/com/android/tools/r8/ir/code/JumpInstruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/JumpInstruction.java
@@ -11,16 +11,16 @@
 
 public abstract class JumpInstruction extends Instruction {
 
-  public JumpInstruction(Value out) {
+  public JumpInstruction() {
     super(null);
   }
 
-  public JumpInstruction(Value out, Value in) {
-    super(out, in);
+  public JumpInstruction(Value in) {
+    super(null, in);
   }
 
-  public JumpInstruction(Value out, List<? extends Value> ins) {
-    super(out, ins);
+  public JumpInstruction(List<? extends Value> ins) {
+    super(null, ins);
   }
 
   public BasicBlock fallthroughBlock() {
diff --git a/src/main/java/com/android/tools/r8/ir/code/Return.java b/src/main/java/com/android/tools/r8/ir/code/Return.java
index d1073bc..163b27a 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Return.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Return.java
@@ -21,11 +21,11 @@
 public class Return extends JumpInstruction {
 
   public Return() {
-    super(null);
+    super();
   }
 
   public Return(Value value) {
-    super(null, value);
+    super(value);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/StringSwitch.java b/src/main/java/com/android/tools/r8/ir/code/StringSwitch.java
index e481ece..6538363 100644
--- a/src/main/java/com/android/tools/r8/ir/code/StringSwitch.java
+++ b/src/main/java/com/android/tools/r8/ir/code/StringSwitch.java
@@ -14,11 +14,9 @@
 import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 
-public class StringSwitch extends JumpInstruction {
+public class StringSwitch extends Switch {
 
   private final DexString[] keys;
-  private final int[] targetBlockIndices;
-  private final int fallthroughBlockIndex;
 
   // Temporary value that will be given a register that we can use for storing a single-width value.
   private final Value temporaryValue;
@@ -29,10 +27,8 @@
       int[] targetBlockIndices,
       int fallthroughBlockIndex,
       ValueNumberGenerator valueNumberGenerator) {
-    super(null, value);
+    super(value, targetBlockIndices, fallthroughBlockIndex);
     this.keys = keys;
-    this.targetBlockIndices = targetBlockIndices;
-    this.fallthroughBlockIndex = fallthroughBlockIndex;
     this.temporaryValue =
         new TemporaryValue(this, valueNumberGenerator.next(), TypeLatticeElement.INT)
             .setMaxRegister(Constants.U8BIT_MAX);
@@ -60,25 +56,15 @@
     }
   }
 
-  private boolean valid() {
+  @Override
+  public boolean valid() {
+    assert super.valid();
     assert keys.length >= 1;
     assert keys.length <= Constants.U16BIT_MAX;
-    assert keys.length == targetBlockIndices.length;
-    for (int i = 1; i < keys.length - 1; i++) {
-      assert targetBlockIndices[i] != fallthroughBlockIndex;
-    }
-    assert targetBlockIndices[keys.length - 1] != fallthroughBlockIndex;
+    assert keys.length == numberOfKeys();
     return true;
   }
 
-  public int size() {
-    return keys.length;
-  }
-
-  public Value value() {
-    return inValues.get(0);
-  }
-
   @Override
   public boolean isStringSwitch() {
     return true;
@@ -93,24 +79,10 @@
     return keys[index];
   }
 
-  public BasicBlock targetBlock(int index) {
-    return getBlock().getSuccessors().get(targetBlockIndices[index]);
-  }
-
-  @Override
-  public BasicBlock fallthroughBlock() {
-    return getBlock().getSuccessors().get(fallthroughBlockIndex);
-  }
-
-  @Override
-  public void setFallthroughBlock(BasicBlock block) {
-    getBlock().getMutableSuccessors().set(fallthroughBlockIndex, block);
-  }
-
   @Override
   public String toString() {
     StringBuilder builder = new StringBuilder(super.toString()).append(System.lineSeparator());
-    for (int i = 0; i < size(); i++) {
+    for (int i = 0; i < numberOfKeys(); i++) {
       builder
           .append("          \"")
           .append(getKey(i))
diff --git a/src/main/java/com/android/tools/r8/ir/code/Switch.java b/src/main/java/com/android/tools/r8/ir/code/Switch.java
new file mode 100644
index 0000000..8dcb6a4
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/code/Switch.java
@@ -0,0 +1,80 @@
+// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.code;
+
+import java.util.function.Consumer;
+
+public abstract class Switch extends JumpInstruction {
+
+  private final int[] targetBlockIndices;
+  private int fallthroughBlockIndex;
+
+  public Switch(Value in, int[] targetBlockIndices, int fallthroughBlockIndex) {
+    super(in);
+    this.targetBlockIndices = targetBlockIndices;
+    this.fallthroughBlockIndex = fallthroughBlockIndex;
+  }
+
+  public Value value() {
+    return inValues.get(0);
+  }
+
+  public boolean valid() {
+    for (int i = 0; i < numberOfKeys(); i++) {
+      assert getTargetBlockIndex(i) != getFallthroughBlockIndex();
+    }
+    return true;
+  }
+
+  public BasicBlock targetBlock(int index) {
+    return getBlock().getSuccessors().get(targetBlockIndices()[index]);
+  }
+
+  public int getTargetBlockIndex(int index) {
+    return targetBlockIndices[index];
+  }
+
+  public int[] targetBlockIndices() {
+    return targetBlockIndices;
+  }
+
+  public void forEachTarget(Consumer<BasicBlock> fn) {
+    for (int i = 0; i < targetBlockIndices.length; i++) {
+      fn.accept(targetBlock(i));
+    }
+  }
+
+  @Override
+  public BasicBlock fallthroughBlock() {
+    return getBlock().getSuccessors().get(fallthroughBlockIndex);
+  }
+
+  public int getFallthroughBlockIndex() {
+    return fallthroughBlockIndex;
+  }
+
+  public void setFallthroughBlockIndex(int i) {
+    fallthroughBlockIndex = i;
+  }
+
+  @Override
+  public void setFallthroughBlock(BasicBlock block) {
+    getBlock().getMutableSuccessors().set(fallthroughBlockIndex, block);
+  }
+
+  public int numberOfKeys() {
+    return targetBlockIndices.length;
+  }
+
+  @Override
+  public boolean isSwitch() {
+    return true;
+  }
+
+  @Override
+  public Switch asSwitch() {
+    return this;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Throw.java b/src/main/java/com/android/tools/r8/ir/code/Throw.java
index 6c91191..7d2a9d5 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Throw.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Throw.java
@@ -17,7 +17,7 @@
 public class Throw extends JumpInstruction {
 
   public Throw(Value exception) {
-    super(null, exception);
+    super(exception);
   }
 
   @Override