Disable desugaring on Multidex

Change-Id: Ie8f3005b6c93eff8226cd85c00b727832b1ef3b9
diff --git a/.gitignore b/.gitignore
index 405e837..59981e8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -130,6 +130,8 @@
 third_party/kotlin/kotlin-compiler-dev
 third_party/kotlinx-coroutines-1.3.6.tar.gz
 third_party/kotlinx-coroutines-1.3.6
+third_party/multidex
+third_party/multidex.tar.gz
 third_party/nest/*
 third_party/openjdk/desugar_jdk_libs
 third_party/openjdk/desugar_jdk_libs.tar.gz
diff --git a/build.gradle b/build.gradle
index 812b438..eca19a7 100644
--- a/build.gradle
+++ b/build.gradle
@@ -8,8 +8,8 @@
 import dx.DxTask
 import net.ltgt.gradle.errorprone.CheckSeverity
 import org.gradle.internal.os.OperatingSystem
-import smali.SmaliTask
 import tasks.DownloadDependency
+import smali.SmaliTask
 import tasks.GetJarsFromConfiguration
 import utils.Utils
 
@@ -378,6 +378,7 @@
                 "kotlin/kotlin-compiler-1.6.0",
                 "kotlin/kotlin-compiler-1.7.0",
                 "kotlinx-coroutines-1.3.6",
+                "multidex",
                 "openjdk/openjdk-rt-1.8",
                 "openjdk/desugar_jdk_libs",
                 "openjdk/desugar_jdk_libs_11",
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs_nio.json b/src/library_desugar/jdk11/desugar_jdk_libs_nio.json
index 423727f..9bc2704 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs_nio.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs_nio.json
@@ -419,12 +419,6 @@
       }
     },
     {
-      "api_level_below_or_equal": 19,
-      "dont_retarget": [
-        "android.support.multidex.MultiDexExtractor$ExtractedDex"
-      ]
-    },
-    {
       "api_level_below_or_equal": 18,
       "rewrite_prefix": {
         "java.lang.DesugarCharacter": "j$.lang.DesugarCharacter"
diff --git a/src/main/java/com/android/tools/r8/dex/CodeToKeep.java b/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
index a5d6098..24d6362 100644
--- a/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
+++ b/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
@@ -98,7 +98,7 @@
       DexType baseType = method.holder.toBaseType(appView.dexItemFactory());
       if (shouldKeep(baseType)) {
         keepClass(baseType);
-        if (!method.holder.isArrayType()) {
+        if (!method.holder.isArrayType() && !isVivifiedType(baseType)) {
           toKeep.get(method.holder).methods.add(method);
         }
       }
@@ -117,7 +117,7 @@
       DexType baseType = field.holder.toBaseType(appView.dexItemFactory());
       if (shouldKeep(baseType)) {
         keepClass(baseType);
-        if (!field.holder.isArrayType()) {
+        if (!field.holder.isArrayType() && !isVivifiedType(baseType)) {
           toKeep.get(field.holder).fields.add(field);
         }
       }
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 3ee7c50..d838596 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -469,6 +469,45 @@
           floatBufferType,
           doubleBufferType);
 
+  private static final List<String> MULTIDEX_PREFIXES =
+      ImmutableList.of("androidx/", "android/support/");
+  private static final List<String> MULTIDEX_SUFFIXES =
+      ImmutableList.of(
+          "multidex/MultiDex$V14$ElementConstructor;",
+          "multidex/MultiDex$V14$ICSElementConstructor;",
+          "multidex/MultiDex$V14$JBMR11ElementConstructor;",
+          "multidex/MultiDex$V14$JBMR2ElementConstructor;",
+          "multidex/MultiDex$V14;",
+          "multidex/MultiDex$V19;",
+          "multidex/MultiDex$V21_PLUS;",
+          "multidex/MultiDex$V4;",
+          "multidex/MultiDexApplication;",
+          "multidex/MultiDexExtractor$1;",
+          "multidex/MultiDexExtractor$ExtractedDex;",
+          "multidex/MultiDexExtractor;",
+          "multidex/MultiDex;",
+          "multidex/ZipUtil;",
+          "multidex/ZipUtil$CentralDirectory;");
+  private static final List<String> MULTIDEX_INSTRUMENTATION =
+      ImmutableList.of(
+          "Landroid/support/multidex/instrumentation/BuildConfig;",
+          "Landroid/test/runner/MultiDexTestRunner;");
+
+  private List<DexType> createMultiDexTypes() {
+    ImmutableList.Builder<DexType> builder = ImmutableList.builder();
+    for (String prefix : MULTIDEX_PREFIXES) {
+      for (String suffix : MULTIDEX_SUFFIXES) {
+        builder.add(createType("L" + prefix + suffix));
+      }
+    }
+    for (String typeString : MULTIDEX_INSTRUMENTATION) {
+      builder.add(createType(typeString));
+    }
+    return builder.build();
+  }
+
+  public List<DexType> multiDexTypes = createMultiDexTypes();
+
   public final DexType doubleConsumer =
       createStaticallyKnownType("Ljava/util/function/DoubleConsumer;");
   public final DexType longConsumer =
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringCollection.java
index 09b456b..8770cd1 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringCollection.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPICallbackSynthesizer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.disabledesugarer.DesugaredLibraryDisableDesugarerPostProcessor;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeterPostProcessor;
 import com.android.tools.r8.ir.desugar.itf.InterfaceMethodProcessorFacade;
 import com.android.tools.r8.ir.desugar.records.RecordDesugaring;
@@ -72,6 +73,11 @@
       if (recordRewriter != null) {
         desugarings.add(recordRewriter);
       }
+      DesugaredLibraryDisableDesugarerPostProcessor disableDesugarer =
+          DesugaredLibraryDisableDesugarerPostProcessor.create(appView);
+      if (disableDesugarer != null) {
+        desugarings.add(disableDesugarer);
+      }
       if (desugarings.isEmpty()) {
         return empty();
       }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
index a42d6e5..54837a8 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
@@ -17,6 +17,7 @@
 import com.android.tools.r8.ir.desugar.apimodel.ApiInvokeOutlinerDesugaring;
 import com.android.tools.r8.ir.desugar.constantdynamic.ConstantDynamicInstructionDesugaring;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.disabledesugarer.DesugaredLibraryDisableDesugarer;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeter;
 import com.android.tools.r8.ir.desugar.icce.AlwaysThrowingInstructionDesugaring;
 import com.android.tools.r8.ir.desugar.invokespecial.InvokeSpecialToSelfDesugaring;
@@ -57,6 +58,7 @@
   private final DesugaredLibraryRetargeter desugaredLibraryRetargeter;
   private final InterfaceMethodRewriter interfaceMethodRewriter;
   private final DesugaredLibraryAPIConverter desugaredLibraryAPIConverter;
+  private final DesugaredLibraryDisableDesugarer disableDesugarer;
   private final AndroidApiLevelCompute apiLevelCompute;
 
   NonEmptyCfInstructionDesugaringCollection(
@@ -76,6 +78,7 @@
       this.desugaredLibraryRetargeter = null;
       this.interfaceMethodRewriter = null;
       this.desugaredLibraryAPIConverter = null;
+      this.disableDesugarer = null;
       return;
     }
     this.nestBasedAccessDesugaring = NestBasedAccessDesugaring.create(appView);
@@ -87,6 +90,10 @@
     if (desugaredLibraryRetargeter != null) {
       desugarings.add(desugaredLibraryRetargeter);
     }
+    disableDesugarer = DesugaredLibraryDisableDesugarer.create(appView);
+    if (disableDesugarer != null) {
+      desugarings.add(disableDesugarer);
+    }
     if (appView.options().apiModelingOptions().enableOutliningOfMethods) {
       yieldingDesugarings.add(new ApiInvokeOutlinerDesugaring(appView, apiLevelCompute));
     }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java
index eeebd32..2d72b93 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java
@@ -103,6 +103,9 @@
     if (isAPIConversionSyntheticType(context.getHolderType(), wrapperSynthesizor, appView)) {
       return false;
     }
+    if (appView.dexItemFactory().multiDexTypes.contains(context.getHolderType())) {
+      return false;
+    }
     return shouldRewriteInvoke(instruction.asInvoke(), context);
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/disabledesugarer/DesugaredLibraryDisableDesugarer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/disabledesugarer/DesugaredLibraryDisableDesugarer.java
new file mode 100644
index 0000000..bd4b771
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/disabledesugarer/DesugaredLibraryDisableDesugarer.java
@@ -0,0 +1,101 @@
+// Copyright (c) 2022, 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.ir.desugar.desugaredlibrary.disabledesugarer;
+
+import com.android.tools.r8.cf.code.CfFieldInstruction;
+import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.cf.code.CfTypeInstruction;
+import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexField;
+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.ProgramMethod;
+import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
+import com.android.tools.r8.ir.desugar.CfInstructionDesugaringCollection;
+import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
+import com.android.tools.r8.ir.desugar.FreshLocalProvider;
+import com.android.tools.r8.ir.desugar.LocalStackAllocator;
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * Disables the rewriting of types in specific classes declared in the desugared library
+ * specification, typically classes that are used pre-native multidex.
+ */
+public class DesugaredLibraryDisableDesugarer implements CfInstructionDesugaring {
+
+  private final AppView<?> appView;
+  private final DesugaredLibraryDisableDesugarerHelper helper;
+
+  public DesugaredLibraryDisableDesugarer(AppView<?> appView) {
+    this.appView = appView;
+    this.helper = new DesugaredLibraryDisableDesugarerHelper(appView);
+  }
+
+  public static DesugaredLibraryDisableDesugarer create(AppView<?> appView) {
+    return DesugaredLibraryDisableDesugarerHelper.shouldCreate(appView)
+        ? new DesugaredLibraryDisableDesugarer(appView)
+        : null;
+  }
+
+  @Override
+  public Collection<CfInstruction> desugarInstruction(
+      CfInstruction instruction,
+      FreshLocalProvider freshLocalProvider,
+      LocalStackAllocator localStackAllocator,
+      CfInstructionDesugaringEventConsumer eventConsumer,
+      ProgramMethod context,
+      MethodProcessingContext methodProcessingContext,
+      CfInstructionDesugaringCollection desugaringCollection,
+      DexItemFactory dexItemFactory) {
+    CfInstruction replacement = rewriteInstruction(instruction, context);
+    return replacement == null ? null : Collections.singleton(replacement);
+  }
+
+  @Override
+  public boolean needsDesugaring(CfInstruction instruction, ProgramMethod context) {
+    return rewriteInstruction(instruction, context) != null;
+  }
+
+  private CfInstruction rewriteInstruction(CfInstruction instruction, ProgramMethod context) {
+    if (!appView.dexItemFactory().multiDexTypes.contains(context.getHolderType())) {
+      return null;
+    }
+    if (instruction.isTypeInstruction()) {
+      return rewriteTypeInstruction(instruction.asTypeInstruction());
+    }
+    if (instruction.isFieldInstruction()) {
+      return rewriteFieldInstruction(instruction.asFieldInstruction(), context);
+    }
+    if (instruction.isInvoke()) {
+      return rewriteInvokeInstruction(instruction.asInvoke(), context);
+    }
+    return null;
+  }
+
+  private CfInstruction rewriteInvokeInstruction(CfInvoke invoke, ProgramMethod context) {
+    DexMethod rewrittenMethod =
+        helper.rewriteMethod(invoke.getMethod(), invoke.isInterface(), context);
+    return rewrittenMethod != null
+        ? new CfInvoke(invoke.getOpcode(), rewrittenMethod, invoke.isInterface())
+        : null;
+  }
+
+  private CfFieldInstruction rewriteFieldInstruction(
+      CfFieldInstruction fieldInstruction, ProgramMethod context) {
+    DexField rewrittenField = helper.rewriteField(fieldInstruction.getField(), context);
+    return rewrittenField != null ? fieldInstruction.createWithField(rewrittenField) : null;
+  }
+
+  private CfInstruction rewriteTypeInstruction(CfTypeInstruction typeInstruction) {
+    DexType rewrittenType = helper.rewriteType(typeInstruction.getType());
+    return rewrittenType != typeInstruction.getType()
+        ? typeInstruction.withType(rewrittenType)
+        : null;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/disabledesugarer/DesugaredLibraryDisableDesugarerHelper.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/disabledesugarer/DesugaredLibraryDisableDesugarerHelper.java
new file mode 100644
index 0000000..f4526ae
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/disabledesugarer/DesugaredLibraryDisableDesugarerHelper.java
@@ -0,0 +1,118 @@
+// Copyright (c) 2022, 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.ir.desugar.desugaredlibrary.disabledesugarer;
+
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter.methodWithVivifiedTypeInSignature;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter.vivifiedTypeFor;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMember;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.FieldResolutionResult;
+import com.android.tools.r8.graph.MemberResolutionResult;
+import com.android.tools.r8.graph.MethodResolutionResult;
+import com.android.tools.r8.graph.ProgramDefinition;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.SuccessfulMemberResolutionResult;
+
+public class DesugaredLibraryDisableDesugarerHelper {
+
+  private final AppView<?> appView;
+
+  public DesugaredLibraryDisableDesugarerHelper(AppView<?> appView) {
+    this.appView = appView;
+  }
+
+  static boolean shouldCreate(AppView<?> appView) {
+    for (DexType multiDexType : appView.dexItemFactory().multiDexTypes) {
+      if (appView.appInfo().definitionForWithoutExistenceAssert(multiDexType) != null) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  DexMethod rewriteMethod(DexMethod method, boolean isInterface, ProgramMethod context) {
+    DexType newHolder = rewriteType(method.getHolderType());
+    DexMethod rewrittenMethod = methodWithVivifiedTypeInSignature(method, newHolder, appView);
+    if (rewrittenMethod == method) {
+      return null;
+    }
+    MethodResolutionResult methodResolutionResult =
+        appView.appInfoForDesugaring().resolveMethodLegacy(method, isInterface);
+    warnIfInvalidResolution(methodResolutionResult, method, context);
+    return rewrittenMethod;
+  }
+
+  DexField rewriteField(DexField field, ProgramDefinition context) {
+    if (isRewrittenType(field.getHolderType())) {
+      // This case never happens within the supported set of classes. We can support it if required.
+      appView
+          .options()
+          .reporter
+          .error("Cannot prevent the desugaring of " + field + " in " + context);
+      return null;
+    }
+    DexType rewrittenFieldType = rewriteType(field.getType());
+    if (rewrittenFieldType == field.getType()) {
+      return null;
+    }
+    FieldResolutionResult fieldResolutionResult =
+        appView.appInfoForDesugaring().resolveField(field);
+    warnIfInvalidResolution(fieldResolutionResult, field, context);
+    return field.withType(rewrittenFieldType, appView.dexItemFactory());
+  }
+
+  /**
+   * All rewritings should apply within private members of multidex types or with library accesses,
+   * else we are leaving escapes of non rewritten types in the program which will lead to runtime
+   * errors. Note that this is conservative and we could allow more escapes if required.
+   */
+  private boolean isValidResolution(MemberResolutionResult<?, ?> resolutionResult) {
+    if (resolutionResult == null || !resolutionResult.isSuccessfulMemberResolutionResult()) {
+      return false;
+    }
+    SuccessfulMemberResolutionResult<?, ?> successfulResult =
+        resolutionResult.asSuccessfulMemberResolutionResult();
+    if (successfulResult.getResolvedHolder().isLibraryClass()) {
+      return true;
+    }
+    return appView
+            .dexItemFactory()
+            .multiDexTypes
+            .contains(successfulResult.getResolvedHolder().getType())
+        && successfulResult.getResolvedMember().isPrivate();
+  }
+
+  private void warnIfInvalidResolution(
+      MemberResolutionResult<?, ?> resolutionResult,
+      DexMember<?, ?> member,
+      ProgramDefinition context) {
+    if (isValidResolution(resolutionResult)) {
+      return;
+    }
+    appView
+        .reporter()
+        .warning(
+            "Preventing the desugaring of "
+                + member
+                + " in "
+                + context
+                + " which could be an invalid escape into the program. ");
+  }
+
+  DexType rewriteType(DexType type) {
+    if (isRewrittenType(type)) {
+      return vivifiedTypeFor(type, appView);
+    }
+    return type;
+  }
+
+  boolean isRewrittenType(DexType type) {
+    return appView.typeRewriter.hasRewrittenType(type, appView);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/disabledesugarer/DesugaredLibraryDisableDesugarerPostProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/disabledesugarer/DesugaredLibraryDisableDesugarerPostProcessor.java
new file mode 100644
index 0000000..2e26d1e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/disabledesugarer/DesugaredLibraryDisableDesugarerPostProcessor.java
@@ -0,0 +1,69 @@
+// Copyright (c) 2022, 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.ir.desugar.desugaredlibrary.disabledesugarer;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedField;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaring;
+import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+
+public class DesugaredLibraryDisableDesugarerPostProcessor implements CfPostProcessingDesugaring {
+
+  private final AppView<?> appView;
+  private final DesugaredLibraryDisableDesugarerHelper helper;
+
+  public DesugaredLibraryDisableDesugarerPostProcessor(AppView<?> appView) {
+    this.appView = appView;
+    this.helper = new DesugaredLibraryDisableDesugarerHelper(appView);
+  }
+
+  public static DesugaredLibraryDisableDesugarerPostProcessor create(AppView<?> appView) {
+    return DesugaredLibraryDisableDesugarerHelper.shouldCreate(appView)
+        ? new DesugaredLibraryDisableDesugarerPostProcessor(appView)
+        : null;
+  }
+
+  @Override
+  public void postProcessingDesugaring(
+      Collection<DexProgramClass> programClasses,
+      CfPostProcessingDesugaringEventConsumer eventConsumer,
+      ExecutorService executorService)
+      throws ExecutionException {
+    for (DexType multiDexType : appView.dexItemFactory().multiDexTypes) {
+      DexClass clazz =
+          appView.appInfoForDesugaring().definitionForWithoutExistenceAssert(multiDexType);
+      if (clazz != null && clazz.isProgramClass()) {
+        rewriteMultiDexProgramClass(clazz.asProgramClass());
+      }
+    }
+  }
+
+  private void rewriteMultiDexProgramClass(DexProgramClass multiDexProgramClass) {
+    multiDexProgramClass.setInstanceFields(
+        rewriteFields(multiDexProgramClass.instanceFields(), multiDexProgramClass));
+    multiDexProgramClass.setStaticFields(
+        rewriteFields(multiDexProgramClass.staticFields(), multiDexProgramClass));
+  }
+
+  private DexEncodedField[] rewriteFields(
+      List<DexEncodedField> fields, DexProgramClass multiDexProgramClass) {
+    List<DexEncodedField> newFields = new ArrayList<>();
+    for (DexEncodedField field : fields) {
+      DexField rewrittenField = helper.rewriteField(field.getReference(), multiDexProgramClass);
+      newFields.add(
+          rewrittenField != null ? field.toTypeSubstitutedField(appView, rewrittenField) : field);
+    }
+    return newFields.toArray(DexEncodedField[]::new);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
index 302c08c..f02550b 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
@@ -175,11 +175,7 @@
 
   private InvokeRetargetingResult computeNewInvokeTarget(
       CfInvoke instruction, ProgramMethod context) {
-    if (appView
-        .options()
-        .machineDesugaredLibrarySpecification
-        .getDontRetarget()
-        .contains(context.getContextType())) {
+    if (appView.dexItemFactory().multiDexTypes.contains(context.getContextType())) {
       return NO_REWRITING;
     }
     CfInvoke cfInvoke = instruction.asInvoke();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java
index bfbf6a8..53b8207 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java
@@ -125,11 +125,7 @@
         // The class has already been desugared.
         continue;
       }
-      if (appView
-          .options()
-          .machineDesugaredLibrarySpecification
-          .getDontRetarget()
-          .contains(clazz.getType())) {
+      if (appView.dexItemFactory().multiDexTypes.contains(clazz.getType())) {
         continue;
       }
       clazz.addExtraInterfaces(
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MultiDexTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MultiDexTest.java
new file mode 100644
index 0000000..f5d5449
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MultiDexTest.java
@@ -0,0 +1,106 @@
+// Copyright (c) 2022, 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.desugar.desugaredlibrary;
+
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11_PATH;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK8;
+import static org.junit.Assert.assertFalse;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import com.google.common.collect.ImmutableList;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class MultiDexTest extends DesugaredLibraryTestBase {
+
+  private static final String[] JAR_NAMES =
+      new String[] {
+        "multidex-1.0.3.jar",
+        "multidex-instrumentation-1.0.3.jar",
+        "multidex-2.0.1.jar",
+        "multidex-instrumentation-2.0.0.jar"
+      };
+  private static final List<Path> MULTIDEX_JARS =
+      Arrays.stream(JAR_NAMES)
+          .map(jar -> Paths.get(ToolHelper.THIRD_PARTY_DIR + "multidex/" + jar))
+          .collect(Collectors.toList());
+
+  private final TestParameters parameters;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+  private final Path multidexJar;
+
+  @Parameters(name = "{0}, spec: {1}, {2}, {3}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+        ImmutableList.of(JDK8, JDK11, JDK11_PATH),
+        ImmutableList.of(D8_L8DEBUG),
+        MULTIDEX_JARS);
+  }
+
+  public MultiDexTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification,
+      Path multidexJar) {
+    this.parameters = parameters;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+    this.multidexJar = multidexJar;
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+        .addProgramFiles(multidexJar)
+        .compile()
+        .inspect(this::assertNoJ$Reference);
+  }
+
+  private void assertNoJ$Reference(CodeInspector inspector) {
+    String prefix = "j$";
+    for (FoundClassSubject clazz : inspector.allClasses()) {
+      clazz.forAllFields(f -> assertFalse(f.type().toString().startsWith(prefix)));
+      clazz.forAllMethods(
+          m -> {
+            if (m.hasCode()) {
+              for (InstructionSubject instruction : m.instructions()) {
+                if (instruction.isInvoke()) {
+                  DexMethod method = instruction.getMethod();
+                  for (DexType referencedType : method.getReferencedTypes()) {
+                    assertFalse(referencedType.toString().startsWith(prefix));
+                  }
+                  assertFalse(method.getHolderType().toString().startsWith(prefix));
+                }
+                if (instruction.isFieldAccess()) {
+                  DexField field = instruction.getField();
+                  assertFalse(field.getType().toString().startsWith(prefix));
+                }
+              }
+            }
+          });
+    }
+  }
+}
diff --git a/third_party/multidex.tar.gz.sha1 b/third_party/multidex.tar.gz.sha1
new file mode 100644
index 0000000..7d22fb6
--- /dev/null
+++ b/third_party/multidex.tar.gz.sha1
@@ -0,0 +1 @@
+f0ea06be076aa1fc45ea5451188121d8e8b992e2
\ No newline at end of file