Reintroduce context aware placement of main-dex synthetics.

Bug: 178127572
Fixes: 181010111
Change-Id: I970479d758ddf876c058e2a18d43fe419b7e5f2a
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/PreventMergeIntoDifferentMainDexGroups.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/PreventMergeIntoDifferentMainDexGroups.java
index f7b8c6e..41c240f 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/PreventMergeIntoDifferentMainDexGroups.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/PreventMergeIntoDifferentMainDexGroups.java
@@ -10,20 +10,23 @@
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.shaking.MainDexInfo;
 import com.android.tools.r8.shaking.MainDexInfo.MainDexGroup;
+import com.android.tools.r8.synthesis.SyntheticItems;
 
 public class PreventMergeIntoDifferentMainDexGroups
     extends MultiClassSameReferencePolicy<MainDexGroup> {
 
   private final MainDexInfo mainDexInfo;
+  private final SyntheticItems synthetics;
 
   public PreventMergeIntoDifferentMainDexGroups(AppView<AppInfoWithLiveness> appView) {
-    this.mainDexInfo = appView.appInfo().getMainDexInfo();
+    mainDexInfo = appView.appInfo().getMainDexInfo();
+    synthetics = appView.getSyntheticItems();
   }
 
   @Override
   public MainDexGroup getMergeKey(DexProgramClass clazz) {
-    return mainDexInfo.canMerge(clazz)
-        ? mainDexInfo.getMergeKey(clazz)
+    return mainDexInfo.canMerge(clazz, synthetics)
+        ? mainDexInfo.getMergeKey(clazz, synthetics)
         : ineligibleForClassMerging();
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
index 33e414f..8e66601 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
@@ -201,13 +201,13 @@
     // If we do this it can increase the size of the main dex dependent classes.
     if (reason != Reason.FORCE
         && inliner.mainDexInfo.disallowInliningIntoContext(
-            appView.appInfo(), method, singleTarget)) {
+            appView.appInfo(), method, singleTarget, appView.getSyntheticItems())) {
       whyAreYouNotInliningReporter.reportInlineeRefersToClassesNotInMainDex();
       return false;
     }
     assert reason != Reason.FORCE
         || !inliner.mainDexInfo.disallowInliningIntoContext(
-            appView.appInfo(), method, singleTarget);
+            appView.appInfo(), method, singleTarget, appView.getSyntheticItems());
     return true;
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java b/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
index f5f4d70..fa3886e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
@@ -391,6 +391,9 @@
   }
 
   private boolean isRebindingNewClassIntoMainDex(ProgramMethod context, DexMethod reboundMethod) {
-    return !appView.appInfo().getMainDexInfo().canRebindReference(context, reboundMethod);
+    return !appView
+        .appInfo()
+        .getMainDexInfo()
+        .canRebindReference(context, reboundMethod, appView.getSyntheticItems());
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
index 289b2ba..802fdb3 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
@@ -92,7 +92,8 @@
             && !appView
                 .appInfo()
                 .getMainDexInfo()
-                .canRebindReference(code.context(), baseClass.getType())) {
+                .canRebindReference(
+                    code.context(), baseClass.getType(), appView.getSyntheticItems())) {
           return;
         }
 
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index fd3c069..e818526 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -1695,7 +1695,7 @@
 
     assert !mode.isFinalMainDexTracing()
             || !options.testing.checkForNotExpandingMainDexTracingResult
-            || appView.appInfo().getMainDexInfo().isTracedRoot(clazz)
+            || appView.appInfo().getMainDexInfo().isTracedRoot(clazz, appView.getSyntheticItems())
             || clazz.toSourceString().contains(ENUM_UNBOXING_UTILITY_CLASS_SUFFIX)
         : "Class " + clazz.toSourceString() + " was not a main dex root in the first round";
 
diff --git a/src/main/java/com/android/tools/r8/shaking/MainDexInfo.java b/src/main/java/com/android/tools/r8/shaking/MainDexInfo.java
index 4e579f2..5d3309a 100644
--- a/src/main/java/com/android/tools/r8/shaking/MainDexInfo.java
+++ b/src/main/java/com/android/tools/r8/shaking/MainDexInfo.java
@@ -6,7 +6,6 @@
 
 import static com.android.tools.r8.shaking.MainDexInfo.MainDexGroup.MAIN_DEX_ROOT;
 import static com.android.tools.r8.utils.LensUtils.rewriteAndApplyIfNotPrimitiveType;
