Introduce LIR after open/closed interfaces analysis

Change-Id: I0920048e14bfe1eaa45ba7063781533fdd073c53
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 797a842..81b1687 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -467,6 +467,9 @@
 
       new CfOpenClosedInterfacesAnalysis(appViewWithLiveness).run(executorService);
 
+      // TODO(b/225838009): Move higher up.
+      LirConverter.enterLirSupportedPhase(appView, executorService);
+
       assert verifyNoJarApplicationReaders(appView.appInfo().classes());
       assert appView.checkForTesting(() -> allReferencesAssignedApiLevel(appViewWithLiveness));
       // Build conservative main dex content after first round of tree shaking. This is used
@@ -497,9 +500,6 @@
           .setMustRetargetInvokesToTargetMethod()
           .run(executorService, timing);
 
-      // TODO(b/225838009): Move higher up.
-      LirConverter.enterLirSupportedPhase(appView, executorService);
-
       BridgeHoistingToSharedSyntheticSuperClass.run(appViewWithLiveness, executorService, timing);
 
       assert ArtProfileCompletenessChecker.verify(appView);
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 7c95315..1b9a92e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -1238,15 +1238,13 @@
     return new ProgramMethod(holder, newMethod);
   }
 
-  public DexEncodedMethod toForwardingMethod(DexClass newHolder, AppView<?> definitions) {
-    return toForwardingMethod(newHolder, definitions, ConsumerUtils.emptyConsumer());
+  public DexEncodedMethod toForwardingMethod(DexClass newHolder, AppView<?> appView) {
+    return toForwardingMethod(newHolder, appView, ConsumerUtils.emptyConsumer());
   }
 
   public DexEncodedMethod toForwardingMethod(
-      DexClass newHolder,
-      AppView<?> definitions,
-      Consumer<DexEncodedMethod.Builder> builderConsumer) {
-    DexMethod newMethod = getReference().withHolder(newHolder, definitions.dexItemFactory());
+      DexClass newHolder, AppView<?> appView, Consumer<DexEncodedMethod.Builder> builderConsumer) {
+    DexMethod newMethod = getReference().withHolder(newHolder, appView.dexItemFactory());
     checkIfObsolete();
 
     // Clear the final flag, as this method is now overwritten. Do this before creating the builder
@@ -1267,8 +1265,7 @@
             builder ->
                 builder
                     .setCode(
-                        ForwardMethodBuilder.builder(definitions.dexItemFactory())
-                            .setStaticSource(newMethod)
+                        ForwardMethodBuilder.builder(appView.dexItemFactory())
                             .applyIf(
                                 isStatic(),
                                 codeBuilder ->
@@ -1276,18 +1273,14 @@
                                         .setStaticSource(newMethod)
                                         .setStaticTarget(
                                             getReference(),
-                                            getReference()
-                                                .getHolderType()
-                                                .isInterface(definitions)),
+                                            getReference().getHolderType().isInterface(appView)),
                                 codeBuilder ->
                                     codeBuilder
                                         .setNonStaticSource(newMethod)
                                         .setSuperTarget(
                                             getReference(),
-                                            getReference()
-                                                .getHolderType()
-                                                .isInterface(definitions)))
-                            .build())
+                                            getReference().getHolderType().isInterface(appView)))
+                            .build(appView))
                     .modifyAccessFlags(MethodAccessFlags::setBridge))
         .setIsLibraryMethodOverrideIf(
             !isStatic() && !isLibraryMethodOverride().isUnknown(), isLibraryMethodOverride())
@@ -1316,7 +1309,7 @@
             ForwardMethodBuilder.builder(factory)
                 .setNonStaticSource(newMethod)
                 .setStaticTarget(forwardMethod, isInterfaceMethodReference)
-                .build())
+                .buildCf())
         .setApiLevelForDefinition(target.getDefinition().getApiLevelForDefinition())
         .setApiLevelForCode(target.getDefinition().getApiLevelForCode())
         .build();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/AccessorMethodSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/AccessorMethodSourceCode.java
