Remove special handling for desugared lambdas in class inliner

Change-Id: I614f37598a38c8bf9456016fd4ce70e39851a180
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index b8ce45a..35f7041 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -274,9 +274,7 @@
       assert appView.rootSet() != null;
       AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
       this.classInliner =
-          options.enableClassInlining && options.enableInlining
-              ? new ClassInliner(lambdaRewriter)
-              : null;
+          options.enableClassInlining && options.enableInlining ? new ClassInliner() : null;
       this.classStaticizer =
           options.enableClassStaticizer ? new ClassStaticizer(appViewWithLiveness, this) : null;
       this.dynamicTypeOptimization =
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
index 36fd691..216a9d7 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
@@ -262,15 +262,6 @@
     return false;
   }
 
-  /**
-   * Returns a synthetic class for desugared lambda or `null` if the `type` does not represent one.
-   * Method can be called concurrently.
-   */
-  public DexProgramClass getLambdaClass(DexType type) {
-    LambdaClass lambdaClass = getKnown(knownLambdaClasses, type);
-    return lambdaClass == null ? null : lambdaClass.getOrCreateLambdaClass();
-  }
-
   /** Generates lambda classes and adds them to the builder. */
   public void finalizeLambdaDesugaringForD8(Builder<?> builder, ExecutorService executorService)
       throws ExecutionException {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
index 36fd914..538cba6 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
@@ -13,7 +13,6 @@
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionOrPhi;
 import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.ir.desugar.LambdaRewriter;
 import com.android.tools.r8.ir.optimize.CodeRewriter;
 import com.android.tools.r8.ir.optimize.Inliner;
 import com.android.tools.r8.ir.optimize.InliningOracle;
@@ -60,14 +59,9 @@
     ELIGIBLE
   }
 
-  private final LambdaRewriter lambdaRewriter;
   private final ConcurrentHashMap<DexClass, EligibilityStatus> knownClasses =
       new ConcurrentHashMap<>();
 
-  public ClassInliner(LambdaRewriter lambdaRewriter) {
-    this.lambdaRewriter = lambdaRewriter;
-  }
-
   private void logEligibilityStatus(
       DexEncodedMethod context, Instruction root, EligibilityStatus status) {
     if (Log.ENABLED && Log.isLoggingEnabledFor(ClassInliner.class)) {
@@ -192,7 +186,6 @@
         InlineCandidateProcessor processor =
             new InlineCandidateProcessor(
                 appView,
-                lambdaRewriter,
                 inliner,
                 clazz -> isClassEligible(appView, clazz),
                 isProcessedConcurrently,
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
index c522ff3..35e84ef 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
@@ -35,7 +35,6 @@
 import com.android.tools.r8.ir.code.InvokeMethodWithReceiver;
 import com.android.tools.r8.ir.code.StaticGet;
 import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.ir.desugar.LambdaRewriter;
 import com.android.tools.r8.ir.optimize.Inliner;
 import com.android.tools.r8.ir.optimize.Inliner.InlineAction;
 import com.android.tools.r8.ir.optimize.Inliner.InliningInfo;
@@ -78,7 +77,6 @@
       ImmutableSet.of(If.Type.EQ, If.Type.NE);
 
   private final AppView<AppInfoWithLiveness> appView;
-  private final LambdaRewriter lambdaRewriter;
   private final Inliner inliner;
   private final Function<DexClass, EligibilityStatus> isClassEligible;
   private final Predicate<DexEncodedMethod> isProcessedConcurrently;
@@ -88,7 +86,6 @@
   private Value eligibleInstance;
   private DexType eligibleClass;
   private DexProgramClass eligibleClassDefinition;
-  private boolean isDesugaredLambda;
 
   private final Map<InvokeMethodWithReceiver, InliningInfo> methodCallsOnInstance =
       new IdentityHashMap<>();
@@ -106,14 +103,12 @@
 
   InlineCandidateProcessor(
       AppView<AppInfoWithLiveness> appView,
-      LambdaRewriter lambdaRewriter,
       Inliner inliner,
       Function<DexClass, EligibilityStatus> isClassEligible,
       Predicate<DexEncodedMethod> isProcessedConcurrently,
       DexEncodedMethod method,
       Instruction root) {
     this.appView = appView;
-    this.lambdaRewriter = lambdaRewriter;
     this.inliner = inliner;
     this.isClassEligible = isClassEligible;
     this.method = method;
@@ -165,11 +160,6 @@
     if (!eligibleClass.isClassType()) {
       return EligibilityStatus.NON_CLASS_TYPE;
     }
-    if (lambdaRewriter != null) {
-      // Check if the class is synthesized for a desugared lambda
-      eligibleClassDefinition = lambdaRewriter.getLambdaClass(eligibleClass);
-      isDesugaredLambda = eligibleClassDefinition != null;
-    }
     if (eligibleClassDefinition == null) {
       eligibleClassDefinition = asProgramClassOrNull(appView.definitionFor(eligibleClass));
     }
@@ -213,65 +203,6 @@
     }
 
     assert root.isStaticGet();
-
-    // We know that desugared lambda classes satisfy eligibility requirements.
-    if (isDesugaredLambda) {
-      return EligibilityStatus.ELIGIBLE;
-    }
-
-    // Checking if we can safely inline class implemented following singleton-like
-    // pattern, by which we assume a static final field holding on to the reference
-    // initialized in class constructor.
-    //
-    // In general we are targeting cases when the class is defined as:
-    //
-    //   class X {
-    //     static final X F;
-    //     static {
-    //       F = new X();
-    //     }
-    //   }
-    //
-    // and being used as follows:
-    //
-    //   void foo() {
-    //     f = X.F;
-    //     f.bar();
-    //   }
-    //
-    // The main difference from the similar case of class inliner with 'new-instance'
-    // instruction is that in this case the instance we inline is not just leaked, but
-    // is actually published via X.F field. There are several risks we need to address
-    // in this case:
-    //
-    //    Risk: instance stored in field X.F has changed after it was initialized in
-    //      class initializer
-    //    Solution: we assume that final field X.F is not modified outside the class
-    //      initializer. In rare cases when it is (e.g. via reflections) it should
-    //      be marked with keep rules
-    //
-    //    Risk: instance stored in field X.F is not initialized yet
-    //    Solution: not initialized instance can only be visible if X.<clinit>
-    //      triggers other class initialization which references X.F. This
-    //      situation should never happen if we:
-    //        -- don't allow any superclasses to have static initializer,
-    //        -- don't allow any subclasses,
-    //        -- guarantee the class has trivial class initializer
-    //           (see CodeRewriter::computeClassInitializerInfo), and
-    //        -- guarantee the instance is initialized with trivial instance
-    //           initializer (see CodeRewriter::computeInstanceInitializerInfo)
-    //
-    //    Risk: instance stored in field X.F was mutated
-    //    Solution: we require that class X does not have any instance fields, and
-    //      if any of its superclasses has instance fields, accessing them will make
-    //      this instance not eligible for inlining. I.e. even though the instance is
-    //      publicized and its state has been mutated, it will not effect the logic
-    //      of class inlining
-    //
-
-    if (!eligibleClassDefinition.instanceFields().isEmpty()) {
-      return EligibilityStatus.HAS_INSTANCE_FIELDS;
-    }
     return EligibilityStatus.ELIGIBLE;
   }
 
@@ -305,10 +236,24 @@
           indirectUsers.addAll(alias.uniqueUsers());
           continue;
         }
-        // Field read/write.
-        if (user.isInstanceGet()
-            || (user.isInstancePut()
-                && receivers.addIllegalReceiverAlias(user.asInstancePut().value()))) {
+
+        if (user.isInstanceGet()) {
+          if (root.isStaticGet()) {
+            // We don't have a replacement for this field read.
+            return user; // Not eligible.
+          }
+          DexEncodedField field =
+              appView.appInfo().resolveField(user.asFieldInstruction().getField());
+          if (field == null || field.isStatic()) {
+            return user; // Not eligible.
+          }
+          continue;
+        }
+
+        if (user.isInstancePut()) {
+          if (!receivers.addIllegalReceiverAlias(user.asInstancePut().value())) {
+            return user; // Not eligible.
+          }
           DexEncodedField field =
               appView.appInfo().resolveField(user.asFieldInstruction().getField());
           if (field == null || field.isStatic()) {
@@ -707,12 +652,6 @@
       return null;
     }
 
-    if (isDesugaredLambda) {
-      // Lambda desugaring synthesizes eligible constructors.
-      markSizeForInlining(invoke, singleTarget);
-      return new InliningInfo(singleTarget, eligibleClass);
-    }
-
     // Check that the entire constructor chain can be inlined into the current context.
     DexItemFactory dexItemFactory = appView.dexItemFactory();
     DexMethod parent = instanceInitializerInfo.getParent();
@@ -878,6 +817,15 @@
       return null;
     }
 
+    if (root.isStaticGet()) {
+      // If we are class inlining a singleton instance from a static-get, then we don't the value of
+      // the fields.
+      ParameterUsage receiverUsage = optimizationInfo.getParameterUsages(0);
+      if (receiverUsage == null || receiverUsage.hasFieldRead) {
+        return null;
+      }
+    }
+
     // If the method returns receiver and the return value is actually
     // used in the code we need to make some additional checks.
     if (!eligibilityAcceptanceCheck.test(eligibility)) {
@@ -1013,6 +961,14 @@
       return false;
     }
 
+    if (root.isStaticGet()) {
+      // If we are class inlining a singleton instance from a static-get, then we don't the value of
+      // the fields.
+      if (parameterUsage.hasFieldRead) {
+        return false;
+      }
+    }
+
     if (parameterUsage.isReturned) {
       if (invoke.outValue() != null && invoke.outValue().hasAnyUsers()) {
         // Used as return value which is not ignored.
@@ -1080,12 +1036,6 @@
 
   private boolean exemptFromInstructionLimit(DexEncodedMethod inlinee) {
     DexType inlineeHolder = inlinee.method.holder;
-    if (isDesugaredLambda && inlineeHolder == eligibleClass) {
-      return true;
-    }
-    if (appView.appInfo().isPinned(inlineeHolder)) {
-      return false;
-    }
     DexClass inlineeClass = appView.definitionFor(inlineeHolder);
     assert inlineeClass != null;
 
@@ -1116,15 +1066,6 @@
     if (isProcessedConcurrently.test(singleTarget)) {
       return false;
     }
-    if (isDesugaredLambda && !singleTarget.accessFlags.isBridge()) {
-      // OK if this is the call to the main method of a desugared lambda (for both direct and
-      // indirect calls).
-      //
-      // Note: This is needed because lambda methods are generally processed in the same batch as
-      // they are class inlined, which means that the call to isInliningCandidate() below will
-      // return false.
-      return true;
-    }
     if (!singleTarget.isInliningCandidate(
         method, Reason.SIMPLE, appView.appInfo(), NopWhyAreYouNotInliningReporter.getInstance())) {
       // If `singleTarget` is not an inlining candidate, we won't be able to inline it here.
diff --git a/src/test/java/com/android/tools/r8/R8RunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/R8RunExamplesAndroidOTest.java
index 8154dfc..92d02ee 100644
--- a/src/test/java/com/android/tools/r8/R8RunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunExamplesAndroidOTest.java
@@ -174,7 +174,7 @@
         .withBuilderTransformation(ToolHelper::allowTestProguardOptions)
         .withBuilderTransformation(
             b -> b.addProguardConfiguration(PROGUARD_OPTIONS_N_PLUS, Origin.unknown()))
-        .withDexCheck(inspector -> checkLambdaCount(inspector, 5, "lambdadesugaringnplus"))
+        .withDexCheck(inspector -> checkLambdaCount(inspector, 7, "lambdadesugaringnplus"))
         .run();
   }