-import static com.android.tools.r8.utils.PredicateUtils.not;
 
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.DexMethod;
@@ -17,6 +16,7 @@
 import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.synthesis.SyntheticItems;
 import com.android.tools.r8.utils.ConsumerUtils;
 import com.google.common.collect.Sets;
 import java.util.Collections;
@@ -81,16 +81,16 @@
     return this == NONE;
   }
 
-  public boolean isFromList(ProgramDefinition definition) {
-    return isFromList(definition.getContextType());
+  public boolean isFromList(ProgramDefinition definition, SyntheticItems synthetics) {
+    return isFromList(definition.getContextType(), synthetics);
   }
 
-  private boolean isFromList(DexReference reference) {
-    return classList.contains(reference.getContextType());
+  private boolean isFromList(DexReference reference, SyntheticItems synthetics) {
+    return isContainedOrHasContainedContext(reference, classList, synthetics);
   }
 
-  public boolean isTracedRoot(ProgramDefinition definition) {
-    return isTracedRoot(definition.getContextType());
+  public boolean isTracedRoot(ProgramDefinition definition, SyntheticItems synthetics) {
+    return isTracedRoot(definition.getContextType(), synthetics);
   }
 
   public boolean isTracedMethodRoot(DexMethod method) {
@@ -98,8 +98,22 @@
     return tracedMethodRoots.contains(method);
   }
 
-  private boolean isTracedRoot(DexReference reference) {
-    return tracedRoots.contains(reference.getContextType());
+  private boolean isTracedRoot(DexReference reference, SyntheticItems synthetics) {
+    return isContainedOrHasContainedContext(reference, tracedRoots, synthetics);
+  }
+
+  private boolean isContainedOrHasContainedContext(
+      DexReference reference, Set<DexType> items, SyntheticItems synthetics) {
+    if (items.isEmpty()) {
+      return false;
+    }
+    DexType type = reference.getContextType();
+    for (DexType context : synthetics.getSynthesizingContexts(type)) {
+      if (items.contains(context)) {
+        return true;
+      }
+    }
+    return items.contains(type);
   }
 
   private boolean isDependency(ProgramDefinition definition) {
@@ -119,8 +133,9 @@
     this.tracedMethodRoots = Sets.newIdentityHashSet();
   }
 
-  public boolean canRebindReference(ProgramMethod context, DexReference referenceToTarget) {
-    MainDexGroup holderGroup = getMainDexGroupInternal(context);
+  public boolean canRebindReference(
+      ProgramMethod context, DexReference referenceToTarget, SyntheticItems synthetics) {
+    MainDexGroup holderGroup = getMainDexGroupInternal(context, synthetics);
     if (holderGroup == MainDexGroup.NOT_IN_MAIN_DEX
         || holderGroup == MainDexGroup.MAIN_DEX_DEPENDENCY) {
       // We are always free to rebind/inline into something not in main-dex or traced dependencies.
@@ -133,20 +148,21 @@
     }
     assert holderGroup == MAIN_DEX_ROOT;
     // Otherwise we allow if either is both root.
-    return getMainDexGroupInternal(referenceToTarget) == MAIN_DEX_ROOT;
+    return getMainDexGroupInternal(referenceToTarget, synthetics) == MAIN_DEX_ROOT;
   }
 
-  public boolean canMerge(ProgramDefinition candidate) {
-    return !isFromList(candidate);
+  public boolean canMerge(ProgramDefinition candidate, SyntheticItems synthetics) {
+    return !isFromList(candidate, synthetics);
   }
 
-  public boolean canMerge(ProgramDefinition source, ProgramDefinition target) {
-    return canMerge(source.getContextType(), target.getContextType());
+  public boolean canMerge(
+      ProgramDefinition source, ProgramDefinition target, SyntheticItems synthetics) {
+    return canMerge(source.getContextType(), target.getContextType(), synthetics);
   }
 
-  private boolean canMerge(DexReference source, DexReference target) {
-    MainDexGroup sourceGroup = getMainDexGroupInternal(source);
-    MainDexGroup targetGroup = getMainDexGroupInternal(target);
+  private boolean canMerge(DexReference source, DexReference target, SyntheticItems synthetics) {
+    MainDexGroup sourceGroup = getMainDexGroupInternal(source, synthetics);
+    MainDexGroup targetGroup = getMainDexGroupInternal(target, synthetics);
     if (sourceGroup != targetGroup) {
       return false;
     }
@@ -155,21 +171,22 @@
     return sourceGroup != MainDexGroup.MAIN_DEX_LIST;
   }
 
-  public MainDexGroup getMergeKey(ProgramDefinition mergeCandidate) {
-    assert canMerge(mergeCandidate);
-    MainDexGroup mainDexGroupInternal = getMainDexGroupInternal(mergeCandidate);
+  public MainDexGroup getMergeKey(ProgramDefinition mergeCandidate, SyntheticItems synthetics) {
+    assert canMerge(mergeCandidate, synthetics);
+    MainDexGroup mainDexGroupInternal = getMainDexGroupInternal(mergeCandidate, synthetics);
     return mainDexGroupInternal == MainDexGroup.MAIN_DEX_LIST ? null : mainDexGroupInternal;
   }
 
-  private MainDexGroup getMainDexGroupInternal(ProgramDefinition definition) {
-    return getMainDexGroupInternal(definition.getReference());
+  private MainDexGroup getMainDexGroupInternal(
+      ProgramDefinition definition, SyntheticItems synthetics) {
+    return getMainDexGroupInternal(definition.getReference(), synthetics);
   }
 
-  private MainDexGroup getMainDexGroupInternal(DexReference reference) {
-    if (isFromList(reference)) {
+  private MainDexGroup getMainDexGroupInternal(DexReference reference, SyntheticItems synthetics) {
+    if (isFromList(reference, synthetics)) {
       return MainDexGroup.MAIN_DEX_LIST;
     }
-    if (isTracedRoot(reference)) {
+    if (isTracedRoot(reference, synthetics)) {
       return MAIN_DEX_ROOT;
     }
     if (isDependency(reference)) {
@@ -179,22 +196,25 @@
   }
 
   public boolean disallowInliningIntoContext(
-      AppInfoWithClassHierarchy appInfo, ProgramDefinition context, ProgramMethod method) {
+      AppInfoWithClassHierarchy appInfo,
+      ProgramDefinition context,
+      ProgramMethod method,
+      SyntheticItems synthetics) {
     if (context.getContextType() == method.getContextType()) {
       return false;
     }
-    MainDexGroup mainDexGroupInternal = getMainDexGroupInternal(context);
+    MainDexGroup mainDexGroupInternal = getMainDexGroupInternal(context, synthetics);
     if (mainDexGroupInternal == MainDexGroup.NOT_IN_MAIN_DEX
         || mainDexGroupInternal == MainDexGroup.MAIN_DEX_DEPENDENCY) {
       return false;
     }
     if (mainDexGroupInternal == MainDexGroup.MAIN_DEX_LIST) {
       return MainDexDirectReferenceTracer.hasReferencesOutsideMainDexClasses(
-          appInfo, method, not(this::isFromList));
+          appInfo, method, t -> !isFromList(t, synthetics));
     }
     assert mainDexGroupInternal == MAIN_DEX_ROOT;
     return MainDexDirectReferenceTracer.hasReferencesOutsideMainDexClasses(
-        appInfo, method, not(this::isTracedRoot));
+        appInfo, method, t -> !isTracedRoot(t, synthetics));
   }
 
   public boolean isEmpty() {
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
index afc9e50..761b314 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -826,7 +826,7 @@
     }
 
     // Check with main dex classes to see if we are allowed to merge.
-    if (!mainDexInfo.canMerge(clazz, targetClass)) {
+    if (!mainDexInfo.canMerge(clazz, targetClass, appView.getSyntheticItems())) {
       return;
     }
 
@@ -1657,7 +1657,8 @@
         }
         // Constructors can have references beyond the root main dex classes. This can increase the
         // size of the main dex dependent classes and we should bail out.
-        if (mainDexInfo.disallowInliningIntoContext(appView.appInfo(), context, method)) {
+        if (mainDexInfo.disallowInliningIntoContext(
+            appView.appInfo(), context, method, appView.getSyntheticItems())) {
           return AbortReason.MAIN_DEX_ROOT_OUTSIDE_REFERENCE;
         }
         return null;