index 67ec80a..81607e3 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/AccessorMethodSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/AccessorMethodSourceCode.java
@@ -47,6 +47,6 @@
       default:
         throw new Unreachable();
     }
-    return forwardMethodBuilder.build();
+    return forwardMethodBuilder.buildCf();
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CovariantReturnTypeAnnotationTransformer.java b/src/main/java/com/android/tools/r8/ir/desugar/CovariantReturnTypeAnnotationTransformer.java
index aa69f8f..f84950a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CovariantReturnTypeAnnotationTransformer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CovariantReturnTypeAnnotationTransformer.java
@@ -192,7 +192,7 @@
                     .keepIf(x -> !isCovariantReturnTypeAnnotation(x.annotation)))
             .setParameterAnnotations(
                 methodDefinition.parameterAnnotationsList.keepIf(Predicates.alwaysTrue()))
-            .setCode(forwardMethodBuilder.build())
+            .setCode(forwardMethodBuilder.buildCf())
             .setApiLevelForDefinition(methodDefinition.getApiLevelForDefinition())
             .setApiLevelForCode(methodDefinition.getApiLevelForCode())
             .build();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaBridgeMethodSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaBridgeMethodSourceCode.java
index ddcdc6e..6ff9258 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaBridgeMethodSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaBridgeMethodSourceCode.java
@@ -19,6 +19,6 @@
         .setVirtualTarget(mainMethod, false)
         .setCastArguments(lambdaClass.appView.appInfoForDesugaring())
         .setCastResult()
-        .build();
+        .buildCf();
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java
index bc82617..29259c9 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java
@@ -272,12 +272,12 @@
                 return ForwardMethodBuilder.builder(factory)
                     .setVirtualTarget(method, libraryHolder.isInterface())
                     .setNonStaticSource(method)
-                    .build();
+                    .buildCf();
               } else {
                 return ForwardMethodBuilder.builder(factory)
                     .setStaticTarget(method, libraryHolder.isInterface())
                     .setStaticSource(method)
-                    .build();
+                    .buildCf();
               }
             });
   }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterSyntheticHelper.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterSyntheticHelper.java
index 99b56db..04db936 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterSyntheticHelper.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterSyntheticHelper.java
@@ -56,7 +56,7 @@
                                     .setVirtualTarget(retarget, false)
                                     .setNonStaticSource(target)
                                     .setCastResult()
-                                    .build()));
+                                    .buildCf()));
     eventConsumer.acceptCovariantRetargetMethod(method, methodProcessingContext.getMethodContext());
     return method.getReference();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/invokespecial/InvokeSpecialToSelfDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/invokespecial/InvokeSpecialToSelfDesugaring.java
index 56c3342..b290ad9 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/invokespecial/InvokeSpecialToSelfDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/invokespecial/InvokeSpecialToSelfDesugaring.java
@@ -117,7 +117,7 @@
             ForwardMethodBuilder.builder(dexItemFactory)
                 .setDirectTarget(bridgeReference, clazz.isInterface())
                 .setNonStaticSource(method.getReference())
-                .build();
+                .buildCf();
 
         // Add the newly created direct method to its holder.
         clazz.addDirectMethod(newDirectMethod.getDefinition());
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
index 2ff0fe6..dd600b3 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
@@ -456,7 +456,7 @@
                                             ForwardMethodBuilder.builder(factory)
                                                 .setStaticTarget(invoke.getMethod(), true)
                                                 .setStaticSource(m)
-                                                .build()));
+                                                .buildCf()));
                 synthesizedMethods.add(newProgramMethod);
                 eventConsumer.acceptInvokeStaticInterfaceOutliningMethod(
                     newProgramMethod, context1);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/nest/AccessBridgeFactory.java b/src/main/java/com/android/tools/r8/ir/desugar/nest/AccessBridgeFactory.java
index 0b7fc43..95604c7 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/nest/AccessBridgeFactory.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/nest/AccessBridgeFactory.java
@@ -59,7 +59,7 @@
                 ForwardMethodBuilder.builder(dexItemFactory)
                     .setNonStaticSourceWithExtraUnusedParameter(bridgeMethodReference)
                     .setConstructorTarget(method.getReference())
