Rewrite lir with lens before first round of vertical class merging

Change-Id: I3504b9d392787c2290ace7c86a94110c21597e48
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 0559d8f..7cabfb6 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -502,6 +502,9 @@
 
       assert ArtProfileCompletenessChecker.verify(appView);
 
+      LirConverter.rewriteLirWithLens(appView, timing, executorService);
+      appView.clearCodeRewritings(executorService, timing);
+
       VerticalClassMerger.createForInitialClassMerging(appViewWithLiveness, timing)
           .runIfNecessary(executorService, timing);
 
diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java
index f597df0..108877b 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -394,6 +394,12 @@
     return definitionSupplier.definitionFor(this).isInterface();
   }
 
+  public boolean isInterfaceOrDefault(
+      DexDefinitionSupplier definitionSupplier, boolean defaultValue) {
+    DexClass clazz = definitionSupplier.definitionFor(this);
+    return clazz != null ? clazz.isInterface() : defaultValue;
+  }
+
   public DexProgramClass asProgramClass(DexDefinitionSupplier definitions) {
     return asProgramClassOrNull(definitions.definitionFor(this));
   }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LirConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/LirConverter.java
index 25df747..8810391 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LirConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LirConverter.java
@@ -84,7 +84,9 @@
 
     GraphLens graphLens = appView.graphLens();
     assert graphLens.isNonIdentityLens();
-    assert appView.codeLens().isAppliedLens() || appView.codeLens().isClearCodeRewritingLens();
+    assert appView.codeLens().isAppliedLens()
+        || appView.codeLens().isClearCodeRewritingLens()
+        || appView.codeLens().isIdentityLens();
 
     MemberRebindingIdentityLens memberRebindingIdentityLens =
         graphLens.asNonIdentityLens().find(GraphLens::isMemberRebindingIdentityLens);
diff --git a/src/main/java/com/android/tools/r8/lightir/LirLensCodeRewriter.java b/src/main/java/com/android/tools/r8/lightir/LirLensCodeRewriter.java
index de48365..b5ab4d1 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirLensCodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirLensCodeRewriter.java
@@ -10,7 +10,6 @@
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexCallSite;
-import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexMethodHandle;
@@ -34,7 +33,6 @@
 import com.android.tools.r8.ir.optimize.AffectedValues;
 import com.android.tools.r8.ir.optimize.DeadCodeRemover;
 import com.android.tools.r8.lightir.LirBuilder.NameComputationPayload;
-import com.android.tools.r8.lightir.LirBuilder.RecordFieldValuesPayload;
 import com.android.tools.r8.lightir.LirCode.TryCatchTable;
 import com.android.tools.r8.naming.dexitembasedstring.NameComputationInfo;
 import com.android.tools.r8.utils.ArrayUtils;
@@ -125,9 +123,10 @@
     assert newMethod.getArity() == method.getArity();
     if (newOpcode != opcode) {
       assert type == newType
-              || (type.isVirtual() && newType.isInterface())
+              || (type.isDirect() && (newType.isInterface() || newType.isVirtual()))
               || (type.isInterface() && newType.isVirtual())
               || (type.isSuper() && newType.isVirtual())
+              || (type.isVirtual() && newType.isInterface())
           : type + " -> " + newType;
       numberOfInvokeOpcodeChanges++;
     } else {
@@ -273,6 +272,9 @@
   }
 
   private InvokeType getInvokeTypeThatMayChange(int opcode) {
+    if (codeLens.isIdentityLens() && LirOpcodeUtils.isInvokeMethod(opcode)) {
+      return LirOpcodeUtils.getInvokeType(opcode);
+    }
     if (opcode == LirOpcodes.INVOKEVIRTUAL) {
       return InvokeType.VIRTUAL;
     }
@@ -400,8 +402,6 @@
     boolean hasFieldReference = false;
     boolean hasPotentialRewrittenMethod = false;
     for (LirConstant constant : code.getConstantPool()) {
-      // RecordFieldValuesPayload is lowered to NewArrayEmpty before lens code rewriting any LIR.
-      assert !(constant instanceof RecordFieldValuesPayload);
       if (constant instanceof DexType) {
         onTypeReference((DexType) constant);
       } else if (constant instanceof DexField) {
@@ -521,15 +521,18 @@
 
   // TODO(b/157111832): This should be part of the graph lens lookup result.
   private boolean lookupIsInterface(DexMethod method, int opcode, MethodLookupResult result) {
+    boolean wasInterface = LirOpcodeUtils.getInterfaceBitFromInvokeOpcode(opcode);
+    // Update interface bit after member rebinding.
+    if (codeLens.isIdentityLens() && method.isNotIdenticalTo(result.getReference())) {
+      return result.getReference().getHolderType().isInterfaceOrDefault(appView, wasInterface);
+    }
+    // Update interface bit after vertical class merging.
     VerticalClassMergerGraphLens verticalClassMergerLens = graphLens.asVerticalClassMergerLens();
     if (verticalClassMergerLens != null
         && verticalClassMergerLens.hasInterfaceBeenMergedIntoClass(method.getHolderType())) {
-      DexClass clazz = appView.definitionFor(result.getReference().getHolderType());
-      if (clazz != null) {
-        return clazz.isInterface();
-      }
+      return result.getReference().getHolderType().isInterfaceOrDefault(appView, wasInterface);
     }
-    return LirOpcodeUtils.getInterfaceBitFromInvokeOpcode(opcode);
+    return wasInterface;
   }
 
   private LirCode<EV> rewriteTryCatchTable(LirCode<EV> code) {
diff --git a/src/main/java/com/android/tools/r8/lightir/LirOpcodeUtils.java b/src/main/java/com/android/tools/r8/lightir/LirOpcodeUtils.java
index ec71974..7b110eb 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirOpcodeUtils.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirOpcodeUtils.java
@@ -12,6 +12,9 @@
 import static com.android.tools.r8.lightir.LirOpcodes.INVOKESUPER_ITF;
 import static com.android.tools.r8.lightir.LirOpcodes.INVOKEVIRTUAL;
 
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.ir.code.InvokeType;
+
 public class LirOpcodeUtils {
 
   public static boolean getInterfaceBitFromInvokeOpcode(int opcode) {
@@ -30,6 +33,27 @@
     }
   }
 
+  public static InvokeType getInvokeType(int opcode) {
+    assert isInvokeMethod(opcode);
+    switch (opcode) {
+      case INVOKEDIRECT:
+      case INVOKEDIRECT_ITF:
+        return InvokeType.DIRECT;
+      case INVOKEINTERFACE:
+        return InvokeType.INTERFACE;
+      case INVOKESTATIC:
+      case INVOKESTATIC_ITF:
+        return InvokeType.STATIC;
+      case INVOKESUPER:
+      case INVOKESUPER_ITF:
+        return InvokeType.SUPER;
+      case INVOKEVIRTUAL:
+        return InvokeType.VIRTUAL;
+      default:
+        throw new Unreachable();
+    }
+  }
+
   public static boolean isInvokeMethod(int opcode) {
     switch (opcode) {
       case INVOKEDIRECT: