Reenable constructor shrinking

Bug: b/246679983
Change-Id: Ic201e5e23144a185080e76042c9e8ce907243ec3
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index d96d546..2ff0966 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -67,10 +67,10 @@
 import com.android.tools.r8.optimize.MemberRebindingAnalysis;
 import com.android.tools.r8.optimize.MemberRebindingIdentityLens;
 import com.android.tools.r8.optimize.MemberRebindingIdentityLensFactory;
-import com.android.tools.r8.optimize.RedundantBridgeRemover;
 import com.android.tools.r8.optimize.bridgehoisting.BridgeHoisting;
 import com.android.tools.r8.optimize.interfaces.analysis.CfOpenClosedInterfacesAnalysis;
 import com.android.tools.r8.optimize.proto.ProtoNormalizer;
+import com.android.tools.r8.optimize.redundantbridgeremoval.RedundantBridgeRemover;
 import com.android.tools.r8.origin.CommandLineOrigin;
 import com.android.tools.r8.profile.art.ArtProfileCompletenessChecker;
 import com.android.tools.r8.profile.art.rewriting.ProfileCollectionAdditions;
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 f30986c..f9a5279 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -475,9 +475,9 @@
     return isInstanceInitializer() || willBeInlinedIntoInstanceInitializer(dexItemFactory);
   }
 
-  public boolean isDefaultInitializer() {
+  public boolean isDefaultInstanceInitializer() {
     checkIfObsolete();
-    return isInstanceInitializer() && getReference().proto.parameters.isEmpty();
+    return isInstanceInitializer() && getParameters().isEmpty();
   }
 
   public boolean isClassInitializer() {
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index 9cdb7f2..5c14069 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -592,6 +592,9 @@
   public final DexType javaUtilSetType = createStaticallyKnownType("Ljava/util/Set;");
 
   public final DexType androidAppActivity = createStaticallyKnownType("Landroid/app/Activity;");
+  public final DexType androidAppFragment = createStaticallyKnownType("Landroid/app/Fragment;");
+  public final DexType androidAppZygotePreload =
+      createStaticallyKnownType("Landroid/app/ZygotePreload;");
   public final DexType androidOsBuildType = createStaticallyKnownType("Landroid/os/Build;");
   public final DexType androidOsBuildVersionType =
       createStaticallyKnownType("Landroid/os/Build$VERSION;");
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/callgraph/CallSiteInformation.java b/src/main/java/com/android/tools/r8/ir/conversion/callgraph/CallSiteInformation.java
index 125b53c..c2e13af 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/callgraph/CallSiteInformation.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/callgraph/CallSiteInformation.java
@@ -86,7 +86,7 @@
           continue;
         }
 
-        if (method.getDefinition().isDefaultInitializer()
+        if (method.getDefinition().isDefaultInstanceInitializer()
             && appView.hasProguardCompatibilityActions()
             && appView.getProguardCompatibilityActions().isCompatInstantiated(method.getHolder())) {
           continue;
diff --git a/src/main/java/com/android/tools/r8/optimize/redundantbridgeremoval/RedundantBridgeRemovalOptions.java b/src/main/java/com/android/tools/r8/optimize/redundantbridgeremoval/RedundantBridgeRemovalOptions.java
new file mode 100644
index 0000000..a902764
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/optimize/redundantbridgeremoval/RedundantBridgeRemovalOptions.java
@@ -0,0 +1,42 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.optimize.redundantbridgeremoval;
+
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexLibraryClass;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.SetUtils;
+import java.util.Collections;
+import java.util.Set;
+
+public class RedundantBridgeRemovalOptions {
+
+  private final InternalOptions options;
+
+  private Set<DexType> noConstructorShrinkingHierarchies;
+
+  public RedundantBridgeRemovalOptions(InternalOptions options) {
+    this.options = options;
+  }
+
+  public void clearNoConstructorShrinkingHierarchiesForTesting() {
+    noConstructorShrinkingHierarchies = Collections.emptySet();
+  }
+
+  public RedundantBridgeRemovalOptions ensureInitialized() {
+    if (noConstructorShrinkingHierarchies == null) {
+      DexItemFactory dexItemFactory = options.dexItemFactory();
+      noConstructorShrinkingHierarchies =
+          SetUtils.newIdentityHashSet(
+              dexItemFactory.androidAppFragment, dexItemFactory.androidAppZygotePreload);
+    }
+    return this;
+  }
+
+  public boolean isPlatformReflectingOnDefaultConstructorInSubclasses(DexLibraryClass clazz) {
+    return noConstructorShrinkingHierarchies.contains(clazz.getType());
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/optimize/RedundantBridgeRemover.java b/src/main/java/com/android/tools/r8/optimize/redundantbridgeremoval/RedundantBridgeRemover.java
similarity index 72%
rename from src/main/java/com/android/tools/r8/optimize/RedundantBridgeRemover.java
rename to src/main/java/com/android/tools/r8/optimize/redundantbridgeremoval/RedundantBridgeRemover.java
index 763c40f..c050859 100644
--- a/src/main/java/com/android/tools/r8/optimize/RedundantBridgeRemover.java
+++ b/src/main/java/com/android/tools/r8/optimize/redundantbridgeremoval/RedundantBridgeRemover.java
@@ -1,9 +1,10 @@
 // Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.optimize;
+package com.android.tools.r8.optimize.redundantbridgeremoval;
 
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
@@ -15,23 +16,35 @@
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.PrunedItems;
 import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
+import com.android.tools.r8.optimize.InvokeSingleTargetExtractor;
 import com.android.tools.r8.optimize.InvokeSingleTargetExtractor.InvokeKind;
-import com.android.tools.r8.optimize.redundantbridgeremoval.RedundantBridgeRemovalLens;
+import com.android.tools.r8.optimize.MemberRebindingIdentityLens;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.shaking.KeepMethodInfo;
+import com.android.tools.r8.utils.IterableUtils;
 import com.android.tools.r8.utils.ThreadUtils;
+import com.android.tools.r8.utils.WorkList;
 import com.android.tools.r8.utils.collections.ProgramMethodSet;
+import com.google.common.collect.Iterables;
+import java.util.Collections;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
+import java.util.function.Consumer;
 
 public class RedundantBridgeRemover {
 
   private final AppView<AppInfoWithLiveness> appView;
+  private final RedundantBridgeRemovalOptions redundantBridgeRemovalOptions;
+
+  private final InvokedReflectivelyFromPlatformAnalysis invokedReflectivelyFromPlatformAnalysis =
+      new InvokedReflectivelyFromPlatformAnalysis();
 
   public RedundantBridgeRemover(AppView<AppInfoWithLiveness> appView) {
     this.appView = appView;
+    this.redundantBridgeRemovalOptions =
+        appView.options().getRedundantBridgeRemovalOptions().ensureInitialized();
   }
 
   private DexClassAndMethod getTargetForRedundantBridge(ProgramMethod method) {
@@ -52,6 +65,9 @@
     if (!isTargetingSuperMethod(method, targetExtractor.getKind(), target)) {
       return null;
     }
+    if (invokedReflectivelyFromPlatformAnalysis.isMaybeInvokedReflectivelyFromPlatform(method)) {
+      return null;
+    }
     // This is a visibility forward, so check for the direct target.
     DexClassAndMethod targetMethod =
         appView.appInfo().unsafeResolveMethodDueToDexFormatLegacy(target).getResolutionPair();
@@ -236,4 +252,88 @@
         });
     appView.pruneItems(prunedItemsBuilder.build(), executorService);
   }
+
+  class InvokedReflectivelyFromPlatformAnalysis {
+
+    // Maps each class to a boolean indicating if the class inherits from android.app.Fragment or
+    // android.app.ZygotePreload.
+    private final Map<DexClass, Boolean> cache = new ConcurrentHashMap<>();
+
+    boolean isMaybeInvokedReflectivelyFromPlatform(ProgramMethod method) {
+      return method.getDefinition().isDefaultInstanceInitializer()
+          && !method.getHolder().isAbstract()
+          && computeIsPlatformReflectingOnDefaultConstructor(method.getHolder());
+    }
+
+    private boolean computeIsPlatformReflectingOnDefaultConstructor(DexProgramClass clazz) {
+      Boolean cacheResult = cache.get(clazz);
+      if (cacheResult != null) {
+        return cacheResult;
+      }
+      WorkList.<WorklistItem>newIdentityWorkList(new NotProcessedWorklistItem(clazz))
+          .process(WorklistItem::accept);
+      assert cache.containsKey(clazz);
+      return cache.get(clazz);
+    }
+
+    abstract class WorklistItem implements Consumer<WorkList<WorklistItem>> {
+
+      protected final DexClass clazz;
+
+      WorklistItem(DexClass clazz) {
+        this.clazz = clazz;
+      }
+
+      Iterable<DexClass> getImmediateSupertypes() {
+        return IterableUtils.flatMap(
+            clazz.allImmediateSupertypes(),
+            supertype -> {
+              DexClass definition = appView.definitionFor(supertype);
+              return definition != null
+                  ? Collections.singletonList(definition)
+                  : Collections.emptyList();
+            });
+      }
+    }
+
+    class NotProcessedWorklistItem extends WorklistItem {
+
+      NotProcessedWorklistItem(DexClass clazz) {
+        super(clazz);
+      }
+
+      @Override
+      public void accept(WorkList<WorklistItem> worklist) {
+        // Enqueue a worklist item to process the current class after processing its super classes.
+        worklist.addFirstIgnoringSeenSet(new ProcessedWorklistItem(clazz));
+        // Enqueue all superclasses for processing.
+        for (DexClass supertype : getImmediateSupertypes()) {
+          if (!cache.containsKey(supertype)) {
+            worklist.addFirstIgnoringSeenSet(new NotProcessedWorklistItem(supertype));
+          }
+        }
+      }
+    }
+
+    class ProcessedWorklistItem extends WorklistItem {
+
+      ProcessedWorklistItem(DexClass clazz) {
+        super(clazz);
+      }
+
+      @Override
+      public void accept(WorkList<WorklistItem> worklist) {
+        cache.put(
+            clazz,
+            Iterables.any(
+                getImmediateSupertypes(),
+                supertype ->
+                    cache.get(supertype)
+                        || (supertype.isLibraryClass()
+                            && redundantBridgeRemovalOptions
+                                .isPlatformReflectingOnDefaultConstructorInSubclasses(
+                                    supertype.asLibraryClass()))));
+      }
+    }
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index f9bd041..3a51f8b 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -74,6 +74,7 @@
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.naming.MapVersion;
 import com.android.tools.r8.optimize.argumentpropagation.ArgumentPropagatorEventConsumer;
+import com.android.tools.r8.optimize.redundantbridgeremoval.RedundantBridgeRemovalOptions;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.position.Position;
 import com.android.tools.r8.profile.art.ArtProfileOptions;
@@ -862,6 +863,8 @@
   private final OpenClosedInterfacesOptions openClosedInterfacesOptions =
       new OpenClosedInterfacesOptions();
   private final ProtoShrinkingOptions protoShrinking = new ProtoShrinkingOptions();
+  private final RedundantBridgeRemovalOptions redundantBridgeRemovalOptions =
+      new RedundantBridgeRemovalOptions(this);
   private final KotlinOptimizationOptions kotlinOptimizationOptions =
       new KotlinOptimizationOptions();
   private final ApiModelTestingOptions apiModelTestingOptions = new ApiModelTestingOptions();
@@ -930,6 +933,10 @@
     return cfCodeAnalysisOptions;
   }
 
+  public RedundantBridgeRemovalOptions getRedundantBridgeRemovalOptions() {
+    return redundantBridgeRemovalOptions;
+  }
+
   public DumpInputFlags getDumpInputFlags() {
     return dumpInputFlags;
   }
@@ -2884,8 +2891,7 @@
   }
 
   public boolean canHaveNonReboundConstructorInvoke() {
-    // TODO(b/246679983): Turned off while diagnosing b/246679983.
-    return false && isGeneratingDex() && minApiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.L);
+    return isGeneratingDex() && minApiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.L);
   }
 
   // b/238399429 Some art 6 vms have issues with multiple monitors in the same method
diff --git a/src/test/java/com/android/tools/r8/TestParameters.java b/src/test/java/com/android/tools/r8/TestParameters.java
index c22f43e..206a8ab 100644
--- a/src/test/java/com/android/tools/r8/TestParameters.java
+++ b/src/test/java/com/android/tools/r8/TestParameters.java
@@ -58,8 +58,7 @@
    * runtime error.
    */
   public boolean canHaveNonReboundConstructorInvoke() {
-    // TODO(b/246679983): Turned off while diagnosing b/246679983.
-    return false && isDexRuntime() && getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.L);
+    return isDexRuntime() && getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.L);
   }
 
   public boolean canUseDefaultAndStaticInterfaceMethods() {
diff --git a/src/test/java/com/android/tools/r8/profile/art/completeness/LambdaStaticLibraryMethodImplementationProfileRewritingTest.java b/src/test/java/com/android/tools/r8/profile/art/completeness/LambdaStaticLibraryMethodImplementationProfileRewritingTest.java
index 2d38860..c83d81d 100644
--- a/src/test/java/com/android/tools/r8/profile/art/completeness/LambdaStaticLibraryMethodImplementationProfileRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/profile/art/completeness/LambdaStaticLibraryMethodImplementationProfileRewritingTest.java
@@ -75,15 +75,22 @@
   }
 
   private void inspectD8(ArtProfileInspector profileInspector, CodeInspector inspector) {
-    inspect(profileInspector, inspector, false);
+    inspect(profileInspector, inspector, false, false);
   }
 
   private void inspectR8(ArtProfileInspector profileInspector, CodeInspector inspector) {
-    inspect(profileInspector, inspector, parameters.isCfRuntime());
+    inspect(
+        profileInspector,
+        inspector,
+        parameters.canHaveNonReboundConstructorInvoke(),
+        parameters.isCfRuntime());
   }
 
   public void inspect(
-      ArtProfileInspector profileInspector, CodeInspector inspector, boolean canUseLambdas) {
+      ArtProfileInspector profileInspector,
+      CodeInspector inspector,
+      boolean canHaveNonReboundConstructorInvoke,
+      boolean canUseLambdas) {
     ClassSubject mainClassSubject = inspector.clazz(Main.class);
     assertThat(mainClassSubject, isPresent());
 
@@ -96,21 +103,26 @@
     assertThat(lambdaClassSubject, notIf(isPresent(), canUseLambdas));
 
     MethodSubject lambdaInitializerSubject = lambdaClassSubject.uniqueInstanceInitializer();
-    assertThat(lambdaInitializerSubject, notIf(isPresent(), canUseLambdas));
+    assertThat(
+        lambdaInitializerSubject,
+        notIf(isPresent(), canHaveNonReboundConstructorInvoke || canUseLambdas));
 
     MethodSubject lambdaMainMethodSubject =
         lambdaClassSubject.uniqueMethodThatMatches(FoundMethodSubject::isVirtual);
     assertThat(lambdaMainMethodSubject, notIf(isPresent(), canUseLambdas));
 
     if (canUseLambdas) {
-      profileInspector.assertContainsMethodRule(mainMethodSubject).assertContainsNoOtherRules();
+      profileInspector.assertContainsMethodRule(mainMethodSubject);
     } else {
       profileInspector
           .assertContainsClassRules(lambdaClassSubject)
-          .assertContainsMethodRules(
-              mainMethodSubject, lambdaInitializerSubject, lambdaMainMethodSubject)
-          .assertContainsNoOtherRules();
+          .assertContainsMethodRules(mainMethodSubject, lambdaMainMethodSubject)
+          .applyIf(
+              !canHaveNonReboundConstructorInvoke,
+              i -> i.assertContainsMethodRule(lambdaInitializerSubject));
     }
+
+    profileInspector.assertContainsNoOtherRules();
   }
 
   static class Main {
diff --git a/src/test/java/com/android/tools/r8/profile/art/completeness/NestBasedAccessBridgesProfileRewritingTest.java b/src/test/java/com/android/tools/r8/profile/art/completeness/NestBasedAccessBridgesProfileRewritingTest.java
index 7d9e9ab..577518d 100644
--- a/src/test/java/com/android/tools/r8/profile/art/completeness/NestBasedAccessBridgesProfileRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/profile/art/completeness/NestBasedAccessBridgesProfileRewritingTest.java
@@ -104,17 +104,22 @@
 
   private void inspectD8(ArtProfileInspector profileInspector, CodeInspector inspector)
       throws Exception {
-    inspect(profileInspector, inspector, parameters.canUseNestBasedAccessesWhenDesugaring());
+    inspect(profileInspector, inspector, false, parameters.canUseNestBasedAccessesWhenDesugaring());
   }
 
   private void inspectR8(ArtProfileInspector profileInspector, CodeInspector inspector)
       throws Exception {
-    inspect(profileInspector, inspector, parameters.canUseNestBasedAccesses());
+    inspect(
+        profileInspector,
+        inspector,
+        parameters.canHaveNonReboundConstructorInvoke(),
+        parameters.canUseNestBasedAccesses());
   }
 
   private void inspect(
       ArtProfileInspector profileInspector,
       CodeInspector inspector,
+      boolean canHaveNonReboundConstructorInvoke,
       boolean canUseNestBasedAccesses)
       throws Exception {
     ClassSubject nestMemberClassSubject = inspector.clazz(NestMember.class);
@@ -128,7 +133,7 @@
         syntheticConstructorArgumentClassSubject, notIf(isPresent(), canUseNestBasedAccesses));
 
     MethodSubject instanceInitializer = nestMemberClassSubject.init();
-    assertThat(instanceInitializer, isPresent());
+    assertThat(instanceInitializer, notIf(isPresent(), canHaveNonReboundConstructorInvoke));
 
     MethodSubject instanceInitializerWithSyntheticArgumentSubject =
         syntheticConstructorArgumentClassSubject.isPresent()
diff --git a/src/test/java/com/android/tools/r8/profile/art/completeness/RecordProfileRewritingTest.java b/src/test/java/com/android/tools/r8/profile/art/completeness/RecordProfileRewritingTest.java
index 5f1886d..6d03704 100644
--- a/src/test/java/com/android/tools/r8/profile/art/completeness/RecordProfileRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/profile/art/completeness/RecordProfileRewritingTest.java
@@ -149,6 +149,7 @@
         profileInspector,
         inspector,
         SyntheticItemsTestUtils.syntheticRecordTagClass(),
+        false,
         parameters.canUseNestBasedAccessesWhenDesugaring(),
         parameters.canUseRecordsWhenDesugaring());
   }
@@ -158,6 +159,7 @@
         profileInspector,
         inspector,
         RECORD_REFERENCE,
+        parameters.canHaveNonReboundConstructorInvoke(),
         parameters.canUseNestBasedAccesses(),
         parameters.canUseRecords());
   }
@@ -166,6 +168,7 @@
       ArtProfileInspector profileInspector,
       CodeInspector inspector,
       ClassReference recordClassReference,
+      boolean canHaveNonReboundConstructorInvoke,
       boolean canUseNestBasedAccesses,
       boolean canUseRecords) {
     ClassSubject mainClassSubject = inspector.clazz(MAIN_REFERENCE);
@@ -177,11 +180,14 @@
     ClassSubject recordTagClassSubject = inspector.clazz(recordClassReference);
     assertThat(recordTagClassSubject, notIf(isPresent(), canUseRecords));
     if (!canUseRecords) {
-      assertEquals(1, recordTagClassSubject.allMethods().size());
+      assertEquals(
+          canHaveNonReboundConstructorInvoke ? 0 : 1, recordTagClassSubject.allMethods().size());
     }
 
     MethodSubject recordTagInstanceInitializerSubject = recordTagClassSubject.init();
-    assertThat(recordTagInstanceInitializerSubject, notIf(isPresent(), canUseRecords));
+    assertThat(
+        recordTagInstanceInitializerSubject,
+        notIf(isPresent(), canHaveNonReboundConstructorInvoke || canUseRecords));
 
     ClassSubject personRecordClassSubject = inspector.clazz(PERSON_REFERENCE);
     assertThat(personRecordClassSubject, isPresent());
@@ -290,11 +296,13 @@
                         hashCodeHelperClassSubject,
                         toStringHelperClassSubject)
                     .assertContainsMethodRules(
-                        recordTagInstanceInitializerSubject,
                         equalsHelperMethodSubject,
                         getFieldsAsObjectsMethodSubject,
                         hashCodeHelperMethodSubject,
-                        toStringHelperMethodSubject))
+                        toStringHelperMethodSubject)
+                    .applyIf(
+                        !canHaveNonReboundConstructorInvoke,
+                        j -> j.assertContainsMethodRule(recordTagInstanceInitializerSubject)))
         .assertContainsNoOtherRules();
   }
 }