-                    .build())
+                    .buildCf())
             .setMethod(bridgeMethodReference)
             .setApiLevelForDefinition(method.getDefinition().getApiLevelForDefinition())
             .setApiLevelForCode(method.getDefinition().getApiLevelForCode())
@@ -90,7 +90,7 @@
                         method.getAccessFlags().isStatic(),
                         builder -> builder.setStaticTarget(method.getReference(), isInterface),
                         builder -> builder.setDirectTarget(method.getReference(), isInterface))
-                    .build())
+                    .buildCf())
             .setMethod(bridgeMethodReference)
             .setApiLevelForDefinition(method.getDefinition().getApiLevelForDefinition())
             .setApiLevelForCode(method.getDefinition().getApiLevelForDefinition())
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/api/InstanceInitializerOutliner.java b/src/main/java/com/android/tools/r8/ir/optimize/api/InstanceInitializerOutliner.java
index a9dfc03..a8abce9 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/api/InstanceInitializerOutliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/api/InstanceInitializerOutliner.java
@@ -272,7 +272,7 @@
                               ForwardMethodBuilder.builder(appView.dexItemFactory())
                                   .setConstructorTargetWithNewInstance(targetMethod)
                                   .setStaticSource(m)
-                                  .build())
+                                  .buildCf())
                       .setOptimizationInfo(
                           DefaultMethodOptimizationInfo.getInstance()
                               .toMutableOptimizationInfo()
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodBuilder.java b/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodBuilder.java
index 0718a90..b8c5959 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodBuilder.java
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.synthetic;
 
+import static com.android.tools.r8.ir.analysis.type.Nullability.definitelyNotNull;
+import static com.android.tools.r8.ir.analysis.type.Nullability.maybeNull;
 import static com.android.tools.r8.utils.ConsumerUtils.emptyConsumer;
 
 import com.android.tools.r8.cf.code.CfCheckCast;
@@ -14,18 +16,28 @@
 import com.android.tools.r8.cf.code.CfReturnVoid;
 import com.android.tools.r8.cf.code.CfStackInstruction;
 import com.android.tools.r8.cf.code.CfStackInstruction.Opcode;
+import com.android.tools.r8.errors.Unimplemented;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.CfCodeWithLens;
+import com.android.tools.r8.graph.Code;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.ir.code.ValueType;
+import com.android.tools.r8.lightir.LirBuilder;
+import com.android.tools.r8.lightir.LirCode;
+import com.android.tools.r8.lightir.LirEncodingStrategy;
+import com.android.tools.r8.lightir.LirStrategy;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableList.Builder;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.function.Consumer;
 import org.objectweb.asm.Opcodes;
 
@@ -159,12 +171,15 @@
     return this;
   }
 
