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