diff --git a/src/test/java/com/android/tools/r8/profile/art/completeness/SyntheticLambdaClassProfileRewritingTest.java b/src/test/java/com/android/tools/r8/profile/art/completeness/SyntheticLambdaClassProfileRewritingTest.java
index 385f94b..ef6b3a3 100644
--- a/src/test/java/com/android/tools/r8/profile/art/completeness/SyntheticLambdaClassProfileRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/profile/art/completeness/SyntheticLambdaClassProfileRewritingTest.java
@@ -68,6 +68,7 @@
     public void inspect(
         ArtProfileInspector profileInspector,
         CodeInspector inspector,
+        boolean canHaveNonReboundConstructorInvoke,
         boolean canUseLambdas,
         boolean canAccessModifyLambdaImplementationMethods) {
       ClassSubject mainClassSubject = inspector.clazz(Main.class);
@@ -106,7 +107,9 @@
       assertThat(lambdaClassSubject, notIf(isPresent(), canUseLambdas));
 
       MethodSubject lambdaInitializerSubject = lambdaClassSubject.uniqueInstanceInitializer();
-      assertThat(lambdaInitializerSubject, notIf(isPresent(), canUseLambdas));
+      assertThat(
+          lambdaInitializerSubject,
+          notIf(isPresent(), canHaveNonReboundConstructorInvoke || canUseLambdas));
 
       MethodSubject lambdaMainMethodSubject =
           lambdaClassSubject.uniqueMethodThatMatches(FoundMethodSubject::isVirtual);
@@ -119,7 +122,9 @@
 
       MethodSubject otherLambdaInitializerSubject =
           otherLambdaClassSubject.uniqueInstanceInitializer();
-      assertThat(otherLambdaInitializerSubject, notIf(isPresent(), canUseLambdas));
+      assertThat(
+          otherLambdaInitializerSubject,
+          notIf(isPresent(), canHaveNonReboundConstructorInvoke || canUseLambdas));
 
       MethodSubject otherLambdaMainMethodSubject =
           otherLambdaClassSubject.uniqueMethodThatMatches(FoundMethodSubject::isVirtual);
@@ -149,8 +154,12 @@
             // interface method implementation does not need to be included in the profile.
             profileInspector
                 .assertContainsClassRules(lambdaClassSubject, otherLambdaClassSubject)
-                .assertContainsMethodRules(
-                    mainMethodSubject, lambdaInitializerSubject, otherLambdaInitializerSubject)
+                .assertContainsMethodRules(mainMethodSubject)
+                .applyIf(
+                    !canHaveNonReboundConstructorInvoke,
+                    i ->
+                        i.assertContainsMethodRules(
+                            lambdaInitializerSubject, otherLambdaInitializerSubject))
                 .assertContainsNoOtherRules();
             break;
           case IMPLEMENTATION_METHOD:
@@ -221,11 +230,16 @@
   }
 
   private void inspectD8(ArtProfileInspector profileInspector, CodeInspector inspector) {
-    artProfileInputOutput.inspect(profileInspector, inspector, false, true);
+    artProfileInputOutput.inspect(profileInspector, inspector, false, false, true);
   }
 
   private void inspectR8(ArtProfileInspector profileInspector, CodeInspector inspector) {
-    artProfileInputOutput.inspect(profileInspector, inspector, parameters.isCfRuntime(), false);
+    artProfileInputOutput.inspect(
+        profileInspector,
+        inspector,
+        parameters.canHaveNonReboundConstructorInvoke(),
+        parameters.isCfRuntime(),
+        false);
   }
 
   static class Main {
diff --git a/src/test/java/com/android/tools/r8/shaking/constructor/ForwardingConstructorUsedFromPlatformShakingOnDexTest.java b/src/test/java/com/android/tools/r8/shaking/constructor/ForwardingConstructorUsedFromPlatformShakingOnDexTest.java
index 534bbb9..7dacf64 100644
--- a/src/test/java/com/android/tools/r8/shaking/constructor/ForwardingConstructorUsedFromPlatformShakingOnDexTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/constructor/ForwardingConstructorUsedFromPlatformShakingOnDexTest.java
@@ -5,14 +5,21 @@
 package com.android.tools.r8.shaking.constructor;
 
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.onlyIf;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assume.assumeFalse;
 
 import com.android.tools.r8.NeverClassInline;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.apimodel.ApiModelingTestHelper;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -22,48 +29,168 @@
 @RunWith(Parameterized.class)
 public class ForwardingConstructorUsedFromPlatformShakingOnDexTest extends TestBase {
 
+  private static final String APPLICATION_INFO_DESCRIPTOR = "Landroid/content/pm/ApplicationInfo;";
+  private static final String FRAGMENT_DESCRIPTOR = "Landroid/app/Fragment;";
+  private static final String ZYGOTE_PRELOAD_DESCRIPTOR = "Landroid/app/ZygotePreload;";
+
+  private static final String EXPECTED_OUTPUT =
+      StringUtils.lines(
+          "Fragment.onCreate()", "MyFragment.onCreate()", "MyZygotePreload.doPreload()");
+
+  private static List<byte[]> transformedProgramClassFileData;
+  private static List<byte[]> transformedLibraryClassFileData;
+
   @Parameter(0)
+  public boolean enableModeling;
+
+  @Parameter(1)
   public TestParameters parameters;
 
-  @Parameters(name = "{0}")
-  public static TestParametersCollection data() {
-    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  @Parameters(name = "{1}, modeling: {0}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+  }
+
+  @BeforeClass
+  public static void setup() throws Exception {
+    transformedProgramClassFileData = getTransformedProgramClasses();
+    transformedLibraryClassFileData = getTransformedLibraryClasses();
   }
 
   @Test
-  public void test() throws Exception {
+  public void testRuntime() throws Exception {
+    assumeFalse(enableModeling);
+    testForRuntime(parameters)
+        .addProgramClassFileData(transformedProgramClassFileData)
+        .addProgramClassFileData(transformedLibraryClassFileData)
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
+  }
+
+  @Test
+  public void testR8() throws Exception {
     testForR8(parameters.getBackend())
-        .addProgramClasses(Main.class, MyFragment.class)
-        .addLibraryClasses(Fragment.class)
+        .addProgramClassFileData(transformedProgramClassFileData)
+        .addLibraryClassFileData(transformedLibraryClassFileData)
         .addLibraryFiles(parameters.getDefaultRuntimeLibrary())
         .addKeepMainRule(Main.class)
+        .applyIf(
+            !enableModeling,
+            testBuilder ->
+                testBuilder.addOptionsModification(
+                    options ->
+                        options
+                            .getRedundantBridgeRemovalOptions()
+                            .clearNoConstructorShrinkingHierarchiesForTesting()))
+        // Since Fragment is first defined in API 11.
+        .apply(ApiModelingTestHelper::disableStubbingOfClasses)
         .enableNeverClassInliningAnnotations()
         .setMinApi(parameters)
         .compile()
         .inspect(this::inspect)
-        .addBootClasspathClasses(Fragment.class)
+        .addRunClasspathClassFileData(transformedLibraryClassFileData)
         .run(parameters.getRuntime(), Main.class)
-        .assertSuccessWithOutputLines("Instantiating");
+        .applyIf(
+            enableModeling || !parameters.canHaveNonReboundConstructorInvoke(),
+            runResult -> runResult.assertSuccessWithOutput(EXPECTED_OUTPUT),
+            runResult -> runResult.assertFailureWithErrorThatThrows(NoSuchMethodException.class));
+  }
+
+  private static List<byte[]> getTransformedProgramClasses() throws Exception {
+    return ImmutableList.of(
+        transformer(Main.class)
+            .replaceClassDescriptorInMethodInstructions(
+                descriptor(Fragment.class), FRAGMENT_DESCRIPTOR)
+            .replaceClassDescriptorInMethodInstructions(
+                descriptor(ZygotePreload.class), ZYGOTE_PRELOAD_DESCRIPTOR)
+            .transform(),
+        transformer(MyFragment.class)
+            .replaceClassDescriptorInMethodInstructions(
+                descriptor(Fragment.class), FRAGMENT_DESCRIPTOR)
+            .setSuper(FRAGMENT_DESCRIPTOR)
+            .transform(),
+        transformer(MyZygotePreload.class)
+            .replaceClassDescriptorInMembers(
+                descriptor(ApplicationInfo.class), APPLICATION_INFO_DESCRIPTOR)
+            .setImplementsClassDescriptors(ZYGOTE_PRELOAD_DESCRIPTOR)
+            .transform());
+  }
+
+  private static List<byte[]> getTransformedLibraryClasses() throws Exception {
+    return ImmutableList.of(
+        transformer(ApplicationInfo.class)
+            .setClassDescriptor(APPLICATION_INFO_DESCRIPTOR)
+            .transform(),
+        transformer(Fragment.class).setClassDescriptor(FRAGMENT_DESCRIPTOR).transform(),
+        transformer(Platform.class)
+            .replaceClassDescriptorInMembers(descriptor(Fragment.class), FRAGMENT_DESCRIPTOR)
+            .replaceClassDescriptorInMethodInstructions(
+                descriptor(Fragment.class), FRAGMENT_DESCRIPTOR)
+            .replaceClassDescriptorInMembers(
+                descriptor(ZygotePreload.class), ZYGOTE_PRELOAD_DESCRIPTOR)
+            .replaceClassDescriptorInMethodInstructions(
+                descriptor(ApplicationInfo.class), APPLICATION_INFO_DESCRIPTOR)
+            .replaceClassDescriptorInMethodInstructions(
+                descriptor(ZygotePreload.class), ZYGOTE_PRELOAD_DESCRIPTOR)
+            .transform(),
+        transformer(ZygotePreload.class)
+            .replaceClassDescriptorInMembers(
+                descriptor(ApplicationInfo.class), APPLICATION_INFO_DESCRIPTOR)
+            .setClassDescriptor(ZYGOTE_PRELOAD_DESCRIPTOR)
+            .transform());
   }
 
   private void inspect(CodeInspector inspector) {
     ClassSubject myFragmentClassSubject = inspector.clazz(MyFragment.class);
     assertThat(myFragmentClassSubject, isPresent());
-    assertThat(myFragmentClassSubject.init(), isPresent());
+    assertThat(
+        myFragmentClassSubject.init(),
+        onlyIf(enableModeling || !parameters.canHaveNonReboundConstructorInvoke(), isPresent()));
+
+    ClassSubject myZygotePreloadClassSubject = inspector.clazz(MyZygotePreload.class);
+    assertThat(myZygotePreloadClassSubject, isPresent());
+    assertThat(
+        myZygotePreloadClassSubject.init(),
+        onlyIf(enableModeling || !parameters.canHaveNonReboundConstructorInvoke(), isPresent()));
   }
 
+  // Library classes.
+
+  public abstract static class ApplicationInfo {}
+
   public abstract static class Fragment {
 
-    public Fragment newInstance() throws Exception {
-      System.out.println("Instantiating");
-      return getClass().getDeclaredConstructor().newInstance();
+    public void onCreate() {
+      System.out.println("Fragment.onCreate()");
     }
   }
 
+  public interface ZygotePreload {
+
+    void doPreload(ApplicationInfo applicationInfo);
+  }
+
+  public static class Platform {
+
+    public static void accept(Fragment fragment) throws Exception {
+      Fragment newFragment = fragment.getClass().getDeclaredConstructor().newInstance();
+      newFragment.onCreate();
+    }
+
+    public static void accept(ZygotePreload runnable) throws Exception {
+      ZygotePreload newZygotePreload = runnable.getClass().getDeclaredConstructor().newInstance();
+      newZygotePreload.doPreload(null);
+    }
+  }
+
+  // Program classes.
+
   public static class Main {
 
     public static void main(String[] args) throws Exception {
-      new MyFragment().newInstance();
+      Platform.accept(new MyFragment());
+      Platform.accept(new MyZygotePreload());
     }
   }
 
@@ -71,5 +198,21 @@
   public static class MyFragment extends Fragment {
 
     public MyFragment() {}
+
+    @Override
+    public void onCreate() {
+      super.onCreate();
+      System.out.println("MyFragment.onCreate()");
+    }
+  }
+
+  public static class MyZygotePreload implements ZygotePreload {
+
+    public MyZygotePreload() {}
+
+    @Override
+    public void doPreload(ApplicationInfo applicationInfo) {
+      System.out.println("MyZygotePreload.doPreload()");
+    }
   }
 }