Preserve itf bit in outliner

Change-Id: I7cc094a799d0da9abf409ff4a14f54db67a0b5bf
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlinerImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlinerImpl.java
index ee3fc44..6c0e779 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlinerImpl.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlinerImpl.java
@@ -115,7 +115,7 @@
  *       {@link OutlineOptions#threshold}). Each selected method is then converted back to IR and
  *       passed to {@link OutlinerImpl#identifyOutlineSites(IRCode)}, which then stores concrete
  *       outlining candidates in {@link OutlinerImpl#outlineSites}.
- *   <li>Third, {@link OutlinerImpl#buildOutlineMethods()} is called to construct the <em>outline
+ *   <li>Third, {@link OutlinerImpl#buildOutlineMethods} is called to construct the <em>outline
  *       support classes</em> containing a static helper method for each outline candidate that
  *       occurs frequently enough. Each selected method is then converted to IR, passed to {@link
  *       OutlinerImpl#applyOutliningCandidate(IRCode)} to perform the outlining, and converted back
@@ -133,7 +133,7 @@
   /** Result of second step (see {@link OutlinerImpl#selectMethodsForOutlining()}. */
   private final Map<Outline, List<ProgramMethod>> outlineSites = new HashMap<>();
 
-  /** Result of third step (see {@link OutlinerImpl#buildOutlineMethods()}. */
+  /** Result of third step (see {@link OutlinerImpl#buildOutlineMethods}. */
   private final Map<Outline, DexMethod> generatedOutlines = new HashMap<>();
 
   static final int MAX_IN_SIZE = 5; // Avoid using ranged calls for outlined code.
@@ -142,7 +142,7 @@
   private final DexItemFactory dexItemFactory;
   private final InliningConstraints inliningConstraints;
 
-  private abstract static class OutlineInstruction {
+  private abstract static class OutlineInstruction implements Comparable<OutlineInstruction> {
 
     // Value signaling that this is the one allowed temporary register for an outline.
     private static final int OUTLINE_TEMP = -1;
@@ -182,12 +182,6 @@
       }
     }
 
-    protected final OutlineInstructionType type;
-
-    protected OutlineInstruction(OutlineInstructionType type) {
-      this.type = type;
-    }
-
     static OutlineInstruction fromInstruction(Instruction instruction) {
       if (instruction.isBinop()) {
         return BinOpOutlineInstruction.fromInstruction(instruction.asBinop());
@@ -200,14 +194,7 @@
     }
 
     @Override
-    public int hashCode() {
-      return type.ordinal();
-    }
-
-    @SuppressWarnings("MissingImplementsComparable")
-    public int compareTo(OutlineInstruction other) {
-      return type.compareTo(other.type);
-    }
+    public abstract int hashCode();
 
     @Override
     public abstract boolean equals(Object other);
@@ -216,6 +203,8 @@
 
     public abstract String getInstructionName();
 
+    public abstract OutlineInstructionType getOutlineInstructionType();
+
     public abstract boolean hasOutValue();
 
     public abstract int numberOfInputs();
@@ -227,10 +216,11 @@
 
   private static class BinOpOutlineInstruction extends OutlineInstruction {
 
+    private final OutlineInstructionType type;
     private final NumericType numericType;
 
     private BinOpOutlineInstruction(OutlineInstructionType type, NumericType numericType) {
-      super(type);
+      this.type = type;
       this.numericType = numericType;
     }
 
@@ -241,22 +231,25 @@
 
     @Override
     public int hashCode() {
-      return super.hashCode() * 7 + numericType.ordinal();
+      return Objects.hash(type, numericType);
     }
 
     @Override
     public boolean equals(Object other) {
+      if (this == other) {
+        return true;
+      }
       if (!(other instanceof BinOpOutlineInstruction)) {
         return false;
       }
       BinOpOutlineInstruction o = (BinOpOutlineInstruction) other;
-      return o.type.equals(type) && o.numericType.equals(numericType);
+      return type.equals(o.type) && numericType.equals(o.numericType);
     }
 
     @Override
     public int compareTo(OutlineInstruction other) {
       if (!(other instanceof BinOpOutlineInstruction)) {
-        return super.compareTo(other);
+        return type.compareTo(other.getOutlineInstructionType());
       }
       BinOpOutlineInstruction o = (BinOpOutlineInstruction) other;
       int result = type.compareTo(o.type);
@@ -277,6 +270,11 @@
     }
 
     @Override
+    public OutlineInstructionType getOutlineInstructionType() {
+      return type;
+    }
+
+    @Override
     public boolean hasOutValue() {
       return true;
     }
@@ -336,30 +334,30 @@
     private final DexType clazz;
 
     NewInstanceOutlineInstruction(DexType clazz) {
-      super(OutlineInstructionType.NEW);
       this.clazz = clazz;
     }
 
     @Override
-    @SuppressWarnings("ReferenceEquality")
     public boolean equals(Object other) {
+      if (this == other) {
+        return true;
+      }
       if (!(other instanceof NewInstanceOutlineInstruction)) {
         return false;
       }
       NewInstanceOutlineInstruction o = (NewInstanceOutlineInstruction) other;
-      boolean result = clazz == o.clazz;
-      return result;
+      return clazz.isIdenticalTo(o.clazz);
     }
 
     @Override
     public int hashCode() {
-      return super.hashCode() * 7 + clazz.hashCode();
+      return Objects.hash(getOutlineInstructionType(), clazz.hashCode());
     }
 
     @Override
     public int compareTo(OutlineInstruction other) {
       if (!(other instanceof NewInstanceOutlineInstruction)) {
-        return super.compareTo(other);
+        return getOutlineInstructionType().compareTo(other.getOutlineInstructionType());
       }
       NewInstanceOutlineInstruction o = (NewInstanceOutlineInstruction) other;
       return clazz.compareTo(o.clazz);
@@ -372,7 +370,12 @@
 
     @Override
     public String getInstructionName() {
-      return type.name();
+      return getOutlineInstructionType().name();
+    }
+
+    @Override
+    public OutlineInstructionType getOutlineInstructionType() {
+      return OutlineInstructionType.NEW;
     }
 
     @Override
@@ -397,9 +400,8 @@
     }
 
     @Override
-    @SuppressWarnings("ReferenceEquality")
     public boolean needsLensRewriting(GraphLens currentGraphLens) {
-      return currentGraphLens.lookupType(clazz) != clazz;
+      return !currentGraphLens.lookupType(clazz).isIdenticalTo(clazz);
     }
   }
 
@@ -409,20 +411,22 @@
     private final boolean hasOutValue;
     private final DexProto proto;
     private final boolean hasReceiver;
+    private final boolean itf;
 
     private InvokeOutlineInstruction(
         DexMethod method,
         InvokeType type,
         boolean hasOutValue,
         ValueType[] inputTypes,
-        DexProto proto) {
-      super(OutlineInstructionType.INVOKE);
+        DexProto proto,
+        boolean itf) {
       hasReceiver = inputTypes.length != method.proto.parameters.values.length;
       assert !hasReceiver || inputTypes[0].isObject();
       this.method = method;
       this.invokeType = type;
       this.hasOutValue = hasOutValue;
       this.proto = proto;
+      this.itf = itf;
     }
 
     static InvokeOutlineInstruction fromInstruction(InvokeMethod invoke) {
@@ -436,35 +440,35 @@
           invoke.getType(),
           invoke.outValue() != null,
           inputTypes,
-          invoke.isInvokePolymorphic() ? invoke.asInvokePolymorphic().getProto() : null);
+          invoke.isInvokePolymorphic() ? invoke.asInvokePolymorphic().getProto() : null,
+          invoke.getInterfaceBit());
     }
 
     @Override
     public int hashCode() {
-      return super.hashCode() * 7
-          + method.hashCode() * 13
-          + invokeType.hashCode()
-          + Boolean.hashCode(hasOutValue)
-          + Objects.hashCode(proto);
+      return Objects.hash(getOutlineInstructionType(), method, invokeType, hasOutValue, proto, itf);
     }
 
     @Override
-    @SuppressWarnings("ReferenceEquality")
     public boolean equals(Object other) {
+      if (this == other) {
+        return true;
+      }
       if (!(other instanceof InvokeOutlineInstruction)) {
         return false;
       }
       InvokeOutlineInstruction o = (InvokeOutlineInstruction) other;
-      return method == o.method
+      return method.isIdenticalTo(o.method)
           && invokeType == o.invokeType
           && hasOutValue == o.hasOutValue
-          && Objects.equals(proto, o.proto);
+          && DexProto.identical(proto, o.proto)
+          && itf == o.itf;
     }
 
     @Override
     public int compareTo(OutlineInstruction other) {
       if (!(other instanceof InvokeOutlineInstruction)) {
-        return super.compareTo(other);
+        return getOutlineInstructionType().compareTo(other.getOutlineInstructionType());
       }
       InvokeOutlineInstruction o = (InvokeOutlineInstruction) other;
       int result = method.compareTo(o.method);
@@ -485,7 +489,11 @@
           return result;
         }
       }
-      assert this.equals(other);
+      result = Boolean.compare(itf, o.itf);
+      if (result != 0) {
+        return result;
+      }
+      assert equals(other);
       return 0;
     }
 
@@ -496,7 +504,12 @@
 
     @Override
     public String getInstructionName() {
-      return type.name() + "-" + invokeType.name();
+      return getOutlineInstructionType().name() + "-" + invokeType.name();
+    }
+
+    @Override
+    public OutlineInstructionType getOutlineInstructionType() {
+      return OutlineInstructionType.INVOKE;
     }
 
     @Override
@@ -536,15 +549,15 @@
             builder.writeRegister(outline.argumentCount(), latticeElement, ThrowingInfo.CAN_THROW);
       }
 
-      Instruction newInstruction = Invoke.create(invokeType, method, proto, outValue, inValues);
+      Instruction newInstruction =
+          Invoke.create(invokeType, method, proto, outValue, inValues, itf);
       builder.add(newInstruction);
       return argumentMapIndex;
     }
 
     @Override
-    @SuppressWarnings("ReferenceEquality")
     public boolean needsLensRewriting(GraphLens currentGraphLens) {
-      return currentGraphLens.getRenamedMethodSignature(method) != method;
+      return !currentGraphLens.getRenamedMethodSignature(method).isIdenticalTo(method);
     }
   }