-  @SuppressWarnings({"BadImport", "ReferenceEquality"})
-  public CfCode build() {
+  public Code build(AppView<?> appView) {
+    return appView.testing().isSupportedLirPhase() ? buildLir(appView) : buildCf();
+  }
+
+  public CfCode buildCf() {
     assert validate();
     int maxStack = 0;
     int maxLocals = 0;
-    Builder<CfInstruction> instructions = ImmutableList.builder();
+    ImmutableList.Builder<CfInstruction> instructions = ImmutableList.builder();
     if (isConstructorDelegate) {
       // A constructor delegate allocates a new instance of the type.
       // It is dup'ed on the stack so it is ready to return after the invoke call.
@@ -205,9 +220,10 @@
       assert !isConstructorDelegate;
       instructions.add(new CfReturnVoid());
     } else {
-      if (!isConstructorDelegate && sourceMethod.getReturnType() != targetMethod.getReturnType()) {
+      if (!isConstructorDelegate
+          && sourceMethod.getReturnType().isNotIdenticalTo(targetMethod.getReturnType())) {
         assert castResult;
-        if (sourceMethod.getReturnType() != factory.objectType) {
+        if (sourceMethod.getReturnType().isNotIdenticalTo(factory.objectType)) {
           instructions.add(new CfCheckCast(sourceMethod.getReturnType()));
         }
       }
@@ -220,9 +236,66 @@
     return new CfCode(sourceMethod.holder, maxStack, maxLocals, instructions.build());
   }
 
-  @SuppressWarnings({"BadImport", "ReferenceEquality"})
+  public LirCode<Integer> buildLir(AppView<?> appView) {
+    assert validate();
+    if (castResult
+        || isConstructorDelegate
+        || sourceMethodHasExtraUnusedParameter
+        || appInfoForCastArguments != null
+        || codeLens != null) {
+      throw new Unimplemented();
+    }
+    if (invokeType != InvokeType.STATIC && invokeType != InvokeType.SPECIAL) {
+      throw new Unimplemented();
+    }
+    if (invokeType == InvokeType.SPECIAL
+        && sourceMethod.getHolderType().isIdenticalTo(targetMethod.getHolderType())) {
+      throw new Unimplemented();
+    }
+
+    boolean isD8R8Synthesized = true;
+    LirEncodingStrategy<Value, Integer> strategy =
+        LirStrategy.getDefaultStrategy().getEncodingStrategy();
+    LirBuilder<Value, Integer> lirBuilder =
+        LirCode.builder(sourceMethod, isD8R8Synthesized, strategy, appView.options());
+
+    // Add all arguments.
+    List<Value> argumentValues = new ArrayList<>();
+    int instructionIndex = 0;
+    for (; instructionIndex < sourceMethod.getNumberOfArguments(staticSource); instructionIndex++) {
+      DexType argumentType = sourceMethod.getArgumentType(instructionIndex, staticSource);
+      TypeElement argumentTypeElement =
+          argumentType.toTypeElement(
+              appView, instructionIndex == 0 && !staticSource ? definitelyNotNull() : maybeNull());
+      Value argumentValue = Value.createNoDebugLocal(instructionIndex, argumentTypeElement);
+      argumentValues.add(argumentValue);
+      strategy.defineValue(argumentValue, argumentValue.getNumber());
+      lirBuilder.addArgument(instructionIndex, argumentType.isBooleanType());
+    }
+
+    if (isStaticTarget()) {
+      lirBuilder.addInvokeStatic(targetMethod, argumentValues, isInterface);
+    } else {
+      lirBuilder.addInvokeSuper(targetMethod, argumentValues, isInterface);
+    }
+
+    if (sourceMethod.getReturnType().isVoidType()) {
+      lirBuilder.addReturnVoid();
+    } else {
+      Value returnValue =
+          Value.createNoDebugLocal(
+              instructionIndex, sourceMethod.getReturnType().toTypeElement(appView));
+      strategy.defineValue(returnValue, returnValue.getNumber());
+      lirBuilder.addReturn(returnValue);
+    }
+
+    return lirBuilder.build();
+  }
+
   private void maybeInsertArgumentCast(
-      int argumentIndex, DexType sourceArgumentType, Builder<CfInstruction> instructions) {
+      int argumentIndex,
+      DexType sourceArgumentType,
+      ImmutableList.Builder<CfInstruction> instructions) {
     if (appInfoForCastArguments == null) {
       return;
     }
@@ -235,8 +308,9 @@
         argumentIndex == -1
             ? targetMethod.holder
             : targetMethod.getParameters().values[argumentIndex];
-    if (sourceArgumentType != targetArgumentType
-        && targetArgumentType != appInfoForCastArguments.dexItemFactory().objectType) {
+    if (sourceArgumentType.isNotIdenticalTo(targetArgumentType)
+        && targetArgumentType.isNotIdenticalTo(
+            appInfoForCastArguments.dexItemFactory().objectType)) {
       assert appInfoForCastArguments.isSubtype(targetArgumentType, sourceArgumentType);
       instructions.add(new CfCheckCast(targetArgumentType));
     }
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
index c177e50..f56f8bc 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
@@ -501,6 +501,7 @@
     MemberRebindingLens memberRebindingLens = lensBuilder.build();
     appView.setGraphLens(memberRebindingLens);
     eventConsumer.finished(appView, memberRebindingLens);
+    appView.dexItemFactory().clearTypeElementsCache();
     appView.notifyOptimizationFinishedForTesting();
   }
 }