Merge commit '1e6ec6788aec5b267c99d2d71771dc2c0499a15f' into dev-release
diff --git a/.gitignore b/.gitignore index d76279a..ae1be52 100644 --- a/.gitignore +++ b/.gitignore
@@ -40,6 +40,8 @@ third_party/android_jar/lib third_party/android_jar/lib-v[0-9][0-9] third_party/android_jar/lib-v[0-9][0-9].tar.gz +third_party/android_jar/lib-master +third_party/android_jar/lib-master.tar.gz third_party/android_jar/lib.tar.gz third_party/android_jar/libcore_latest third_party/android_jar/libcore_latest.tar.gz @@ -63,6 +65,8 @@ third_party/benchmarks/wordpress.tar.gz third_party/binary_compatibility_tests/compiler_api_tests.tar.gz third_party/binary_compatibility_tests/compiler_api_tests +third_party/bundletool/bundletool-1.11.0 +third_party/bundletool/bundletool-1.11.0.tar.gz third_party/cf_segments third_party/cf_segments.tar.gz third_party/chrome/* @@ -272,6 +276,8 @@ tools/*/host/art-12.0.0-beta4.tar.gz tools/*/host/art-13-dev tools/*/host/art-13-dev.tar.gz +tools/*/host/art-master +tools/*/host/art-master.tar.gz tools/*/art.tar.gz tools/*/dalvik tools/*/dalvik-4.0.4
diff --git a/Regress78493232.jar b/Regress78493232.jar deleted file mode 100644 index 6dee6f0..0000000 --- a/Regress78493232.jar +++ /dev/null Binary files differ
diff --git a/build.gradle b/build.gradle index a138d84..8f84e7f 100644 --- a/build.gradle +++ b/build.gradle
@@ -349,9 +349,11 @@ "android_jar/lib-v31", "android_jar/lib-v32", "android_jar/lib-v33", + "android_jar/lib-master", "api_database/api_database", "api-outlining/simple-app-dump", "binary_compatibility_tests/compiler_api_tests", + "bundletool/bundletool-1.11.0", "core-lambda-stubs", "dagger/2.41", "dart-sdk", @@ -410,6 +412,7 @@ "linux/art-10.0.0", "linux/host/art-12.0.0-beta4", "linux/host/art-13-dev", + "linux/host/art-master", "linux/dalvik", "linux/dalvik-4.0.4", "${osString}/dx",
diff --git a/scripts/update-host-art.sh b/scripts/update-host-art.sh index 58165cd..44e5a49 100755 --- a/scripts/update-host-art.sh +++ b/scripts/update-host-art.sh
@@ -91,9 +91,24 @@ ANDROID_TARGET_BUILD=$ANDROID_CHECKOUT/out/target DEST=$DEST_ROOT/$ART_DIR -# Clean out the previous version of Art +# Clean out the previous version of Art. rm -rf $DEST +# Copy build_spec.xml for documentation. +mkdir -p $DEST +if [ -f $ANDROID_CHECKOUT/build_spec.xml ]; then + cp $ANDROID_CHECKOUT/build_spec.xml $DEST + # Remove the build spec to ensure it is created anew for a new build. + rm $ANDROID_CHECKOUT/build_spec.xml +else + echo "File $ANDROID_CHECKOUT/build_spec.xml not found. Please run" + echo + echo " repo manifest -r -o build_spec.xml" + echo + echo "in $ANDROID_CHECKOUT" + exit 1 +fi + # Required binaries and scripts. mkdir -p $DEST/bin if [ -f $ANDROID_HOST_BUILD/bin/art ]; then
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs_path.json b/src/library_desugar/jdk11/desugar_jdk_libs_path.json index e1298de..4128a53 100644 --- a/src/library_desugar/jdk11/desugar_jdk_libs_path.json +++ b/src/library_desugar/jdk11/desugar_jdk_libs_path.json
@@ -437,6 +437,14 @@ "j$.util.Optional": "java.util.Optional" } } + }, + { + "api_level_below_or_equal": 18, + "retarget_static_field": { + "sun.nio.cs.US_ASCII sun.nio.cs.US_ASCII#INSTANCE": "java.nio.charset.Charset java.nio.charset.StandardCharsets#US_ASCII", + "sun.nio.cs.ISO_8859_1 sun.nio.cs.ISO_8859_1#INSTANCE": "java.nio.charset.Charset java.nio.charset.StandardCharsets#ISO_8859_1", + "sun.nio.cs.UTF_8 sun.nio.cs.UTF_8#INSTANCE": "java.nio.charset.Charset java.nio.charset.StandardCharsets#UTF_8" + } } ], "shrinker_config": [
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java index 03ec1dd..8be1456 100644 --- a/src/main/java/com/android/tools/r8/D8.java +++ b/src/main/java/com/android/tools/r8/D8.java
@@ -11,7 +11,7 @@ import com.android.tools.r8.dex.ApplicationWriter; import com.android.tools.r8.dex.Marker; import com.android.tools.r8.dex.Marker.Tool; -import com.android.tools.r8.experimental.startup.StartupInstrumentation; +import com.android.tools.r8.experimental.startup.instrumentation.StartupInstrumentation; import com.android.tools.r8.graph.AppInfo; import com.android.tools.r8.graph.AppServices; import com.android.tools.r8.graph.AppView;
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java index 7498045..9818440 100644 --- a/src/main/java/com/android/tools/r8/R8Command.java +++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -10,7 +10,6 @@ import com.android.tools.r8.dump.DumpOptions; import com.android.tools.r8.errors.DexFileOverflowDiagnostic; import com.android.tools.r8.experimental.graphinfo.GraphConsumer; -import com.android.tools.r8.experimental.startup.StartupConfiguration; import com.android.tools.r8.features.FeatureSplitConfiguration; import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.inspector.Inspector; @@ -975,11 +974,6 @@ internal.featureSplitConfiguration = featureSplitConfiguration; - internal - .getStartupOptions() - .setStartupConfiguration( - StartupConfiguration.createStartupConfiguration(getDexItemFactory(), getReporter())); - internal.syntheticProguardRulesConsumer = syntheticProguardRulesConsumer; internal.outputInspections = InspectorImpl.wrapInspections(getOutputInspections());
diff --git a/src/main/java/com/android/tools/r8/StartupProfileProvider.java b/src/main/java/com/android/tools/r8/StartupProfileProvider.java new file mode 100644 index 0000000..fc5e4b1 --- /dev/null +++ b/src/main/java/com/android/tools/r8/StartupProfileProvider.java
@@ -0,0 +1,13 @@ +// 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; + +/** Interface for providing a startup profile to the compiler. */ +@FunctionalInterface +public interface StartupProfileProvider { + + /** Return the startup profile. */ + String get(); +}
diff --git a/src/main/java/com/android/tools/r8/StringResource.java b/src/main/java/com/android/tools/r8/StringResource.java index a28f936..515f2ab 100644 --- a/src/main/java/com/android/tools/r8/StringResource.java +++ b/src/main/java/com/android/tools/r8/StringResource.java
@@ -33,7 +33,7 @@ * * @param file Path of file with UTF-8 encoded text. */ - static StringResource fromFile(Path file) { + static FileResource fromFile(Path file) { return fromFile(file, StandardCharsets.UTF_8); } @@ -45,7 +45,7 @@ * @param file Path of file. * @param charset Charset coding of file. */ - static StringResource fromFile(Path file, Charset charset) { + static FileResource fromFile(Path file, Charset charset) { return new FileResource(file, charset); } @@ -74,7 +74,7 @@ } @Override - public String getString() throws ResourceException { + public String getString() { return content; } } @@ -105,5 +105,13 @@ throw new ResourceException(origin, e); } } + + public String getStringWithRuntimeException() { + try { + return getString(); + } catch (ResourceException e) { + throw new RuntimeException(e); + } + } } }
diff --git a/src/main/java/com/android/tools/r8/androidapi/AndroidApiLevelCompute.java b/src/main/java/com/android/tools/r8/androidapi/AndroidApiLevelCompute.java index fec4b65..eaf3a3d 100644 --- a/src/main/java/com/android/tools/r8/androidapi/AndroidApiLevelCompute.java +++ b/src/main/java/com/android/tools/r8/androidapi/AndroidApiLevelCompute.java
@@ -20,7 +20,7 @@ public AndroidApiLevelCompute() { knownApiLevelCache = new KnownApiLevel[AndroidApiLevel.LATEST.getLevel() + 1]; for (AndroidApiLevel value : AndroidApiLevel.values()) { - if (value != AndroidApiLevel.ANDROID_PLATFORM) { + if (value != AndroidApiLevel.ANDROID_PLATFORM && value != AndroidApiLevel.MASTER) { knownApiLevelCache[value.getLevel()] = new KnownApiLevel(value); } } @@ -30,6 +30,9 @@ if (apiLevel == AndroidApiLevel.ANDROID_PLATFORM) { return ComputedApiLevel.platform(); } + if (apiLevel == AndroidApiLevel.MASTER) { + return ComputedApiLevel.master(); + } return knownApiLevelCache[apiLevel.getLevel()]; } @@ -55,9 +58,13 @@ } public ComputedApiLevel computeInitialMinApiLevel(InternalOptions options) { - return options.getMinApiLevel() == AndroidApiLevel.ANDROID_PLATFORM - ? ComputedApiLevel.platform() - : new KnownApiLevel(options.getMinApiLevel()); + if (options.getMinApiLevel() == AndroidApiLevel.ANDROID_PLATFORM) { + return ComputedApiLevel.platform(); + } + if (options.getMinApiLevel() == AndroidApiLevel.MASTER) { + return ComputedApiLevel.master(); + } + return new KnownApiLevel(options.getMinApiLevel()); } public ComputedApiLevel getPlatformApiLevelOrUnknown(AppView<?> appView) {
diff --git a/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java b/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java index b1b581b..50855bb 100644 --- a/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java +++ b/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java
@@ -76,7 +76,10 @@ if (reference.getContextType() == factory.objectType) { return appView.computedMinApiLevel(); } - if (appView.options().machineDesugaredLibrarySpecification.isSupported(reference)) { + if (appView + .options() + .machineDesugaredLibrarySpecification + .isContextTypeMaintainedOrRewritten(reference)) { // If we end up desugaring the reference, the library classes is bridged by j$ which is part // of the program. return appView.computedMinApiLevel();
diff --git a/src/main/java/com/android/tools/r8/androidapi/ComputedApiLevel.java b/src/main/java/com/android/tools/r8/androidapi/ComputedApiLevel.java index 3ff4dcb..7562429 100644 --- a/src/main/java/com/android/tools/r8/androidapi/ComputedApiLevel.java +++ b/src/main/java/com/android/tools/r8/androidapi/ComputedApiLevel.java
@@ -27,6 +27,10 @@ return KnownApiLevel.PLATFORM_INSTANCE; } + static KnownApiLevel master() { + return KnownApiLevel.MASTER_INSTANCE; + } + default boolean isNotSetApiLevel() { return false; } @@ -151,6 +155,8 @@ private static final KnownApiLevel PLATFORM_INSTANCE = new KnownApiLevel(AndroidApiLevel.ANDROID_PLATFORM); + private static final KnownApiLevel MASTER_INSTANCE = new KnownApiLevel(AndroidApiLevel.MASTER); + private final AndroidApiLevel apiLevel; KnownApiLevel(AndroidApiLevel apiLevel) {
diff --git a/src/main/java/com/android/tools/r8/cf/LoadStoreHelper.java b/src/main/java/com/android/tools/r8/cf/LoadStoreHelper.java index faf9046..f180e60 100644 --- a/src/main/java/com/android/tools/r8/cf/LoadStoreHelper.java +++ b/src/main/java/com/android/tools/r8/cf/LoadStoreHelper.java
@@ -204,11 +204,17 @@ } add(store, storeBlock, instruction.getPosition(), it); if (hasCatchHandlers && !instruction.instructionTypeCanThrow()) { - it.split(this.code, this.blockIterator); - this.blockIterator.previous(); + splitAfterStoredOutValue(it); } } + // DebugLocalWrite encodes a store and it needs to consistently split out the catch range after + // its store. + public void splitAfterStoredOutValue(InstructionListIterator it) { + it.split(this.code, this.blockIterator); + this.blockIterator.previous(); + } + public void popOutType(DexType type, Instruction instruction, InstructionListIterator it) { popOutValue(createStackValue(type, 0), instruction, it); }
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java index b0d4999..4932691 100644 --- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java +++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -21,8 +21,10 @@ import com.android.tools.r8.debuginfo.DebugRepresentation.DebugRepresentationPredicate; import com.android.tools.r8.dex.FileWriter.ByteBufferResult; import com.android.tools.r8.dex.VirtualFile.FilePerInputClassDistributor; +import com.android.tools.r8.dex.VirtualFile.ItemUseInfo; import com.android.tools.r8.errors.CompilationError; import com.android.tools.r8.experimental.startup.StartupCompleteness; +import com.android.tools.r8.experimental.startup.StartupOrder; import com.android.tools.r8.features.FeatureSplitConfiguration.DataResourceProvidersAndConsumer; import com.android.tools.r8.graph.AppServices; import com.android.tools.r8.graph.AppView; @@ -34,6 +36,7 @@ import com.android.tools.r8.graph.DexEncodedArray; import com.android.tools.r8.graph.DexEncodedField; import com.android.tools.r8.graph.DexEncodedMethod; +import com.android.tools.r8.graph.DexItem; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexString; import com.android.tools.r8.graph.DexType; @@ -53,6 +56,7 @@ import com.android.tools.r8.utils.Box; import com.android.tools.r8.utils.DescriptorUtils; import com.android.tools.r8.utils.ExceptionUtils; +import com.android.tools.r8.utils.IntBox; import com.android.tools.r8.utils.InternalGlobalSyntheticsProgramConsumer; import com.android.tools.r8.utils.InternalGlobalSyntheticsProgramConsumer.InternalGlobalSyntheticsDexIndexedConsumer; import com.android.tools.r8.utils.InternalGlobalSyntheticsProgramConsumer.InternalGlobalSyntheticsDexPerFileConsumer; @@ -214,7 +218,16 @@ && options.enableMainDexListCheck) { distributor = new VirtualFile.MonoDexDistributor(this, classes, options); } else { - distributor = new VirtualFile.FillFilesDistributor(this, classes, options, executorService); + // Retrieve the startup order for writing the app. In R8, the startup order is created + // up-front to guide optimizations through-out the compilation. In D8, the startup + // order is only used for writing the app, so we create it here for the first time. + StartupOrder startupOrder = + appView.appInfo().hasClassHierarchy() + ? appView.appInfoWithClassHierarchy().getStartupOrder() + : StartupOrder.createInitialStartupOrder(options); + distributor = + new VirtualFile.FillFilesDistributor( + this, classes, options, executorService, startupOrder); } List<VirtualFile> virtualFiles = distributor.run(); @@ -493,12 +506,39 @@ timing.end(); } + private <T extends DexItem> void printUse(Map<T, ItemUseInfo> useMap, String label) { + assert options.testing.calculateItemUseCountInDex; + List<IntBox> notMany = new ArrayList<>(); + for (int i = 0; i < ItemUseInfo.getManyCount() - 1; i++) { + notMany.add(new IntBox()); + } + IntBox many = new IntBox(); + useMap.forEach( + (item, itemUseInfo) -> { + if (itemUseInfo.isMany()) { + many.increment(); + } else { + assert itemUseInfo.getSize() >= 1; + notMany.get(itemUseInfo.getSize() - 1).increment(); + } + }); + + System.out.print(label); + for (int i = 0; i < ItemUseInfo.getManyCount() - 1; i++) { + System.out.print("," + notMany.get(i).get()); + notMany.add(new IntBox()); + } + System.out.println("," + many.get()); + } + private void writeVirtualFile( VirtualFile virtualFile, Timing timing, List<DexString> forcedStrings) { if (virtualFile.isEmpty()) { return; } + printItemUseInfo(virtualFile); + ProgramConsumer consumer; ByteBufferProvider byteBufferProvider; @@ -886,4 +926,39 @@ return value; } } + + private void printItemUseInfo(VirtualFile virtualFile) { + if (options.testing.calculateItemUseCountInDex) { + synchronized (System.out) { + System.out.print("\"Item\""); + for (int i = 0; i < ItemUseInfo.getManyCount() - 1; i++) { + System.out.print(",\"" + (i + 1) + " use\""); + } + System.out.println(",\"Not single use\""); + printUse(virtualFile.indexedItems.stringsUse, "Strings"); + printUse(virtualFile.indexedItems.typesUse, "Types"); + printUse(virtualFile.indexedItems.protosUse, "Protos"); + printUse(virtualFile.indexedItems.fieldsUse, "Fields"); + printUse(virtualFile.indexedItems.methodsUse, "Methods"); + printUse(virtualFile.indexedItems.callSitesUse, "CallSites"); + printUse(virtualFile.indexedItems.methodHandlesUse, "MethodHandles"); + if (options.testing.calculateItemUseCountInDexDumpSingleUseStrings) { + virtualFile.indexedItems.stringsUse.forEach( + (string, info) -> { + if (info.getSizeOrMany() == 1) { + System.out.println(info.getUse().iterator().next() + ": " + string.toString()); + } + }); + } + } + } else { + assert virtualFile.indexedItems.stringsUse.isEmpty(); + assert virtualFile.indexedItems.typesUse.isEmpty(); + assert virtualFile.indexedItems.protosUse.isEmpty(); + assert virtualFile.indexedItems.fieldsUse.isEmpty(); + assert virtualFile.indexedItems.methodsUse.isEmpty(); + assert virtualFile.indexedItems.callSitesUse.isEmpty(); + assert virtualFile.indexedItems.methodHandlesUse.isEmpty(); + } + } }
diff --git a/src/main/java/com/android/tools/r8/dex/MixedSectionLayoutStrategy.java b/src/main/java/com/android/tools/r8/dex/MixedSectionLayoutStrategy.java index 2381e6f..13a4a2c 100644 --- a/src/main/java/com/android/tools/r8/dex/MixedSectionLayoutStrategy.java +++ b/src/main/java/com/android/tools/r8/dex/MixedSectionLayoutStrategy.java
@@ -22,15 +22,16 @@ public static MixedSectionLayoutStrategy create( AppView<?> appView, MixedSectionOffsets mixedSectionOffsets, VirtualFile virtualFile) { - StartupOrder startupOrderForWriting = - appView.options().getStartupOptions().isStartupLayoutOptimizationsEnabled() - && virtualFile.getId() == 0 - && appView.hasClassHierarchy() - ? appView - .appInfoWithClassHierarchy() - .getStartupOrder() - .toStartupOrderForWriting(appView) - : StartupOrder.empty(); + StartupOrder startupOrderForWriting; + if (virtualFile.getStartupOrder().isEmpty()) { + startupOrderForWriting = StartupOrder.empty(); + } else { + assert virtualFile.getId() == 0; + startupOrderForWriting = + appView.options().getStartupOptions().isStartupLayoutOptimizationsEnabled() + ? virtualFile.getStartupOrder().toStartupOrderForWriting(appView) + : StartupOrder.empty(); + } MixedSectionLayoutStrategy mixedSectionLayoutStrategy = startupOrderForWriting.isEmpty() ? new DefaultMixedSectionLayoutStrategy(appView, mixedSectionOffsets)
diff --git a/src/main/java/com/android/tools/r8/dex/VirtualFile.java b/src/main/java/com/android/tools/r8/dex/VirtualFile.java index 55923ed..fafe700 100644 --- a/src/main/java/com/android/tools/r8/dex/VirtualFile.java +++ b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
@@ -4,7 +4,6 @@ package com.android.tools.r8.dex; import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull; -import static com.google.common.base.Predicates.alwaysFalse; import com.android.tools.r8.FeatureSplit; import com.android.tools.r8.debuginfo.DebugRepresentation; @@ -56,6 +55,7 @@ import java.util.HashSet; import java.util.IdentityHashMap; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; @@ -70,36 +70,38 @@ public static final int MAX_ENTRIES = Constants.U16BIT_MAX + 1; private final int id; - private final VirtualFileIndexedItemCollection indexedItems; + public final VirtualFileIndexedItemCollection indexedItems; private final IndexedItemTransaction transaction; private final FeatureSplit featureSplit; + private final StartupOrder startupOrder; private final DexString primaryClassDescriptor; private DebugRepresentation debugRepresentation; VirtualFile(int id, AppView<?> appView) { - this(id, appView, null, null); + this(id, appView, null, null, StartupOrder.empty()); } VirtualFile( int id, AppView<?> appView, FeatureSplit featureSplit) { - this(id, appView, null, featureSplit); + this(id, appView, null, featureSplit, StartupOrder.empty()); } private VirtualFile( int id, AppView<?> appView, DexProgramClass primaryClass) { - this(id, appView, primaryClass, null); + this(id, appView, primaryClass, null, StartupOrder.empty()); } private VirtualFile( int id, AppView<?> appView, DexProgramClass primaryClass, - FeatureSplit featureSplit) { + FeatureSplit featureSplit, + StartupOrder startupOrder) { this.id = id; this.indexedItems = new VirtualFileIndexedItemCollection(appView); this.transaction = new IndexedItemTransaction(indexedItems, appView); @@ -108,6 +110,7 @@ ? null : appView.getNamingLens().lookupClassDescriptor(primaryClass.type); this.featureSplit = featureSplit; + this.startupOrder = startupOrder; } public int getId() { @@ -127,6 +130,10 @@ return featureSplit; } + public StartupOrder getStartupOrder() { + return startupOrder; + } + public String getPrimaryClassDescriptor() { return primaryClassDescriptor == null ? null : primaryClassDescriptor.toString(); } @@ -351,13 +358,17 @@ protected final InternalOptions options; DistributorBase( - ApplicationWriter writer, Collection<DexProgramClass> classes, InternalOptions options) { + ApplicationWriter writer, + Collection<DexProgramClass> classes, + InternalOptions options, + StartupOrder startupOrder) { super(writer); this.options = options; this.classes = SetUtils.newIdentityHashSet(classes); - // Create the primary dex file. The distribution will add more if needed. - mainDexFile = new VirtualFile(0, appView); + // Create the primary dex file. The distribution will add more if needed. We use the startup + // order (if any) to guide the layout of the primary dex file. + mainDexFile = new VirtualFile(0, appView, null, null, startupOrder); assert virtualFiles.isEmpty(); virtualFiles.add(mainDexFile); addMarkers(mainDexFile); @@ -428,7 +439,7 @@ } protected void addFeatureSplitFiles( - Map<FeatureSplit, Set<DexProgramClass>> featureSplitClasses) { + Map<FeatureSplit, Set<DexProgramClass>> featureSplitClasses, StartupOrder startupOrder) { if (featureSplitClasses.isEmpty()) { return; } @@ -451,6 +462,7 @@ appView, featureSplitSetEntry.getValue(), originalNames, + startupOrder, nextFileId) .run(); } @@ -458,15 +470,19 @@ } public static class FillFilesDistributor extends DistributorBase { + private final ExecutorService executorService; + private final StartupOrder startupOrder; FillFilesDistributor( ApplicationWriter writer, Collection<DexProgramClass> classes, InternalOptions options, - ExecutorService executorService) { - super(writer, classes, options); + ExecutorService executorService, + StartupOrder startupOrder) { + super(writer, classes, options, startupOrder); this.executorService = executorService; + this.startupOrder = startupOrder; } @Override @@ -507,10 +523,16 @@ .distribute(); } else { new PackageSplitPopulator( - virtualFiles, filesForDistribution, appView, classes, originalNames, nextFileId) + virtualFiles, + filesForDistribution, + appView, + classes, + originalNames, + startupOrder, + nextFileId) .run(); } - addFeatureSplitFiles(featureSplitClasses); + addFeatureSplitFiles(featureSplitClasses, startupOrder); assert totalClassNumber == virtualFiles.stream().mapToInt(dex -> dex.classes().size()).sum(); return virtualFiles; @@ -520,7 +542,7 @@ public static class MonoDexDistributor extends DistributorBase { MonoDexDistributor( ApplicationWriter writer, Collection<DexProgramClass> classes, InternalOptions options) { - super(writer, classes, options); + super(writer, classes, options, StartupOrder.empty()); } @Override @@ -536,14 +558,63 @@ if (options.featureSplitConfiguration != null) { if (!featureSplitClasses.isEmpty()) { // TODO(141334414): Figure out if we allow multidex in features even when mono-dexing - addFeatureSplitFiles(featureSplitClasses); + addFeatureSplitFiles(featureSplitClasses, StartupOrder.empty()); } } return virtualFiles; } } - private static class VirtualFileIndexedItemCollection implements IndexedItemCollection { + public static class ItemUseInfo { + + private static final Set<DexProgramClass> MANY = null; + private static final int manyCount = 3; + + private Set<DexProgramClass> use; + + ItemUseInfo(Set<DexProgramClass> initialUse) { + use = initialUse.size() >= manyCount ? MANY : initialUse; + } + + public void addUse(Set<DexProgramClass> moreUse) { + if (use == MANY) { + return; + } + if (moreUse.size() >= manyCount) { + use = MANY; + return; + } + use.addAll(moreUse); + if (use.size() >= manyCount) { + use = MANY; + } + } + + public static int getManyCount() { + return manyCount; + } + + public boolean isMany() { + return use == MANY; + } + + public int getSize() { + assert use != MANY; + return use.size(); + } + + public int getSizeOrMany() { + if (use == MANY) return -1; + return use.size(); + } + + public Set<DexProgramClass> getUse() { + assert !isMany(); + return use; + } + } + + public static class VirtualFileIndexedItemCollection implements IndexedItemCollection { private final GraphLens graphLens; private final InitClassLens initClassLens; @@ -558,6 +629,14 @@ private final Set<DexCallSite> callSites = Sets.newIdentityHashSet(); private final Set<DexMethodHandle> methodHandles = Sets.newIdentityHashSet(); + public final Map<DexString, ItemUseInfo> stringsUse = new IdentityHashMap<>(); + public final Map<DexType, ItemUseInfo> typesUse = new IdentityHashMap<>(); + public final Map<DexProto, ItemUseInfo> protosUse = new IdentityHashMap<>(); + public final Map<DexField, ItemUseInfo> fieldsUse = new IdentityHashMap<>(); + public final Map<DexMethod, ItemUseInfo> methodsUse = new IdentityHashMap<>(); + public final Map<DexCallSite, ItemUseInfo> callSitesUse = new IdentityHashMap<>(); + public final Map<DexMethodHandle, ItemUseInfo> methodHandlesUse = new IdentityHashMap<>(); + public VirtualFileIndexedItemCollection(AppView<?> appView) { this.graphLens = appView.graphLens(); this.initClassLens = appView.initClassLens(); @@ -616,6 +695,238 @@ public static class IndexedItemTransaction implements IndexedItemCollection { + public interface ClassUseCollector { + + void collectClassDependencies(DexProgramClass clazz); + + void collectClassDependenciesDone(); + + void clear(); + + Map<DexString, Set<DexProgramClass>> getStringsUse(); + + Map<DexType, Set<DexProgramClass>> getTypesUse(); + + Map<DexProto, Set<DexProgramClass>> getProtosUse(); + + Map<DexField, Set<DexProgramClass>> getFieldsUse(); + + Map<DexMethod, Set<DexProgramClass>> getMethodsUse(); + + Map<DexCallSite, Set<DexProgramClass>> getCallSitesUse(); + + Map<DexMethodHandle, Set<DexProgramClass>> getMethodHandlesUse(); + } + + public static class EmptyIndexedItemUsedByClasses implements ClassUseCollector { + @Override + public void collectClassDependencies(DexProgramClass clazz) { + // Do nothing. + } + + @Override + public void collectClassDependenciesDone() { + // Do nothing. + } + + @Override + public void clear() { + // DO nothing. + } + + @Override + public Map<DexString, Set<DexProgramClass>> getStringsUse() { + assert false; + return null; + } + + @Override + public Map<DexType, Set<DexProgramClass>> getTypesUse() { + assert false; + return null; + } + + @Override + public Map<DexProto, Set<DexProgramClass>> getProtosUse() { + assert false; + return null; + } + + @Override + public Map<DexField, Set<DexProgramClass>> getFieldsUse() { + assert false; + return null; + } + + @Override + public Map<DexMethod, Set<DexProgramClass>> getMethodsUse() { + assert false; + return null; + } + + @Override + public Map<DexCallSite, Set<DexProgramClass>> getCallSitesUse() { + assert false; + return null; + } + + @Override + public Map<DexMethodHandle, Set<DexProgramClass>> getMethodHandlesUse() { + assert false; + return null; + } + } + + public static class IndexedItemsUsedByClassesInTransaction + implements IndexedItemCollection, ClassUseCollector { + + private final AppView<?> appView; + private final LensCodeRewriterUtils rewriter; + private final VirtualFileIndexedItemCollection base; + private final IndexedItemTransaction transaction; + + private final Set<DexProgramClass> classes = new LinkedHashSet<>(); + + private final Map<DexString, Set<DexProgramClass>> stringsUse = new IdentityHashMap<>(); + private final Map<DexType, Set<DexProgramClass>> typesUse = new IdentityHashMap<>(); + private final Map<DexProto, Set<DexProgramClass>> protosUse = new IdentityHashMap<>(); + private final Map<DexField, Set<DexProgramClass>> fieldsUse = new IdentityHashMap<>(); + private final Map<DexMethod, Set<DexProgramClass>> methodsUse = new IdentityHashMap<>(); + private final Map<DexCallSite, Set<DexProgramClass>> callSitesUse = new IdentityHashMap<>(); + private final Map<DexMethodHandle, Set<DexProgramClass>> methodHandlessUse = + new LinkedHashMap<>(); + + DexProgramClass currentClass = null; + + private IndexedItemsUsedByClassesInTransaction( + AppView<?> appView, + LensCodeRewriterUtils rewriter, + VirtualFileIndexedItemCollection base, + IndexedItemTransaction transaction) { + this.appView = appView; + this.rewriter = rewriter; + this.base = base; + this.transaction = transaction; + } + + @Override + public void collectClassDependencies(DexProgramClass clazz) { + clazz.collectIndexedItems(appView, this, rewriter); + } + + @Override + public boolean addClass(DexProgramClass clazz) { + assert currentClass == null; + currentClass = clazz; + assert !classes.contains(clazz); + classes.add(clazz); + return true; + } + + @Override + public void collectClassDependenciesDone() { + currentClass = null; + } + + @Override + public boolean addString(DexString string) { + collectUse(string, transaction.strings, base.strings, stringsUse); + return true; + } + + @Override + public boolean addType(DexType type) { + collectUse(type, transaction.types, base.types, typesUse); + return true; + } + + @Override + public boolean addProto(DexProto proto) { + collectUse(proto, transaction.protos, base.protos, protosUse); + return true; + } + + @Override + public boolean addField(DexField field) { + collectUse(field, transaction.fields, base.fields, fieldsUse); + return true; + } + + @Override + public boolean addMethod(DexMethod method) { + collectUse(method, transaction.methods, base.methods, methodsUse); + return true; + } + + @Override + public boolean addCallSite(DexCallSite callSite) { + collectUse(callSite, transaction.callSites, base.callSites, callSitesUse); + return true; + } + + @Override + public boolean addMethodHandle(DexMethodHandle methodHandle) { + collectUse(methodHandle, transaction.methodHandles, base.methodHandles, methodHandlessUse); + return true; + } + + private <T extends DexItem> void collectUse( + T item, Set<T> set, Set<T> baseSet, Map<T, Set<DexProgramClass>> use) { + assert baseSet.contains(item) || set.contains(item); + if (set.contains(item)) { + assert classes.contains(currentClass); + } + use.computeIfAbsent(item, unused -> Sets.newIdentityHashSet()).add(currentClass); + } + + @Override + public Map<DexString, Set<DexProgramClass>> getStringsUse() { + return stringsUse; + } + + @Override + public Map<DexType, Set<DexProgramClass>> getTypesUse() { + return typesUse; + } + + @Override + public Map<DexProto, Set<DexProgramClass>> getProtosUse() { + return protosUse; + } + + @Override + public Map<DexField, Set<DexProgramClass>> getFieldsUse() { + return fieldsUse; + } + + @Override + public Map<DexMethod, Set<DexProgramClass>> getMethodsUse() { + return methodsUse; + } + + @Override + public Map<DexCallSite, Set<DexProgramClass>> getCallSitesUse() { + return callSitesUse; + } + + @Override + public Map<DexMethodHandle, Set<DexProgramClass>> getMethodHandlesUse() { + return methodHandlessUse; + } + + @Override + public void clear() { + classes.clear(); + stringsUse.clear(); + typesUse.clear(); + protosUse.clear(); + fieldsUse.clear(); + methodsUse.clear(); + callSitesUse.clear(); + methodHandlessUse.clear(); + } + } + private final AppView<?> appView; private final VirtualFileIndexedItemCollection base; private final LensCodeRewriterUtils rewriter; @@ -629,10 +940,16 @@ private final Set<DexCallSite> callSites = new LinkedHashSet<>(); private final Set<DexMethodHandle> methodHandles = new LinkedHashSet<>(); + private final ClassUseCollector indexedItemsReferencedFromClassesInTransaction; + private IndexedItemTransaction(VirtualFileIndexedItemCollection base, AppView<?> appView) { this.appView = appView; this.base = base; this.rewriter = new LensCodeRewriterUtils(appView, true); + this.indexedItemsReferencedFromClassesInTransaction = + appView.options().testing.calculateItemUseCountInDex + ? new IndexedItemsUsedByClassesInTransaction(appView, rewriter, base, this) + : new EmptyIndexedItemUsedByClasses(); } private NamingLens getNamingLens() { @@ -640,55 +957,82 @@ } private <T extends DexItem> boolean maybeInsert(T item, Set<T> set, Set<T> baseSet) { - if (baseSet.contains(item) || set.contains(item)) { + return maybeInsert(item, set, baseSet, true); + } + + private <T extends DexItem> boolean maybeInsert( + T item, Set<T> set, Set<T> baseSet, boolean requireCurrentClass) { + if (baseSet.contains(item)) { return false; } - set.add(item); - return true; + boolean added = set.add(item); + assert !added || !requireCurrentClass || classes.contains(currentClass); + return added; } void addClassAndDependencies(DexProgramClass clazz) { clazz.collectIndexedItems(appView, this, rewriter); + addClassDone(); + indexedItemsReferencedFromClassesInTransaction.collectClassDependencies(clazz); + indexedItemsReferencedFromClassesInTransaction.collectClassDependenciesDone(); } + DexProgramClass currentClass = null; + @Override public boolean addClass(DexProgramClass dexProgramClass) { + assert currentClass == null; + currentClass = dexProgramClass; return maybeInsert(dexProgramClass, classes, base.classes); } + public void addClassDone() { + currentClass = null; + } + @Override public boolean addField(DexField field) { + assert currentClass != null; return maybeInsert(field, fields, base.fields); } @Override public boolean addMethod(DexMethod method) { + assert currentClass != null; return maybeInsert(method, methods, base.methods); } @Override public boolean addString(DexString string) { - return maybeInsert(string, strings, base.strings); + if (currentClass == null) { + // Only marker strings can be added outside a class context. + assert string.startsWith("~~"); + } + return maybeInsert(string, strings, base.strings, false); } @Override public boolean addProto(DexProto proto) { + assert currentClass != null; return maybeInsert(proto, protos, base.protos); } @Override public boolean addType(DexType type) { + assert currentClass != null; assert SyntheticNaming.verifyNotInternalSynthetic(type); return maybeInsert(type, types, base.types); } @Override public boolean addCallSite(DexCallSite callSite) { + assert currentClass != null; return maybeInsert(callSite, callSites, base.callSites); } @Override public boolean addMethodHandle(DexMethodHandle methodHandle) { + assert currentClass != null; return maybeInsert(methodHandle, methodHandles, base.methodHandles); } @@ -721,6 +1065,40 @@ commitItemsIn(strings, base::addString); commitItemsIn(callSites, base::addCallSite); commitItemsIn(methodHandles, base::addMethodHandle); + + if (appView.options().testing.calculateItemUseCountInDex) { + transferUsedBy( + indexedItemsReferencedFromClassesInTransaction.getStringsUse(), base.stringsUse); + transferUsedBy(indexedItemsReferencedFromClassesInTransaction.getTypesUse(), base.typesUse); + transferUsedBy( + indexedItemsReferencedFromClassesInTransaction.getProtosUse(), base.protosUse); + transferUsedBy( + indexedItemsReferencedFromClassesInTransaction.getFieldsUse(), base.fieldsUse); + transferUsedBy( + indexedItemsReferencedFromClassesInTransaction.getMethodsUse(), base.methodsUse); + transferUsedBy( + indexedItemsReferencedFromClassesInTransaction.getCallSitesUse(), base.callSitesUse); + transferUsedBy( + indexedItemsReferencedFromClassesInTransaction.getMethodHandlesUse(), + base.methodHandlesUse); + } + } + + private <T extends DexItem> void transferUsedBy( + Map<T, Set<DexProgramClass>> classesInTransactionReferringToItem, + Map<T, ItemUseInfo> itemUse) { + assert appView.options().testing.calculateItemUseCountInDex; + classesInTransactionReferringToItem.forEach( + (item, classes) -> { + ItemUseInfo currentItemUse = itemUse.get(item); + if (currentItemUse == null) { + itemUse.put(item, new ItemUseInfo(classes)); + } else { + currentItemUse.addUse(classes); + } + }); + + classesInTransactionReferringToItem.clear(); } void abort() { @@ -730,6 +1108,8 @@ protos.clear(); types.clear(); strings.clear(); + + indexedItemsReferencedFromClassesInTransaction.clear(); } public boolean isEmpty() { @@ -883,12 +1263,13 @@ public static PackageSplitClassPartioning create( Collection<DexProgramClass> classes, - AppView<?> appView, - Map<DexProgramClass, String> originalNames) { + Map<DexProgramClass, String> originalNames, + StartupOrder startupOrder, + SyntheticItems syntheticItems) { return create( classes, getClassesByPackageComparator(originalNames), - getStartupClassPredicate(appView)); + getStartupClassPredicate(startupOrder, syntheticItems)); } private static PackageSplitClassPartioning create( @@ -938,12 +1319,8 @@ }; } - private static Predicate<DexProgramClass> getStartupClassPredicate(AppView<?> appView) { - if (!appView.hasClassHierarchy()) { - return alwaysFalse(); - } - StartupOrder startupOrder = appView.appInfoWithClassHierarchy().getStartupOrder(); - SyntheticItems syntheticItems = appView.getSyntheticItems(); + private static Predicate<DexProgramClass> getStartupClassPredicate( + StartupOrder startupOrder, SyntheticItems syntheticItems) { return clazz -> startupOrder.contains(clazz.getType(), syntheticItems); } @@ -980,8 +1357,11 @@ AppView<?> appView, Collection<DexProgramClass> classes, Map<DexProgramClass, String> originalNames, + StartupOrder startupOrder, IntBox nextFileId) { - this.classPartioning = PackageSplitClassPartioning.create(classes, appView, originalNames); + this.classPartioning = + PackageSplitClassPartioning.create( + classes, originalNames, startupOrder, appView.getSyntheticItems()); this.originalNames = originalNames; this.dexItemFactory = appView.dexItemFactory(); this.options = appView.options(); @@ -1016,7 +1396,7 @@ return; } - assert options.getStartupOptions().hasStartupConfiguration(); + assert options.getStartupOptions().hasStartupProfileProvider(); // In practice, all startup classes should fit in a single dex file, so optimistically try to // commit the startup classes using a single transaction.
diff --git a/src/main/java/com/android/tools/r8/errors/UnsupportedDesugaredLibraryConfigurationVersionDiagnostic.java b/src/main/java/com/android/tools/r8/errors/UnsupportedDesugaredLibraryConfigurationVersionDiagnostic.java new file mode 100644 index 0000000..7e2455a --- /dev/null +++ b/src/main/java/com/android/tools/r8/errors/UnsupportedDesugaredLibraryConfigurationVersionDiagnostic.java
@@ -0,0 +1,46 @@ +// 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.errors; + +import com.android.tools.r8.Diagnostic; +import com.android.tools.r8.Keep; +import com.android.tools.r8.origin.Origin; +import com.android.tools.r8.position.Position; + +@Keep +public class UnsupportedDesugaredLibraryConfigurationVersionDiagnostic implements Diagnostic { + + private static final String dagRoot = "https://developer.android.com"; + private static final String versionMatrixUrl = + dagRoot + "/studio/build/library-desugaring-versions"; + private static final String desugaredLibraryUrl = dagRoot + "/studio/build/library-desugaring"; + + private final Origin origin; + + public UnsupportedDesugaredLibraryConfigurationVersionDiagnostic(Origin origin) { + this.origin = origin; + } + + @Override + public Origin getOrigin() { + return origin; + } + + @Override + public Position getPosition() { + return Position.UNKNOWN; + } + + @Override + public String getDiagnosticMessage() { + return "Unsupported desugared library configuration version, please upgrade the D8/R8" + + " compiler." + + " See " + + versionMatrixUrl + + "." + + " To learn more about library desugaring read " + + desugaredLibraryUrl + + "."; + } +}
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupClass.java b/src/main/java/com/android/tools/r8/experimental/startup/StartupClass.java index 7ae4d30..b6c6311 100644 --- a/src/main/java/com/android/tools/r8/experimental/startup/StartupClass.java +++ b/src/main/java/com/android/tools/r8/experimental/startup/StartupClass.java
@@ -56,6 +56,17 @@ return this; } + @Override + public void serializeToString( + StringBuilder builder, + Function<C, String> classSerializer, + Function<M, String> methodSerializer) { + if (isSynthetic()) { + builder.append('S'); + } + builder.append(classSerializer.apply(getReference())); + } + public static class Builder<C, M> extends StartupItem.Builder<C, M, Builder<C, M>> { @Override
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupCompleteness.java b/src/main/java/com/android/tools/r8/experimental/startup/StartupCompleteness.java index 8d75d7c..ca0b88f 100644 --- a/src/main/java/com/android/tools/r8/experimental/startup/StartupCompleteness.java +++ b/src/main/java/com/android/tools/r8/experimental/startup/StartupCompleteness.java
@@ -31,7 +31,7 @@ this.startupOrder = appView.hasClassHierarchy() ? appView.appInfoWithClassHierarchy().getStartupOrder() - : StartupOrder.empty(); + : StartupOrder.createInitialStartupOrder(appView.options()); } /**
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupConfiguration.java b/src/main/java/com/android/tools/r8/experimental/startup/StartupConfiguration.java deleted file mode 100644 index 2f1a23d..0000000 --- a/src/main/java/com/android/tools/r8/experimental/startup/StartupConfiguration.java +++ /dev/null
@@ -1,125 +0,0 @@ -// Copyright (c) 2021, 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.experimental.startup; - -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.utils.ExceptionDiagnostic; -import com.android.tools.r8.utils.FileUtils; -import com.android.tools.r8.utils.Reporter; -import com.android.tools.r8.utils.StringDiagnostic; -import com.google.common.collect.ImmutableList; -import java.io.IOException; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.List; -import java.util.function.Consumer; - -public class StartupConfiguration { - - private final List<StartupItem<DexType, DexMethod, ?>> startupItems; - - public StartupConfiguration(List<StartupItem<DexType, DexMethod, ?>> startupItems) { - this.startupItems = startupItems; - } - - public static Builder builder() { - return new Builder(); - } - - /** - * Parses the supplied startup configuration, if any. The startup configuration is a list of class - * and method descriptors. - * - * <p>Example: - * - * <pre> - * Landroidx/compose/runtime/ComposerImpl;->updateValue(Ljava/lang/Object;)V - * Landroidx/compose/runtime/ComposerImpl;->updatedNodeCount(I)I - * Landroidx/compose/runtime/ComposerImpl;->validateNodeExpected()V - * Landroidx/compose/runtime/CompositionImpl;->applyChanges()V - * Landroidx/compose/runtime/ComposerKt;->findLocation(Ljava/util/List;I)I - * Landroidx/compose/runtime/ComposerImpl; - * </pre> - */ - public static StartupConfiguration createStartupConfiguration( - DexItemFactory dexItemFactory, Reporter reporter) { - String propertyValue = System.getProperty("com.android.tools.r8.startup.config"); - return propertyValue != null - ? createStartupConfigurationFromFile(dexItemFactory, reporter, Paths.get(propertyValue)) - : null; - } - - public static StartupConfiguration createStartupConfigurationFromFile( - DexItemFactory dexItemFactory, Reporter reporter, Path path) { - reporter.warning("Use of startupconfig is experimental"); - - List<String> startupDescriptors; - try { - startupDescriptors = FileUtils.readAllLines(path); - } catch (IOException e) { - throw reporter.fatalError(new ExceptionDiagnostic(e)); - } - - if (startupDescriptors.isEmpty()) { - return null; - } - - return createStartupConfigurationFromLines(dexItemFactory, reporter, startupDescriptors); - } - - public static StartupConfiguration createStartupConfigurationFromLines( - DexItemFactory dexItemFactory, Reporter reporter, List<String> startupDescriptors) { - List<StartupItem<DexType, DexMethod, ?>> startupItems = new ArrayList<>(); - StartupConfigurationParser.createDexParser(dexItemFactory) - .parseLines( - startupDescriptors, - startupItems::add, - startupItems::add, - error -> - reporter.warning( - new StringDiagnostic( - "Invalid descriptor for startup class or method: " + error))); - return new StartupConfiguration(startupItems); - } - - public boolean hasStartupItems() { - return !startupItems.isEmpty(); - } - - public List<StartupItem<DexType, DexMethod, ?>> getStartupItems() { - return startupItems; - } - - public static class Builder { - - private final ImmutableList.Builder<StartupItem<DexType, DexMethod, ?>> startupItemsBuilder = - ImmutableList.builder(); - - public Builder addStartupItem(StartupItem<DexType, DexMethod, ?> startupItem) { - this.startupItemsBuilder.add(startupItem); - return this; - } - - public Builder addStartupClass(StartupClass<DexType, DexMethod> startupClass) { - return addStartupItem(startupClass); - } - - public Builder addStartupMethod(StartupMethod<DexType, DexMethod> startupMethod) { - return addStartupItem(startupMethod); - } - - public Builder apply(Consumer<Builder> consumer) { - consumer.accept(this); - return this; - } - - public StartupConfiguration build() { - return new StartupConfiguration(startupItemsBuilder.build()); - } - } -}
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupItem.java b/src/main/java/com/android/tools/r8/experimental/startup/StartupItem.java index 74e69e2..e2ea09b 100644 --- a/src/main/java/com/android/tools/r8/experimental/startup/StartupItem.java +++ b/src/main/java/com/android/tools/r8/experimental/startup/StartupItem.java
@@ -64,6 +64,11 @@ return (flags & FLAG_SYNTHETIC) != 0; } + public abstract void serializeToString( + StringBuilder builder, + Function<C, String> classSerializer, + Function<M, String> methodSerializer); + @Override public boolean equals(Object obj) { if (this == obj) {
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupMethod.java b/src/main/java/com/android/tools/r8/experimental/startup/StartupMethod.java index 871e179..00ddca9 100644 --- a/src/main/java/com/android/tools/r8/experimental/startup/StartupMethod.java +++ b/src/main/java/com/android/tools/r8/experimental/startup/StartupMethod.java
@@ -43,6 +43,17 @@ return this; } + @Override + public void serializeToString( + StringBuilder builder, + Function<C, String> classSerializer, + Function<M, String> methodSerializer) { + if (isSynthetic()) { + builder.append('S'); + } + builder.append(methodSerializer.apply(getReference())); + } + public static class Builder<C, M> extends StartupItem.Builder<C, M, Builder<C, M>> { @Override
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupOptions.java b/src/main/java/com/android/tools/r8/experimental/startup/StartupOptions.java index e737c9d..7d1b4dc 100644 --- a/src/main/java/com/android/tools/r8/experimental/startup/StartupOptions.java +++ b/src/main/java/com/android/tools/r8/experimental/startup/StartupOptions.java
@@ -4,9 +4,13 @@ package com.android.tools.r8.experimental.startup; -import static com.android.tools.r8.utils.SystemPropertyUtils.getSystemPropertyForDevelopment; import static com.android.tools.r8.utils.SystemPropertyUtils.parseSystemPropertyForDevelopmentOrDefault; +import com.android.tools.r8.StartupProfileProvider; +import com.android.tools.r8.StringResource; +import com.android.tools.r8.utils.SystemPropertyUtils; +import java.nio.file.Paths; + public class StartupOptions { /** @@ -15,7 +19,7 @@ */ private boolean enableMinimalStartupDex = parseSystemPropertyForDevelopmentOrDefault( - "com.android.tools.r8.startup.minimalstartupdex", false); + "com.android.tools.r8.startup.minimalstartupdex", true); /** * When enabled, optimizations crossing the startup/non-startup boundary will be allowed. @@ -39,75 +43,18 @@ "com.android.tools.r8.startup.completenesscheck", false); /** - * When enabled, each method will be instrumented to notify the startup InstrumentationServer that - * it has been executed. - * - * <p>This will also inject the startup runtime library (i.e., the InstrumentationServer) into the - * app. - */ - private boolean enableStartupInstrumentation = - parseSystemPropertyForDevelopmentOrDefault("com.android.tools.r8.startup.instrument", false); - - /** * When enabled, the layout of the primary dex file will be generated using the startup list, * using {@link com.android.tools.r8.dex.StartupMixedSectionLayoutStrategy}. */ private boolean enableStartupLayoutOptimizations = parseSystemPropertyForDevelopmentOrDefault("com.android.tools.r8.startup.layout", true); - /** - * Specifies the synthetic context of the startup runtime library. When this is set, the startup - * runtime library will only be injected into the app when the synthetic context is in the - * program. This can be used to avoid that the startup runtime library is injected multiple times - * in presence of separate compilation. - * - * <p>Example synthetic context: "app.tivi.home.MainActivity". - * - * <p>Note that this is only meaningful when {@link #enableStartupInstrumentation} is set to true. - */ - private String startupInstrumentationServerSyntheticContext = - getSystemPropertyForDevelopment( - "com.android.tools.r8.startup.instrumentationserversyntheticcontext"); - - /** - * Specifies the logcat tag that should be used by the InstrumentationServer when logging events. - * - * <p>When a logcat tag is not specified, the InstrumentationServer will not print events to - * logcat. Instead, the startup events must be obtained by requesting the InstrumentationServer to - * write the events to a file. - */ - private String startupInstrumentationTag = - getSystemPropertyForDevelopment("com.android.tools.r8.startup.instrumentationtag"); - - private StartupConfiguration startupConfiguration; - - public boolean hasStartupInstrumentationServerSyntheticContext() { - return startupInstrumentationServerSyntheticContext != null; - } - - public String getStartupInstrumentationServerSyntheticContext() { - return startupInstrumentationServerSyntheticContext; - } - - public StartupOptions setStartupInstrumentationServerSyntheticContext( - String startupInstrumentationServerSyntheticContext) { - this.startupInstrumentationServerSyntheticContext = - startupInstrumentationServerSyntheticContext; - return this; - } - - public boolean hasStartupInstrumentationTag() { - return startupInstrumentationTag != null; - } - - public String getStartupInstrumentationTag() { - return startupInstrumentationTag; - } - - public StartupOptions setStartupInstrumentationTag(String startupInstrumentationTag) { - this.startupInstrumentationTag = startupInstrumentationTag; - return this; - } + private StartupProfileProvider startupProfileProvider = + SystemPropertyUtils.applySystemProperty( + "com.android.tools.r8.startup.profile", + propertyValue -> + StringResource.fromFile(Paths.get(propertyValue))::getStringWithRuntimeException, + () -> null); public boolean isMinimalStartupDexEnabled() { return enableMinimalStartupDex; @@ -122,12 +69,9 @@ return enableStartupBoundaryOptimizations; } - public boolean isStartupInstrumentationEnabled() { - return enableStartupInstrumentation; - } - - public StartupOptions setEnableStartupInstrumentation() { - enableStartupInstrumentation = true; + public StartupOptions setEnableStartupBoundaryOptimizations( + boolean enableStartupBoundaryOptimizations) { + this.enableStartupBoundaryOptimizations = enableStartupBoundaryOptimizations; return this; } @@ -149,16 +93,16 @@ return this; } - public boolean hasStartupConfiguration() { - return startupConfiguration != null; + public boolean hasStartupProfileProvider() { + return startupProfileProvider != null; } - public StartupConfiguration getStartupConfiguration() { - return startupConfiguration; + public StartupProfileProvider getStartupProfileProvider() { + return startupProfileProvider; } - public StartupOptions setStartupConfiguration(StartupConfiguration startupConfiguration) { - this.startupConfiguration = startupConfiguration; + public StartupOptions setStartupProfileProvider(StartupProfileProvider startupProfileProvider) { + this.startupProfileProvider = startupProfileProvider; return this; } }
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupOrder.java b/src/main/java/com/android/tools/r8/experimental/startup/StartupOrder.java index b1803eb..9f9bf65 100644 --- a/src/main/java/com/android/tools/r8/experimental/startup/StartupOrder.java +++ b/src/main/java/com/android/tools/r8/experimental/startup/StartupOrder.java
@@ -19,15 +19,11 @@ StartupOrder() {} public static StartupOrder createInitialStartupOrder(InternalOptions options) { - if (!options.getStartupOptions().hasStartupConfiguration()) { + StartupProfile startupProfile = StartupProfile.parseStartupProfile(options); + if (startupProfile == null || startupProfile.getStartupItems().isEmpty()) { return empty(); } - StartupConfiguration startupConfiguration = - options.getStartupOptions().getStartupConfiguration(); - if (!startupConfiguration.hasStartupItems()) { - return empty(); - } - return new NonEmptyStartupOrder(new LinkedHashSet<>(startupConfiguration.getStartupItems())); + return new NonEmptyStartupOrder(new LinkedHashSet<>(startupProfile.getStartupItems())); } public static StartupOrder empty() {
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupProfile.java b/src/main/java/com/android/tools/r8/experimental/startup/StartupProfile.java new file mode 100644 index 0000000..20cd31b --- /dev/null +++ b/src/main/java/com/android/tools/r8/experimental/startup/StartupProfile.java
@@ -0,0 +1,109 @@ +// Copyright (c) 2021, 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.experimental.startup; + +import com.android.tools.r8.StartupProfileProvider; +import com.android.tools.r8.graph.DexMethod; +import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.utils.InternalOptions; +import com.android.tools.r8.utils.StringDiagnostic; +import com.android.tools.r8.utils.StringUtils; +import com.google.common.collect.ImmutableList; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +public class StartupProfile { + + private final List<StartupItem<DexType, DexMethod, ?>> startupItems; + + public StartupProfile(List<StartupItem<DexType, DexMethod, ?>> startupItems) { + this.startupItems = startupItems; + } + + public static Builder builder() { + return new Builder(); + } + + /** + * Parses the supplied startup configuration, if any. The startup configuration is a list of class + * and method descriptors. + * + * <p>Example: + * + * <pre> + * Landroidx/compose/runtime/ComposerImpl;->updateValue(Ljava/lang/Object;)V + * Landroidx/compose/runtime/ComposerImpl;->updatedNodeCount(I)I + * Landroidx/compose/runtime/ComposerImpl;->validateNodeExpected()V + * Landroidx/compose/runtime/CompositionImpl;->applyChanges()V + * Landroidx/compose/runtime/ComposerKt;->findLocation(Ljava/util/List;I)I + * Landroidx/compose/runtime/ComposerImpl; + * </pre> + */ + public static StartupProfile parseStartupProfile(InternalOptions options) { + if (!options.getStartupOptions().hasStartupProfileProvider()) { + return null; + } + StartupProfileProvider resource = options.getStartupOptions().getStartupProfileProvider(); + List<String> startupDescriptors = StringUtils.splitLines(resource.get()); + return createStartupConfigurationFromLines(options, startupDescriptors); + } + + public static StartupProfile createStartupConfigurationFromLines( + InternalOptions options, List<String> startupDescriptors) { + List<StartupItem<DexType, DexMethod, ?>> startupItems = new ArrayList<>(); + StartupConfigurationParser.createDexParser(options.dexItemFactory()) + .parseLines( + startupDescriptors, + startupItems::add, + startupItems::add, + error -> + options.reporter.warning( + new StringDiagnostic( + "Invalid descriptor for startup class or method: " + error))); + return new StartupProfile(startupItems); + } + + public List<StartupItem<DexType, DexMethod, ?>> getStartupItems() { + return startupItems; + } + + public String serializeToString() { + StringBuilder builder = new StringBuilder(); + for (StartupItem<DexType, DexMethod, ?> startupItem : startupItems) { + startupItem.serializeToString(builder, DexType::toSmaliString, DexMethod::toSmaliString); + builder.append('\n'); + } + return builder.toString(); + } + + public static class Builder { + + private final ImmutableList.Builder<StartupItem<DexType, DexMethod, ?>> startupItemsBuilder = + ImmutableList.builder(); + + public Builder addStartupItem(StartupItem<DexType, DexMethod, ?> startupItem) { + this.startupItemsBuilder.add(startupItem); + return this; + } + + public Builder addStartupClass(StartupClass<DexType, DexMethod> startupClass) { + return addStartupItem(startupClass); + } + + public Builder addStartupMethod(StartupMethod<DexType, DexMethod> startupMethod) { + return addStartupItem(startupMethod); + } + + public Builder apply(Consumer<Builder> consumer) { + consumer.accept(this); + return this; + } + + public StartupProfile build() { + return new StartupProfile(startupItemsBuilder.build()); + } + } +}
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupInstrumentation.java b/src/main/java/com/android/tools/r8/experimental/startup/instrumentation/StartupInstrumentation.java similarity index 87% rename from src/main/java/com/android/tools/r8/experimental/startup/StartupInstrumentation.java rename to src/main/java/com/android/tools/r8/experimental/startup/instrumentation/StartupInstrumentation.java index 76abc9d..7e8db58 100644 --- a/src/main/java/com/android/tools/r8/experimental/startup/StartupInstrumentation.java +++ b/src/main/java/com/android/tools/r8/experimental/startup/instrumentation/StartupInstrumentation.java
@@ -2,7 +2,7 @@ // 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.experimental.startup; +package com.android.tools.r8.experimental.startup.instrumentation; import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull; import static com.android.tools.r8.utils.PredicateUtils.not; @@ -54,21 +54,21 @@ private final IRConverter converter; private final DexItemFactory dexItemFactory; private final InternalOptions options; - private final StartupReferences references; - private final StartupOptions startupOptions; + private final StartupInstrumentationReferences references; + private final StartupInstrumentationOptions startupInstrumentationOptions; private StartupInstrumentation(AppView<AppInfo> appView) { this.appView = appView; this.converter = new IRConverter(appView, Timing.empty()); this.dexItemFactory = appView.dexItemFactory(); this.options = appView.options(); - this.references = new StartupReferences(dexItemFactory); - this.startupOptions = options.getStartupOptions(); + this.references = new StartupInstrumentationReferences(dexItemFactory); + this.startupInstrumentationOptions = options.getStartupInstrumentationOptions(); } public static void run(AppView<AppInfo> appView, ExecutorService executorService) throws ExecutionException { - if (appView.options().getStartupOptions().isStartupInstrumentationEnabled()) { + if (appView.options().getStartupInstrumentationOptions().isStartupInstrumentationEnabled()) { StartupInstrumentation startupInstrumentation = new StartupInstrumentation(appView); startupInstrumentation.instrumentAllClasses(executorService); startupInstrumentation.injectStartupRuntimeLibrary(executorService); @@ -89,11 +89,11 @@ // If the startup options has a synthetic context for the startup instrumentation server, then // only inject the runtime library if the synthetic context exists in program to avoid injecting // the runtime library multiple times when there is separate compilation. - if (startupOptions.hasStartupInstrumentationServerSyntheticContext()) { + if (startupInstrumentationOptions.hasStartupInstrumentationServerSyntheticContext()) { DexType syntheticContext = dexItemFactory.createType( DescriptorUtils.javaTypeToDescriptor( - startupOptions.getStartupInstrumentationServerSyntheticContext())); + startupInstrumentationOptions.getStartupInstrumentationServerSyntheticContext())); if (asProgramClassOrNull(appView.definitionFor(syntheticContext)) == null) { return; } @@ -113,7 +113,7 @@ private List<DexProgramClass> createStartupRuntimeLibraryClasses() { DexProgramClass instrumentationServerImplClass = InstrumentationServerImplFactory.createClass(dexItemFactory); - if (startupOptions.hasStartupInstrumentationTag()) { + if (startupInstrumentationOptions.hasStartupInstrumentationTag()) { instrumentationServerImplClass .lookupUniqueStaticFieldWithName(dexItemFactory.createString("writeToLogcat")) .setStaticValue(DexValueBoolean.create(true)); @@ -121,7 +121,8 @@ .lookupUniqueStaticFieldWithName(dexItemFactory.createString("logcatTag")) .setStaticValue( new DexValueString( - dexItemFactory.createString(startupOptions.getStartupInstrumentationTag()))); + dexItemFactory.createString( + startupInstrumentationOptions.getStartupInstrumentationTag()))); } return ImmutableList.of( @@ -174,8 +175,11 @@ // Insert invoke to record that the enclosing class is a startup class. SyntheticItems syntheticItems = appView.getSyntheticItems(); - boolean isSyntheticClass = syntheticItems.isSyntheticClass(method.getHolder()); - if (method.getDefinition().isClassInitializer() && !isSyntheticClass) { + boolean generalizeSyntheticToSyntheticOfSyntheticContexts = + startupInstrumentationOptions.isGeneralizationOfSyntheticsToSyntheticContextEnabled() + && syntheticItems.isSyntheticClass(method.getHolder()); + if (method.getDefinition().isClassInitializer() + && !generalizeSyntheticToSyntheticOfSyntheticContexts) { DexMethod methodToInvoke = references.addNonSyntheticMethod; DexType classToPrint = method.getHolderType(); Value descriptorValue = @@ -193,7 +197,7 @@ if (!skipMethodLogging) { DexMethod methodToInvoke; DexReference referenceToPrint; - if (isSyntheticClass) { + if (generalizeSyntheticToSyntheticOfSyntheticContexts) { Collection<DexType> synthesizingContexts = syntheticItems.getSynthesizingContextTypes(method.getHolderType()); assert synthesizingContexts.size() == 1; @@ -216,6 +220,8 @@ .build()); } + converter.deadCodeRemover.run(code, Timing.empty()); + DexCode instrumentedCode = new IRToDexFinalizer(appView, converter.deadCodeRemover) .finalizeCode(code, BytecodeMetadataProvider.empty(), Timing.empty());
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/instrumentation/StartupInstrumentationOptions.java b/src/main/java/com/android/tools/r8/experimental/startup/instrumentation/StartupInstrumentationOptions.java new file mode 100644 index 0000000..bfb3f87 --- /dev/null +++ b/src/main/java/com/android/tools/r8/experimental/startup/instrumentation/StartupInstrumentationOptions.java
@@ -0,0 +1,104 @@ +// 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.experimental.startup.instrumentation; + +import static com.android.tools.r8.utils.SystemPropertyUtils.getSystemPropertyForDevelopment; +import static com.android.tools.r8.utils.SystemPropertyUtils.parseSystemPropertyForDevelopmentOrDefault; + +public class StartupInstrumentationOptions { + + /** + * When enabled, the instrumentation for synthetics will print the name of the synthetic context + * instead of printing the name of the synthetic itself. + */ + private boolean enableGeneralizationOfSyntheticsToSyntheticContext = + parseSystemPropertyForDevelopmentOrDefault( + "com.android.tools.r8.startup.instrumentation.generalizesynthetics", false); + + /** + * When enabled, each method will be instrumented to notify the startup InstrumentationServer that + * it has been executed. + * + * <p>This will also inject the startup runtime library (i.e., the InstrumentationServer) into the + * app. + */ + private boolean enableStartupInstrumentation = + parseSystemPropertyForDevelopmentOrDefault( + "com.android.tools.r8.startup.instrumentation.instrument", false); + + /** + * Specifies the synthetic context of the startup runtime library. When this is set, the startup + * runtime library will only be injected into the app when the synthetic context is in the + * program. This can be used to avoid that the startup runtime library is injected multiple times + * in presence of separate compilation. + * + * <p>Example synthetic context: "app.tivi.home.MainActivity". + * + * <p>Note that this is only meaningful when {@link #enableStartupInstrumentation} is set to true. + */ + private String startupInstrumentationServerSyntheticContext = + getSystemPropertyForDevelopment( + "com.android.tools.r8.startup.instrumentation.instrumentationserversyntheticcontext"); + + /** + * Specifies the logcat tag that should be used by the InstrumentationServer when logging events. + * + * <p>When a logcat tag is not specified, the InstrumentationServer will not print events to + * logcat. Instead, the startup events must be obtained by requesting the InstrumentationServer to + * write the events to a file. + */ + private String startupInstrumentationTag = + getSystemPropertyForDevelopment( + "com.android.tools.r8.startup.instrumentation.instrumentationtag"); + + public boolean hasStartupInstrumentationServerSyntheticContext() { + return startupInstrumentationServerSyntheticContext != null; + } + + public String getStartupInstrumentationServerSyntheticContext() { + return startupInstrumentationServerSyntheticContext; + } + + public StartupInstrumentationOptions setStartupInstrumentationServerSyntheticContext( + String startupInstrumentationServerSyntheticContext) { + this.startupInstrumentationServerSyntheticContext = + startupInstrumentationServerSyntheticContext; + return this; + } + + public boolean hasStartupInstrumentationTag() { + return startupInstrumentationTag != null; + } + + public String getStartupInstrumentationTag() { + return startupInstrumentationTag; + } + + public StartupInstrumentationOptions setStartupInstrumentationTag( + String startupInstrumentationTag) { + this.startupInstrumentationTag = startupInstrumentationTag; + return this; + } + + public boolean isGeneralizationOfSyntheticsToSyntheticContextEnabled() { + return enableGeneralizationOfSyntheticsToSyntheticContext; + } + + public StartupInstrumentationOptions setEnableGeneralizationOfSyntheticsToSyntheticContext( + boolean enableGeneralizationOfSyntheticsToSyntheticContext) { + this.enableGeneralizationOfSyntheticsToSyntheticContext = + enableGeneralizationOfSyntheticsToSyntheticContext; + return this; + } + + public boolean isStartupInstrumentationEnabled() { + return enableStartupInstrumentation; + } + + public StartupInstrumentationOptions setEnableStartupInstrumentation() { + enableStartupInstrumentation = true; + return this; + } +}
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupReferences.java b/src/main/java/com/android/tools/r8/experimental/startup/instrumentation/StartupInstrumentationReferences.java similarity index 87% rename from src/main/java/com/android/tools/r8/experimental/startup/StartupReferences.java rename to src/main/java/com/android/tools/r8/experimental/startup/instrumentation/StartupInstrumentationReferences.java index a041f1e..fbfa5e2 100644 --- a/src/main/java/com/android/tools/r8/experimental/startup/StartupReferences.java +++ b/src/main/java/com/android/tools/r8/experimental/startup/instrumentation/StartupInstrumentationReferences.java
@@ -2,20 +2,20 @@ // 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.experimental.startup; +package com.android.tools.r8.experimental.startup.instrumentation; import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexType; -public class StartupReferences { +class StartupInstrumentationReferences { final DexType instrumentationServerType; final DexType instrumentationServerImplType; final DexMethod addNonSyntheticMethod; final DexMethod addSyntheticMethod; - StartupReferences(DexItemFactory dexItemFactory) { + StartupInstrumentationReferences(DexItemFactory dexItemFactory) { instrumentationServerType = dexItemFactory.createType("Lcom/android/tools/r8/startup/InstrumentationServer;"); instrumentationServerImplType =
diff --git a/src/main/java/com/android/tools/r8/features/ClassToFeatureSplitMap.java b/src/main/java/com/android/tools/r8/features/ClassToFeatureSplitMap.java index 5b8e3db..68af78a 100644 --- a/src/main/java/com/android/tools/r8/features/ClassToFeatureSplitMap.java +++ b/src/main/java/com/android/tools/r8/features/ClassToFeatureSplitMap.java
@@ -164,7 +164,6 @@ FeatureSplit feature; boolean isSynthetic = syntheticItems.isSyntheticClass(type); if (isSynthetic) { - assert !classToFeatureSplitMap.containsKey(type); if (syntheticItems.isSyntheticOfKind(type, k -> k.ENUM_UNBOXING_SHARED_UTILITY_CLASS)) { // Use the startup base if there is one, such that we don't merge non-startup classes with // the shared utility class in case it is used during startup. The use of base startup @@ -176,6 +175,9 @@ : FeatureSplit.BASE_STARTUP; } feature = syntheticItems.getContextualFeatureSplitOrDefault(type, FeatureSplit.BASE); + // Verify the synthetic is not in the class to feature split map or the synthetic has the same + // feature split as its context. + assert classToFeatureSplitMap.getOrDefault(type, feature) == feature; } else { feature = classToFeatureSplitMap.getOrDefault(type, FeatureSplit.BASE); }
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java index 1aa41dc..f6edecd 100644 --- a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java +++ b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
@@ -221,10 +221,6 @@ return accessFlags.isProtected(); } - public boolean isPublic() { - return accessFlags.isPublic(); - } - @Override public boolean isStaticMember() { return isStatic();
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java index 7f42e49..806b7a7 100644 --- a/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java +++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java
@@ -73,6 +73,10 @@ return getAccessFlags().isPrivate(); } + public final boolean isPublic() { + return getAccessFlags().isPublic(); + } + public abstract ProgramMember<D, R> asProgramMember(DexDefinitionSupplier definitions); public abstract <T> T apply(
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 ce22d5c..05b5030 100644 --- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java +++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -189,6 +189,10 @@ return accessFlags; } + public int getArgumentIndexFromParameterIndex(int parameterIndex) { + return parameterIndex + getFirstNonReceiverArgumentIndex(); + } + public DexType getArgumentType(int argumentIndex) { return getReference().getArgumentType(argumentIndex, isStatic()); } @@ -324,6 +328,11 @@ return getReference().getParameters(); } + public int getParameterIndexFromArgumentIndex(int argumentIndex) { + assert argumentIndex >= getFirstNonReceiverArgumentIndex(); + return argumentIndex - getFirstNonReceiverArgumentIndex(); + } + public DexType getReturnType() { return getReference().getReturnType(); } @@ -434,10 +443,6 @@ return accessFlags.isNative(); } - public boolean isPublic() { - return accessFlags.isPublic(); - } - public boolean isSynchronized() { return accessFlags.isSynchronized(); }
diff --git a/src/main/java/com/android/tools/r8/graph/DexTypeList.java b/src/main/java/com/android/tools/r8/graph/DexTypeList.java index 880b51d..7be2dce 100644 --- a/src/main/java/com/android/tools/r8/graph/DexTypeList.java +++ b/src/main/java/com/android/tools/r8/graph/DexTypeList.java
@@ -8,6 +8,7 @@ import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.dex.MixedSectionCollection; import com.android.tools.r8.utils.ArrayUtils; +import com.android.tools.r8.utils.IntObjConsumer; import com.android.tools.r8.utils.structural.StructuralItem; import com.android.tools.r8.utils.structural.StructuralMapping; import com.android.tools.r8.utils.structural.StructuralSpecification; @@ -104,6 +105,13 @@ } } + public void forEach(IntObjConsumer<DexType> consumer) { + for (int parameterIndex = 0; parameterIndex < values.length; parameterIndex++) { + DexType parameter = values[parameterIndex]; + consumer.accept(parameterIndex, parameter); + } + } + public void forEachReverse(Consumer<? super DexType> consumer) { for (int i = values.length - 1; i >= 0; i--) { consumer.accept(values[i]);
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java index 70f752e..21fccf4 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
@@ -51,6 +51,7 @@ import com.android.tools.r8.horizontalclassmerging.policies.PreventClassMethodAndDefaultMethodCollisions; import com.android.tools.r8.horizontalclassmerging.policies.RespectPackageBoundaries; import com.android.tools.r8.horizontalclassmerging.policies.SameFeatureSplit; +import com.android.tools.r8.horizontalclassmerging.policies.SameFilePolicy; import com.android.tools.r8.horizontalclassmerging.policies.SameInstanceFields; import com.android.tools.r8.horizontalclassmerging.policies.SameMainDexGroup; import com.android.tools.r8.horizontalclassmerging.policies.SameNestHost; @@ -273,6 +274,7 @@ ImmediateProgramSubtypingInfo immediateSubtypingInfo = ImmediateProgramSubtypingInfo.create(appView); builder.add( + new SameFilePolicy(appView), new CheckAbstractClasses(appView), new NoClassAnnotationCollisions(), new SameFeatureSplit(appView),
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameFilePolicy.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameFilePolicy.java new file mode 100644 index 0000000..5643d8c --- /dev/null +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameFilePolicy.java
@@ -0,0 +1,34 @@ +// 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.horizontalclassmerging.policies; + +import com.android.tools.r8.graph.AppView; +import com.android.tools.r8.graph.DexProgramClass; +import com.android.tools.r8.horizontalclassmerging.MultiClassSameReferencePolicy; +import com.android.tools.r8.utils.InternalOptions.HorizontalClassMergerOptions; + +public class SameFilePolicy extends MultiClassSameReferencePolicy<String> { + + private final HorizontalClassMergerOptions options; + + public SameFilePolicy(AppView<?> appView) { + this.options = appView.options().horizontalClassMergerOptions(); + } + + @Override + public String getMergeKey(DexProgramClass clazz) { + return clazz.getType().toDescriptorString().replaceAll("^([^$]+)\\$.*", "$1"); + } + + @Override + public String getName() { + return "SameFilePolicy"; + } + + @Override + public boolean shouldSkipPolicy() { + return !options.isSameFilePolicyEnabled(); + } +}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/ClassTypeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/ClassTypeElement.java index 6101905..26993a6 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/type/ClassTypeElement.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/type/ClassTypeElement.java
@@ -479,14 +479,17 @@ if (s1.isEmpty() || s2.isEmpty()) { return InterfaceCollection.empty(); } - InterfaceCollection cached = - appView.dexItemFactory().leastUpperBoundOfInterfacesTable.get(s1, s2); - if (cached != null) { - return cached; - } - cached = appView.dexItemFactory().leastUpperBoundOfInterfacesTable.get(s2, s1); - if (cached != null) { - return cached; + // Synchronization is required, see b/242286733. + synchronized (appView.dexItemFactory().leastUpperBoundOfInterfacesTable) { + InterfaceCollection cached = + appView.dexItemFactory().leastUpperBoundOfInterfacesTable.get(s1, s2); + if (cached != null) { + return cached; + } + cached = appView.dexItemFactory().leastUpperBoundOfInterfacesTable.get(s2, s1); + if (cached != null) { + return cached; + } } Map<DexType, InterfaceMarker> seen = new IdentityHashMap<>(); Queue<InterfaceWithMarker> worklist = new ArrayDeque<>();
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstantValueUtils.java b/src/main/java/com/android/tools/r8/ir/code/ConstantValueUtils.java index 86d04e5..9855ee6 100644 --- a/src/main/java/com/android/tools/r8/ir/code/ConstantValueUtils.java +++ b/src/main/java/com/android/tools/r8/ir/code/ConstantValueUtils.java
@@ -13,11 +13,12 @@ /** * If the given value is a constant class, then returns the corresponding {@link DexType}. - * Otherwise returns null. + * Otherwise returns null. This should only be used for tracing. */ - public static DexType getDexTypeRepresentedByValue( + public static DexType getDexTypeRepresentedByValueForTracing( Value value, DexDefinitionSupplier definitions) { - Value alias = value.getAliasedValue(); + Value alias = + value.getAliasedValue(IgnoreDebugLocalWriteAliasedValueConfiguration.getInstance()); if (alias.isPhi()) { return null; }
diff --git a/src/main/java/com/android/tools/r8/ir/code/DebugLocalWrite.java b/src/main/java/com/android/tools/r8/ir/code/DebugLocalWrite.java index ad9be48..b17536e 100644 --- a/src/main/java/com/android/tools/r8/ir/code/DebugLocalWrite.java +++ b/src/main/java/com/android/tools/r8/ir/code/DebugLocalWrite.java
@@ -65,6 +65,10 @@ public void insertLoadAndStores(InstructionListIterator it, LoadStoreHelper helper) { helper.loadInValues(this, it); // A local-write does not have an outgoing stack value, but in writes directly to the local. + assert !instructionTypeCanThrow(); + if (getBlock().hasCatchHandlers()) { + helper.splitAfterStoredOutValue(it); + } } @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/IgnoreDebugLocalWriteAliasedValueConfiguration.java b/src/main/java/com/android/tools/r8/ir/code/IgnoreDebugLocalWriteAliasedValueConfiguration.java new file mode 100644 index 0000000..c9dcfa2 --- /dev/null +++ b/src/main/java/com/android/tools/r8/ir/code/IgnoreDebugLocalWriteAliasedValueConfiguration.java
@@ -0,0 +1,31 @@ +// 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.code; + +public class IgnoreDebugLocalWriteAliasedValueConfiguration implements AliasedValueConfiguration { + + private static final IgnoreDebugLocalWriteAliasedValueConfiguration INSTANCE = + new IgnoreDebugLocalWriteAliasedValueConfiguration(); + + private IgnoreDebugLocalWriteAliasedValueConfiguration() {} + + public static IgnoreDebugLocalWriteAliasedValueConfiguration getInstance() { + return INSTANCE; + } + + @Override + public boolean isIntroducingAnAlias(Instruction instruction) { + return instruction.isAssume() || instruction.isDebugLocalWrite(); + } + + @Override + public Value getAliasForOutValue(Instruction instruction) { + assert instruction.isAssume() || instruction.isDebugLocalWrite(); + + return instruction.isAssume() + ? instruction.asAssume().src() + : instruction.asDebugLocalWrite().src(); + } +}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java b/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java index 3dcfa35..224b457 100644 --- a/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java +++ b/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java
@@ -13,6 +13,7 @@ import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.type.TypeElement; +import com.android.tools.r8.utils.BooleanUtils; import com.android.tools.r8.utils.ConsumerUtils; import com.android.tools.r8.utils.InternalOptions; import com.google.common.collect.Sets; @@ -141,6 +142,10 @@ boolean removeOrReplaceCurrentInstructionByInitClassIfPossible( AppView<?> appView, IRCode code, DexType type, Consumer<InitClass> consumer); + default void replaceCurrentInstructionWithConstBoolean(IRCode code, boolean value) { + replaceCurrentInstructionWithConstInt(code, BooleanUtils.intValue(value)); + } + void replaceCurrentInstructionWithConstClass( AppView<?> appView, IRCode code, DexType type, DebugLocalInfo localInfo);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java index 3c0046f..3050bdc 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java
@@ -8,17 +8,21 @@ import com.android.tools.r8.androidapi.AndroidApiLevelCompute; import com.android.tools.r8.androidapi.ComputedApiLevel; +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.contexts.CompilationContext.MethodProcessingContext; import com.android.tools.r8.contexts.CompilationContext.UniqueContext; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexClass; +import com.android.tools.r8.graph.DexEncodedMember; import com.android.tools.r8.graph.DexEncodedMethod; +import com.android.tools.r8.graph.DexField; import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexLibraryClass; import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexProto; +import com.android.tools.r8.graph.DexReference; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.MethodAccessFlags; import com.android.tools.r8.graph.ProgramMethod; @@ -27,11 +31,16 @@ 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 com.android.tools.r8.ir.synthetic.FieldAccessorBuilder; import com.android.tools.r8.ir.synthetic.ForwardMethodBuilder; +import com.android.tools.r8.synthesis.SyntheticMethodBuilder; import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.TraversalContinuation; import com.google.common.collect.ImmutableList; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; +import java.util.function.Function; /** * This desugaring will outline calls to library methods that are introduced after the min-api @@ -57,11 +66,12 @@ MethodProcessingContext methodProcessingContext, CfInstructionDesugaringCollection desugaringCollection, DexItemFactory dexItemFactory) { - ComputedApiLevel computedApiLevel = getComputedApiLevelForMethodOnHolderWithMinApi(instruction); + ComputedApiLevel computedApiLevel = + getComputedApiLevelInstructionOnHolderWithMinApi(instruction); if (computedApiLevel.isGreaterThan(appView.computedMinApiLevel())) { return desugarLibraryCall( methodProcessingContext.createUniqueContext(), - instruction.asInvoke(), + instruction, computedApiLevel, dexItemFactory, eventConsumer, @@ -75,59 +85,68 @@ if (context.getDefinition().isD8R8Synthesized()) { return false; } - return getComputedApiLevelForMethodOnHolderWithMinApi(instruction) + return getComputedApiLevelInstructionOnHolderWithMinApi(instruction) .isGreaterThan(appView.computedMinApiLevel()); } - private ComputedApiLevel getComputedApiLevelForMethodOnHolderWithMinApi( + private ComputedApiLevel getComputedApiLevelInstructionOnHolderWithMinApi( CfInstruction instruction) { - if (!instruction.isInvoke()) { + if (!instruction.isInvoke() && !instruction.isFieldInstruction()) { return appView.computedMinApiLevel(); } - CfInvoke cfInvoke = instruction.asInvoke(); - if (cfInvoke.isInvokeSpecial()) { + DexReference reference; + if (instruction.isInvoke()) { + CfInvoke cfInvoke = instruction.asInvoke(); + if (cfInvoke.isInvokeSpecial()) { + return appView.computedMinApiLevel(); + } + reference = cfInvoke.getMethod(); + } else { + reference = instruction.asFieldInstruction().getField(); + } + if (!reference.getContextType().isClassType()) { return appView.computedMinApiLevel(); } - DexType holderType = cfInvoke.getMethod().getHolderType(); - if (!holderType.isClassType()) { - return appView.computedMinApiLevel(); - } - DexClass holder = appView.definitionFor(holderType); + DexClass holder = appView.definitionFor(reference.getContextType()); if (holder == null || !holder.isLibraryClass()) { return appView.computedMinApiLevel(); } - ComputedApiLevel methodApiLevel = - apiLevelCompute.computeApiLevelForLibraryReference( - cfInvoke.getMethod(), ComputedApiLevel.unknown()); - if (appView.computedMinApiLevel().isGreaterThanOrEqualTo(methodApiLevel) - || isApiLevelLessThanOrEqualTo9(methodApiLevel) - || methodApiLevel.isUnknownApiLevel()) { + ComputedApiLevel referenceApiLevel = + apiLevelCompute.computeApiLevelForLibraryReference(reference, ComputedApiLevel.unknown()); + if (appView.computedMinApiLevel().isGreaterThanOrEqualTo(referenceApiLevel) + || isApiLevelLessThanOrEqualTo9(referenceApiLevel) + || referenceApiLevel.isUnknownApiLevel()) { return appView.computedMinApiLevel(); } // Check for protected or package private access flags before outlining. if (holder.isInterface()) { - return methodApiLevel; + return referenceApiLevel; } else { - DexEncodedMethod methodDefinition = - simpleLookupInClassHierarchy(holder.asLibraryClass(), cfInvoke.getMethod()); - return methodDefinition != null && methodDefinition.isPublic() - ? methodApiLevel + DexEncodedMember<?, ?> definition = + simpleLookupInClassHierarchy( + holder.asLibraryClass(), + reference.isDexMethod() + ? x -> x.lookupMethod(reference.asDexMethod()) + : x -> x.lookupField(reference.asDexField())); + return definition != null && definition.isPublic() + ? referenceApiLevel : appView.computedMinApiLevel(); } } - private DexEncodedMethod simpleLookupInClassHierarchy(DexLibraryClass holder, DexMethod method) { - DexEncodedMethod result = holder.lookupMethod(method); + private DexEncodedMember<?, ?> simpleLookupInClassHierarchy( + DexLibraryClass holder, Function<DexClass, DexEncodedMember<?, ?>> lookup) { + DexEncodedMember<?, ?> result = lookup.apply(holder); if (result != null) { return result; } - TraversalContinuation<DexEncodedMethod, ?> traversalResult = + TraversalContinuation<DexEncodedMember<?, ?>, ?> traversalResult = appView .appInfoForDesugaring() .traverseSuperClasses( holder, (ignored, superClass, ignored_) -> { - DexEncodedMethod definition = superClass.lookupMethod(method); + DexEncodedMember<?, ?> definition = lookup.apply(superClass); if (definition != null) { return TraversalContinuation.doBreak(definition); } @@ -143,29 +162,24 @@ private Collection<CfInstruction> desugarLibraryCall( UniqueContext uniqueContext, - CfInvoke invoke, + CfInstruction instruction, ComputedApiLevel computedApiLevel, DexItemFactory factory, ApiInvokeOutlinerDesugaringEventConsumer eventConsumer, ProgramMethod context) { - DexMethod method = invoke.getMethod(); + assert instruction.isInvoke() || instruction.isFieldInstruction(); ProgramMethod outlinedMethod = - ensureOutlineMethod(uniqueContext, method, computedApiLevel, factory, invoke); + ensureOutlineMethod(uniqueContext, instruction, computedApiLevel, factory, context); eventConsumer.acceptOutlinedMethod(outlinedMethod, context); return ImmutableList.of(new CfInvoke(INVOKESTATIC, outlinedMethod.getReference(), false)); } private ProgramMethod ensureOutlineMethod( UniqueContext context, - DexMethod apiMethod, + CfInstruction instruction, ComputedApiLevel apiLevel, DexItemFactory factory, - CfInvoke invoke) { - DexClass libraryHolder = appView.definitionFor(apiMethod.getHolderType()); - assert libraryHolder != null; - boolean isVirtualMethod = invoke.isInvokeVirtual() || invoke.isInvokeInterface(); - assert verifyLibraryHolderAndInvoke(libraryHolder, apiMethod, isVirtualMethod); - DexProto proto = factory.prependHolderToProtoIf(apiMethod, isVirtualMethod); + ProgramMethod programContext) { return appView .getSyntheticItems() .createMethod( @@ -174,7 +188,6 @@ appView, syntheticMethodBuilder -> { syntheticMethodBuilder - .setProto(proto) .setAccessFlags( MethodAccessFlags.builder() .setPublic() @@ -183,24 +196,83 @@ .setBridge() .build()) .setApiLevelForDefinition(apiLevel) - .setApiLevelForCode(apiLevel) - .setCode( - m -> { - if (isVirtualMethod) { - return ForwardMethodBuilder.builder(factory) - .setVirtualTarget(apiMethod, libraryHolder.isInterface()) - .setNonStaticSource(apiMethod) - .build(); - } else { - return ForwardMethodBuilder.builder(factory) - .setStaticTarget(apiMethod, libraryHolder.isInterface()) - .setStaticSource(apiMethod) - .build(); - } - }); + .setApiLevelForCode(apiLevel); + if (instruction.isInvoke()) { + setCodeForInvoke(syntheticMethodBuilder, instruction.asInvoke(), factory); + } else { + assert instruction.isCfInstruction(); + setCodeForFieldInstruction( + syntheticMethodBuilder, + instruction.asFieldInstruction(), + factory, + programContext); + } }); } + private void setCodeForInvoke( + SyntheticMethodBuilder methodBuilder, CfInvoke invoke, DexItemFactory factory) { + DexMethod method = invoke.getMethod(); + DexClass libraryHolder = appView.definitionFor(method.getHolderType()); + assert libraryHolder != null; + boolean isVirtualMethod = invoke.isInvokeVirtual() || invoke.isInvokeInterface(); + assert verifyLibraryHolderAndInvoke(libraryHolder, method, isVirtualMethod); + DexProto proto = factory.prependHolderToProtoIf(method, isVirtualMethod); + methodBuilder + .setProto(proto) + .setCode( + m -> { + if (isVirtualMethod) { + return ForwardMethodBuilder.builder(factory) + .setVirtualTarget(method, libraryHolder.isInterface()) + .setNonStaticSource(method) + .build(); + } else { + return ForwardMethodBuilder.builder(factory) + .setStaticTarget(method, libraryHolder.isInterface()) + .setStaticSource(method) + .build(); + } + }); + } + + private void setCodeForFieldInstruction( + SyntheticMethodBuilder methodBuilder, + CfFieldInstruction fieldInstruction, + DexItemFactory factory, + ProgramMethod programContext) { + DexField field = fieldInstruction.getField(); + DexClass libraryHolder = appView.definitionFor(field.getHolderType()); + assert libraryHolder != null; + boolean isInstance = + fieldInstruction.isInstanceFieldPut() || fieldInstruction.isInstanceFieldGet(); + // Outlined field references will return a value if getter and only takes arguments if + // instance or if put or two arguments if both. + DexType returnType = fieldInstruction.isFieldGet() ? field.getType() : factory.voidType; + List<DexType> parameters = new ArrayList<>(); + if (isInstance) { + parameters.add(libraryHolder.getType()); + } + if (fieldInstruction.isFieldPut()) { + parameters.add(field.getType()); + } + methodBuilder + .setProto(factory.createProto(returnType, parameters)) + .setCode( + m -> + FieldAccessorBuilder.builder() + .applyIf( + isInstance, + thenConsumer -> thenConsumer.setInstanceField(field), + elseConsumer -> elseConsumer.setStaticField(field)) + .applyIf( + fieldInstruction.isFieldGet(), + FieldAccessorBuilder::setGetter, + FieldAccessorBuilder::setSetter) + .setSourceMethod(programContext.getReference()) + .build()); + } + private boolean verifyLibraryHolderAndInvoke( DexClass libraryHolder, DexMethod apiMethod, boolean isVirtualInvoke) { DexEncodedMethod libraryApiMethodDefinition = libraryHolder.lookupMethod(apiMethod);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java index 5f8e35a..0be57c5 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
@@ -290,8 +290,7 @@ for (Map.Entry<String, JsonElement> retarget : jsonFlagSet.get(RETARGET_STATIC_FIELD_KEY).getAsJsonObject().entrySet()) { builder.retargetStaticField( - parseField(retarget.getKey()), - stringDescriptorToDexType(retarget.getValue().getAsString())); + parseField(retarget.getKey()), parseField(retarget.getValue().getAsString())); } } if (jsonFlagSet.has(RETARGET_METHOD_KEY)) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java index 5c70c34..a927cdf 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java
@@ -30,7 +30,7 @@ private final Set<String> maintainPrefix; private final Map<String, Map<String, String>> rewriteDerivedPrefix; private final Map<DexType, DexType> emulatedInterfaces; - private final Map<DexField, DexType> retargetStaticField; + private final Map<DexField, DexField> retargetStaticField; private final Map<DexMethod, DexType> covariantRetarget; private final Map<DexMethod, DexType> retargetMethod; private final Map<DexMethod, DexType> retargetMethodEmulatedDispatch; @@ -49,7 +49,7 @@ Set<String> maintainPrefix, Map<String, Map<String, String>> rewriteDerivedPrefix, Map<DexType, DexType> emulateLibraryInterface, - Map<DexField, DexType> retargetStaticField, + Map<DexField, DexField> retargetStaticField, Map<DexMethod, DexType> covariantRetarget, Map<DexMethod, DexType> retargetMethod, Map<DexMethod, DexType> retargetMethodEmulatedDispatch, @@ -148,7 +148,7 @@ return emulatedInterfaces; } - public Map<DexField, DexType> getRetargetStaticField() { + public Map<DexField, DexField> getRetargetStaticField() { return retargetStaticField; } @@ -217,7 +217,7 @@ private final Set<String> maintainPrefix; private final Map<String, Map<String, String>> rewriteDerivedPrefix; private final Map<DexType, DexType> emulatedInterfaces; - private final Map<DexField, DexType> retargetStaticField; + private final Map<DexField, DexField> retargetStaticField; private final Map<DexMethod, DexType> covariantRetarget; private final Map<DexMethod, DexType> retargetMethod; private final Map<DexMethod, DexType> retargetMethodEmulatedDispatch; @@ -261,7 +261,7 @@ Set<String> maintainPrefix, Map<String, Map<String, String>> rewriteDerivedPrefix, Map<DexType, DexType> emulateLibraryInterface, - Map<DexField, DexType> retargetStaticField, + Map<DexField, DexField> retargetStaticField, Map<DexMethod, DexType> covariantRetarget, Map<DexMethod, DexType> retargetMethod, Map<DexMethod, DexType> retargetMethodEmulatedDispatch, @@ -388,11 +388,11 @@ return this; } - public Builder retargetStaticField(DexField key, DexType rewrittenType) { + public Builder retargetStaticField(DexField key, DexField value) { put( retargetStaticField, key, - rewrittenType, + value, HumanDesugaredLibrarySpecificationParser.RETARGET_STATIC_FIELD_KEY); return this; }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecificationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecificationParser.java index e17494f..1779022 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecificationParser.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecificationParser.java
@@ -8,6 +8,7 @@ import static com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser.isHumanSpecification; import com.android.tools.r8.StringResource; +import com.android.tools.r8.errors.UnsupportedDesugaredLibraryConfigurationVersionDiagnostic; import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.ir.desugar.desugaredlibrary.TopLevelFlagsBuilder; import com.android.tools.r8.origin.Origin; @@ -172,11 +173,7 @@ int formatVersion = formatVersionElement.getAsInt(); if (formatVersion > MAX_SUPPORTED_VERSION) { throw reporter.fatalError( - new StringDiagnostic( - "Unsupported desugared library configuration version, please upgrade the D8/R8" - + " compiler." - + " See https://developer.android.com/studio/build/library-desugaring-versions.", - origin)); + new UnsupportedDesugaredLibraryConfigurationVersionDiagnostic(origin)); } String version = required(jsonConfig, VERSION_KEY).getAsString();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java index dad5fd5..1b83bf8 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java
@@ -197,11 +197,7 @@ } public boolean isSupported(DexReference reference) { - // Support through type rewriting. - if (getRewriteType().containsKey(reference.getContextType())) { - return true; - } - if (getMaintainType().contains(reference.getContextType())) { + if (isContextTypeMaintainedOrRewritten(reference)) { return true; } if (!reference.isDexMethod()) { @@ -223,6 +219,12 @@ return false; } + public boolean isContextTypeMaintainedOrRewritten(DexReference reference) { + // Support through type rewriting. + return getRewriteType().containsKey(reference.getContextType()) + || getMaintainType().contains(reference.getContextType()); + } + @Override public MachineDesugaredLibrarySpecification toMachineSpecification( DexApplication app, Timing timing) throws IOException {
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 b9c92a6..302c08c 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
@@ -75,7 +75,7 @@ MethodProcessingContext methodProcessingContext, CfInstructionDesugaringCollection desugaringCollection, DexItemFactory dexItemFactory) { - if (instruction.isFieldInstruction() && needsDesugaring(instruction, context)) { + if (instruction.isStaticFieldGet() && needsDesugaring(instruction, context)) { return desugarFieldInstruction(instruction.asFieldInstruction(), context); } else if (instruction.isInvoke() && needsDesugaring(instruction, context)) { return desugarInvoke(instruction.asInvoke(), eventConsumer, context, methodProcessingContext); @@ -87,7 +87,7 @@ CfFieldInstruction fieldInstruction, ProgramMethod context) { DexField fieldRetarget = fieldRetarget(fieldInstruction, context); assert fieldRetarget != null; - assert fieldInstruction.isStaticFieldGet() || fieldInstruction.isStaticFieldPut(); + assert fieldInstruction.isStaticFieldGet(); return Collections.singletonList(fieldInstruction.createWithField(fieldRetarget)); } @@ -106,7 +106,7 @@ @Override public boolean needsDesugaring(CfInstruction instruction, ProgramMethod context) { - if (instruction.isFieldInstruction()) { + if (instruction.isStaticFieldGet()) { return fieldRetarget(instruction.asFieldInstruction(), context) != null; } else if (instruction.isInvoke()) { return computeNewInvokeTarget(instruction.asInvoke(), context).hasNewInvokeTarget();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineRetargetConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineRetargetConverter.java index 7dcb8a8..6078e9d 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineRetargetConverter.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineRetargetConverter.java
@@ -40,7 +40,7 @@ BiConsumer<String, Set<? extends DexReference>> warnConsumer) { rewritingFlags .getRetargetStaticField() - .forEach((field, type) -> convertRetargetField(builder, field, type)); + .forEach((field, rewrittenField) -> convertRetargetField(builder, field, rewrittenField)); rewritingFlags .getCovariantRetarget() .forEach((method, type) -> convertCovariantRetarget(builder, method, type)); @@ -56,15 +56,14 @@ } private void convertRetargetField( - MachineRewritingFlags.Builder builder, DexField field, DexType type) { + MachineRewritingFlags.Builder builder, DexField field, DexField rewrittenField) { DexClass holder = appInfo.definitionFor(field.holder); DexEncodedField foundField = holder.lookupField(field); if (foundField == null) { missingReferences.add(field); return; } - builder.putStaticFieldRetarget( - field, appInfo.dexItemFactory().createField(type, field.type, field.name)); + builder.putStaticFieldRetarget(field, rewrittenField); } private void convertRetargetMethodEmulatedDispatch(
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java index 85802c1..36b96dc 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -2045,23 +2045,6 @@ // Locate the closest dominator block for all user blocks. DominatorTree dominatorTree = dominatorTreeMemoization.computeIfAbsent(); BasicBlock dominator = dominatorTree.closestDominator(userBlocks); - // If the closest dominator block is a block that uses the constant for a phi the constant - // needs to go in the immediate dominator block so that it is available for phi moves. - for (Phi phi : instruction.outValue().uniquePhiUsers()) { - if (phi.getBlock() == dominator) { - if (instruction.outValue().numberOfAllUsers() == 1 && - phi.usesValueOneTime(instruction.outValue())) { - // Out value is used only one time, move the constant directly to the corresponding - // branch rather than into the dominator to avoid to generate a const on paths which - // does not required it. - int predIndex = phi.getOperands().indexOf(instruction.outValue()); - dominator = dominator.getPredecessors().get(predIndex); - } else { - dominator = dominatorTree.immediateDominator(dominator); - } - break; - } - } if (instruction.instructionTypeCanThrow()) { if (block.hasCatchHandlers() || dominator.hasCatchHandlers()) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java index 10cdd99..543eeb7 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
@@ -38,6 +38,7 @@ import com.android.tools.r8.ir.code.IRCode; import com.android.tools.r8.ir.code.If; import com.android.tools.r8.ir.code.InstanceGet; +import com.android.tools.r8.ir.code.InstanceOf; import com.android.tools.r8.ir.code.InstancePut; import com.android.tools.r8.ir.code.Instruction; import com.android.tools.r8.ir.code.InstructionListIterator; @@ -589,6 +590,15 @@ private void removeMiscUsages(IRCode code, Set<Value> affectedValues) { boolean needToRemoveUnreachableBlocks = false; for (Instruction user : eligibleInstance.uniqueUsers()) { + if (user.isInstanceOf()) { + InstanceOf instanceOf = user.asInstanceOf(); + InstructionListIterator instructionIterator = + user.getBlock().listIterator(code, instanceOf); + instructionIterator.replaceCurrentInstructionWithConstBoolean( + code, appView.appInfo().isSubtype(eligibleClass.getType(), instanceOf.type())); + continue; + } + if (user.isInvokeMethod()) { InvokeMethod invoke = user.asInvokeMethod();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java index 525041d..b1ea459 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
@@ -489,7 +489,8 @@ } if (user.isInvokeStatic()) { - DexClassAndMethod singleTarget = user.asInvokeStatic().lookupSingleTarget(appView, context); + InvokeStatic invoke = user.asInvokeStatic(); + DexClassAndMethod singleTarget = invoke.lookupSingleTarget(appView, context); if (singleTarget == null) { return false; } @@ -498,6 +499,33 @@ // in the valueOf utility method. addRequiredNameData(enumClass); markMethodDependsOnLibraryModelisation(context); + // The out-value must be cast before it is used, or an assume instruction must strengthen + // its dynamic type, so that the out-value is analyzed by the enum unboxing analysis. + if (invoke.hasOutValue()) { + if (invoke.outValue().hasPhiUsers()) { + return false; + } + for (Instruction enumUser : invoke.outValue().uniqueUsers()) { + if (enumUser.isAssumeWithDynamicTypeAssumption()) { + Assume assume = enumUser.asAssume(); + if (assume + .getDynamicTypeAssumption() + .getDynamicType() + .getDynamicUpperBoundType() + .equalUpToNullability(enumClass.getType().toTypeElement(appView))) { + // OK. + continue; + } + } else if (enumUser.isCheckCast()) { + CheckCast checkCast = enumUser.asCheckCast(); + if (checkCast.getType() == enumClass.getType()) { + // OK. + continue; + } + } + return false; + } + } return true; } if (singleTarget.getReference()
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java b/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java index f9266b0..050b1ff 100644 --- a/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java +++ b/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java
@@ -504,7 +504,7 @@ private List<MappingInformation> additionalMappingInfo = EMPTY_MAPPING_INFORMATION; - private MappedRange( + MappedRange( Range minifiedRange, MethodSignature signature, Range originalRange, String renamedName) { this.minifiedRange = minifiedRange; this.signature = signature;
diff --git a/src/main/java/com/android/tools/r8/naming/ComposingBuilder.java b/src/main/java/com/android/tools/r8/naming/ComposingBuilder.java new file mode 100644 index 0000000..6e1bc00 --- /dev/null +++ b/src/main/java/com/android/tools/r8/naming/ComposingBuilder.java
@@ -0,0 +1,577 @@ +// 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.naming; + +import static com.android.tools.r8.utils.FunctionUtils.ignoreArgument; + +import com.android.tools.r8.naming.ClassNamingForNameMapper.MappedRange; +import com.android.tools.r8.naming.ClassNamingForNameMapper.MappedRangesOfName; +import com.android.tools.r8.naming.MemberNaming.MethodSignature; +import com.android.tools.r8.naming.mappinginformation.MapVersionMappingInformation; +import com.android.tools.r8.naming.mappinginformation.MappingInformation; +import com.android.tools.r8.naming.mappinginformation.RewriteFrameMappingInformation; +import com.android.tools.r8.naming.mappinginformation.RewriteFrameMappingInformation.ThrowsCondition; +import com.android.tools.r8.references.Reference; +import com.android.tools.r8.utils.BiMapContainer; +import com.android.tools.r8.utils.ChainableStringConsumer; +import com.android.tools.r8.utils.ConsumerUtils; +import com.android.tools.r8.utils.ListUtils; +import com.android.tools.r8.utils.SegmentTree; +import it.unimi.dsi.fastutil.ints.Int2ReferenceMap; +import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +public class ComposingBuilder { + + /** + * To ensure we can do alpha renaming of classes and members without polluting the existing + * mappping, we use a committed map that we update for each class name mapping. That allows us to + * rename to existing renamed names as long as these are also renamed later in the map. + */ + private final Map<String, ComposingClassBuilder> committed = new HashMap<>(); + + private Map<String, ComposingClassBuilder> current = new HashMap<>(); + + private MapVersionMappingInformation currentMapVersion = null; + + private final ComposingSharedData sharedData = new ComposingSharedData(); + + public void compose(ClassNameMapper classNameMapper) throws MappingComposeException { + MapVersionMappingInformation thisMapVersion = classNameMapper.getFirstMapVersionInformation(); + if (thisMapVersion != null) { + if (currentMapVersion == null + || currentMapVersion.getMapVersion().isLessThan(thisMapVersion.getMapVersion())) { + currentMapVersion = thisMapVersion; + } + } + sharedData.patchupMappingInformation(classNameMapper); + for (ClassNamingForNameMapper classMapping : classNameMapper.getClassNameMappings().values()) { + compose(classMapping); + } + commit(); + } + + private void compose(ClassNamingForNameMapper classMapping) throws MappingComposeException { + String originalName = classMapping.originalName; + ComposingClassBuilder composingClassBuilder = committed.get(originalName); + String renamedName = classMapping.renamedName; + if (composingClassBuilder == null) { + composingClassBuilder = new ComposingClassBuilder(originalName, renamedName, sharedData); + } else { + composingClassBuilder.setRenamedName(renamedName); + committed.remove(originalName); + } + ComposingClassBuilder duplicateMapping = current.put(renamedName, composingClassBuilder); + if (duplicateMapping != null) { + throw new MappingComposeException( + "Duplicate class mapping. Both '" + + duplicateMapping.getOriginalName() + + "' and '" + + originalName + + "' maps to '" + + renamedName + + "'."); + } + composingClassBuilder.compose(classMapping); + } + + private void commit() throws MappingComposeException { + for (Entry<String, ComposingClassBuilder> newEntry : current.entrySet()) { + String renamedName = newEntry.getKey(); + ComposingClassBuilder classBuilder = newEntry.getValue(); + ComposingClassBuilder duplicateMapping = committed.put(renamedName, classBuilder); + if (duplicateMapping != null) { + throw new MappingComposeException( + "Duplicate class mapping. Both '" + + duplicateMapping.getOriginalName() + + "' and '" + + classBuilder.getOriginalName() + + "' maps to '" + + renamedName + + "'."); + } + } + current = new HashMap<>(); + } + + @Override + public String toString() { + List<ComposingClassBuilder> classBuilders = new ArrayList<>(committed.values()); + classBuilders.sort(Comparator.comparing(ComposingClassBuilder::getOriginalName)); + StringBuilder sb = new StringBuilder(); + // TODO(b/241763080): Keep preamble of mapping files" + if (currentMapVersion != null) { + sb.append("# ").append(currentMapVersion.serialize()).append("\n"); + } + ChainableStringConsumer wrap = ChainableStringConsumer.wrap(sb::append); + for (ComposingClassBuilder classBuilder : classBuilders) { + classBuilder.write(wrap); + } + return sb.toString(); + } + + public static class ComposingSharedData { + + /** + * RewriteFrameInformation contains condition clauses that are bound to the residual program. As + * a result of that, we have to patch up the conditions when we compose new class mappings. + */ + private final List<RewriteFrameMappingInformation> mappingInformationToPatchUp = + new ArrayList<>(); + + private void patchupMappingInformation(ClassNameMapper classNameMapper) { + BiMapContainer<String, String> obfuscatedToOriginalMapping = + classNameMapper.getObfuscatedToOriginalMapping(); + for (RewriteFrameMappingInformation rewriteMappingInfo : mappingInformationToPatchUp) { + rewriteMappingInfo + .getConditions() + .forEach( + rewriteCondition -> { + ThrowsCondition throwsCondition = rewriteCondition.asThrowsCondition(); + if (throwsCondition != null) { + String originalName = throwsCondition.getClassReference().getTypeName(); + String obfuscatedName = obfuscatedToOriginalMapping.inverse.get(originalName); + if (obfuscatedName != null) { + throwsCondition.setClassReferenceInternal( + Reference.classFromTypeName(obfuscatedName)); + } + } + }); + } + } + } + + public static class ComposingClassBuilder { + + private static final String INDENTATION = " "; + private static final int NO_RANGE_FROM = -1; + + private final String originalName; + private String renamedName; + private final Map<String, List<MemberNaming>> fieldMembers = new HashMap<>(); + // Ideally we would have liked to use the signature as a key since this uniquely specifies a + // method. However, because a mapping file has no right hand side, we therefore assume that a + // starting position uniquely identifies a method. If no position is given there can be only + // one method since any shrinker should put in line numbers for overloads. + private final Map<String, SegmentTree<List<MappedRange>>> methodMembers = new HashMap<>(); + private List<MappingInformation> additionalMappingInfo = null; + private final ComposingSharedData sharedData; + + private ComposingClassBuilder( + String originalName, String renamedName, ComposingSharedData sharedData) { + this.originalName = originalName; + this.renamedName = renamedName; + this.sharedData = sharedData; + } + + public void setRenamedName(String renamedName) { + this.renamedName = renamedName; + } + + public String getOriginalName() { + return originalName; + } + + public String getRenamedName() { + return renamedName; + } + + public void compose(ClassNamingForNameMapper mapper) throws MappingComposeException { + List<MappingInformation> newMappingInfo = mapper.getAdditionalMappingInfo(); + if (newMappingInfo != null && !newMappingInfo.isEmpty()) { + if (additionalMappingInfo == null) { + additionalMappingInfo = new ArrayList<>(); + } + additionalMappingInfo.addAll(newMappingInfo); + } + composeFieldNamings(mapper); + composeMethodNamings(mapper); + } + + private void composeFieldNamings(ClassNamingForNameMapper mapper) + throws MappingComposeException { + mapper.forAllFieldNaming( + fieldNaming -> { + List<MemberNaming> memberNamings = fieldMembers.get(fieldNaming.getOriginalName()); + if (memberNamings == null) { + fieldMembers + .computeIfAbsent(fieldNaming.getRenamedName(), ignoreArgument(ArrayList::new)) + .add(fieldNaming); + return; + } + // There is no right-hand side of field mappings thus if we have seen an existing + // mapping we cannot compose the type. For fields we check that the original type is + // the same or we throw an error since we cannot guarantee a proper composition. + for (int i = 0; i < memberNamings.size(); i++) { + MemberNaming memberNaming = memberNamings.get(i); + assert memberNaming.getRenamedName().equals(fieldNaming.getOriginalName()); + if (memberNaming.renamedSignature.equals(fieldNaming.getOriginalSignature())) { + memberNamings.set( + i, + new MemberNaming( + memberNaming.getOriginalSignature(), fieldNaming.getRenamedName())); + return; + } + } + throw new MappingComposeException( + "Unable to compose field naming '" + + fieldNaming + + "' since the original type has changed."); + }); + } + + private void composeMethodNamings(ClassNamingForNameMapper mapper) + throws MappingComposeException { + for (Entry<String, MappedRangesOfName> entry : mapper.mappedRangesByRenamedName.entrySet()) { + MappedRangesOfName value = entry.getValue(); + List<MappedRange> mappedRanges = value.getMappedRanges(); + MappedRangeResult mappedRangeResult; + int index = 0; + while ((mappedRangeResult = getMappedRangesForMethod(mappedRanges, index)) != null) { + index = mappedRangeResult.endIndex; + MappedRange newMappedRange = mappedRangeResult.lastRange; + String originalName = newMappedRange.signature.getName(); + SegmentTree<List<MappedRange>> listSegmentTree = methodMembers.get(originalName); + List<MappedRange> existingMappedRanges = null; + if (listSegmentTree != null) { + Entry<Integer, List<MappedRange>> existingEntry = + listSegmentTree.findEntry(mappedRangeResult.startOriginalPosition); + // We assume that all new minified ranges for a method are rewritten in the new map + // such that no previous existing positions exists. + if (existingEntry != null) { + listSegmentTree.removeSegment(existingEntry.getKey()); + existingMappedRanges = existingEntry.getValue(); + } + } + Range minifiedRange = mappedRangeResult.lastRange.minifiedRange; + int endMinifiedPosition = minifiedRange == null ? NO_RANGE_FROM : minifiedRange.to; + methodMembers + .computeIfAbsent(newMappedRange.renamedName, ignored -> new SegmentTree<>(false)) + .add( + mappedRangeResult.startMinifiedPosition, + endMinifiedPosition, + composeMappedRangesForMethod(existingMappedRanges, mappedRangeResult.allRanges)); + } + } + } + + /*** + * Iterates over mapped ranges in order, starting from index, and adds to an internal result as + * long as the current mapped range is the same method and return a mapped range result + * containing all ranges for a method along with some additional information. + */ + private MappedRangeResult getMappedRangesForMethod(List<MappedRange> mappedRanges, int index) { + if (index >= mappedRanges.size()) { + return null; + } + List<MappedRange> seenMappedRanges = new ArrayList<>(); + MappedRange lastSeen = mappedRanges.get(index); + seenMappedRanges.add(lastSeen); + if (lastSeen.minifiedRange == null) { + return new MappedRangeResult( + NO_RANGE_FROM, NO_RANGE_FROM, index + 1, lastSeen, seenMappedRanges); + } + int startMinifiedPosition = lastSeen.minifiedRange.from; + int startOriginalPosition = + lastSeen.originalRange == null ? NO_RANGE_FROM : lastSeen.originalRange.from; + for (int i = index + 1; i < mappedRanges.size(); i++) { + MappedRange thisMappedRange = mappedRanges.get(i); + // We assume that if we see a mapping where the minified range is 0 then we will not find + // another mapping where it is not null. + if (thisMappedRange.minifiedRange == null) { + assert !lastSeen.signature.equals(thisMappedRange.signature); + break; + } + // Otherwise break if we see a signature that is not equal to the current one and it + // has another minified range meaning it is not an inlinee. + if (!thisMappedRange.signature.equals(lastSeen.signature) + && !thisMappedRange.minifiedRange.equals(lastSeen.minifiedRange) + && !isInlineMappedRange(mappedRanges, i)) { + break; + } + for (MappingInformation mappingInformation : thisMappedRange.getAdditionalMappingInfo()) { + if (mappingInformation.isRewriteFrameMappingInformation()) { + sharedData.mappingInformationToPatchUp.add( + mappingInformation.asRewriteFrameMappingInformation()); + } + } + seenMappedRanges.add(thisMappedRange); + lastSeen = thisMappedRange; + } + return new MappedRangeResult( + startMinifiedPosition, + startOriginalPosition, + index + seenMappedRanges.size(), + lastSeen, + seenMappedRanges); + } + + private List<MappedRange> composeMappedRangesForMethod( + List<MappedRange> existingRanges, List<MappedRange> newRanges) + throws MappingComposeException { + assert !newRanges.isEmpty(); + if (existingRanges == null || existingRanges.isEmpty()) { + return newRanges; + } + // The new minified ranges may have ranges that range over positions that has additional + // information, such as inlinees: + // Existing: + // 1:2:void caller():14:15 -> x + // 3:3:void inlinee():42:42 -> x + // 3:3:void caller():16:16 -> x + // 4:10:void caller():17:23 -> x + // ... + // New mapping: + // 1:5:void x():1:5 -> y + // 6:10:void x():6:6 -> y + // ... + // It is important that we therefore split up the new ranges to map everything back to the + // existing original mappings: + // Resulting mapping: + // 1:2:void caller():14:15 -> y + // 3:3:void inlinee():42:42 -> y + // 3:3:void caller():16:16 -> y + // 4:5:void caller():17:18 -> y + // 6:10:void caller():19:19 -> y + // ... + Int2ReferenceMap<List<MappedRange>> mappedRangesForPosition = + getExistingMapping(existingRanges); + List<MappedRange> newComposedRanges = new ArrayList<>(); + for (int i = 0; i < newRanges.size(); i++) { + if (isInlineMappedRange(newRanges, i)) { + throw new MappingComposeException( + "Unexpected inline frame '" + existingRanges.get(i) + "' in composing map."); + } + MappedRange newRange = newRanges.get(i); + if (newRange.originalRange == null) { + List<MappedRange> existingMappedRanges = mappedRangesForPosition.get(NO_RANGE_FROM); + assert existingMappedRanges.size() <= 1; + if (existingMappedRanges.isEmpty()) { + newComposedRanges.add(newRange); + } else { + MappedRange existingRange = existingMappedRanges.get(0); + newComposedRanges.add( + new MappedRange( + newRange.minifiedRange, + existingRange.signature, + existingRange.originalRange, + newRange.renamedName)); + } + } else { + // First check if the original range matches the existing minified range. + List<MappedRange> existingMappedRanges = + mappedRangesForPosition.get(newRange.originalRange.from); + if (existingMappedRanges == null) { + throw new MappingComposeException( + "Unexpected missing original position for '" + newRange + "'."); + } + if (ListUtils.last(existingMappedRanges).minifiedRange.equals(newRange.originalRange)) { + computeComposedMappedRange( + newComposedRanges, + newRange, + existingMappedRanges, + newRange.minifiedRange.from, + newRange.minifiedRange.to); + } else { + // Otherwise, we have a situation where the minified range references over multiple + // existing ranges. We simply chop op when the range changes on the right hand side. To + // ensure we do not mess up the spans from the original range, we have to check if the + // current starting position is inside an original range, and then chop it off. + // Similarly, when writing the last block, we have to cut it off to match. + int lastStartingMinifiedFrom = newRange.minifiedRange.from; + for (int position = newRange.minifiedRange.from; + position <= newRange.minifiedRange.to; + position++) { + List<MappedRange> existingMappedRangesForPosition = + mappedRangesForPosition.get(newRange.getOriginalLineNumber(position)); + if (existingMappedRangesForPosition == null) { + throw new MappingComposeException( + "Unexpected missing original position for '" + newRange + "'."); + } + if (!ListUtils.last(existingMappedRanges) + .minifiedRange + .equals(ListUtils.last(existingMappedRangesForPosition).minifiedRange)) { + computeComposedMappedRange( + newComposedRanges, + newRange, + existingMappedRanges, + lastStartingMinifiedFrom, + position - 1); + lastStartingMinifiedFrom = position; + existingMappedRanges = existingMappedRangesForPosition; + } + } + computeComposedMappedRange( + newComposedRanges, + newRange, + existingMappedRanges, + lastStartingMinifiedFrom, + newRange.minifiedRange.to); + } + } + } + return newComposedRanges; + } + + /*** + * Builds a position to mapped ranges for mappings for looking up all mapped ranges for a given + * position. + */ + private Int2ReferenceMap<List<MappedRange>> getExistingMapping( + List<MappedRange> existingRanges) { + Int2ReferenceMap<List<MappedRange>> mappedRangesForPosition = + new Int2ReferenceOpenHashMap<>(); + List<MappedRange> currentRangesForPosition = new ArrayList<>(); + for (int i = 0; i < existingRanges.size(); i++) { + MappedRange mappedRange = existingRanges.get(i); + currentRangesForPosition.add(mappedRange); + if (!isInlineMappedRange(existingRanges, i)) { + if (mappedRange.minifiedRange == null) { + mappedRangesForPosition.put(NO_RANGE_FROM, currentRangesForPosition); + } else { + for (int position = mappedRange.minifiedRange.from; + position <= mappedRange.minifiedRange.to; + position++) { + mappedRangesForPosition.put(position, currentRangesForPosition); + } + } + currentRangesForPosition = new ArrayList<>(); + } + } + return mappedRangesForPosition; + } + + private void computeComposedMappedRange( + List<MappedRange> newComposedRanges, + MappedRange newMappedRange, + List<MappedRange> existingMappedRanges, + int lastStartingMinifiedFrom, + int position) { + Range existingRange = existingMappedRanges.get(0).minifiedRange; + assert existingMappedRanges.stream().allMatch(x -> x.minifiedRange.equals(existingRange)); + Range newMinifiedRange = new Range(lastStartingMinifiedFrom, position); + boolean copyOriginalRange = existingRange.equals(newMappedRange.originalRange); + for (MappedRange existingMappedRange : existingMappedRanges) { + Range existingOriginalRange = existingMappedRange.originalRange; + Range newOriginalRange; + if (copyOriginalRange || existingOriginalRange.span() == 1) { + newOriginalRange = existingOriginalRange; + } else { + // Find the window that the new range points to into the original range. + int existingMinifiedPos = newMappedRange.getOriginalLineNumber(lastStartingMinifiedFrom); + int newOriginalStart = existingMappedRange.getOriginalLineNumber(existingMinifiedPos); + if (newMappedRange.originalRange.span() == 1) { + newOriginalRange = new Range(newOriginalStart, newOriginalStart); + } else { + assert newMinifiedRange.span() <= existingOriginalRange.span(); + newOriginalRange = + new Range(newOriginalStart, newOriginalStart + newMinifiedRange.span() - 1); + } + } + MappedRange computedRange = + new MappedRange( + newMinifiedRange, + existingMappedRange.signature, + newOriginalRange, + newMappedRange.renamedName); + existingMappedRange + .getAdditionalMappingInfo() + .forEach( + info -> computedRange.addMappingInformation(info, ConsumerUtils.emptyConsumer())); + newComposedRanges.add(computedRange); + } + } + + private boolean isInlineMappedRange(List<MappedRange> mappedRanges, int index) { + if (index + 1 >= mappedRanges.size()) { + return false; + } + return mappedRanges + .get(index) + .minifiedRange + .equals(mappedRanges.get(index + 1).minifiedRange); + } + + public void write(ChainableStringConsumer consumer) { + consumer.accept(originalName).accept(" -> ").accept(renamedName).accept(":\n"); + if (additionalMappingInfo != null) { + additionalMappingInfo.forEach( + info -> consumer.accept("# " + info.serialize()).accept("\n")); + } + writeFields(consumer); + writeMethods(consumer); + } + + private void writeFields(ChainableStringConsumer consumer) { + ArrayList<MemberNaming> fieldNamings = new ArrayList<>(); + for (List<MemberNaming> namingsForKey : fieldMembers.values()) { + fieldNamings.addAll(namingsForKey); + } + fieldNamings.sort(Comparator.comparing(MemberNaming::getOriginalName)); + fieldNamings.forEach( + naming -> { + consumer.accept(INDENTATION).accept(naming.toString()).accept("\n"); + }); + } + + private void writeMethods(ChainableStringConsumer consumer) { + Map<String, List<MappedRange>> signatureToMappedRanges = new HashMap<>(); + methodMembers + .values() + .forEach( + segmentTree -> { + segmentTree.visitSegments( + mappedRanges -> { + MethodSignature originalSignature = ListUtils.last(mappedRanges).signature; + List<MappedRange> put = + signatureToMappedRanges.put( + originalSignature.getName() + "_" + originalSignature, mappedRanges); + assert put == null; + }); + }); + ArrayList<String> strings = new ArrayList<>(signatureToMappedRanges.keySet()); + Collections.sort(strings); + for (String key : strings) { + signatureToMappedRanges + .get(key) + .forEach( + mappedRange -> { + consumer.accept(INDENTATION).accept(mappedRange.toString()).accept("\n"); + for (MappingInformation info : mappedRange.getAdditionalMappingInfo()) { + consumer.accept(INDENTATION).accept("# ").accept(info.serialize()).accept("\n"); + } + }); + } + } + + private static class MappedRangeResult { + + private final int startMinifiedPosition; + private final int startOriginalPosition; + private final int endIndex; + private final MappedRange lastRange; + private final List<MappedRange> allRanges; + + public MappedRangeResult( + int startMinifiedPosition, + int startOriginalPosition, + int endIndex, + MappedRange lastRange, + List<MappedRange> allRanges) { + this.startMinifiedPosition = startMinifiedPosition; + this.startOriginalPosition = startOriginalPosition; + this.endIndex = endIndex; + this.lastRange = lastRange; + this.allRanges = allRanges; + } + } + } +}
diff --git a/src/main/java/com/android/tools/r8/naming/MappingComposeException.java b/src/main/java/com/android/tools/r8/naming/MappingComposeException.java new file mode 100644 index 0000000..f443d0e --- /dev/null +++ b/src/main/java/com/android/tools/r8/naming/MappingComposeException.java
@@ -0,0 +1,15 @@ +// 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.naming; + +import com.android.tools.r8.Keep; + +@Keep +public class MappingComposeException extends Exception { + + public MappingComposeException(String message) { + super(message); + } +}
diff --git a/src/main/java/com/android/tools/r8/naming/MappingComposer.java b/src/main/java/com/android/tools/r8/naming/MappingComposer.java new file mode 100644 index 0000000..6450ab6 --- /dev/null +++ b/src/main/java/com/android/tools/r8/naming/MappingComposer.java
@@ -0,0 +1,24 @@ +// 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.naming; + +/** + * MappingComposer is a utility to do composition of mapping files to map line numbers correctly + * when having shrunken input that will end up using DEX PC mappings. + */ +public class MappingComposer { + + public static String compose(ClassNameMapper... classNameMappers) throws MappingComposeException { + assert classNameMappers.length > 0; + if (classNameMappers.length == 1) { + return classNameMappers[0].toString(); + } + ComposingBuilder builder = new ComposingBuilder(); + for (ClassNameMapper classNameMapper : classNameMappers) { + builder.compose(classNameMapper); + } + return builder.toString(); + } +}
diff --git a/src/main/java/com/android/tools/r8/naming/MemberNaming.java b/src/main/java/com/android/tools/r8/naming/MemberNaming.java index bf0a8dd..0c833bd 100644 --- a/src/main/java/com/android/tools/r8/naming/MemberNaming.java +++ b/src/main/java/com/android/tools/r8/naming/MemberNaming.java
@@ -162,6 +162,10 @@ } } + public String getName() { + return name; + } + enum SignatureKind { METHOD, FIELD
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/RewriteFrameMappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/RewriteFrameMappingInformation.java index 82b2a0b..00eb800 100644 --- a/src/main/java/com/android/tools/r8/naming/mappinginformation/RewriteFrameMappingInformation.java +++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/RewriteFrameMappingInformation.java
@@ -162,7 +162,7 @@ static final String FUNCTION_NAME = "throws"; - private final ClassReference classReference; + private ClassReference classReference; private ThrowsCondition(ClassReference classReference) { this.classReference = classReference; @@ -183,6 +183,14 @@ return this; } + public void setClassReferenceInternal(ClassReference reference) { + this.classReference = reference; + } + + public ClassReference getClassReference() { + return classReference; + } + @Override public boolean evaluate(RetraceStackTraceContextImpl context) { return classReference.equals(context.getThrownException());
diff --git a/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java b/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java index 16e3dfb..3dd736b 100644 --- a/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java +++ b/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java
@@ -78,13 +78,16 @@ } private boolean isTargetingSuperMethod(ProgramMethod method, InvokeKind kind, DexMethod target) { + if (kind == InvokeKind.ILLEGAL) { + return false; + } if (kind == InvokeKind.SUPER) { return true; } if (kind == InvokeKind.STATIC) { return appView.appInfo().isStrictSubtypeOf(method.getHolderType(), target.holder); } - assert false : "Unexpected invoke-kind for visibility bridge"; + assert false : "Unexpected invoke-kind for visibility bridge: " + kind; return false; }
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java index f968d56..bf1afad 100644 --- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java +++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java
@@ -42,6 +42,7 @@ import com.android.tools.r8.utils.AccessUtils; import com.android.tools.r8.utils.AndroidApiLevelUtils; import com.android.tools.r8.utils.BooleanBox; +import com.android.tools.r8.utils.BooleanUtils; import com.android.tools.r8.utils.IntBox; import com.android.tools.r8.utils.InternalOptions; import com.android.tools.r8.utils.InternalOptions.CallSiteOptimizationOptions; @@ -84,45 +85,63 @@ static class AllowedPrototypeChanges { private static final AllowedPrototypeChanges EMPTY = - new AllowedPrototypeChanges(null, Int2ReferenceMaps.emptyMap(), IntSets.EMPTY_SET); + new AllowedPrototypeChanges(false, null, Int2ReferenceMaps.emptyMap(), IntSets.EMPTY_SET); + boolean canBeConvertedToStaticMethod; DexType newReturnType; Int2ReferenceMap<DexType> newParameterTypes; IntSet removableParameterIndices; AllowedPrototypeChanges( + boolean canBeConvertedToStaticMethod, DexType newReturnType, Int2ReferenceMap<DexType> newParameterTypes, IntSet removableParameterIndices) { + this.canBeConvertedToStaticMethod = canBeConvertedToStaticMethod; this.newReturnType = newReturnType; this.newParameterTypes = newParameterTypes; this.removableParameterIndices = removableParameterIndices; } - public static AllowedPrototypeChanges create(RewrittenPrototypeDescription prototypeChanges) { + public static AllowedPrototypeChanges create( + ProgramMethod method, RewrittenPrototypeDescription prototypeChanges) { if (prototypeChanges.isEmpty()) { return empty(); } + ArgumentInfoCollection argumentInfoCollection = prototypeChanges.getArgumentInfoCollection(); + boolean canBeConvertedToStaticMethod = argumentInfoCollection.isConvertedToStaticMethod(); + assert !canBeConvertedToStaticMethod + || (method.getDefinition().isInstance() + && argumentInfoCollection.getArgumentInfo(0).isRemovedReceiverInfo()); DexType newReturnType = prototypeChanges.hasRewrittenReturnInfo() ? prototypeChanges.getRewrittenReturnInfo().getNewType() : null; Int2ReferenceMap<DexType> newParameterTypes = new Int2ReferenceOpenHashMap<>(); IntSet removableParameterIndices = new IntOpenHashSet(); - prototypeChanges - .getArgumentInfoCollection() - .forEach( - (argumentIndex, argumentInfo) -> { - if (argumentInfo.isRemovedArgumentInfo()) { - removableParameterIndices.add(argumentIndex); - } else { - assert argumentInfo.isRewrittenTypeInfo(); - RewrittenTypeInfo rewrittenTypeInfo = argumentInfo.asRewrittenTypeInfo(); - newParameterTypes.put(argumentIndex, rewrittenTypeInfo.getNewType()); - } - }); + argumentInfoCollection.forEach( + (argumentIndex, argumentInfo) -> { + if (argumentInfo.isRemovedReceiverInfo()) { + // Skip as the receiver is not in the proto. + assert canBeConvertedToStaticMethod; + } else { + int parameterIndex = + method.getDefinition().getParameterIndexFromArgumentIndex(argumentIndex); + assert parameterIndex >= 0; + if (argumentInfo.isRemovedArgumentInfo()) { + removableParameterIndices.add(parameterIndex); + } else { + assert argumentInfo.isRewrittenTypeInfo(); + RewrittenTypeInfo rewrittenTypeInfo = argumentInfo.asRewrittenTypeInfo(); + newParameterTypes.put(parameterIndex, rewrittenTypeInfo.getNewType()); + } + } + }); return new AllowedPrototypeChanges( - newReturnType, newParameterTypes, removableParameterIndices); + canBeConvertedToStaticMethod, + newReturnType, + newParameterTypes, + removableParameterIndices); } public static AllowedPrototypeChanges empty() { @@ -131,7 +150,11 @@ @Override public int hashCode() { - return Objects.hash(newReturnType, newParameterTypes, removableParameterIndices); + return Objects.hash( + canBeConvertedToStaticMethod, + newReturnType, + newParameterTypes, + removableParameterIndices); } @Override @@ -140,7 +163,8 @@ return false; } AllowedPrototypeChanges other = (AllowedPrototypeChanges) obj; - return newReturnType == other.newReturnType + return canBeConvertedToStaticMethod == other.canBeConvertedToStaticMethod + && newReturnType == other.newReturnType && newParameterTypes.equals(other.newParameterTypes) && removableParameterIndices.equals(other.removableParameterIndices); } @@ -359,10 +383,11 @@ // Find the parameters that are either (i) the same constant, (ii) all unused, or (iii) // all possible to strengthen to the same stronger type, in all methods. + boolean canBeConvertedToStaticMethod = canRemoveReceiverFromVirtualMethods(methods); Int2ReferenceMap<DexType> newParameterTypes = new Int2ReferenceOpenHashMap<>(); IntSet removableVirtualMethodParametersInAllMethods = new IntArraySet(); for (int parameterIndex = 0; - parameterIndex < signature.getProto().getArity() + 1; + parameterIndex < signature.getParameters().size(); parameterIndex++) { if (canRemoveParameterFromVirtualMethods(methods, parameterIndex)) { removableVirtualMethodParametersInAllMethods.add(parameterIndex); @@ -380,12 +405,14 @@ getReturnValueForVirtualMethods(methods, signature); DexType newReturnType = getNewReturnTypeForVirtualMethods(methods, returnValueForVirtualMethods); - if (newReturnType != null + if (canBeConvertedToStaticMethod + || newReturnType != null || !newParameterTypes.isEmpty() || !removableVirtualMethodParametersInAllMethods.isEmpty()) { allowedPrototypeChangesForVirtualMethods.put( signature, new AllowedPrototypeChanges( + canBeConvertedToStaticMethod, newReturnType, newParameterTypes, removableVirtualMethodParametersInAllMethods)); @@ -467,28 +494,30 @@ return false; } + private boolean canRemoveReceiverFromVirtualMethods(ProgramMethodSet methods) { + if (methods.size() > 1) { + // Method staticizing would break dynamic dispatch. + return false; + } + ProgramMethod method = methods.getFirst(); + return method.getOptimizationInfo().hasUnusedArguments() + && method.getOptimizationInfo().getUnusedArguments().get(0) + && ParameterRemovalUtils.canRemoveUnusedParametersFrom(appView, method) + && ParameterRemovalUtils.canRemoveUnusedParameter(appView, method, 0); + } + private boolean canRemoveParameterFromVirtualMethods( ProgramMethodSet methods, int parameterIndex) { - if (parameterIndex == 0) { - if (methods.size() > 1) { - // Method staticizing would break dynamic dispatch. - return false; - } - ProgramMethod method = methods.getFirst(); - return method.getOptimizationInfo().hasUnusedArguments() - && method.getOptimizationInfo().getUnusedArguments().get(parameterIndex) - && ParameterRemovalUtils.canRemoveUnusedParametersFrom(appView, method) - && ParameterRemovalUtils.canRemoveUnusedParameter(appView, method, parameterIndex); - } + int argumentIndex = parameterIndex + 1; for (ProgramMethod method : methods) { if (method.getDefinition().isAbstract()) { // OK, this parameter can be removed. continue; } if (method.getOptimizationInfo().hasUnusedArguments() - && method.getOptimizationInfo().getUnusedArguments().get(parameterIndex) + && method.getOptimizationInfo().getUnusedArguments().get(argumentIndex) && ParameterRemovalUtils.canRemoveUnusedParametersFrom(appView, method) - && ParameterRemovalUtils.canRemoveUnusedParameter(appView, method, parameterIndex)) { + && ParameterRemovalUtils.canRemoveUnusedParameter(appView, method, argumentIndex)) { // OK, this parameter is unused. continue; } @@ -497,7 +526,7 @@ ConcreteCallSiteOptimizationInfo concreteOptimizationInfo = optimizationInfo.asConcreteCallSiteOptimizationInfo(); AbstractValue abstractValue = - concreteOptimizationInfo.getAbstractArgumentValue(parameterIndex); + concreteOptimizationInfo.getAbstractArgumentValue(argumentIndex); if (abstractValue.isSingleValue() && abstractValue.asSingleValue().isMaterializableInContext(appView, method)) { // OK, this parameter has a constant value and can be removed. @@ -544,9 +573,6 @@ private DexType getNewParameterTypeForVirtualMethods( ProgramMethodSet methods, int parameterIndex) { - if (parameterIndex == 0) { - return null; - } DexType newParameterType = null; for (ProgramMethod method : methods) { if (method.getAccessFlags().isAbstract()) { @@ -561,7 +587,7 @@ newParameterType = newParameterTypeForMethod; } assert newParameterType == null - || newParameterType != methods.getFirst().getArgumentType(parameterIndex); + || newParameterType != methods.getFirst().getParameter(parameterIndex); return newParameterType; } @@ -734,7 +760,7 @@ ProgramMethod method, RewrittenPrototypeDescription prototypeChanges) { DexMethodSignature methodSignatureWithoutPrototypeChanges = method.getMethodSignature(); AllowedPrototypeChanges allowedPrototypeChanges = - AllowedPrototypeChanges.create(prototypeChanges); + AllowedPrototypeChanges.create(method, prototypeChanges); // Check if there is a reserved signature for this already. DexMethodSignature reservedSignature = @@ -742,6 +768,9 @@ .getOrDefault(methodSignatureWithoutPrototypeChanges, Collections.emptyMap()) .get(allowedPrototypeChanges); if (reservedSignature != null) { + assert reservedSignature + .getProto() + .equals(prototypeChanges.rewriteMethod(method, dexItemFactory).getProto()); return reservedSignature.withHolder(method.getHolderType(), dexItemFactory); } @@ -882,14 +911,16 @@ removableParameterIndices); } + boolean canBeConvertedToStaticMethod = allowedPrototypeChanges.canBeConvertedToStaticMethod; RewrittenPrototypeDescription prototypeChanges = computePrototypeChangesForMethod( method, + canBeConvertedToStaticMethod, allowedPrototypeChanges.newReturnType, newParameterTypes::get, removableParameterIndices::contains); assert prototypeChanges.getArgumentInfoCollection().numberOfRemovedArguments() - == removableParameterIndices.size(); + == BooleanUtils.intValue(canBeConvertedToStaticMethod) + removableParameterIndices.size(); return prototypeChanges; } @@ -902,24 +933,26 @@ ArgumentInfoCollection.Builder argumentInfoCollectionBuilder = ArgumentInfoCollection.builder() .setArgumentInfosSize(method.getDefinition().getNumberOfArguments()); - for (int argumentIndex = 0; - argumentIndex < method.getDefinition().getNumberOfArguments(); - argumentIndex++) { - if (removableParameterIndices.contains(argumentIndex)) { - argumentInfoCollectionBuilder.addArgumentInfo( - argumentIndex, - RemovedArgumentInfo.builder().setType(method.getArgumentType(argumentIndex)).build()); - } else if (newParameterTypes.containsKey(argumentIndex)) { - DexType newParameterType = newParameterTypes.get(argumentIndex); - argumentInfoCollectionBuilder.addArgumentInfo( - argumentIndex, - RewrittenTypeInfo.builder() - .setCastType(newParameterType) - .setOldType(method.getArgumentType(argumentIndex)) - .setNewType(newParameterType) - .build()); - } - } + method + .getParameters() + .forEach( + (parameterIndex, parameter) -> { + int argumentIndex = + method.getDefinition().getArgumentIndexFromParameterIndex(parameterIndex); + if (removableParameterIndices.contains(parameterIndex)) { + argumentInfoCollectionBuilder.addArgumentInfo( + argumentIndex, RemovedArgumentInfo.builder().setType(parameter).build()); + } else if (newParameterTypes.containsKey(parameterIndex)) { + DexType newParameterType = newParameterTypes.get(parameterIndex); + argumentInfoCollectionBuilder.addArgumentInfo( + argumentIndex, + RewrittenTypeInfo.builder() + .setCastType(newParameterType) + .setOldType(parameter) + .setNewType(newParameterType) + .build()); + } + }); return RewrittenPrototypeDescription.create( Collections.emptyList(), computeReturnChangesForMethod(method, newReturnType), @@ -932,7 +965,11 @@ ? parameterIndex -> getNewParameterType(method, parameterIndex) : parameterIndex -> null; return computePrototypeChangesForMethod( - method, getNewReturnType(method), parameterIndexToParameterType, parameterIndex -> true); + method, + true, + getNewReturnType(method), + parameterIndexToParameterType, + parameterIndex -> true); } private DexType getNewReturnType(ProgramMethod method) { @@ -996,7 +1033,6 @@ } else { returnValue = method.getOptimizationInfo().getAbstractReturnValue(); } - return returnValue.isSingleValue() && returnValue.asSingleValue().isMaterializableInAllContexts(appView) ? returnValue.asSingleValue() @@ -1007,12 +1043,13 @@ if (!appView.getKeepInfo(method).isParameterTypeStrengtheningAllowed(options)) { return null; } - DexType staticType = method.getArgumentType(parameterIndex); + DexType staticType = method.getParameter(parameterIndex); if (!staticType.isClassType()) { return null; } + int argumentIndex = method.getDefinition().getArgumentIndexFromParameterIndex(parameterIndex); DynamicType dynamicType = - method.getOptimizationInfo().getArgumentInfos().getDynamicType(parameterIndex); + method.getOptimizationInfo().getArgumentInfos().getDynamicType(argumentIndex); if (dynamicType == null || dynamicType.isUnknown()) { return null; } @@ -1046,24 +1083,27 @@ private RewrittenPrototypeDescription computePrototypeChangesForMethod( ProgramMethod method, + boolean canBeConvertedToStaticMethod, DexType newReturnType, IntFunction<DexType> newParameterTypes, IntPredicate removableParameterIndices) { return RewrittenPrototypeDescription.create( Collections.emptyList(), computeReturnChangesForMethod(method, newReturnType), - computeParameterChangesForMethod(method, newParameterTypes, removableParameterIndices)); + computeParameterChangesForMethod( + method, canBeConvertedToStaticMethod, newParameterTypes, removableParameterIndices)); } private ArgumentInfoCollection computeParameterChangesForMethod( ProgramMethod method, + boolean canBeConvertedToStaticMethod, IntFunction<DexType> newParameterTypes, IntPredicate removableParameterIndices) { ArgumentInfoCollection.Builder parameterChangesBuilder = ArgumentInfoCollection.builder() .setArgumentInfosSize(method.getDefinition().getNumberOfArguments()); if (method.getDefinition().isInstance() - && removableParameterIndices.test(0) + && canBeConvertedToStaticMethod && method.getOptimizationInfo().hasUnusedArguments() && method.getOptimizationInfo().getUnusedArguments().get(0) && ParameterRemovalUtils.canRemoveUnusedParametersFrom(appView, method) @@ -1075,19 +1115,19 @@ } CallSiteOptimizationInfo optimizationInfo = method.getOptimizationInfo().getArgumentInfos(); - for (int argumentIndex = method.getDefinition().getFirstNonReceiverArgumentIndex(); - argumentIndex < method.getDefinition().getNumberOfArguments(); - argumentIndex++) { - if (removableParameterIndices.test(argumentIndex)) { + for (int parameterIndex = 0; + parameterIndex < method.getParameters().size(); + parameterIndex++) { + int argumentIndex = + parameterIndex + method.getDefinition().getFirstNonReceiverArgumentIndex(); + if (removableParameterIndices.test(parameterIndex)) { if (method.getOptimizationInfo().hasUnusedArguments() && method.getOptimizationInfo().getUnusedArguments().get(argumentIndex) && ParameterRemovalUtils.canRemoveUnusedParametersFrom(appView, method) && ParameterRemovalUtils.canRemoveUnusedParameter(appView, method, argumentIndex)) { parameterChangesBuilder.addArgumentInfo( argumentIndex, - RemovedArgumentInfo.builder() - .setType(method.getArgumentType(argumentIndex)) - .build()); + RemovedArgumentInfo.builder().setType(method.getParameter(parameterIndex)).build()); continue; } @@ -1098,15 +1138,15 @@ argumentIndex, RemovedArgumentInfo.builder() .setSingleValue(abstractValue.asSingleValue()) - .setType(method.getArgumentType(argumentIndex)) + .setType(method.getParameter(parameterIndex)) .build()); continue; } } - DexType dynamicType = newParameterTypes.apply(argumentIndex); + DexType dynamicType = newParameterTypes.apply(parameterIndex); if (dynamicType != null) { - DexType staticType = method.getArgumentType(argumentIndex); + DexType staticType = method.getParameter(parameterIndex); assert dynamicType != staticType; parameterChangesBuilder.addArgumentInfo( argumentIndex,
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java index 4d9598e..1008d80 100644 --- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java +++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -4981,7 +4981,7 @@ } DexType instantiatedType = - ConstantValueUtils.getDexTypeRepresentedByValue( + ConstantValueUtils.getDexTypeRepresentedByValueForTracing( invoke.asInvokeVirtual().getReceiver(), appView); if (instantiatedType == null || !instantiatedType.isClassType()) { // Give up, we can't tell which class is being instantiated, or the type is not a class type. @@ -5027,7 +5027,7 @@ } DexType instantiatedType = - ConstantValueUtils.getDexTypeRepresentedByValue( + ConstantValueUtils.getDexTypeRepresentedByValueForTracing( constructorDefinition.getReceiver(), appView); if (instantiatedType == null || !instantiatedType.isClassType()) { // Give up, we can't tell which constructor is being invoked, or the type is not a class type. @@ -5076,7 +5076,8 @@ } DexType type = - ConstantValueUtils.getDexTypeRepresentedByValue(arrayPutInstruction.value(), appView); + ConstantValueUtils.getDexTypeRepresentedByValueForTracing( + arrayPutInstruction.value(), appView); if (type == null) { return; } @@ -5131,7 +5132,8 @@ } ArrayPut arrayPut = user.asArrayPut(); - DexType type = ConstantValueUtils.getDexTypeRepresentedByValue(arrayPut.value(), appView); + DexType type = + ConstantValueUtils.getDexTypeRepresentedByValueForTracing(arrayPut.value(), appView); if (type == null || !type.isClassType()) { continue; }
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java index 6065527..0d767c6 100644 --- a/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java +++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
@@ -676,7 +676,11 @@ // actually equal. GraphLens graphLens = appView.graphLens(); boolean includeContext = - intermediate || appView.options().getStartupOptions().isStartupInstrumentationEnabled(); + intermediate + || appView + .options() + .getStartupInstrumentationOptions() + .isStartupInstrumentationEnabled(); List<T> sortedPotentialMembers = ListUtils.sort( potentialEquivalence,
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java b/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java index 6bec653..cbad6e6 100644 --- a/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java +++ b/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
@@ -43,6 +43,7 @@ S(31), Sv2(32), T(33), + MASTER(34), // API level for master is tentative. ANDROID_PLATFORM(10000); // When updating LATEST and a new version goes stable, add a new api-versions.xml to third_party @@ -166,6 +167,8 @@ return Sv2; case 33: return T; + case 34: + return MASTER; case 10000: return ANDROID_PLATFORM; default:
diff --git a/src/main/java/com/android/tools/r8/utils/DexVersion.java b/src/main/java/com/android/tools/r8/utils/DexVersion.java index ac962fa..492c87b 100644 --- a/src/main/java/com/android/tools/r8/utils/DexVersion.java +++ b/src/main/java/com/android/tools/r8/utils/DexVersion.java
@@ -41,6 +41,7 @@ // ANDROID_PLATFORM is an unknown higher api version we therefore choose the highest known // version. case ANDROID_PLATFORM: + case MASTER: case T: case Sv2: case S:
diff --git a/src/main/java/com/android/tools/r8/utils/FileUtils.java b/src/main/java/com/android/tools/r8/utils/FileUtils.java index ef26890..b8b8286 100644 --- a/src/main/java/com/android/tools/r8/utils/FileUtils.java +++ b/src/main/java/com/android/tools/r8/utils/FileUtils.java
@@ -216,6 +216,8 @@ // own Input/OutputStream, but an external one which one can define on a different Charset than // default. We do not support this at the moment since R8 on dex is used only in tests, and // UTF_8 is the default charset used in tests. - throw new RuntimeException("R8 can run on dex only with UTF_8 as the default charset."); + throw new RuntimeException( + "R8 can run on dex only with UTF_8 as the default charset, but the charset used is " + + Charset.defaultCharset()); } }
diff --git a/src/main/java/com/android/tools/r8/utils/InternalGlobalSyntheticsProgramProvider.java b/src/main/java/com/android/tools/r8/utils/InternalGlobalSyntheticsProgramProvider.java index 6b2d828..33edbcb 100644 --- a/src/main/java/com/android/tools/r8/utils/InternalGlobalSyntheticsProgramProvider.java +++ b/src/main/java/com/android/tools/r8/utils/InternalGlobalSyntheticsProgramProvider.java
@@ -9,7 +9,7 @@ import com.android.tools.r8.ProgramResourceProvider; import com.android.tools.r8.ResourceException; import com.android.tools.r8.Version; -import com.android.tools.r8.origin.ArchiveEntryOrigin; +import com.android.tools.r8.origin.Origin; import com.google.common.io.ByteStreams; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -25,6 +25,21 @@ public class InternalGlobalSyntheticsProgramProvider implements ProgramResourceProvider { + public static class GlobalsEntryOrigin extends Origin { + + private final String entryName; + + public GlobalsEntryOrigin(String entryName, Origin parent) { + super(parent); + this.entryName = entryName; + } + + @Override + public String part() { + return "global(" + entryName + ")"; + } + } + private final List<GlobalSyntheticsResourceProvider> providers; private List<ProgramResource> resources = null; @@ -69,7 +84,7 @@ + Version.getVersionString()); } } else if (name.endsWith(FileUtils.GLOBAL_SYNTHETIC_EXTENSION) && seen.add(name)) { - ArchiveEntryOrigin origin = new ArchiveEntryOrigin(name, provider.getOrigin()); + GlobalsEntryOrigin origin = new GlobalsEntryOrigin(name, provider.getOrigin()); String descriptor = guessTypeDescriptor(name); byte[] bytes = ByteStreams.toByteArray(stream); Set<String> descriptors = Collections.singleton(descriptor);
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 4653b96..d784613 100644 --- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java +++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -39,6 +39,7 @@ import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.experimental.graphinfo.GraphConsumer; import com.android.tools.r8.experimental.startup.StartupOptions; +import com.android.tools.r8.experimental.startup.instrumentation.StartupInstrumentationOptions; import com.android.tools.r8.features.FeatureSplitConfiguration; import com.android.tools.r8.graph.AppInfoWithClassHierarchy; import com.android.tools.r8.graph.AppView; @@ -816,6 +817,8 @@ private final ApiModelTestingOptions apiModelTestingOptions = new ApiModelTestingOptions(); private final DesugarSpecificOptions desugarSpecificOptions = new DesugarSpecificOptions(); private final StartupOptions startupOptions = new StartupOptions(); + private final StartupInstrumentationOptions startupInstrumentationOptions = + new StartupInstrumentationOptions(); public final TestingOptions testing = new TestingOptions(); public List<ProguardConfigurationRule> mainDexKeepRules = ImmutableList.of(); @@ -879,6 +882,10 @@ return startupOptions; } + public StartupInstrumentationOptions getStartupInstrumentationOptions() { + return startupInstrumentationOptions; + } + public TestingOptions getTestingOptions() { return testing; } @@ -1504,6 +1511,7 @@ private boolean enableInterfaceMerging = System.getProperty("com.android.tools.r8.enableHorizontalInterfaceMerging") != null; private boolean enableInterfaceMergingInInitial = false; + private boolean enableSameFilePolicy = false; private boolean enableSyntheticMerging = true; private boolean ignoreRuntimeTypeChecksForTesting = false; private boolean restrictToSynthetics = false; @@ -1559,6 +1567,10 @@ return ignoreRuntimeTypeChecksForTesting; } + public boolean isSameFilePolicyEnabled() { + return enableSameFilePolicy; + } + public boolean isSyntheticMergingEnabled() { return enableSyntheticMerging; } @@ -1586,10 +1598,18 @@ enableInterfaceMerging = true; } + public void setEnableInterfaceMerging(boolean enableInterfaceMerging) { + this.enableInterfaceMerging = enableInterfaceMerging; + } + public void setEnableInterfaceMergingInInitial() { enableInterfaceMergingInInitial = true; } + public void setEnableSameFilePolicy(boolean enableSameFilePolicy) { + this.enableSameFilePolicy = enableSameFilePolicy; + } + public void setIgnoreRuntimeTypeChecksForTesting() { ignoreRuntimeTypeChecksForTesting = true; } @@ -1776,6 +1796,10 @@ private boolean hasReadCheckDeterminism = false; private DeterminismChecker determinismChecker = null; + // Testing options to analyse locality of items in DEX files when they are generated. + public boolean calculateItemUseCountInDex = false; + public boolean calculateItemUseCountInDexDumpSingleUseStrings = false; + private DeterminismChecker getDeterminismChecker() { // Lazily read the env-var so that it can be set after options init. if (determinismChecker == null && !hasReadCheckDeterminism) {
diff --git a/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java b/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java index a5bbfcb..920b83c 100644 --- a/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java +++ b/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
@@ -9,6 +9,7 @@ import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.references.Reference; +import com.android.tools.r8.utils.InternalGlobalSyntheticsProgramProvider.GlobalsEntryOrigin; import com.google.common.collect.ImmutableList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; @@ -60,13 +61,7 @@ public static ProgramClassConflictResolver defaultConflictResolver(Reporter reporter) { // The default conflict resolver only merges synthetic classes generated by D8 correctly. // All other conflicts are reported as a fatal error. - return (DexProgramClass a, DexProgramClass b) -> { - assert a.type == b.type; - if (a.accessFlags.isSynthetic() && b.accessFlags.isSynthetic()) { - return mergeClasses(reporter, a, b); - } - throw reportDuplicateTypes(reporter, a, b); - }; + return (DexProgramClass a, DexProgramClass b) -> mergeClasses(reporter, a, b); } private static RuntimeException reportDuplicateTypes( @@ -79,6 +74,31 @@ private static DexProgramClass mergeClasses( Reporter reporter, DexProgramClass a, DexProgramClass b) { + assert a.type == b.type; + boolean syntheticA = a.accessFlags.isSynthetic(); + boolean syntheticB = b.accessFlags.isSynthetic(); + if (syntheticA && syntheticB) { + return mergeIfLegacySynthetics(reporter, a, b); + } else if (syntheticA) { + return mergeIfGlobalSynthetic(reporter, a, b); + } else if (syntheticB) { + return mergeIfGlobalSynthetic(reporter, b, a); + } + throw reportDuplicateTypes(reporter, a, b); + } + + private static DexProgramClass mergeIfGlobalSynthetic( + Reporter reporter, DexProgramClass synthetic, DexProgramClass nonSynthetic) { + assert synthetic.accessFlags.isSynthetic(); + assert !nonSynthetic.accessFlags.isSynthetic(); + if (synthetic.getOrigin() instanceof GlobalsEntryOrigin) { + return nonSynthetic; + } + throw reportDuplicateTypes(reporter, nonSynthetic, synthetic); + } + + private static DexProgramClass mergeIfLegacySynthetics( + Reporter reporter, DexProgramClass a, DexProgramClass b) { if (a.type.isLegacySynthesizedTypeAllowedDuplication()) { assert assertEqualClasses(a, b); return a;
diff --git a/src/main/java/com/android/tools/r8/utils/SegmentTree.java b/src/main/java/com/android/tools/r8/utils/SegmentTree.java index 1fc95b0..9962b1c 100644 --- a/src/main/java/com/android/tools/r8/utils/SegmentTree.java +++ b/src/main/java/com/android/tools/r8/utils/SegmentTree.java
@@ -6,9 +6,10 @@ import java.util.Map; import java.util.TreeMap; +import java.util.function.Consumer; /** - * Implementation of a discrete segment tree where intervals are specified by their start end and + * Implementation of a discrete segment tree where intervals are specified by their start and end * point. Both points are considered part of the interval. */ public class SegmentTree<V> { @@ -79,4 +80,21 @@ public int size() { return size; } + + public void removeSegment(int start) { + if (internalTree.remove(start) != null) { + size = size - 1; + } + } + + public void visitSegments(Consumer<V> consumer) { + internalTree + .values() + .forEach( + segment -> { + if (segment != null) { + consumer.accept(segment); + } + }); + } }
diff --git a/src/main/java/com/android/tools/r8/utils/StringUtils.java b/src/main/java/com/android/tools/r8/utils/StringUtils.java index 7275934..f1e4e18 100644 --- a/src/main/java/com/android/tools/r8/utils/StringUtils.java +++ b/src/main/java/com/android/tools/r8/utils/StringUtils.java
@@ -155,9 +155,13 @@ } public static String lines(List<String> lines) { + return lines(lines, LINE_SEPARATOR); + } + + private static String lines(List<String> lines, String lineSeperator) { StringBuilder builder = new StringBuilder(); for (String line : lines) { - builder.append(line).append(LINE_SEPARATOR); + builder.append(line).append(lineSeperator); } return builder.toString(); } @@ -166,6 +170,10 @@ return lines(Arrays.asList(lines)); } + public static String unixLines(String... lines) { + return lines(Arrays.asList(lines), "\n"); + } + public static String withNativeLineSeparator(String s) { s = s.replace("\r\n", "\n"); if (LINE_SEPARATOR.equals("\r\n")) {
diff --git a/src/main/java/com/android/tools/r8/utils/SystemPropertyUtils.java b/src/main/java/com/android/tools/r8/utils/SystemPropertyUtils.java index d8d4a38..a984560 100644 --- a/src/main/java/com/android/tools/r8/utils/SystemPropertyUtils.java +++ b/src/main/java/com/android/tools/r8/utils/SystemPropertyUtils.java
@@ -7,10 +7,21 @@ import static com.google.common.base.Predicates.alwaysTrue; import com.android.tools.r8.Version; +import java.util.function.Function; import java.util.function.Predicate; +import java.util.function.Supplier; public class SystemPropertyUtils { + public static <T> T applySystemProperty( + String propertyName, Function<String, T> propertyFoundFn, Supplier<T> propertyNotFoundFn) { + if (isSystemPropertySet(propertyName)) { + return propertyFoundFn.apply(System.getProperty(propertyName)); + } else { + return propertyNotFoundFn.get(); + } + } + public static String getSystemPropertyForDevelopment(String propertyName) { return Version.isDevelopmentVersion() ? System.getProperty(propertyName) : null; }
diff --git a/src/main/java/com/android/tools/r8/utils/Timing.java b/src/main/java/com/android/tools/r8/utils/Timing.java index 94288b4..b4519a9 100644 --- a/src/main/java/com/android/tools/r8/utils/Timing.java +++ b/src/main/java/com/android/tools/r8/utils/Timing.java
@@ -299,6 +299,7 @@ Node mergeTarget = item.mergeTarget.children.computeIfAbsent(title, t -> new Node(t, trackMemory)); mergeTarget.duration += child.duration; + mergeTarget.endMemory = child.endMemory; if (!child.children.isEmpty()) { worklist.addLast(new Item(mergeTarget, child)); } @@ -308,6 +309,7 @@ public void end() { assert !parent.children.containsKey(merged.title); + merged.end(); parent.children.put(merged.title, merged); } }
diff --git a/src/main/java/com/android/tools/r8/utils/ZipUtils.java b/src/main/java/com/android/tools/r8/utils/ZipUtils.java index 34714e4..fc9157d 100644 --- a/src/main/java/com/android/tools/r8/utils/ZipUtils.java +++ b/src/main/java/com/android/tools/r8/utils/ZipUtils.java
@@ -35,6 +35,7 @@ import java.util.Spliterator; import java.util.Spliterators; import java.util.function.BiFunction; +import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.StreamSupport; @@ -162,35 +163,39 @@ } public static List<Path> unzip(Path zipFile, Path outDirectory) throws IOException { - return unzip(zipFile.toString(), outDirectory.toFile(), (entry) -> true).stream() - .map(File::toPath) - .collect(Collectors.toList()); + return unzip(zipFile, outDirectory, (entry) -> true, Function.identity()); } public static List<File> unzip(String zipFile, File outDirectory) throws IOException { - return unzip(zipFile, outDirectory, (entry) -> true); + return unzip(Paths.get(zipFile), outDirectory.toPath(), (entry) -> true, Path::toFile); } - public static List<File> unzip(String zipFile, File outDirectory, Predicate<ZipEntry> filter) + public static List<Path> unzip(Path zipFile, Path outDirectory, Predicate<ZipEntry> filter) throws IOException { - final Path outDirectoryPath = outDirectory.toPath(); - final List<File> outFiles = new ArrayList<>(); - iter(zipFile, (entry, input) -> { - String name = entry.getName(); - if (!entry.isDirectory() && filter.test(entry)) { - if (name.contains("..")) { - // Protect against malicious archives. - throw new CompilationError("Invalid entry name \"" + name + "\""); + return unzip(zipFile, outDirectory, filter, Function.identity()); + } + + public static <T> List<T> unzip( + Path zipFile, Path outDirectory, Predicate<ZipEntry> filter, Function<Path, T> map) + throws IOException { + final List<T> outFiles = new ArrayList<>(); + iter( + zipFile, + (entry, input) -> { + String name = entry.getName(); + if (!entry.isDirectory() && filter.test(entry)) { + if (name.contains("..")) { + // Protect against malicious archives. + throw new CompilationError("Invalid entry name \"" + name + "\""); + } + Path outPath = outDirectory.resolve(name); + outPath.toFile().getParentFile().mkdirs(); + try (OutputStream output = new FileOutputStream(outPath.toFile())) { + ByteStreams.copy(input, output); + } + outFiles.add(map.apply(outPath)); } - Path outPath = outDirectoryPath.resolve(name); - File outFile = outPath.toFile(); - outFile.getParentFile().mkdirs(); - try (OutputStream output = new FileOutputStream(outFile)) { - ByteStreams.copy(input, output); - } - outFiles.add(outFile); - } - }); + }); return outFiles; }
diff --git a/src/test/java/com/android/tools/r8/R8TestBuilder.java b/src/test/java/com/android/tools/r8/R8TestBuilder.java index 3bdfa4b..824203a 100644 --- a/src/test/java/com/android/tools/r8/R8TestBuilder.java +++ b/src/test/java/com/android/tools/r8/R8TestBuilder.java
@@ -346,6 +346,19 @@ return self(); } + public T allowUnusedDontWarnJavaLangClassValue() { + addOptionsModification( + options -> options.testing.allowedUnusedDontWarnPatterns.add("java.lang.ClassValue")); + return self(); + } + + public T allowUnusedDontWarnJavaLangClassValue(boolean condition) { + if (condition) { + allowUnusedDontWarnJavaLangClassValue(); + } + return self(); + } + public T allowUnusedDontWarnPatterns() { return addOptionsModification(options -> options.testing.allowUnusedDontWarnRules = true); }
diff --git a/src/test/java/com/android/tools/r8/R8TestCompileResult.java b/src/test/java/com/android/tools/r8/R8TestCompileResult.java index f343c0f..be01cef 100644 --- a/src/test/java/com/android/tools/r8/R8TestCompileResult.java +++ b/src/test/java/com/android/tools/r8/R8TestCompileResult.java
@@ -112,18 +112,10 @@ } @SafeVarargs + @Override public final <E extends Throwable> R8TestCompileResult inspectMultiDex( ThrowingConsumer<CodeInspector, E>... consumers) throws IOException, E { - Path out = state.getNewTempFolder(); - getApp().writeToDirectory(out, OutputMode.DexIndexed); - consumers[0].accept(new CodeInspector(out.resolve("classes.dex"), getProguardMap())); - for (int i = 1; i < consumers.length; i++) { - Path dex = out.resolve("classes" + (i + 1) + ".dex"); - CodeInspector inspector = - dex.toFile().exists() ? new CodeInspector(dex, getProguardMap()) : CodeInspector.empty(); - consumers[i].accept(inspector); - } - return self(); + return inspectMultiDex(writeProguardMap(), consumers); } public final <E extends Throwable> R8TestCompileResult inspectGraph(
diff --git a/src/test/java/com/android/tools/r8/SoftVerificationErrorJarRunner.java b/src/test/java/com/android/tools/r8/SoftVerificationErrorJarRunner.java index 80a2879..b345c16 100644 --- a/src/test/java/com/android/tools/r8/SoftVerificationErrorJarRunner.java +++ b/src/test/java/com/android/tools/r8/SoftVerificationErrorJarRunner.java
@@ -64,8 +64,8 @@ File filteredProgramFolder = temp.newFolder(); BooleanBox seenTestRunner = new BooleanBox(); ZipUtils.unzip( - tempFolder.resolve("program.jar").toFile().toString(), - filteredProgramFolder, + tempFolder.resolve("program.jar"), + filteredProgramFolder.toPath(), zipEntry -> { if (zipEntry.getName().equals("com/example/softverificationsample/TestRunner.class")) { seenTestRunner.set();
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java index 98f1627..4f8181d 100644 --- a/src/test/java/com/android/tools/r8/TestBase.java +++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -2052,8 +2052,13 @@ String[] lines1 = m1.getCode().toString().split("\n"); String[] lines2 = m2.getCode().toString().split("\n"); if (lines1.length != lines2.length) { - sb.append("Different number of lines."); - sb.append("\n"); + sb.append("Different number of lines: ") + .append(lines1.length) + .append(" and ") + .append(lines2.length) + .append(".") + .append("\n"); + printDiffForDifferentLineNumber(sb, lines1, lines2); } else { for (int i = 0; i < lines1.length; i++) { if (!lines1[i].equals(lines2[i])) { @@ -2069,6 +2074,38 @@ return sb.toString(); } + // Identify the initial common lines and print the first 7 lines after the first difference. + private static void printDiffForDifferentLineNumber( + StringBuilder sb, String[] lines1, String[] lines2) { + int maxPrint = 7; + int i; + for (i = 0; i < lines1.length && i < lines2.length; i++) { + if (!lines1[i].equals(lines2[i])) { + break; + } + } + sb.append("Method 1:").append("\n"); + printExtraLines(i, lines1, maxPrint, sb); + sb.append("Method 2:").append("\n"); + printExtraLines(i, lines2, maxPrint, sb); + } + + private static void printExtraLines(int i, String[] lines1, int maxPrint, StringBuilder sb) { + if (i < lines1.length) { + int j; + for (j = i; j < lines1.length && j < (i + maxPrint); j++) { + sb.append(lines1[j]); + sb.append("\n"); + } + if (j != lines1.length) { + sb.append("..."); + sb.append("\n"); + } + } else { + sb.append("No difference in method.").append("\n"); + } + } + public static boolean filesAreEqual(Path file1, Path file2) throws IOException { long size = Files.size(file1); long sizeOther = Files.size(file2);
diff --git a/src/test/java/com/android/tools/r8/TestCompileResult.java b/src/test/java/com/android/tools/r8/TestCompileResult.java index 4d557ea..b15e669 100644 --- a/src/test/java/com/android/tools/r8/TestCompileResult.java +++ b/src/test/java/com/android/tools/r8/TestCompileResult.java
@@ -444,6 +444,27 @@ return self(); } + @SuppressWarnings("unchecked") + public <E extends Throwable> CR inspectMultiDex(ThrowingConsumer<CodeInspector, E>... consumers) + throws IOException, E { + return inspectMultiDex(null, consumers); + } + + @SafeVarargs + public final <E extends Throwable> CR inspectMultiDex( + Path mappingFile, ThrowingConsumer<CodeInspector, E>... consumers) throws IOException, E { + Path out = state.getNewTempFolder(); + getApp().writeToDirectory(out, OutputMode.DexIndexed); + consumers[0].accept(new CodeInspector(out.resolve("classes.dex"), mappingFile)); + for (int i = 1; i < consumers.length; i++) { + Path dex = out.resolve("classes" + (i + 1) + ".dex"); + CodeInspector inspector = + dex.toFile().exists() ? new CodeInspector(dex, mappingFile) : CodeInspector.empty(); + consumers[i].accept(inspector); + } + return self(); + } + public <E extends Throwable> CR inspectWithOptions( ThrowingConsumer<CodeInspector, E> consumer, Consumer<InternalOptions> debugOptionsConsumer) throws IOException, E {
diff --git a/src/test/java/com/android/tools/r8/TestCondition.java b/src/test/java/com/android/tools/r8/TestCondition.java index b1a6207..e4cec10 100644 --- a/src/test/java/com/android/tools/r8/TestCondition.java +++ b/src/test/java/com/android/tools/r8/TestCondition.java
@@ -28,6 +28,7 @@ ART_V12_0_0, ART_V13_0_0, ART_DEFAULT, + ART_MASTER, JAVA; static final Runtime LOWEST_ART_VERSION = ART_V4_0_4; @@ -57,6 +58,8 @@ return ART_V13_0_0; case DEFAULT: return ART_DEFAULT; + case MASTER: + return ART_MASTER; default: throw new Unreachable(); }
diff --git a/src/test/java/com/android/tools/r8/TestParametersBuilder.java b/src/test/java/com/android/tools/r8/TestParametersBuilder.java index cd34cd5..c4fc8c4 100644 --- a/src/test/java/com/android/tools/r8/TestParametersBuilder.java +++ b/src/test/java/com/android/tools/r8/TestParametersBuilder.java
@@ -128,11 +128,16 @@ return withCfRuntimeFilter(vm -> vm.lessThan(endExclusive)); } - /** Add all available DEX runtimes. */ - public TestParametersBuilder withDexRuntimes() { + /** Add all available DEX runtimes including master. */ + public TestParametersBuilder withDexRuntimesIncludingMaster() { return withDexRuntimeFilter(vm -> true); } + /** Add all available DEX runtimes except master. */ + public TestParametersBuilder withDexRuntimes() { + return withDexRuntimeFilter(vm -> vm != DexVm.Version.MASTER); + } + public TestParametersBuilder withDexRuntimesAndAllApiLevels() { return withDexRuntimes().withAllApiLevels(); }
diff --git a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java index e1de2d3..d28d969 100644 --- a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java +++ b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
@@ -81,6 +81,7 @@ return self(); } + @Deprecated public T noMinification() { return minification(false); }
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java index 88b929a..d948ad2 100644 --- a/src/test/java/com/android/tools/r8/ToolHelper.java +++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -259,7 +259,9 @@ ART_12_0_0_TARGET(Version.V12_0_0, Kind.TARGET), ART_12_0_0_HOST(Version.V12_0_0, Kind.HOST), ART_13_0_0_TARGET(Version.V13_0_0, Kind.TARGET), - ART_13_0_0_HOST(Version.V13_0_0, Kind.HOST); + ART_13_0_0_HOST(Version.V13_0_0, Kind.HOST), + ART_MASTER_TARGET(Version.MASTER, Kind.TARGET), + ART_MASTER_HOST(Version.MASTER, Kind.HOST); private static final ImmutableMap<String, DexVm> SHORT_NAME_MAP = Arrays.stream(DexVm.values()).collect(ImmutableMap.toImmutableMap( @@ -277,7 +279,8 @@ V9_0_0("9.0.0"), V10_0_0("10.0.0"), V12_0_0("12.0.0"), - V13_0_0("13.0.0"); + V13_0_0("13.0.0"), + MASTER("master"); /** This should generally be the latest DEX VM fully supported. */ // TODO(b/204855476): Rename to DEFAULT alias once the checked in VM is removed. @@ -342,10 +345,15 @@ return V13_0_0; } + public static Version master() { + return MASTER; + } + static { - // Ensure first is always first and last is always last. + // Ensure first is always first and last is always last except for master. assert Arrays.stream(values()).allMatch(v -> v == first() || v.compareTo(first()) > 0); - assert Arrays.stream(values()).allMatch(v -> v == last() || v.compareTo(last()) < 0); + assert Arrays.stream(values()) + .allMatch(v -> v == last() || v == master() || v.compareTo(last()) < 0); } } @@ -610,6 +618,7 @@ private static final Map<DexVm, String> ART_DIRS = ImmutableMap.<DexVm, String>builder() .put(DexVm.ART_DEFAULT, "art") + .put(DexVm.ART_MASTER_HOST, "host/art-master") .put(DexVm.ART_13_0_0_HOST, "host/art-13-dev") .put(DexVm.ART_12_0_0_HOST, "host/art-12.0.0-beta4") .put(DexVm.ART_10_0_0_HOST, "art-10.0.0") @@ -624,6 +633,7 @@ private static final Map<DexVm, String> ART_BINARY_VERSIONS = ImmutableMap.<DexVm, String>builder() .put(DexVm.ART_DEFAULT, "bin/art") + .put(DexVm.ART_MASTER_HOST, "bin/art") .put(DexVm.ART_13_0_0_HOST, "bin/art") .put(DexVm.ART_12_0_0_HOST, "bin/art") .put(DexVm.ART_10_0_0_HOST, "bin/art") @@ -854,6 +864,9 @@ } private static Path getAndroidJarPath(AndroidApiLevel apiLevel) { + if (apiLevel == AndroidApiLevel.MASTER) { + return Paths.get("third_party/android_jar/lib-master/android.jar"); + } String jar = String.format( ANDROID_JAR_PATTERN, (apiLevel == AndroidApiLevel.getDefault() ? DEFAULT_MIN_SDK : apiLevel).getLevel()); @@ -1021,6 +1034,8 @@ public static AndroidApiLevel getMinApiLevelForDexVm(DexVm dexVm) { switch (dexVm.version) { + case MASTER: + return AndroidApiLevel.MASTER; case V13_0_0: return AndroidApiLevel.T; case V12_0_0:
diff --git a/src/test/java/com/android/tools/r8/accessrelaxation/ConstructorRelaxationTest.java b/src/test/java/com/android/tools/r8/accessrelaxation/ConstructorRelaxationTest.java index 4f91077..f7afbc4 100644 --- a/src/test/java/com/android/tools/r8/accessrelaxation/ConstructorRelaxationTest.java +++ b/src/test/java/com/android/tools/r8/accessrelaxation/ConstructorRelaxationTest.java
@@ -189,7 +189,7 @@ o.inlinerOptions().enableInlining = false; o.enableVerticalClassMerging = false; }) - .noMinification() + .addDontObfuscate() .addKeepMainRule(mainClass) .allowAccessModification() .setMinApi(parameters.getRuntime())
diff --git a/src/test/java/com/android/tools/r8/accessrelaxation/NonConstructorRelaxationTest.java b/src/test/java/com/android/tools/r8/accessrelaxation/NonConstructorRelaxationTest.java index 29e44c0..aff91c6 100644 --- a/src/test/java/com/android/tools/r8/accessrelaxation/NonConstructorRelaxationTest.java +++ b/src/test/java/com/android/tools/r8/accessrelaxation/NonConstructorRelaxationTest.java
@@ -86,7 +86,7 @@ .enableMemberValuePropagationAnnotations() .enableUnusedArgumentAnnotations(!enableUnusedArgumentRemoval) .addKeepMainRule(mainClass) - .noMinification() + .addDontObfuscate() .addKeepRules( // Note: we use '-checkdiscard' to indirectly check that the access relaxation is // done which leads to inlining of all pB*** methods so they are removed. Without @@ -172,7 +172,7 @@ .enableInliningAnnotations() .enableMemberValuePropagationAnnotations() .enableNoHorizontalClassMergingAnnotations() - .noMinification() + .addDontObfuscate() .addKeepRules( "-checkdiscard class " + Base.class.getCanonicalName() + "{", " *** p*();",
diff --git a/src/test/java/com/android/tools/r8/androidapi/AndroidJarMasterTest.java b/src/test/java/com/android/tools/r8/androidapi/AndroidJarMasterTest.java new file mode 100644 index 0000000..6f2a237 --- /dev/null +++ b/src/test/java/com/android/tools/r8/androidapi/AndroidJarMasterTest.java
@@ -0,0 +1,58 @@ +// 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.androidapi; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.ToolHelper; +import com.android.tools.r8.utils.AndroidApiLevel; +import com.android.tools.r8.utils.StringUtils; +import java.util.List; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class AndroidJarMasterTest extends TestBase { + + @Parameter() public TestParameters parameters; + + @Parameters(name = "{0}") + public static List<Object[]> data() { + return buildParameters( + getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build()); + } + + private static final String EXPECTED_OUTPUT = StringUtils.lines("Hello, world!"); + + @Test + public void testD8() throws Exception { + testForD8(parameters.getBackend()) + .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.MASTER)) + .addInnerClasses(getClass()) + .setMinApi(parameters.getApiLevel()) + .run(parameters.getRuntime(), TestClass.class) + .assertSuccessWithOutput(EXPECTED_OUTPUT); + } + + @Test + public void testR8() throws Exception { + testForR8(parameters.getBackend()) + .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.MASTER)) + .addInnerClasses(getClass()) + .addKeepMainRule(TestClass.class) + .setMinApi(parameters.getApiLevel()) + .run(parameters.getRuntime(), TestClass.class) + .assertSuccessWithOutput(EXPECTED_OUTPUT); + } + + static class TestClass { + + public static void main(String[] args) { + System.out.println("Hello, world!"); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/annotations/AnnotationWithInjectedMethodsTest.java b/src/test/java/com/android/tools/r8/annotations/AnnotationWithInjectedMethodsTest.java index be3ee34..da34ea7 100644 --- a/src/test/java/com/android/tools/r8/annotations/AnnotationWithInjectedMethodsTest.java +++ b/src/test/java/com/android/tools/r8/annotations/AnnotationWithInjectedMethodsTest.java
@@ -54,7 +54,7 @@ .addKeepClassAndMembersRules(AnnotationWithInjectedMethod.class) .addKeepRuntimeVisibleAnnotations() .addOptionsModification(options -> options.testing.allowInjectedAnnotationMethods = true) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockMergeProgramDefinedDuplicateTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockMergeProgramDefinedDuplicateTest.java new file mode 100644 index 0000000..0a72589 --- /dev/null +++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockMergeProgramDefinedDuplicateTest.java
@@ -0,0 +1,178 @@ +// 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.apimodel; + +import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass; +import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer; +import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod; +import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; + +import com.android.tools.r8.CompilationMode; +import com.android.tools.r8.OutputMode; +import com.android.tools.r8.SingleTestRunResult; +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestCompilerBuilder; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.references.Reference; +import com.android.tools.r8.synthesis.globals.GlobalSyntheticsTestingConsumer; +import com.android.tools.r8.utils.AndroidApiLevel; +import com.android.tools.r8.utils.codeinspector.ClassSubject; +import com.android.tools.r8.utils.codeinspector.CodeInspector; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ApiModelMockMergeProgramDefinedDuplicateTest extends TestBase { + + private final AndroidApiLevel mockLevel = AndroidApiLevel.M; + + @Parameter() public TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withDexRuntimes().withAllApiLevels().build(); + } + + private boolean isGreaterOrEqualToMockLevel() { + return parameters.isDexRuntime() && parameters.getApiLevel().isGreaterThanOrEqualTo(mockLevel); + } + + private void setupTestCompileBuilder( + TestCompilerBuilder<?, ?, ?, ?, ?> testBuilder, Class<?> programClass) + throws NoSuchMethodException { + testBuilder + .addProgramClasses(programClass) + .addLibraryClasses(LibraryClass.class) + .addDefaultRuntimeLibrary(parameters) + .setMinApi(parameters.getApiLevel()) + .apply(ApiModelingTestHelper::enableApiCallerIdentification) + .apply(ApiModelingTestHelper::enableStubbingOfClasses) + .apply(setMockApiLevelForClass(LibraryClass.class, mockLevel)) + .apply(setMockApiLevelForDefaultInstanceInitializer(LibraryClass.class, mockLevel)) + .apply(setMockApiLevelForMethod(LibraryClass.class.getDeclaredMethod("foo"), mockLevel)) + .apply(setMockApiLevelForMethod(LibraryClass.class.getDeclaredMethod("bar"), mockLevel)); + } + + private boolean addToBootClasspath() { + return parameters.isDexRuntime() + && parameters.getRuntime().maxSupportedApiLevel().isGreaterThanOrEqualTo(mockLevel); + } + + @Test + public void testD8DebugDexFilePerClassFile() throws Exception { + testD8Merge(CompilationMode.DEBUG); + } + + @Test + public void testD8ReleaseDexFilePerClassFile() throws Exception { + testD8Merge(CompilationMode.RELEASE); + } + + private Path runD8ForClass( + Class<?> clazz, GlobalSyntheticsTestingConsumer global, CompilationMode mode) + throws Exception { + return testForD8() + .setMode(mode) + .setOutputMode(OutputMode.DexFilePerClassFile) + .apply(b -> b.getBuilder().setGlobalSyntheticsConsumer(global)) + .apply(builder -> setupTestCompileBuilder(builder, clazz)) + .compile() + .writeToZip(); + } + + public void testD8Merge(CompilationMode mode) throws Exception { + List<Path> paths = new ArrayList<>(); + GlobalSyntheticsTestingConsumer mainGlobals = new GlobalSyntheticsTestingConsumer(); + GlobalSyntheticsTestingConsumer testCallingFooGlobals = new GlobalSyntheticsTestingConsumer(); + GlobalSyntheticsTestingConsumer testCallingBarGlobals = new GlobalSyntheticsTestingConsumer(); + paths.add(runD8ForClass(Main.class, mainGlobals, mode)); + paths.add(runD8ForClass(TestCallingFoo.class, testCallingFooGlobals, mode)); + paths.add(runD8ForClass(TestCallingBar.class, testCallingBarGlobals, mode)); + assertFalse(mainGlobals.hasGlobals()); + if (isGreaterOrEqualToMockLevel()) { + assertFalse(testCallingFooGlobals.hasGlobals()); + assertFalse(testCallingBarGlobals.hasGlobals()); + } else { + // The TestCallingX does reference the mock and should have globals. + assertNotNull( + testCallingFooGlobals.getProvider(Reference.classFromClass(TestCallingFoo.class))); + assertNotNull( + testCallingBarGlobals.getProvider(Reference.classFromClass(TestCallingBar.class))); + } + + testForD8() + .setMode(mode) + .addProgramFiles(paths) + // Add the actual LibraryClass definition to the code, thus the globals will need to merge + // the synthetic stubs but also disregard them due to a program definition being present. + .addProgramClasses(LibraryClass.class) + .setMinApi(parameters.getApiLevel()) + .apply( + b -> + b.getBuilder() + .addGlobalSyntheticsResourceProviders(testCallingFooGlobals.getProviders()) + .addGlobalSyntheticsResourceProviders(testCallingBarGlobals.getProviders())) + .compile() + .inspect(this::inspect) + .applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class)) + .run(parameters.getRuntime(), Main.class) + .apply(this::checkOutput); + } + + private void inspect(CodeInspector inspector) { + ClassSubject libraryClassSubject = inspector.clazz(LibraryClass.class); + assertThat(libraryClassSubject, isPresent()); + assertThat(libraryClassSubject.uniqueMethodWithName("foo"), isPresent()); + assertThat(libraryClassSubject.uniqueMethodWithName("bar"), isPresent()); + } + + private void checkOutput(SingleTestRunResult<?> runResult) { + runResult.assertSuccessWithOutputLines("LibraryClass::foo", "LibraryClass::bar"); + } + + // Only present form api level 23, but also included in program. + public static class LibraryClass { + + public void foo() { + System.out.println("LibraryClass::foo"); + } + + public void bar() { + System.out.println("LibraryClass::bar"); + } + } + + public static class TestCallingFoo { + + public static void callFoo() { + new LibraryClass().foo(); + } + } + + public static class TestCallingBar { + + public static void callBar() { + new LibraryClass().bar(); + } + } + + public static class Main { + + public static void main(String[] args) { + TestCallingFoo.callFoo(); + TestCallingBar.callBar(); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfDefaultInterfaceMethodsTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfDefaultInterfaceMethodsTest.java index 420bf8d..9a243d3 100644 --- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfDefaultInterfaceMethodsTest.java +++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfDefaultInterfaceMethodsTest.java
@@ -52,7 +52,7 @@ // We are testing that we do not inline/merge higher api-levels .apply(ApiModelingTestHelper::disableOutliningAndStubbing) .enableNoMethodStaticizingAnnotations() - .noMinification() + .addDontObfuscate() .compile() .inspect( inspector -> {
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelStaticTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelStaticMethodTest.java similarity index 94% rename from src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelStaticTest.java rename to src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelStaticMethodTest.java index 1b7713d..72ca50d 100644 --- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelStaticTest.java +++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelStaticMethodTest.java
@@ -20,7 +20,7 @@ import org.junit.runners.Parameterized.Parameters; @RunWith(Parameterized.class) -public class ApiModelNoInliningOfHigherApiLevelStaticTest extends TestBase { +public class ApiModelNoInliningOfHigherApiLevelStaticMethodTest extends TestBase { private final TestParameters parameters; @@ -29,7 +29,7 @@ return getTestParameters().withAllRuntimesAndApiLevels().build(); } - public ApiModelNoInliningOfHigherApiLevelStaticTest(TestParameters parameters) { + public ApiModelNoInliningOfHigherApiLevelStaticMethodTest(TestParameters parameters) { this.parameters = parameters; }
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfStaticInterfaceMethodsTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfStaticInterfaceMethodsTest.java index 22714a3..9411c7d 100644 --- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfStaticInterfaceMethodsTest.java +++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfStaticInterfaceMethodsTest.java
@@ -52,7 +52,7 @@ .apply(ApiModelingTestHelper::enableApiCallerIdentification) // We are testing that we do not inline/merge higher api-levels .apply(ApiModelingTestHelper::disableOutliningAndStubbing) - .noMinification() + .addDontObfuscate() .enableInliningAnnotations() .compile() .inspect(
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoVerticalMergingSubReferenceApiTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoVerticalMergingSubReferenceApiTest.java index d105c17..f49536b 100644 --- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoVerticalMergingSubReferenceApiTest.java +++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoVerticalMergingSubReferenceApiTest.java
@@ -65,7 +65,7 @@ inspector.assertNoClassesMerged(); } }) - .noMinification() + .addDontObfuscate() .compile() .inspect( inspector -> {
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineInstanceFieldTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineInstanceFieldTest.java new file mode 100644 index 0000000..2d9de46 --- /dev/null +++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineInstanceFieldTest.java
@@ -0,0 +1,145 @@ +// 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.apimodel; + +import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass; +import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer; +import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForField; +import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat; +import static org.junit.Assume.assumeTrue; + +import com.android.tools.r8.CompilationMode; +import com.android.tools.r8.SingleTestRunResult; +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestCompilerBuilder; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.testing.AndroidBuildVersion; +import com.android.tools.r8.utils.AndroidApiLevel; +import com.android.tools.r8.utils.codeinspector.CodeInspector; +import java.lang.reflect.Field; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ApiModelOutlineInstanceFieldTest extends TestBase { + + private static final AndroidApiLevel classApiLevel = AndroidApiLevel.M; + private static final AndroidApiLevel fieldApiLevel = AndroidApiLevel.P; + + private static final String[] EXPECTED = + new String[] {"LibraryClass::getField", "LibraryClass::putField"}; + + @Parameter public TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); + } + + private void setupTestBuilder(TestCompilerBuilder<?, ?, ?, ?, ?> testBuilder) throws Exception { + testBuilder + .addLibraryClasses(LibraryClass.class) + .addDefaultRuntimeLibrary(parameters) + .addProgramClasses(Main.class) + .setMinApi(parameters.getApiLevel()) + .addAndroidBuildVersion() + .apply(setMockApiLevelForClass(LibraryClass.class, classApiLevel)) + .apply(setMockApiLevelForDefaultInstanceInitializer(LibraryClass.class, classApiLevel)) + .apply(setMockApiLevelForField(LibraryClass.class.getField("getField"), fieldApiLevel)) + .apply(setMockApiLevelForField(LibraryClass.class.getField("putField"), fieldApiLevel)) + .apply(ApiModelingTestHelper::enableApiCallerIdentification) + .apply(ApiModelingTestHelper::enableOutliningOfMethods) + .apply(ApiModelingTestHelper::disableStubbingOfClasses); + } + + public boolean addToBootClasspath() { + return parameters.isDexRuntime() + && parameters.getApiLevel().isGreaterThanOrEqualTo(classApiLevel); + } + + @Test + public void testD8Debug() throws Exception { + assumeTrue(parameters.isDexRuntime()); + testForD8() + .setMode(CompilationMode.DEBUG) + .apply(this::setupTestBuilder) + .compile() + .inspect(this::inspect) + .applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class)) + .run(parameters.getRuntime(), Main.class) + .apply(this::checkOutput); + } + + @Test + public void testD8Release() throws Exception { + assumeTrue(parameters.isDexRuntime()); + testForD8() + .setMode(CompilationMode.RELEASE) + .apply(this::setupTestBuilder) + .compile() + .inspect(this::inspect) + .applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class)) + .run(parameters.getRuntime(), Main.class) + .apply(this::checkOutput); + } + + @Test + public void testR8() throws Exception { + testForR8(parameters.getBackend()) + .apply(this::setupTestBuilder) + .addKeepMainRule(Main.class) + .compile() + .inspect(this::inspect) + .applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class)) + .run(parameters.getRuntime(), Main.class) + .apply(this::checkOutput); + } + + private void inspect(CodeInspector inspector) throws Exception { + Field[] fields = + new Field[] { + LibraryClass.class.getField("getField"), LibraryClass.class.getField("putField") + }; + for (Field field : fields) { + verifyThat(inspector, parameters, field) + .isOutlinedFromUntil(Main.class.getMethod("main", String[].class), fieldApiLevel); + } + } + + private void checkOutput(SingleTestRunResult<?> runResult) { + if (parameters.isDexRuntime() + && parameters.getApiLevel().isGreaterThanOrEqualTo(classApiLevel)) { + runResult.assertSuccessWithOutputLines(EXPECTED); + } else { + runResult.assertSuccessWithOutputLines("Not calling API"); + } + } + + // Only present from api level 23. + public static class LibraryClass { + + public String getField = "LibraryClass::getField"; + + public String putField; + } + + public static class Main { + + public static void main(String[] args) { + if (AndroidBuildVersion.VERSION >= 23) { + LibraryClass libraryClass = new LibraryClass(); + System.out.println(libraryClass.getField); + libraryClass.putField = "LibraryClass::putField"; + System.out.println(libraryClass.putField); + } else { + System.out.println("Not calling API"); + } + } + } +}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineStaticFieldTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineStaticFieldTest.java new file mode 100644 index 0000000..79b2cb8 --- /dev/null +++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineStaticFieldTest.java
@@ -0,0 +1,142 @@ +// 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.apimodel; + +import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass; +import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForField; +import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat; +import static org.junit.Assume.assumeTrue; + +import com.android.tools.r8.CompilationMode; +import com.android.tools.r8.SingleTestRunResult; +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestCompilerBuilder; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.testing.AndroidBuildVersion; +import com.android.tools.r8.utils.AndroidApiLevel; +import com.android.tools.r8.utils.codeinspector.CodeInspector; +import java.lang.reflect.Field; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ApiModelOutlineStaticFieldTest extends TestBase { + + private static final AndroidApiLevel classApiLevel = AndroidApiLevel.M; + private static final AndroidApiLevel fieldApiLevel = AndroidApiLevel.P; + + private static final String[] EXPECTED = + new String[] {"LibraryClass::getField", "LibraryClass::putField"}; + + @Parameter public TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); + } + + private void setupTestBuilder(TestCompilerBuilder<?, ?, ?, ?, ?> testBuilder) throws Exception { + testBuilder + .addLibraryClasses(LibraryClass.class) + .addDefaultRuntimeLibrary(parameters) + .addProgramClasses(Main.class) + .setMinApi(parameters.getApiLevel()) + .addAndroidBuildVersion() + .apply(setMockApiLevelForClass(LibraryClass.class, classApiLevel)) + .apply(setMockApiLevelForField(LibraryClass.class.getField("getField"), fieldApiLevel)) + .apply(setMockApiLevelForField(LibraryClass.class.getField("putField"), fieldApiLevel)) + .apply(ApiModelingTestHelper::enableApiCallerIdentification) + .apply(ApiModelingTestHelper::enableOutliningOfMethods) + .apply(ApiModelingTestHelper::disableStubbingOfClasses); + } + + public boolean addToBootClasspath() { + return parameters.isDexRuntime() + && parameters.getApiLevel().isGreaterThanOrEqualTo(classApiLevel); + } + + @Test + public void testD8Debug() throws Exception { + assumeTrue(parameters.isDexRuntime()); + testForD8() + .setMode(CompilationMode.DEBUG) + .apply(this::setupTestBuilder) + .compile() + .inspect(this::inspect) + .applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class)) + .run(parameters.getRuntime(), Main.class) + .apply(this::checkOutput); + } + + @Test + public void testD8Release() throws Exception { + assumeTrue(parameters.isDexRuntime()); + testForD8() + .setMode(CompilationMode.RELEASE) + .apply(this::setupTestBuilder) + .compile() + .inspect(this::inspect) + .applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class)) + .run(parameters.getRuntime(), Main.class) + .apply(this::checkOutput); + } + + @Test + public void testR8() throws Exception { + testForR8(parameters.getBackend()) + .apply(this::setupTestBuilder) + .addKeepMainRule(Main.class) + .compile() + .inspect(this::inspect) + .applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class)) + .run(parameters.getRuntime(), Main.class) + .apply(this::checkOutput); + } + + private void inspect(CodeInspector inspector) throws Exception { + Field[] fields = + new Field[] { + LibraryClass.class.getField("getField"), LibraryClass.class.getField("putField") + }; + for (Field field : fields) { + verifyThat(inspector, parameters, field) + .isOutlinedFromUntil(Main.class.getMethod("main", String[].class), fieldApiLevel); + } + } + + private void checkOutput(SingleTestRunResult<?> runResult) { + if (parameters.isDexRuntime() + && parameters.getApiLevel().isGreaterThanOrEqualTo(classApiLevel)) { + runResult.assertSuccessWithOutputLines(EXPECTED); + } else { + runResult.assertSuccessWithOutputLines("Not calling API"); + } + } + + // Only present from api level 23. + public static class LibraryClass { + + public static String getField = "LibraryClass::getField"; + + public static String putField; + } + + public static class Main { + + public static void main(String[] args) { + if (AndroidBuildVersion.VERSION >= 23) { + System.out.println(LibraryClass.getField); + LibraryClass.putField = "LibraryClass::putField"; + System.out.println(LibraryClass.putField); + } else { + System.out.println("Not calling API"); + } + } + } +}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java index ed2343a..4166e5e 100644 --- a/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java +++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java
@@ -4,6 +4,7 @@ package com.android.tools.r8.apimodel; +import static com.android.tools.r8.utils.codeinspector.CodeMatchers.accessesField; import static com.android.tools.r8.utils.codeinspector.CodeMatchers.invokesMethod; import static com.android.tools.r8.utils.codeinspector.CodeMatchers.invokesMethodWithName; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; @@ -11,10 +12,12 @@ import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import com.android.tools.r8.TestCompilerBuilder; import com.android.tools.r8.TestParameters; import com.android.tools.r8.ThrowableConsumer; +import com.android.tools.r8.references.FieldReference; import com.android.tools.r8.references.MethodReference; import com.android.tools.r8.references.Reference; import com.android.tools.r8.utils.AndroidApiLevel; @@ -193,6 +196,12 @@ inspector, parameters, Reference.methodFromMethod(method)); } + static ApiModelingFieldVerificationHelper verifyThat( + CodeInspector inspector, TestParameters parameters, Field field) { + return new ApiModelingFieldVerificationHelper( + inspector, parameters, Reference.fieldFromField(field)); + } + public static void assertNoSynthesizedClasses(CodeInspector inspector) { assertEquals( Collections.emptySet(), @@ -224,6 +233,51 @@ } } + public static class ApiModelingFieldVerificationHelper { + + private final CodeInspector inspector; + private final FieldReference fieldOfInterest; + private final TestParameters parameters; + + private ApiModelingFieldVerificationHelper( + CodeInspector inspector, TestParameters parameters, FieldReference fieldOfInterest) { + this.inspector = inspector; + this.fieldOfInterest = fieldOfInterest; + this.parameters = parameters; + } + + void isOutlinedFromUntil(Method method, AndroidApiLevel apiLevel) { + if (parameters.isDexRuntime() && parameters.getApiLevel().isLessThan(apiLevel)) { + isOutlinedFrom(method); + } else { + isNotOutlinedFrom(method); + } + } + + void isOutlinedFrom(Method method) { + // Check that the call is in a synthetic class. + List<FoundMethodSubject> outlinedMethod = + inspector.allClasses().stream() + .flatMap(clazz -> clazz.allMethods().stream()) + .filter( + methodSubject -> + methodSubject.isSynthetic() + && accessesField(fieldOfInterest).matches(methodSubject)) + .collect(Collectors.toList()); + assertFalse(outlinedMethod.isEmpty()); + // Assert that method invokes the outline + MethodSubject caller = inspector.method(method); + assertThat(caller, isPresent()); + assertThat(caller, invokesMethod(outlinedMethod.get(0))); + } + + void isNotOutlinedFrom(Method method) { + MethodSubject caller = inspector.method(method); + assertThat(caller, isPresent()); + assertThat(caller, accessesField(fieldOfInterest)); + } + } + public static class ApiModelingMethodVerificationHelper { private final CodeInspector inspector;
diff --git a/src/test/java/com/android/tools/r8/bridgeremoval/B77836766.java b/src/test/java/com/android/tools/r8/bridgeremoval/B77836766.java index 57c41a8..d08bb2f 100644 --- a/src/test/java/com/android/tools/r8/bridgeremoval/B77836766.java +++ b/src/test/java/com/android/tools/r8/bridgeremoval/B77836766.java
@@ -147,7 +147,7 @@ .addOptionsModification(this::configure) .enableConstantArgumentAnnotations() .noHorizontalClassMerging(cls2Class.name) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect( @@ -280,7 +280,7 @@ .addOptionsModification(this::configure) .enableConstantArgumentAnnotations() .noHorizontalClassMerging(derivedIntegerClass.name) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect( @@ -392,7 +392,7 @@ .addKeepMainRule(mainClass.name) .addOptionsModification(this::configure) .enableConstantArgumentAnnotations() - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect( @@ -481,7 +481,7 @@ .addKeepMainRule(mainClass.name) .addOptionsModification(this::configure) .enableConstantArgumentAnnotations() - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(
diff --git a/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/BridgeHoistingAccessibilityTest.java b/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/BridgeHoistingAccessibilityTest.java index 1eb5247..eac0142 100644 --- a/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/BridgeHoistingAccessibilityTest.java +++ b/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/BridgeHoistingAccessibilityTest.java
@@ -80,7 +80,7 @@ .enableNoVerticalClassMergingAnnotations() .enableNeverClassInliningAnnotations() // TODO(b/173398086): uniqueMethodWithName() does not work with argument changes. - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(this::inspect)
diff --git a/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/KeptBridgeHoistingTest.java b/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/KeptBridgeHoistingTest.java index e45bdcc..458a8d2 100644 --- a/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/KeptBridgeHoistingTest.java +++ b/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/KeptBridgeHoistingTest.java
@@ -46,7 +46,7 @@ .enableNoVerticalClassMergingAnnotations() .enableNeverClassInliningAnnotations() // TODO(b/173398086): uniqueMethodWithName() does not work with signature changes. - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(this::inspect)
diff --git a/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/NonSuperclassBridgeHoistingTest.java b/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/NonSuperclassBridgeHoistingTest.java index 2819311..ff05bfd 100644 --- a/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/NonSuperclassBridgeHoistingTest.java +++ b/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/NonSuperclassBridgeHoistingTest.java
@@ -48,7 +48,7 @@ .enableNoVerticalClassMergingAnnotations() .enableNeverClassInliningAnnotations() // TODO(b/173398086): uniqueMethodWithName() does not work with signature changes. - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(this::inspect)
diff --git a/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/PositiveBridgeHoistingTest.java b/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/PositiveBridgeHoistingTest.java index 120d7b4..2ac940a 100644 --- a/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/PositiveBridgeHoistingTest.java +++ b/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/PositiveBridgeHoistingTest.java
@@ -59,7 +59,7 @@ .enableNoMethodStaticizingAnnotations() .enableNoHorizontalClassMergingAnnotations() // TODO(b/173398086): uniqueMethodWithName() does not work with argument changes. - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(this::inspect)
diff --git a/src/test/java/com/android/tools/r8/cf/AlwaysNullGetItemTestRunner.java b/src/test/java/com/android/tools/r8/cf/AlwaysNullGetItemTestRunner.java index f99896f..a459923 100644 --- a/src/test/java/com/android/tools/r8/cf/AlwaysNullGetItemTestRunner.java +++ b/src/test/java/com/android/tools/r8/cf/AlwaysNullGetItemTestRunner.java
@@ -39,7 +39,7 @@ testForR8(parameters.getBackend()) .addProgramClassesAndInnerClasses(CLASS) .debug() - .noMinification() + .addDontObfuscate() .noTreeShaking() .setMinApi(parameters.getApiLevel()) .compile()
diff --git a/src/test/java/com/android/tools/r8/cf/BasicBlockMuncherQuadraticTest.java b/src/test/java/com/android/tools/r8/cf/BasicBlockMuncherQuadraticTest.java index 7ab71ea..6cb424f 100644 --- a/src/test/java/com/android/tools/r8/cf/BasicBlockMuncherQuadraticTest.java +++ b/src/test/java/com/android/tools/r8/cf/BasicBlockMuncherQuadraticTest.java
@@ -16,7 +16,7 @@ testForR8(Backend.CF) .addKeepMainRule(MethodHolder.class) .addInnerClasses(BasicBlockMuncherQuadraticTest.class) - .noMinification() + .addDontObfuscate() .addOptionsModification(options -> options.testing.basicBlockMuncherIterationLimit = 50000) .compile(); }
diff --git a/src/test/java/com/android/tools/r8/cf/CfDebugLocalStackMapVerificationTest.java b/src/test/java/com/android/tools/r8/cf/CfDebugLocalStackMapVerificationTest.java index 5108c8d..0f1668f 100644 --- a/src/test/java/com/android/tools/r8/cf/CfDebugLocalStackMapVerificationTest.java +++ b/src/test/java/com/android/tools/r8/cf/CfDebugLocalStackMapVerificationTest.java
@@ -5,10 +5,7 @@ package com.android.tools.r8.cf; import static org.hamcrest.CoreMatchers.containsString; -import static org.junit.Assert.assertThrows; -import com.android.tools.r8.CompilationFailedException; -import com.android.tools.r8.CompilationMode; import com.android.tools.r8.TestBase; import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestParametersCollection; @@ -18,12 +15,6 @@ import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameter; import org.junit.runners.Parameterized.Parameters; -import org.objectweb.asm.AnnotationVisitor; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.FieldVisitor; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; /** Regression tests for b/237567012 */ @RunWith(Parameterized.class) @@ -59,7 +50,7 @@ } @Test - public void testSmallReproD8() throws Exception { + public void testD8() throws Exception { testForD8(parameters.getBackend()) .addProgramClasses(SmallRepro.class) .setMinApi(AndroidApiLevel.B) @@ -69,967 +60,25 @@ options.testing.neverReuseCfLocalRegisters = true; }) .run(parameters.getRuntime(), SmallRepro.class) - // TODO(b/237567012): Run should succeed with printing of FOO. - .assertFailureWithErrorThatThrows(VerifyError.class); + .assertSuccessWithOutputThatMatches(containsString("FOO")); } @Test public void testR8() throws Exception { - // TODO(b/237567012): We should not fail compilation. - assertThrows( - CompilationFailedException.class, - () -> - testForR8(parameters.getBackend()) - .addProgramClassFileData(CfDebugLocalStackMapVerificationTest$MainDump.dump()) - .addKeepMainRule(Main.class) - .setMode(CompilationMode.DEBUG) - .addDontWarn("*") - // TODO(b/237567012): Remove option when resolved. - .addOptionsModification( - options -> options.enableCheckAllInstructionsDuringStackMapVerification = true) - .compile() - .run(parameters.getRuntime(), Main.class)); - } - - public static class Main { - - // InvokeSuspend is taken from an input program.jar and copied verbatim in the dump below. - public Object invokeSuspend(Object o) { - return o; - } - - public static void main(String[] args) { - new Main().invokeSuspend(null); - } - } - - public static class CfDebugLocalStackMapVerificationTest$MainDump implements Opcodes { - - public static byte[] dump() throws Exception { - - ClassWriter classWriter = new ClassWriter(0); - FieldVisitor fieldVisitor; - MethodVisitor methodVisitor; - AnnotationVisitor annotationVisitor0; - - classWriter.visit( - V1_8, - ACC_FINAL | ACC_SUPER, - binaryName(Main.class), - null, - "kotlin/coroutines/jvm/internal/SuspendLambda", - new String[] {"kotlin/jvm/functions/Function2"}); - - { - fieldVisitor = classWriter.visitField(0, "L$1", "Ljava/lang/Object;", null, null); - fieldVisitor.visitEnd(); - } - { - fieldVisitor = classWriter.visitField(0, "L$2", "Ljava/lang/Object;", null, null); - fieldVisitor.visitEnd(); - } - { - fieldVisitor = classWriter.visitField(0, "label", "I", null, null); - fieldVisitor.visitEnd(); - } - { - fieldVisitor = - classWriter.visitField( - ACC_PRIVATE | ACC_SYNTHETIC, "L$0", "Ljava/lang/Object;", null, null); - fieldVisitor.visitEnd(); - } - { - fieldVisitor = - classWriter.visitField( - ACC_FINAL | ACC_SYNTHETIC, - "this$0", - "Lio/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber;", - null, - null); - fieldVisitor.visitEnd(); - } - { - methodVisitor = - classWriter.visitMethod( - 0, - "<init>", - "(Lio/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber;Lkotlin/coroutines/Continuation;)V", - "(Lio/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber;Lkotlin/coroutines/Continuation<-Lio/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1;>;)V", - null); - methodVisitor.visitCode(); - Label label0 = new Label(); - methodVisitor.visitLabel(label0); - methodVisitor.visitVarInsn(ALOAD, 0); - methodVisitor.visitVarInsn(ALOAD, 1); - methodVisitor.visitFieldInsn( - PUTFIELD, - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1", - "this$0", - "Lio/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber;"); - methodVisitor.visitVarInsn(ALOAD, 0); - methodVisitor.visitInsn(ICONST_2); - methodVisitor.visitVarInsn(ALOAD, 2); - methodVisitor.visitMethodInsn( - INVOKESPECIAL, - "kotlin/coroutines/jvm/internal/SuspendLambda", - "<init>", - "(ILkotlin/coroutines/Continuation;)V", - false); - methodVisitor.visitInsn(RETURN); - Label label1 = new Label(); - methodVisitor.visitLabel(label1); - methodVisitor.visitLocalVariable( - "this", - "Lio/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1;", - null, - label0, - label1, - 0); - methodVisitor.visitLocalVariable( - "$receiver", - "Lio/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber;", - null, - label0, - label1, - 1); - methodVisitor.visitLocalVariable( - "$completion", "Lkotlin/coroutines/Continuation;", null, label0, label1, 2); - methodVisitor.visitMaxs(3, 3); - methodVisitor.visitEnd(); - } - { - methodVisitor = - classWriter.visitMethod( - ACC_PUBLIC | ACC_FINAL, - "invokeSuspend", - "(Ljava/lang/Object;)Ljava/lang/Object;", - null, - null); - { - annotationVisitor0 = - methodVisitor.visitAnnotation("Lorg/jetbrains/annotations/Nullable;", false); - annotationVisitor0.visitEnd(); - } - methodVisitor.visitAnnotableParameterCount(1, false); - { - annotationVisitor0 = - methodVisitor.visitParameterAnnotation( - 0, "Lorg/jetbrains/annotations/NotNull;", false); - annotationVisitor0.visitEnd(); - } - methodVisitor.visitCode(); - Label label0 = new Label(); - Label label1 = new Label(); - Label label2 = new Label(); - methodVisitor.visitTryCatchBlock(label0, label1, label2, "java/lang/Throwable"); - Label label3 = new Label(); - Label label4 = new Label(); - methodVisitor.visitTryCatchBlock(label3, label4, label2, "java/lang/Throwable"); - Label label5 = new Label(); - Label label6 = new Label(); - methodVisitor.visitTryCatchBlock(label5, label6, label2, "java/lang/Throwable"); - Label label7 = new Label(); - methodVisitor.visitTryCatchBlock(label0, label1, label7, null); - methodVisitor.visitTryCatchBlock(label3, label4, label7, null); - methodVisitor.visitTryCatchBlock(label5, label6, label7, null); - methodVisitor.visitTryCatchBlock(label2, label7, label7, null); - Label label8 = new Label(); - methodVisitor.visitTryCatchBlock(label7, label8, label7, null); - Label label9 = new Label(); - Label label10 = new Label(); - methodVisitor.visitTryCatchBlock( - label9, label1, label10, "kotlinx/coroutines/channels/ClosedReceiveChannelException"); - methodVisitor.visitTryCatchBlock( - label3, label4, label10, "kotlinx/coroutines/channels/ClosedReceiveChannelException"); - methodVisitor.visitTryCatchBlock( - label5, label10, label10, "kotlinx/coroutines/channels/ClosedReceiveChannelException"); - methodVisitor.visitMethodInsn( - INVOKESTATIC, - "kotlin/coroutines/intrinsics/IntrinsicsKt", - "getCOROUTINE_SUSPENDED", - "()Ljava/lang/Object;", - false); - Label label11 = new Label(); - methodVisitor.visitLabel(label11); - methodVisitor.visitLineNumber(60, label11); - methodVisitor.visitVarInsn(ASTORE, 10); - methodVisitor.visitVarInsn(ALOAD, 0); - methodVisitor.visitFieldInsn( - GETFIELD, - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1", - "label", - "I"); - Label label12 = new Label(); - Label label13 = new Label(); - Label label14 = new Label(); - Label label15 = new Label(); - methodVisitor.visitTableSwitchInsn(0, 2, label15, new Label[] {label12, label13, label14}); - methodVisitor.visitLabel(label12); - methodVisitor.visitFrame( - Opcodes.F_FULL, - 11, - new Object[] { - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1", - "java/lang/Object", - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - "java/lang/Object" - }, - 0, - new Object[] {}); - methodVisitor.visitVarInsn(ALOAD, 1); - methodVisitor.visitMethodInsn( - INVOKESTATIC, "kotlin/ResultKt", "throwOnFailure", "(Ljava/lang/Object;)V", false); - Label label16 = new Label(); - methodVisitor.visitLabel(label16); - methodVisitor.visitVarInsn(ALOAD, 0); - methodVisitor.visitFieldInsn( - GETFIELD, - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1", - "L$0", - "Ljava/lang/Object;"); - methodVisitor.visitTypeInsn(CHECKCAST, "kotlinx/coroutines/CoroutineScope"); - methodVisitor.visitVarInsn(ASTORE, 2); - methodVisitor.visitLabel(label9); - methodVisitor.visitLineNumber(61, label9); - methodVisitor.visitInsn(NOP); - Label label17 = new Label(); - methodVisitor.visitLabel(label17); - methodVisitor.visitLineNumber(62, label17); - methodVisitor.visitVarInsn(ALOAD, 0); - methodVisitor.visitFieldInsn( - GETFIELD, - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1", - "this$0", - "Lio/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber;"); - methodVisitor.visitMethodInsn( - INVOKESTATIC, - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber", - "access$getQueue$p", - "(Lio/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber;)Lkotlinx/coroutines/channels/Channel;", - false); - methodVisitor.visitTypeInsn(CHECKCAST, "kotlinx/coroutines/channels/ReceiveChannel"); - methodVisitor.visitVarInsn(ASTORE, 3); - methodVisitor.visitVarInsn(ALOAD, 0); - methodVisitor.visitFieldInsn( - GETFIELD, - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1", - "this$0", - "Lio/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber;"); - methodVisitor.visitVarInsn(ASTORE, 4); - Label label18 = new Label(); - methodVisitor.visitLabel(label18); - methodVisitor.visitInsn(ICONST_0); - methodVisitor.visitVarInsn(ISTORE, 5); - Label label19 = new Label(); - methodVisitor.visitLabel(label19); - methodVisitor.visitLineNumber(146, label19); - methodVisitor.visitInsn(NOP); - Label label20 = new Label(); - methodVisitor.visitLabel(label20); - methodVisitor.visitLineNumber(149, label20); - methodVisitor.visitInsn(ACONST_NULL); - methodVisitor.visitVarInsn(ASTORE, 6); - methodVisitor.visitLabel(label0); - methodVisitor.visitLineNumber(150, label0); - methodVisitor.visitInsn(NOP); - Label label21 = new Label(); - methodVisitor.visitLabel(label21); - methodVisitor.visitLineNumber(151, label21); - methodVisitor.visitInsn(ICONST_0); - methodVisitor.visitVarInsn(ISTORE, 7); - Label label22 = new Label(); - methodVisitor.visitLabel(label22); - methodVisitor.visitLineNumber(63, label22); - methodVisitor.visitFrame( - Opcodes.F_FULL, - 11, - new Object[] { - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1", - "java/lang/Object", - "kotlinx/coroutines/CoroutineScope", - "kotlinx/coroutines/channels/ReceiveChannel", - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber", - Opcodes.INTEGER, - Opcodes.NULL, - Opcodes.INTEGER, - Opcodes.TOP, - Opcodes.TOP, - "java/lang/Object" - }, - 0, - new Object[] {}); - methodVisitor.visitVarInsn(ALOAD, 2); - methodVisitor.visitMethodInsn( - INVOKESTATIC, - "kotlinx/coroutines/CoroutineScopeKt", - "isActive", - "(Lkotlinx/coroutines/CoroutineScope;)Z", - false); - Label label23 = new Label(); - methodVisitor.visitJumpInsn(IFEQ, label23); - Label label24 = new Label(); - methodVisitor.visitLabel(label24); - methodVisitor.visitLineNumber(64, label24); - methodVisitor.visitVarInsn(ALOAD, 4); - methodVisitor.visitMethodInsn( - INVOKESTATIC, - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber", - "access$getQueue$p", - "(Lio/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber;)Lkotlinx/coroutines/channels/Channel;", - false); - methodVisitor.visitMethodInsn( - INVOKEINTERFACE, - "kotlinx/coroutines/channels/Channel", - "tryReceive-PtdJZtk", - "()Ljava/lang/Object;", - true); - methodVisitor.visitMethodInsn( - INVOKESTATIC, - "kotlinx/coroutines/channels/ChannelResult", - "getOrNull-impl", - "(Ljava/lang/Object;)Ljava/lang/Object;", - false); - methodVisitor.visitTypeInsn(CHECKCAST, "java/nio/ByteBuffer"); - methodVisitor.visitVarInsn(ASTORE, 8); - Label label25 = new Label(); - methodVisitor.visitLabel(label25); - methodVisitor.visitLineNumber(65, label25); - methodVisitor.visitVarInsn(ALOAD, 8); - Label label26 = new Label(); - methodVisitor.visitJumpInsn(IFNONNULL, label26); - Label label27 = new Label(); - methodVisitor.visitLabel(label27); - methodVisitor.visitLineNumber(66, label27); - methodVisitor.visitVarInsn(ALOAD, 4); - methodVisitor.visitFieldInsn( - GETFIELD, - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber", - "subscription", - "Ljava/lang/Object;"); - methodVisitor.visitTypeInsn(CHECKCAST, "java/util/concurrent/Flow$Subscription"); - methodVisitor.visitInsn(DUP); - Label label28 = new Label(); - methodVisitor.visitJumpInsn(IFNULL, label28); - methodVisitor.visitInsn(LCONST_1); - methodVisitor.visitMethodInsn( - INVOKEINTERFACE, "java/util/concurrent/Flow$Subscription", "request", "(J)V", true); - Label label29 = new Label(); - methodVisitor.visitJumpInsn(GOTO, label29); - methodVisitor.visitLabel(label28); - methodVisitor.visitFrame( - Opcodes.F_FULL, - 11, - new Object[] { - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1", - "java/lang/Object", - "kotlinx/coroutines/CoroutineScope", - "kotlinx/coroutines/channels/ReceiveChannel", - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber", - Opcodes.INTEGER, - Opcodes.NULL, - Opcodes.INTEGER, - "java/nio/ByteBuffer", - Opcodes.TOP, - "java/lang/Object" - }, - 1, - new Object[] {"java/util/concurrent/Flow$Subscription"}); - methodVisitor.visitInsn(POP); - methodVisitor.visitLabel(label29); - methodVisitor.visitLineNumber(67, label29); - methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - methodVisitor.visitVarInsn(ALOAD, 4); - methodVisitor.visitMethodInsn( - INVOKESTATIC, - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber", - "access$getQueue$p", - "(Lio/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber;)Lkotlinx/coroutines/channels/Channel;", - false); - methodVisitor.visitVarInsn(ALOAD, 0); - methodVisitor.visitVarInsn(ALOAD, 0); - methodVisitor.visitVarInsn(ALOAD, 2); - methodVisitor.visitFieldInsn( - PUTFIELD, - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1", - "L$0", - "Ljava/lang/Object;"); - methodVisitor.visitVarInsn(ALOAD, 0); - methodVisitor.visitVarInsn(ALOAD, 3); - methodVisitor.visitFieldInsn( - PUTFIELD, - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1", - "L$1", - "Ljava/lang/Object;"); - methodVisitor.visitVarInsn(ALOAD, 0); - methodVisitor.visitVarInsn(ALOAD, 4); - methodVisitor.visitFieldInsn( - PUTFIELD, - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1", - "L$2", - "Ljava/lang/Object;"); - methodVisitor.visitVarInsn(ALOAD, 0); - methodVisitor.visitInsn(ICONST_1); - methodVisitor.visitFieldInsn( - PUTFIELD, - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1", - "label", - "I"); - methodVisitor.visitMethodInsn( - INVOKEINTERFACE, - "kotlinx/coroutines/channels/Channel", - "receive", - "(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;", - true); - methodVisitor.visitLabel(label1); - methodVisitor.visitInsn(DUP); - methodVisitor.visitVarInsn(ALOAD, 10); - Label label30 = new Label(); - methodVisitor.visitJumpInsn(IF_ACMPNE, label30); - Label label31 = new Label(); - methodVisitor.visitLabel(label31); - methodVisitor.visitLineNumber(60, label31); - methodVisitor.visitVarInsn(ALOAD, 10); - methodVisitor.visitInsn(ARETURN); - methodVisitor.visitLabel(label13); - methodVisitor.visitFrame( - Opcodes.F_FULL, - 11, - new Object[] { - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1", - "java/lang/Object", - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - "java/lang/Object" - }, - 0, - new Object[] {}); - methodVisitor.visitInsn(ICONST_0); - methodVisitor.visitVarInsn(ISTORE, 5); - Label label32 = new Label(); - methodVisitor.visitLabel(label32); - methodVisitor.visitInsn(ICONST_0); - methodVisitor.visitVarInsn(ISTORE, 7); - Label label33 = new Label(); - methodVisitor.visitLabel(label33); - methodVisitor.visitInsn(ACONST_NULL); - methodVisitor.visitVarInsn(ASTORE, 6); - methodVisitor.visitVarInsn(ALOAD, 0); - methodVisitor.visitFieldInsn( - GETFIELD, - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1", - "L$2", - "Ljava/lang/Object;"); - methodVisitor.visitTypeInsn( - CHECKCAST, - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber"); - methodVisitor.visitVarInsn(ASTORE, 4); - methodVisitor.visitVarInsn(ALOAD, 0); - methodVisitor.visitFieldInsn( - GETFIELD, - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1", - "L$1", - "Ljava/lang/Object;"); - methodVisitor.visitTypeInsn(CHECKCAST, "kotlinx/coroutines/channels/ReceiveChannel"); - methodVisitor.visitVarInsn(ASTORE, 3); - Label label34 = new Label(); - methodVisitor.visitLabel(label34); - methodVisitor.visitVarInsn(ALOAD, 0); - methodVisitor.visitFieldInsn( - GETFIELD, - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1", - "L$0", - "Ljava/lang/Object;"); - methodVisitor.visitTypeInsn(CHECKCAST, "kotlinx/coroutines/CoroutineScope"); - methodVisitor.visitVarInsn(ASTORE, 2); - methodVisitor.visitLabel(label3); - methodVisitor.visitInsn(NOP); - methodVisitor.visitVarInsn(ALOAD, 1); - methodVisitor.visitMethodInsn( - INVOKESTATIC, "kotlin/ResultKt", "throwOnFailure", "(Ljava/lang/Object;)V", false); - methodVisitor.visitVarInsn(ALOAD, 1); - methodVisitor.visitLabel(label30); - methodVisitor.visitFrame( - Opcodes.F_FULL, - 11, - new Object[] { - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1", - "java/lang/Object", - "kotlinx/coroutines/CoroutineScope", - "kotlinx/coroutines/channels/ReceiveChannel", - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber", - Opcodes.INTEGER, - Opcodes.NULL, - Opcodes.INTEGER, - Opcodes.TOP, - Opcodes.TOP, - "java/lang/Object" - }, - 1, - new Object[] {"java/lang/Object"}); - methodVisitor.visitTypeInsn(CHECKCAST, "java/nio/ByteBuffer"); - methodVisitor.visitVarInsn(ASTORE, 8); - methodVisitor.visitLabel(label26); - methodVisitor.visitLineNumber(70, label26); - methodVisitor.visitFrame( - Opcodes.F_FULL, - 11, - new Object[] { - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1", - "java/lang/Object", - "kotlinx/coroutines/CoroutineScope", - "kotlinx/coroutines/channels/ReceiveChannel", - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber", - Opcodes.INTEGER, - Opcodes.NULL, - Opcodes.INTEGER, - "java/nio/ByteBuffer", - Opcodes.TOP, - "java/lang/Object" - }, - 0, - new Object[] {}); - methodVisitor.visitVarInsn(ALOAD, 4); - methodVisitor.visitMethodInsn( - INVOKESTATIC, - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber", - "access$getResponseChannel$p", - "(Lio/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber;)Lio/ktor/utils/io/ByteChannel;", - false); - methodVisitor.visitVarInsn(ALOAD, 8); - methodVisitor.visitVarInsn(ALOAD, 0); - methodVisitor.visitVarInsn(ALOAD, 0); - methodVisitor.visitVarInsn(ALOAD, 2); - methodVisitor.visitFieldInsn( - PUTFIELD, - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1", - "L$0", - "Ljava/lang/Object;"); - methodVisitor.visitVarInsn(ALOAD, 0); - methodVisitor.visitVarInsn(ALOAD, 3); - methodVisitor.visitFieldInsn( - PUTFIELD, - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1", - "L$1", - "Ljava/lang/Object;"); - methodVisitor.visitVarInsn(ALOAD, 0); - methodVisitor.visitVarInsn(ALOAD, 4); - methodVisitor.visitFieldInsn( - PUTFIELD, - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1", - "L$2", - "Ljava/lang/Object;"); - methodVisitor.visitVarInsn(ALOAD, 0); - methodVisitor.visitInsn(ICONST_2); - methodVisitor.visitFieldInsn( - PUTFIELD, - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1", - "label", - "I"); - methodVisitor.visitMethodInsn( - INVOKEINTERFACE, - "io/ktor/utils/io/ByteChannel", - "writeFully", - "(Ljava/nio/ByteBuffer;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;", - true); - methodVisitor.visitLabel(label4); - methodVisitor.visitInsn(DUP); - methodVisitor.visitVarInsn(ALOAD, 10); - Label label35 = new Label(); - methodVisitor.visitJumpInsn(IF_ACMPNE, label35); - Label label36 = new Label(); - methodVisitor.visitLabel(label36); - methodVisitor.visitLineNumber(60, label36); - methodVisitor.visitVarInsn(ALOAD, 10); - methodVisitor.visitInsn(ARETURN); - methodVisitor.visitLabel(label14); - methodVisitor.visitFrame( - Opcodes.F_FULL, - 11, - new Object[] { - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1", - "java/lang/Object", - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - "java/lang/Object" - }, - 0, - new Object[] {}); - methodVisitor.visitInsn(ICONST_0); - methodVisitor.visitVarInsn(ISTORE, 5); - Label label37 = new Label(); - methodVisitor.visitLabel(label37); - methodVisitor.visitInsn(ICONST_0); - methodVisitor.visitVarInsn(ISTORE, 7); - Label label38 = new Label(); - methodVisitor.visitLabel(label38); - methodVisitor.visitInsn(ACONST_NULL); - methodVisitor.visitVarInsn(ASTORE, 6); - methodVisitor.visitVarInsn(ALOAD, 0); - methodVisitor.visitFieldInsn( - GETFIELD, - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1", - "L$2", - "Ljava/lang/Object;"); - methodVisitor.visitTypeInsn( - CHECKCAST, - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber"); - methodVisitor.visitVarInsn(ASTORE, 4); - methodVisitor.visitVarInsn(ALOAD, 0); - methodVisitor.visitFieldInsn( - GETFIELD, - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1", - "L$1", - "Ljava/lang/Object;"); - methodVisitor.visitTypeInsn(CHECKCAST, "kotlinx/coroutines/channels/ReceiveChannel"); - methodVisitor.visitVarInsn(ASTORE, 3); - Label label39 = new Label(); - methodVisitor.visitLabel(label39); - methodVisitor.visitVarInsn(ALOAD, 0); - methodVisitor.visitFieldInsn( - GETFIELD, - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1", - "L$0", - "Ljava/lang/Object;"); - methodVisitor.visitTypeInsn(CHECKCAST, "kotlinx/coroutines/CoroutineScope"); - methodVisitor.visitVarInsn(ASTORE, 2); - methodVisitor.visitLabel(label5); - methodVisitor.visitInsn(NOP); - methodVisitor.visitVarInsn(ALOAD, 1); - methodVisitor.visitMethodInsn( - INVOKESTATIC, "kotlin/ResultKt", "throwOnFailure", "(Ljava/lang/Object;)V", false); - methodVisitor.visitVarInsn(ALOAD, 1); - methodVisitor.visitLabel(label35); - methodVisitor.visitLineNumber(70, label35); - methodVisitor.visitFrame( - Opcodes.F_FULL, - 11, - new Object[] { - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1", - "java/lang/Object", - "kotlinx/coroutines/CoroutineScope", - "kotlinx/coroutines/channels/ReceiveChannel", - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber", - Opcodes.INTEGER, - Opcodes.NULL, - Opcodes.INTEGER, - Opcodes.TOP, - Opcodes.TOP, - "java/lang/Object" - }, - 1, - new Object[] {"java/lang/Object"}); - methodVisitor.visitInsn(POP); - methodVisitor.visitJumpInsn(GOTO, label22); - methodVisitor.visitLabel(label23); - methodVisitor.visitLineNumber(72, label23); - methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - methodVisitor.visitInsn(NOP); - Label label40 = new Label(); - methodVisitor.visitLabel(label40); - methodVisitor.visitFieldInsn(GETSTATIC, "kotlin/Unit", "INSTANCE", "Lkotlin/Unit;"); - methodVisitor.visitVarInsn(ASTORE, 9); - methodVisitor.visitLabel(label6); - methodVisitor.visitLineNumber(156, label6); - methodVisitor.visitVarInsn(ALOAD, 3); - methodVisitor.visitVarInsn(ALOAD, 6); - methodVisitor.visitMethodInsn( - INVOKESTATIC, - "kotlinx/coroutines/channels/ChannelsKt", - "cancelConsumed", - "(Lkotlinx/coroutines/channels/ReceiveChannel;Ljava/lang/Throwable;)V", - false); - Label label41 = new Label(); - methodVisitor.visitLabel(label41); - methodVisitor.visitLineNumber(151, label41); - Label label42 = new Label(); - methodVisitor.visitJumpInsn(GOTO, label42); - methodVisitor.visitLabel(label2); - methodVisitor.visitLineNumber(152, label2); - methodVisitor.visitFrame( - Opcodes.F_FULL, - 11, - new Object[] { - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1", - "java/lang/Object", - "kotlinx/coroutines/CoroutineScope", - "kotlinx/coroutines/channels/ReceiveChannel", - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber", - Opcodes.INTEGER, - Opcodes.NULL, - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - "java/lang/Object" - }, - 1, - new Object[] {"java/lang/Throwable"}); - methodVisitor.visitVarInsn(ASTORE, 9); - Label label43 = new Label(); - methodVisitor.visitLabel(label43); - methodVisitor.visitLineNumber(153, label43); - methodVisitor.visitVarInsn(ALOAD, 9); - methodVisitor.visitVarInsn(ASTORE, 6); - Label label44 = new Label(); - methodVisitor.visitLabel(label44); - methodVisitor.visitLineNumber(154, label44); - methodVisitor.visitVarInsn(ALOAD, 9); - methodVisitor.visitInsn(ATHROW); - methodVisitor.visitLabel(label7); - methodVisitor.visitLineNumber(155, label7); - methodVisitor.visitFrame( - Opcodes.F_FULL, - 11, - new Object[] { - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1", - "java/lang/Object", - "kotlinx/coroutines/CoroutineScope", - "kotlinx/coroutines/channels/ReceiveChannel", - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber", - Opcodes.INTEGER, - "java/lang/Throwable", - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - "java/lang/Object" - }, - 1, - new Object[] {"java/lang/Throwable"}); - methodVisitor.visitVarInsn(ASTORE, 9); - methodVisitor.visitLabel(label8); - methodVisitor.visitLineNumber(156, label8); - methodVisitor.visitVarInsn(ALOAD, 3); - methodVisitor.visitVarInsn(ALOAD, 6); - methodVisitor.visitMethodInsn( - INVOKESTATIC, - "kotlinx/coroutines/channels/ChannelsKt", - "cancelConsumed", - "(Lkotlinx/coroutines/channels/ReceiveChannel;Ljava/lang/Throwable;)V", - false); - methodVisitor.visitVarInsn(ALOAD, 9); - methodVisitor.visitInsn(ATHROW); - methodVisitor.visitLabel(label10); - methodVisitor.visitLineNumber(73, label10); - methodVisitor.visitFrame( - Opcodes.F_FULL, - 11, - new Object[] { - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1", - "java/lang/Object", - "kotlinx/coroutines/CoroutineScope", - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - "java/lang/Object" - }, - 1, - new Object[] {"kotlinx/coroutines/channels/ClosedReceiveChannelException"}); - methodVisitor.visitVarInsn(ASTORE, 3); - methodVisitor.visitLabel(label42); - methodVisitor.visitLineNumber(75, label42); - methodVisitor.visitFrame( - Opcodes.F_FULL, - 11, - new Object[] { - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1", - "java/lang/Object", - "kotlinx/coroutines/CoroutineScope", - "java/lang/Object", - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - "java/lang/Object" - }, - 0, - new Object[] {}); - methodVisitor.visitFieldInsn(GETSTATIC, "kotlin/Unit", "INSTANCE", "Lkotlin/Unit;"); - methodVisitor.visitInsn(ARETURN); - methodVisitor.visitLabel(label15); - methodVisitor.visitFrame( - Opcodes.F_FULL, - 11, - new Object[] { - "io/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1", - "java/lang/Object", - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - Opcodes.TOP, - "java/lang/Object" - }, - 0, - new Object[] {}); - methodVisitor.visitTypeInsn(NEW, "java/lang/IllegalStateException"); - methodVisitor.visitInsn(DUP); - methodVisitor.visitLdcInsn("call to 'resume' before 'invoke' with coroutine"); - methodVisitor.visitMethodInsn( - INVOKESPECIAL, - "java/lang/IllegalStateException", - "<init>", - "(Ljava/lang/String;)V", - false); - methodVisitor.visitInsn(ATHROW); - methodVisitor.visitLocalVariable( - "$this$launch", "Lkotlinx/coroutines/CoroutineScope;", null, label9, label13, 2); - methodVisitor.visitLocalVariable( - "$this$launch", "Lkotlinx/coroutines/CoroutineScope;", null, label3, label14, 2); - methodVisitor.visitLocalVariable( - "$this$launch", "Lkotlinx/coroutines/CoroutineScope;", null, label5, label23, 2); - methodVisitor.visitLocalVariable( - "$this$consume$iv", - "Lkotlinx/coroutines/channels/ReceiveChannel;", - null, - label18, - label13, - 3); - methodVisitor.visitLocalVariable( - "$this$consume$iv", - "Lkotlinx/coroutines/channels/ReceiveChannel;", - null, - label34, - label14, - 3); - methodVisitor.visitLocalVariable( - "$this$consume$iv", - "Lkotlinx/coroutines/channels/ReceiveChannel;", - null, - label39, - label40, - 3); - methodVisitor.visitLocalVariable( - "$this$consume$iv", - "Lkotlinx/coroutines/channels/ReceiveChannel;", - null, - label40, - label41, - 3); - methodVisitor.visitLocalVariable( - "$this$consume$iv", - "Lkotlinx/coroutines/channels/ReceiveChannel;", - null, - label2, - label10, - 3); - methodVisitor.visitLocalVariable( - "cause$iv", "Ljava/lang/Throwable;", null, label0, label13, 6); - methodVisitor.visitLocalVariable( - "cause$iv", "Ljava/lang/Throwable;", null, label34, label14, 6); - methodVisitor.visitLocalVariable( - "cause$iv", "Ljava/lang/Throwable;", null, label39, label40, 6); - methodVisitor.visitLocalVariable( - "cause$iv", "Ljava/lang/Throwable;", null, label40, label41, 6); - methodVisitor.visitLocalVariable( - "cause$iv", "Ljava/lang/Throwable;", null, label2, label44, 6); - methodVisitor.visitLocalVariable( - "cause$iv", "Ljava/lang/Throwable;", null, label44, label10, 6); - methodVisitor.visitLocalVariable( - "buffer", "Ljava/nio/ByteBuffer;", null, label25, label27, 8); - methodVisitor.visitLocalVariable( - "buffer", "Ljava/nio/ByteBuffer;", null, label26, label4, 8); - methodVisitor.visitLocalVariable("e$iv", "Ljava/lang/Throwable;", null, label43, label7, 9); - methodVisitor.visitLocalVariable( - "$i$a$-consume-JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1$1", - "I", - null, - label22, - label13, - 7); - methodVisitor.visitLocalVariable("$i$f$consume", "I", null, label19, label13, 5); - methodVisitor.visitLocalVariable( - "this", - "Lio/ktor/client/engine/java/JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1;", - null, - label16, - label15, - 0); - methodVisitor.visitLocalVariable( - "$result", "Ljava/lang/Object;", null, label16, label15, 1); - methodVisitor.visitLocalVariable( - "$i$a$-consume-JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1$1", - "I", - null, - label33, - label14, - 7); - methodVisitor.visitLocalVariable("$i$f$consume", "I", null, label32, label14, 5); - methodVisitor.visitLocalVariable( - "$i$a$-consume-JavaHttpResponseBodyHandler$JavaHttpResponseBodySubscriber$1$1", - "I", - null, - label38, - label40, - 7); - methodVisitor.visitLocalVariable("$i$f$consume", "I", null, label37, label10, 5); - methodVisitor.visitMaxs(5, 11); - methodVisitor.visitEnd(); - } - { - methodVisitor = - classWriter.visitMethod( - ACC_PUBLIC | ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null); - methodVisitor.visitCode(); - Label label0 = new Label(); - methodVisitor.visitLabel(label0); - methodVisitor.visitLineNumber(70, label0); - methodVisitor.visitTypeInsn( - NEW, "com/android/tools/r8/cf/CfDebugLocalStackMapVerificationTest$Main"); - methodVisitor.visitInsn(DUP); - methodVisitor.visitMethodInsn( - INVOKESPECIAL, - "com/android/tools/r8/cf/CfDebugLocalStackMapVerificationTest$Main", - "<init>", - "()V", - false); - methodVisitor.visitInsn(ACONST_NULL); - methodVisitor.visitMethodInsn( - INVOKEVIRTUAL, - "com/android/tools/r8/cf/CfDebugLocalStackMapVerificationTest$Main", - "invokeSuspend", - "(Ljava/lang/Object;)Ljava/lang/Object;", - false); - methodVisitor.visitInsn(POP); - Label label1 = new Label(); - methodVisitor.visitLabel(label1); - methodVisitor.visitLineNumber(71, label1); - methodVisitor.visitInsn(RETURN); - Label label2 = new Label(); - methodVisitor.visitLabel(label2); - methodVisitor.visitLocalVariable("args", "[Ljava/lang/String;", null, label0, label2, 0); - methodVisitor.visitMaxs(2, 1); - methodVisitor.visitEnd(); - } - classWriter.visitEnd(); - - return classWriter.toByteArray(); - } + testForR8(parameters.getBackend()) + .debug() + .addProgramClasses(SmallRepro.class) + .addKeepAllAttributes() + .addDontShrink() + .addDontObfuscate() + .addDontOptimize() + .addOptionsModification( + options -> { + options.testing.neverReuseCfLocalRegisters = true; + // TODO(b/237567012): Remove option when resolved. + options.enableCheckAllInstructionsDuringStackMapVerification = true; + }) + .run(parameters.getRuntime(), SmallRepro.class) + .assertSuccessWithOutputThatMatches(containsString("FOO")); } }
diff --git a/src/test/java/com/android/tools/r8/cf/CloserTestRunner.java b/src/test/java/com/android/tools/r8/cf/CloserTestRunner.java index bce6ae0..dea6642 100644 --- a/src/test/java/com/android/tools/r8/cf/CloserTestRunner.java +++ b/src/test/java/com/android/tools/r8/cf/CloserTestRunner.java
@@ -44,7 +44,7 @@ .addProgramClasses(CloserTest.class) .addKeepMainRule(CloserTest.class) .setMode(CompilationMode.RELEASE) - .noMinification() + .addDontObfuscate() .noTreeShaking() .enableInliningAnnotations() .compile()
diff --git a/src/test/java/com/android/tools/r8/cf/DebugInfoTestRunner.java b/src/test/java/com/android/tools/r8/cf/DebugInfoTestRunner.java index 75a8b55..0d62e66 100644 --- a/src/test/java/com/android/tools/r8/cf/DebugInfoTestRunner.java +++ b/src/test/java/com/android/tools/r8/cf/DebugInfoTestRunner.java
@@ -53,7 +53,7 @@ return testForR8(backend) .debug() .noTreeShaking() - .noMinification() + .addDontObfuscate() .addOptionsModification(o -> o.invalidDebugInfoFatal = true); } }
diff --git a/src/test/java/com/android/tools/r8/cf/GetClassLdcClassTest.java b/src/test/java/com/android/tools/r8/cf/GetClassLdcClassTest.java index c5284c0..07d16af 100644 --- a/src/test/java/com/android/tools/r8/cf/GetClassLdcClassTest.java +++ b/src/test/java/com/android/tools/r8/cf/GetClassLdcClassTest.java
@@ -65,7 +65,7 @@ .addKeepMainRule(TestClass.class) // We cannot keep class Runner, as that prohibits getClass optimization. // Instead disable minification and inlining of the Runner class and method. - .noMinification() + .addDontObfuscate() .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .run(parameters.getRuntime(), TestClass.class) @@ -90,7 +90,7 @@ .addKeepMainRule(TestClass.class) // We cannot keep class Runner, as that prohibits getClass optimization. // Instead disable minification and inlining of the Runner class and method. - .noMinification() + .addDontObfuscate() .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .run(parameters.getRuntime(), TestClass.class);
diff --git a/src/test/java/com/android/tools/r8/cf/KeepDeserializeLambdaMethodTestRunner.java b/src/test/java/com/android/tools/r8/cf/KeepDeserializeLambdaMethodTestRunner.java index 7b52abd..0bdb4f8 100644 --- a/src/test/java/com/android/tools/r8/cf/KeepDeserializeLambdaMethodTestRunner.java +++ b/src/test/java/com/android/tools/r8/cf/KeepDeserializeLambdaMethodTestRunner.java
@@ -91,9 +91,7 @@ // TODO(b/148836254): Support deserialized lambdas without the need of additional rules. "-keep class * { private static synthetic void lambda$*(); }"); } else { - builder - .noMinification() - .noTreeShaking(); + builder.addDontObfuscate().noTreeShaking(); } builder .run(parameters.getRuntime(), getMainClass())
diff --git a/src/test/java/com/android/tools/r8/cf/PrintSeedsWithDeserializeLambdaMethodTest.java b/src/test/java/com/android/tools/r8/cf/PrintSeedsWithDeserializeLambdaMethodTest.java index 33b13a9..255e2be 100644 --- a/src/test/java/com/android/tools/r8/cf/PrintSeedsWithDeserializeLambdaMethodTest.java +++ b/src/test/java/com/android/tools/r8/cf/PrintSeedsWithDeserializeLambdaMethodTest.java
@@ -58,7 +58,7 @@ options -> options.getOpenClosedInterfacesOptions().suppressAllOpenInterfaces()) .addPrintSeeds() .allowStdoutMessages() - .noMinification() + .addDontObfuscate() .noTreeShaking() .run(parameters.getRuntime(), getMainClass()) .assertSuccessWithOutput(EXPECTED)
diff --git a/src/test/java/com/android/tools/r8/cf/TryRangeTestRunner.java b/src/test/java/com/android/tools/r8/cf/TryRangeTestRunner.java index 8f5dc82..7c9d4ac 100644 --- a/src/test/java/com/android/tools/r8/cf/TryRangeTestRunner.java +++ b/src/test/java/com/android/tools/r8/cf/TryRangeTestRunner.java
@@ -39,7 +39,7 @@ .addProgramClasses(TryRangeTest.class) .addKeepMainRule(TryRangeTest.class) .setMode(CompilationMode.RELEASE) - .noMinification() + .addDontObfuscate() .noTreeShaking() .enableInliningAnnotations() .addOptionsModification(o -> o.enableLoadStoreOptimization = false) @@ -54,7 +54,7 @@ .addProgramClasses(TryRangeTestLimitRange.class) .addKeepMainRule(TryRangeTestLimitRange.class) .setMode(CompilationMode.RELEASE) - .noMinification() + .addDontObfuscate() .noTreeShaking() .enableInliningAnnotations() .addOptionsModification(
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingWithStartupClassesTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingWithStartupClassesTest.java index 30b9700..417a097 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingWithStartupClassesTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingWithStartupClassesTest.java
@@ -5,10 +5,11 @@ package com.android.tools.r8.classmerging.horizontal; import com.android.tools.r8.NeverInline; +import com.android.tools.r8.StartupProfileProvider; import com.android.tools.r8.TestBase; import com.android.tools.r8.TestParameters; import com.android.tools.r8.experimental.startup.StartupClass; -import com.android.tools.r8.experimental.startup.StartupConfiguration; +import com.android.tools.r8.experimental.startup.StartupProfile; import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.utils.BooleanUtils; import com.google.common.collect.ImmutableList; @@ -49,21 +50,21 @@ .addOptionsModification( options -> { DexItemFactory dexItemFactory = options.dexItemFactory(); - options - .getStartupOptions() - .setStartupConfiguration( - StartupConfiguration.builder() - .apply( - builder -> - getStartupClasses() - .forEach( - startupClass -> - builder.addStartupClass( - StartupClass.dexBuilder() - .setClassReference( - toDexType(startupClass, dexItemFactory)) - .build()))) - .build()); + StartupProfile startupProfile = + StartupProfile.builder() + .apply( + builder -> + getStartupClasses() + .forEach( + startupClass -> + builder.addStartupClass( + StartupClass.dexBuilder() + .setClassReference( + toDexType(startupClass, dexItemFactory)) + .build()))) + .build(); + StartupProfileProvider startupProfileProvider = startupProfile::serializeToString; + options.getStartupOptions().setStartupProfileProvider(startupProfileProvider); }) .addHorizontallyMergedClassesInspector( inspector ->
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassMemberReferenceTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassMemberReferenceTest.java index 41694f6..db6cc21 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassMemberReferenceTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassMemberReferenceTest.java
@@ -26,7 +26,7 @@ return testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .noMinification() + .addDontObfuscate() .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel());
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceCollisionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceCollisionTest.java index fb7e05e..07f3fce 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceCollisionTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceCollisionTest.java
@@ -31,7 +31,7 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .noMinification() + .addDontObfuscate() .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .enableNoVerticalClassMergingAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceFixedCollisionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceFixedCollisionTest.java index 4dfb6df..43bbf33 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceFixedCollisionTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceFixedCollisionTest.java
@@ -31,7 +31,7 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .noMinification() + .addDontObfuscate() .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .enableNoVerticalClassMergingAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceImplementedByParentTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceImplementedByParentTest.java index 65b57aa..5904824 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceImplementedByParentTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceImplementedByParentTest.java
@@ -31,7 +31,7 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .noMinification() + .addDontObfuscate() .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .enableNoVerticalClassMergingAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerSubClassCollisionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerSubClassCollisionTest.java index 5e8b88d..b00bc63 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerSubClassCollisionTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerSubClassCollisionTest.java
@@ -26,7 +26,7 @@ testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .noMinification() + .addDontObfuscate() .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .enableNoVerticalClassMergingAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontalstatic/InliningAfterStaticClassMergerTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontalstatic/InliningAfterStaticClassMergerTest.java index 75e26f1..18017a1 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontalstatic/InliningAfterStaticClassMergerTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontalstatic/InliningAfterStaticClassMergerTest.java
@@ -86,7 +86,7 @@ .addOptionsModification( options -> options.libraryInterfacesMayHaveStaticInitialization = true) .enableMemberValuePropagationAnnotations() - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), TestClass.class) .assertSuccessWithOutput(expected)
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontalstatic/StaticClassMergerVisibilityTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontalstatic/StaticClassMergerVisibilityTest.java index 189ac21..7555576 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontalstatic/StaticClassMergerVisibilityTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontalstatic/StaticClassMergerVisibilityTest.java
@@ -46,7 +46,7 @@ .assertMergedInto(C.class, D.class)) .enableInliningAnnotations() .setMinApi(parameters.getApiLevel()) - .noMinification() + .addDontObfuscate() .run(parameters.getRuntime(), Main.class) .assertSuccessWithOutputLines("A.print()", "B.print()", "C.print()", "D.print()") .inspect(
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/B141942381.java b/src/test/java/com/android/tools/r8/classmerging/vertical/B141942381.java index d840b52..5ab767d 100644 --- a/src/test/java/com/android/tools/r8/classmerging/vertical/B141942381.java +++ b/src/test/java/com/android/tools/r8/classmerging/vertical/B141942381.java
@@ -52,7 +52,7 @@ .setMinApi(parameters.getApiLevel()) .addKeepAttributes("Signatures") .enableNeverClassInliningAnnotations() - .noMinification() + .addDontObfuscate() .compile() .inspect(this::inspect) .run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/IncorrectRewritingOfInvokeSuperTest.java b/src/test/java/com/android/tools/r8/classmerging/vertical/IncorrectRewritingOfInvokeSuperTest.java index 505aa07..2ecdb10 100644 --- a/src/test/java/com/android/tools/r8/classmerging/vertical/IncorrectRewritingOfInvokeSuperTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/vertical/IncorrectRewritingOfInvokeSuperTest.java
@@ -35,7 +35,7 @@ .addKeepMainRule(TestClass.class) .addOptionsModification(options -> options.enableUnusedInterfaceRemoval = false) .enableInliningAnnotations() - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getRuntime()) .run(parameters.getRuntime(), TestClass.class) .assertSuccess();
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerTest.java b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerTest.java index cbbb43e..ae53238 100644 --- a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerTest.java
@@ -101,7 +101,7 @@ .addProgramFiles(EXAMPLE_JAR) .addKeepRuleFiles(proguardConfig) .enableProguardTestOptions() - .noMinification() + .addDontObfuscate() .addOptionsModification(optionsConsumer) .setMinApi(parameters.getApiLevel()) .compile() @@ -1183,7 +1183,7 @@ appBuilder.addProgramResourceProvider(provider); } }) - .noMinification() + .addDontObfuscate() .enableProguardTestOptions() .setMinApi(parameters.getApiLevel()) .compile();
diff --git a/src/test/java/com/android/tools/r8/compatproguard/CompatKeepClassMemberNamesTestRunner.java b/src/test/java/com/android/tools/r8/compatproguard/CompatKeepClassMemberNamesTestRunner.java index 68e882e..dba64d3 100644 --- a/src/test/java/com/android/tools/r8/compatproguard/CompatKeepClassMemberNamesTestRunner.java +++ b/src/test/java/com/android/tools/r8/compatproguard/CompatKeepClassMemberNamesTestRunner.java
@@ -114,7 +114,7 @@ .addProgramClasses(CLASSES) .addKeepMainRule(MAIN_CLASS) .addInliningAnnotations() - .noMinification() + .addDontObfuscate() .compile()); } @@ -143,7 +143,7 @@ RR extends TestRunResult<RR>, T extends TestShrinkerBuilder<C, B, CR, RR, T>> T buildWithMembersRule(TestShrinkerBuilder<C, B, CR, RR, T> builder) { - return buildWithMembersRuleEnableMinification(builder).noMinification(); + return buildWithMembersRuleEnableMinification(builder).addDontObfuscate(); } private <CR extends TestCompileResult<CR, RR>, RR extends TestRunResult<RR>> @@ -211,7 +211,7 @@ .addKeepMainRule(MAIN_CLASS) .addKeepRules("-keepclassmembers " + KEEP_RULE_NON_STATIC) .addInliningAnnotations() - .noMinification(); + .addDontObfuscate(); } @Test @@ -315,7 +315,7 @@ .addProgramClasses(CLASSES) .addKeepMainRule(MAIN_CLASS) .addInliningAnnotations() - .noMinification() + .addDontObfuscate() .addKeepRules("-keepclassmembers class " + Bar.class.getTypeName()) .compile()); } @@ -344,7 +344,7 @@ RR extends TestRunResult<RR>, T extends TestShrinkerBuilder<C, B, CR, RR, T>> T buildWithMemberNamesRule(TestShrinkerBuilder<C, B, CR, RR, T> builder) { - return buildWithMemberNamesRuleEnableMinification(builder).noMinification(); + return buildWithMemberNamesRuleEnableMinification(builder).addDontObfuscate(); } private <CR extends TestCompileResult<CR, RR>, RR extends TestRunResult<RR>>
diff --git a/src/test/java/com/android/tools/r8/compatproguard/ForNameTest.java b/src/test/java/com/android/tools/r8/compatproguard/ForNameTest.java index a5a9f0a1..97cb7c9 100644 --- a/src/test/java/com/android/tools/r8/compatproguard/ForNameTest.java +++ b/src/test/java/com/android/tools/r8/compatproguard/ForNameTest.java
@@ -78,7 +78,7 @@ // Add main dex rule to disable Class.forName() optimization. .addMainDexRules("-keep class " + CLASS_NAME) .addDontOptimize() - .noMinification() + .addDontObfuscate() .noTreeShaking() .setMinApi(AndroidApiLevel.B));
diff --git a/src/test/java/com/android/tools/r8/debug/KotlinStdLibCompilationTest.java b/src/test/java/com/android/tools/r8/debug/KotlinStdLibCompilationTest.java index 2c3a478..0f0a782 100644 --- a/src/test/java/com/android/tools/r8/debug/KotlinStdLibCompilationTest.java +++ b/src/test/java/com/android/tools/r8/debug/KotlinStdLibCompilationTest.java
@@ -57,7 +57,7 @@ .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.LATEST)) .addKeepAllAttributes() .allowDiagnosticWarningMessages() - .noMinification() + .addDontObfuscate() .noTreeShaking() .setMode(CompilationMode.DEBUG) .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/debug/LambdaOuterContextTestRunner.java b/src/test/java/com/android/tools/r8/debug/LambdaOuterContextTestRunner.java index 99a19f5..0e77b85 100644 --- a/src/test/java/com/android/tools/r8/debug/LambdaOuterContextTestRunner.java +++ b/src/test/java/com/android/tools/r8/debug/LambdaOuterContextTestRunner.java
@@ -11,7 +11,6 @@ import com.android.tools.r8.debug.LambdaOuterContextTest.Converter; import com.android.tools.r8.utils.StringUtils; import org.apache.harmony.jpda.tests.framework.jdwp.Value; -import org.junit.Ignore; import org.junit.Test; public class LambdaOuterContextTestRunner extends DebugTestBase { @@ -40,7 +39,7 @@ testForR8(Backend.CF) .addProgramClassesAndInnerClasses(CLASS) .debug() - .noMinification() + .addDontObfuscate() .noTreeShaking() .compile(); compileResult.run(CLASS).assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/debug/LineNumberOptimizationTest.java b/src/test/java/com/android/tools/r8/debug/LineNumberOptimizationTest.java index af193de..c161a96 100644 --- a/src/test/java/com/android/tools/r8/debug/LineNumberOptimizationTest.java +++ b/src/test/java/com/android/tools/r8/debug/LineNumberOptimizationTest.java
@@ -52,7 +52,7 @@ .setMinApi(parameters.getApiLevel()) .setMode(dontOptimizeByEnablingDebug ? CompilationMode.DEBUG : CompilationMode.RELEASE) .noTreeShaking() - .noMinification() + .addDontObfuscate() .addKeepAttributeSourceFile() .addKeepAttributeLineNumberTable() .addOptionsModification(
diff --git a/src/test/java/com/android/tools/r8/debug/LoadInvokeLoadOptimizationTestRunner.java b/src/test/java/com/android/tools/r8/debug/LoadInvokeLoadOptimizationTestRunner.java index 9242d61..e382d39 100644 --- a/src/test/java/com/android/tools/r8/debug/LoadInvokeLoadOptimizationTestRunner.java +++ b/src/test/java/com/android/tools/r8/debug/LoadInvokeLoadOptimizationTestRunner.java
@@ -40,7 +40,7 @@ temp -> testForR8(temp, backend) .noTreeShaking() - .noMinification() + .addDontObfuscate() .addKeepRules("-keepattributes SourceFile,LineNumberTable") .addProgramClasses(CLASS) .setMinApi(minApi)
diff --git a/src/test/java/com/android/tools/r8/debuginfo/KotlinDebugInfoTestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/KotlinDebugInfoTestRunner.java index 80a51c8..cb0ee5c 100644 --- a/src/test/java/com/android/tools/r8/debuginfo/KotlinDebugInfoTestRunner.java +++ b/src/test/java/com/android/tools/r8/debuginfo/KotlinDebugInfoTestRunner.java
@@ -85,7 +85,7 @@ .addOptionsModification(options -> options.invalidDebugInfoFatal = true) .apply(configuration) .debug() - .noMinification() + .addDontObfuscate() .noTreeShaking() .compile() .run(parameters.getRuntime(), className)
diff --git a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTestRunner.java b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTestRunner.java index c04e3eb..0136d59 100644 --- a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTestRunner.java +++ b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTestRunner.java
@@ -57,12 +57,13 @@ @Test public void testR8Cf() throws Throwable { - R8TestCompileResult compileResult = testForR8(Backend.CF) - .addProgramClassesAndInnerClasses(CLASS) - .noMinification() - .noTreeShaking() - .debug() - .compile(); + R8TestCompileResult compileResult = + testForR8(Backend.CF) + .addProgramClassesAndInnerClasses(CLASS) + .addDontObfuscate() + .noTreeShaking() + .debug() + .compile(); compileResult // TODO(b/123506120): Add .assertNoMessages() .run(CLASS)
diff --git a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithSelfReferenceTestRunner.java b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithSelfReferenceTestRunner.java index 409d776..499527f 100644 --- a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithSelfReferenceTestRunner.java +++ b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithSelfReferenceTestRunner.java
@@ -103,7 +103,7 @@ testForR8(parameters.getBackend()) .addProgramClassesAndInnerClasses(CLASS) .setMinApi(parameters.getApiLevel()) - .noMinification() + .addDontObfuscate() .noTreeShaking() .addKeepAllAttributes() .debug()
diff --git a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithUnderscoreThisTestRunner.java b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithUnderscoreThisTestRunner.java index 9860a15..263a87e 100644 --- a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithUnderscoreThisTestRunner.java +++ b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithUnderscoreThisTestRunner.java
@@ -114,7 +114,7 @@ testForR8(parameters.getBackend()) .addProgramClassesAndInnerClasses(CLASS) .addKeepAllClassesRule() - .noMinification() + .addDontObfuscate() .setMode(CompilationMode.DEBUG) .addOptionsModification( internalOptions -> {
diff --git a/src/test/java/com/android/tools/r8/desugar/DesugarLambdaContextDuplicateInLibraryTest.java b/src/test/java/com/android/tools/r8/desugar/DesugarLambdaContextDuplicateInLibraryTest.java index 98839fa..c712d37 100644 --- a/src/test/java/com/android/tools/r8/desugar/DesugarLambdaContextDuplicateInLibraryTest.java +++ b/src/test/java/com/android/tools/r8/desugar/DesugarLambdaContextDuplicateInLibraryTest.java
@@ -48,7 +48,7 @@ @Test public void testOnlyProgram() throws Exception { testForR8(parameters.getBackend()) - .noMinification() + .addDontObfuscate() .addProgramClasses(PROGRAM) .addProgramClasses(LIBRARY) .addKeepMainRule(MAIN) @@ -73,7 +73,7 @@ @Test public void testDuplicate() throws Exception { testForR8(parameters.getBackend()) - .noMinification() // Don't minify so the name collision will happen. + .addDontObfuscate() // Don't minify so the name collision will happen. .addProgramClasses(PROGRAM) .addProgramClasses(LIBRARY) .addLibraryClasses(LIBRARY)
diff --git a/src/test/java/com/android/tools/r8/desugar/DesugaredLambdaImplementationInliningTest.java b/src/test/java/com/android/tools/r8/desugar/DesugaredLambdaImplementationInliningTest.java index cb1b96e..6a0f410 100644 --- a/src/test/java/com/android/tools/r8/desugar/DesugaredLambdaImplementationInliningTest.java +++ b/src/test/java/com/android/tools/r8/desugar/DesugaredLambdaImplementationInliningTest.java
@@ -45,7 +45,7 @@ testForR8Compat(parameters.getBackend()) .addProgramClasses(TestClass.class) .addKeepMainRule(TestClass.class) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), TestClass.class) .assertSuccessWithOutput(EXPECTED)
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/BackportMainDexTest.java b/src/test/java/com/android/tools/r8/desugar/backports/BackportMainDexTest.java index 81f0674..a3bec4a 100644 --- a/src/test/java/com/android/tools/r8/desugar/backports/BackportMainDexTest.java +++ b/src/test/java/com/android/tools/r8/desugar/backports/BackportMainDexTest.java
@@ -238,7 +238,7 @@ MainDexConsumer mainDexConsumer = parameters.isDexRuntime() ? new MainDexConsumer() : null; testForR8(parameters.getBackend()) .debug() // Use debug mode to force a minimal main dex. - .noMinification() // Disable minification so we can inspect the synthetic names. + .addDontObfuscate() // Disable minification so we can inspect the synthetic names. .applyIf(mainDexConsumer != null, b -> b.setProgramConsumer(mainDexConsumer)) .addProgramClasses(CLASSES) .addKeepMainRule(TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/TestBackportedNotPresentInAndroidJar.java b/src/test/java/com/android/tools/r8/desugar/backports/TestBackportedNotPresentInAndroidJar.java index 195dfd2..1ca4309 100644 --- a/src/test/java/com/android/tools/r8/desugar/backports/TestBackportedNotPresentInAndroidJar.java +++ b/src/test/java/com/android/tools/r8/desugar/backports/TestBackportedNotPresentInAndroidJar.java
@@ -79,6 +79,9 @@ @Test public void testBackportedMethodsPerAPILevel() throws Exception { for (AndroidApiLevel apiLevel : AndroidApiLevel.values()) { + if (apiLevel == AndroidApiLevel.MASTER) { + continue; + } if (apiLevel == AndroidApiLevel.T) { continue; }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ConcurrentHashMapSubclassV2Test.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ConcurrentHashMapSubclassV2Test.java index 20f26fc..102902a 100644 --- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ConcurrentHashMapSubclassV2Test.java +++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ConcurrentHashMapSubclassV2Test.java
@@ -12,8 +12,8 @@ import com.android.tools.r8.TestParameters; import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification; import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification; +import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.StringUtils; -import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import org.junit.Assume; @@ -52,34 +52,39 @@ this.compilationMode = compilationMode; } + private boolean isDefinedOnBootClasspath() { + return parameters + .getRuntime() + .asDex() + .getMinApiLevel() + .isGreaterThanOrEqualTo(AndroidApiLevel.N); + } + @Test - public void test() throws Exception { - Assume.assumeFalse( - "b/237701688", compilationMode.isDebug() && compilationSpecification == R8_L8SHRINK); + public void test() throws Throwable { + Assume.assumeTrue("b/237701688", compilationSpecification == R8_L8SHRINK); testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification) .addInnerClasses(getClass()) - .setMode(compilationMode) .addKeepMainRule(Executor.class) + .setMode(compilationMode) + .addOptionsModification( + options -> { + // Devirtualizing is correcting the invalid member-rebinding. + if (compilationMode.isRelease()) { + options.enableDevirtualization = false; + } + }) .run(parameters.getRuntime(), Executor.class) .assertSuccessWithOutput(EXPECTED_RESULT); } - @SuppressWarnings("unchecked") static class Executor { public static void main(String[] args) { - StringListConcurrentHashMap<String> map = new StringListConcurrentHashMap<>(); - map.putKeyAndArray("foo"); + StringListConcurrentHashMap map = new StringListConcurrentHashMap(); + map.putIfAbsent("foo", "bar"); System.out.println(map.keys().nextElement()); } } - static class StringListConcurrentHashMap<K> extends ConcurrentHashMap<K, List<String>> { - StringListConcurrentHashMap() { - super(); - } - - void putKeyAndArray(K key) { - this.putIfAbsent(key, new ArrayList<>()); - } - } + static class StringListConcurrentHashMap extends ConcurrentHashMap<String, String> {} }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LegacyDesugaredLibraryConfigurationParsingTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LegacyDesugaredLibraryConfigurationParsingTest.java index 8d06a2f..c08abd3 100644 --- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LegacyDesugaredLibraryConfigurationParsingTest.java +++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LegacyDesugaredLibraryConfigurationParsingTest.java
@@ -5,6 +5,7 @@ import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage; import static com.android.tools.r8.DiagnosticsMatcher.diagnosticOrigin; +import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType; import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.RELEASED_1_1_5; import static org.hamcrest.CoreMatchers.allOf; import static org.hamcrest.CoreMatchers.containsString; @@ -17,6 +18,7 @@ import com.android.tools.r8.TestDiagnosticMessagesImpl; import com.android.tools.r8.TestParameters; import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification; +import com.android.tools.r8.errors.UnsupportedDesugaredLibraryConfigurationVersionDiagnostic; import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification; @@ -190,7 +192,14 @@ diagnostics -> diagnostics.assertErrorsMatch( allOf( + diagnosticType(UnsupportedDesugaredLibraryConfigurationVersionDiagnostic.class), diagnosticMessage(containsString("upgrade the D8/R8 compiler")), + diagnosticMessage( + containsString( + "https://developer.android.com/studio/build/library-desugaring-versions")), + diagnosticMessage( + containsString( + "https://developer.android.com/studio/build/library-desugaring")), diagnosticOrigin(origin)))); }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LocalDateEpochTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LocalDateEpochTest.java index 3d1a75b..a1a428b 100644 --- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LocalDateEpochTest.java +++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LocalDateEpochTest.java
@@ -89,7 +89,7 @@ DexField src = options.dexItemFactory().createField(date, date, epoch); HumanRewritingFlags rewritingFlags = HumanRewritingFlags.builder(options.reporter, Origin.unknown()) - .retargetStaticField(src, desugarDate) + .retargetStaticField(src, src.withHolder(desugarDate, options.dexItemFactory())) .amendLibraryField( src, FieldAccessFlags.fromSharedAccessFlags(
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/WrapperEqualityTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/WrapperEqualityTest.java index 77b7738..2956c19 100644 --- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/WrapperEqualityTest.java +++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/WrapperEqualityTest.java
@@ -177,6 +177,7 @@ appConsumer = consumer; } + @SuppressWarnings("unchecked") public static void setSupplier(Supplier supplier) { appSupplier = supplier; }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/StandardCharsetTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/StandardCharsetTest.java index eb887cc..181cd69 100644 --- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/StandardCharsetTest.java +++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/StandardCharsetTest.java
@@ -17,7 +17,10 @@ import java.io.IOException; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.Collection; +import java.util.Collections; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; @@ -33,7 +36,7 @@ private final CompilationSpecification compilationSpecification; private static final String EXPECTED_RESULT = - StringUtils.lines("%E3%81%8B", "%82%A0%82%A9%97%43%24%E3%81%8B", "true"); + StringUtils.lines("%E3%81%8B", "%82%A0%82%A9%97%43%24%E3%81%8B", "true", "true", "written"); @Parameters(name = "{0}, spec: {1}, {2}") public static List<Object[]> data() { @@ -53,11 +56,11 @@ } @Test - public void test() throws Exception { + public void test() throws Throwable { testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification) .addProgramClassFileData(getProgramClassFileData()) .addKeepMainRule(TestClass.class) - .run(parameters.getRuntime(), TestClass.class) + .run(parameters.getRuntime(), TestClass.class, temp.newFile().toString()) .assertSuccessWithOutput(EXPECTED_RESULT); } @@ -95,6 +98,17 @@ + encode("$", "Shift_JIS") + encode("か", StandardCharsets.UTF_8)); System.out.println(Character.isBmpCodePoint('か')); + + System.out.println(Charset.defaultCharset() == StandardCharsets.UTF_8); + + // The following Files methods internally uses UTF_8 references. + String path = args[0]; + try { + Files.write(Paths.get(path), Collections.singleton("written")); + System.out.println(Files.readAllLines(Paths.get(path)).get(0)); + } catch (IOException e) { + System.out.println("IOException"); + } } // Replaced in the transformer by JDK 11 URLEncoder#encode.
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/legacy/L8TestWithLegacySpecification.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/legacy/L8TestWithLegacySpecification.java index 3a6fd81..c0e4cf6 100644 --- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/legacy/L8TestWithLegacySpecification.java +++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/legacy/L8TestWithLegacySpecification.java
@@ -47,6 +47,7 @@ .sorted() .filter(apiLevel -> apiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.L)) .filter(apiLevel -> apiLevel.isLessThan(AndroidApiLevel.ANDROID_PLATFORM)) + .filter(apiLevel -> apiLevel != AndroidApiLevel.MASTER) .collect(Collectors.toList()), CompilationMode.values(), ImmutableList.of(
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/r8ondex/HelloWorldCompiledOnArtTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/r8ondex/HelloWorldCompiledOnArtTest.java index dd5acbd..b7a1a0b 100644 --- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/r8ondex/HelloWorldCompiledOnArtTest.java +++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/r8ondex/HelloWorldCompiledOnArtTest.java
@@ -9,12 +9,10 @@ import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION; import static junit.framework.TestCase.assertEquals; import static junit.framework.TestCase.assertTrue; -import static org.junit.Assume.assumeTrue; import com.android.tools.r8.D8; import com.android.tools.r8.R8; import com.android.tools.r8.TestParameters; -import com.android.tools.r8.TestRuntime; import com.android.tools.r8.ToolHelper; import com.android.tools.r8.ToolHelper.DexVm.Version; import com.android.tools.r8.ToolHelper.ProcessResult; @@ -29,7 +27,6 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; -import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -38,25 +35,6 @@ @RunWith(Parameterized.class) public class HelloWorldCompiledOnArtTest extends DesugaredLibraryTestBase { - // TODO(b/142621961): Create an abstraction to easily run tests on External DexR8. - // Manage pathMock in the abstraction. - private static Path pathMock; - - @BeforeClass - public static void compilePathBackport() throws Exception { - assumeTrue("JDK8 is not checked-in on Windows", !ToolHelper.isWindows()); - pathMock = getStaticTemp().newFolder("PathMock").toPath(); - javac(TestRuntime.getCheckedInJdk8(), getStaticTemp()) - .setOutputPath(pathMock) - .addSourceFiles( - getAllFilesWithSuffixInDirectory(Paths.get("src/test/r8OnArtBackport"), "java")) - .compile(); - } - - public static Path[] getPathBackport() throws Exception { - return getAllFilesWithSuffixInDirectory(pathMock, "class"); - } - private final TestParameters parameters; private final CompilationSpecification compilationSpecification; private final LibraryDesugaringSpecification libraryDesugaringSpecification; @@ -65,7 +43,7 @@ public static List<Object[]> data() { return buildParameters( getTestParameters() - .withDexRuntimesStartingFromIncluding(Version.V7_0_0) + .withDexRuntimesStartingFromIncluding(Version.V5_1_1) .withApiLevelsStartingAtIncluding(AndroidApiLevel.L) .build(), ImmutableList.of(JDK11_PATH), @@ -132,14 +110,11 @@ } private DesugaredLibraryTestCompileResult<?> compileR8ToDexWithD8() throws Exception { - Path[] pathBackport = getPathBackport(); + assert parameters.getApiLevel().getLevel() >= AndroidApiLevel.O.getLevel() + || libraryDesugaringSpecification.hasNioFileDesugaring(parameters); return testForDesugaredLibrary( parameters, libraryDesugaringSpecification, compilationSpecification) .addProgramFiles(ToolHelper.R8_WITH_RELOCATED_DEPS_JAR) - .applyIf( - parameters.getApiLevel().getLevel() < AndroidApiLevel.O.getLevel() - && !libraryDesugaringSpecification.hasNioFileDesugaring(parameters), - b -> b.addProgramFiles(pathBackport)) .addOptionsModification( options -> { options.testing.enableD8ResourcesPassThrough = true;
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/r8ondex/R8CompiledThroughDexTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/r8ondex/R8CompiledThroughDexTest.java index af9ac89..44eb8fa 100644 --- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/r8ondex/R8CompiledThroughDexTest.java +++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/r8ondex/R8CompiledThroughDexTest.java
@@ -4,6 +4,8 @@ package com.android.tools.r8.desugar.desugaredlibrary.r8ondex; +import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG; +import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11_PATH; import static junit.framework.TestCase.assertEquals; import static org.junit.Assert.assertTrue; @@ -13,14 +15,16 @@ import com.android.tools.r8.R8; import com.android.tools.r8.R8Command; import com.android.tools.r8.R8Command.Builder; +import com.android.tools.r8.StringResource; import com.android.tools.r8.TestBase; import com.android.tools.r8.TestParameters; -import com.android.tools.r8.TestParametersCollection; import com.android.tools.r8.TestRuntime; import com.android.tools.r8.ToolHelper; import com.android.tools.r8.ToolHelper.DexVm.Version; import com.android.tools.r8.ToolHelper.ProcessResult; import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase; +import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification; +import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification; import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.DeterminismChecker; import com.android.tools.r8.utils.Pair; @@ -38,25 +42,34 @@ import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; -// TODO(b/142621961): Parametrize at least L and P instead of just P. @RunWith(Parameterized.class) public class R8CompiledThroughDexTest extends DesugaredLibraryTestBase { - private static final boolean minify = false; - private final TestParameters parameters; + private final CompilationSpecification compilationSpecification; + private final LibraryDesugaringSpecification libraryDesugaringSpecification; - @Parameters(name = "{0}") - public static TestParametersCollection data() { + @Parameters(name = "{0}, spec: {1}, {2}") + public static List<Object[]> data() { // We only run this test with ART 8 and with full desugaring to avoid the large runtime on ART. - return getTestParameters() - .withDexRuntime(Version.V8_1_0) - .withApiLevel(AndroidApiLevel.B) - .build(); + return buildParameters( + getTestParameters() + // Android 5 and 6 do not seem to work with more than 512 Mb of RAM. + .withDexRuntime(Version.V8_1_0) + // TODO(b/241748003): Broken strictly below 19 due to charset issue. + .withApiLevel(AndroidApiLevel.N) + .build(), + ImmutableList.of(JDK11_PATH), + ImmutableList.of(D8_L8DEBUG)); } - public R8CompiledThroughDexTest(TestParameters parameters) { + public R8CompiledThroughDexTest( + TestParameters parameters, + LibraryDesugaringSpecification libraryDesugaringSpecification, + CompilationSpecification compilationSpecification) { this.parameters = parameters; + this.compilationSpecification = compilationSpecification; + this.libraryDesugaringSpecification = libraryDesugaringSpecification; } private static String commandLinePathFor(String string) { @@ -84,13 +97,21 @@ arguments.add("--min-api").add(Integer.toString(parameters.getApiLevel().getLevel())); buildup.add(b -> b.setMinApiLevel(parameters.getApiLevel().getLevel())); - arguments.add("--lib").add(commandLinePathFor(ToolHelper.JAVA_8_RUNTIME)); - buildup.add(b -> b.addLibraryFiles(ToolHelper.getJava8RuntimeJar())); + arguments.add("--lib").add(commandLinePathFor(ToolHelper.getAndroidJar(AndroidApiLevel.R))); + buildup.add(b -> b.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.R))); arguments.add("--pg-conf").add(commandLinePathFor(R8_KEEP)); buildup.add(b -> b.addProguardConfigurationFiles(Paths.get(R8_KEEP))); - if (!minify) { + arguments + .add("--desugared-lib") + .add(commandLinePathFor(libraryDesugaringSpecification.getSpecification())); + buildup.add( + b -> + b.addDesugaredLibraryConfiguration( + StringResource.fromFile(libraryDesugaringSpecification.getSpecification()))); + + if (!compilationSpecification.isProgramShrink()) { arguments.add("--no-minification"); buildup.add(b -> b.setDisableMinification(true)); } @@ -167,7 +188,10 @@ Path outputThroughDex = outputFolder.resolve("outThroughDex.zip"); ProcessResult artProcessResult = ToolHelper.runArtRaw( - Collections.singletonList(commandLinePathFor(outputThroughCf)), + ImmutableList.of( + commandLinePathFor(outputThroughCf), + commandLinePathFor( + getNonShrunkDesugaredLib(parameters, libraryDesugaringSpecification))), R8.class.getTypeName(), builder -> builder.appendArtOption("--64").appendArtOption("-Xmx512m"), parameters.getRuntime().asDex().getVm(), @@ -183,9 +207,10 @@ System.out.println(artProcessResult); } assertEquals(0, artProcessResult.exitCode); - assertTrue( + assertProgramsEqual( "The output of R8/JVM in-process and R8/ART external differ.", - TestBase.filesAreEqual(outputThroughCf, outputThroughDex)); + outputThroughCf, + outputThroughDex); } }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/DesugaredLibraryTestBuilder.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/DesugaredLibraryTestBuilder.java index 28d4db2..46d0b73 100644 --- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/DesugaredLibraryTestBuilder.java +++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/DesugaredLibraryTestBuilder.java
@@ -282,7 +282,7 @@ } public DesugaredLibraryTestBuilder<T> noMinification() { - withR8TestBuilder(R8TestBuilder::noMinification); + withR8TestBuilder(R8TestBuilder::addDontObfuscate); return this; }
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/FullNestOnProgramPathTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/FullNestOnProgramPathTest.java index 832e72d..6fb309f 100644 --- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/FullNestOnProgramPathTest.java +++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/FullNestOnProgramPathTest.java
@@ -106,7 +106,7 @@ for (String nestID : NEST_IDS) { testForR8(parameters.getBackend()) .noTreeShaking() - .noMinification() + .addDontObfuscate() .addKeepAllAttributes() .setMinApi(parameters.getApiLevel()) .addProgramFiles(classesOfNest(nestID)) @@ -149,7 +149,7 @@ return testForR8(getStaticTemp(), backend) .apply(configuration) .noTreeShaking() - .noMinification() + .addDontObfuscate() .addKeepAllAttributes() .addOptionsModification(options -> options.enableNestReduction = false) .addProgramFiles(JAR)
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestCompilationExceptionTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestCompilationExceptionTest.java index 2533da9..c7c4b21 100644 --- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestCompilationExceptionTest.java +++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestCompilationExceptionTest.java
@@ -92,7 +92,7 @@ } else { return testForR8(parameters.getBackend()) .noTreeShaking() - .noMinification() + .addDontObfuscate() .addKeepAllAttributes() .setMinApi(parameters.getApiLevel()) .addProgramFiles(matchingClasses)
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestConstructorRemovedArgTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestConstructorRemovedArgTest.java index 04eac5e..adfc202 100644 --- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestConstructorRemovedArgTest.java +++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestConstructorRemovedArgTest.java
@@ -44,7 +44,7 @@ String nestID = "constructors"; testForR8(parameters.getBackend()) .addKeepMainRule(getMainClass(nestID)) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .addOptionsModification(options -> options.enableClassInlining = false) .addProgramFiles(classesOfNest(nestID)) @@ -60,7 +60,7 @@ testForR8(parameters.getBackend()) .noTreeShaking() .addKeepMainRule(getMainClass(nestID)) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .addOptionsModification(options -> options.enableClassInlining = false) .addProgramFiles(classesOfNest(nestID))
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestMemberPropagatedTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestMemberPropagatedTest.java index 8107d71..3e86e4f 100644 --- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestMemberPropagatedTest.java +++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestMemberPropagatedTest.java
@@ -41,7 +41,7 @@ List<Path> toCompile = classesMatching("NestPvtFieldPropagated"); testForR8(parameters.getBackend()) .addKeepMainRule(getMainClass("memberPropagated")) - .noMinification() + .addDontObfuscate() .addOptionsModification( options -> { options.enableClassInlining = false;
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestMethodInlinedTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestMethodInlinedTest.java index 8eb08f4..a235beb 100644 --- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestMethodInlinedTest.java +++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestMethodInlinedTest.java
@@ -55,7 +55,7 @@ List<Path> toCompile = classesMatching("NestPvtMethodCallInlined"); testForR8(parameters.getBackend()) .addKeepMainRule(getMainClass("pvtCallInlined")) - .noMinification() + .addDontObfuscate() .addOptionsModification( options -> { options.enableClassInlining = false;
diff --git a/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java b/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java index 9a74bb5..96af73c 100644 --- a/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java +++ b/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java
@@ -152,7 +152,7 @@ R8FullTestBuilder builder = testForR8(parameters.getBackend()) .addProgramClassFileData(PROGRAM_DATA) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .addKeepMainRule(MAIN_TYPE); if (parameters.isCfRuntime()) {
diff --git a/src/test/java/com/android/tools/r8/desugar/twr/TwrCloseResourceDuplicationTest.java b/src/test/java/com/android/tools/r8/desugar/twr/TwrCloseResourceDuplicationTest.java index dd43eb9..f774b57 100644 --- a/src/test/java/com/android/tools/r8/desugar/twr/TwrCloseResourceDuplicationTest.java +++ b/src/test/java/com/android/tools/r8/desugar/twr/TwrCloseResourceDuplicationTest.java
@@ -124,7 +124,7 @@ parameters.getApiLevel().isLessThan(apiLevelWithTwrCloseResourceSupport()), builder -> builder.addDontWarn("java.lang.AutoCloseable")) .setMinApi(parameters.getApiLevel()) - .noMinification() + .addDontObfuscate() .run(parameters.getRuntime(), MAIN.typeName(), getZipFile()) .assertSuccessWithOutput(EXPECTED) .inspect(
diff --git a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterInlineRegression.java b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterInlineRegression.java index dfc4327..186346f 100644 --- a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterInlineRegression.java +++ b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterInlineRegression.java
@@ -48,7 +48,7 @@ // Link against android.jar that contains ReflectiveOperationException. .addLibraryFiles(parameters.getDefaultAndroidJarAbove(AndroidApiLevel.K)) .enableNoVerticalClassMergingAnnotations() - .noMinification(); + .addDontObfuscate(); ProcessResult processResult = testR8Splitter( parameters,
diff --git a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterMergeRegression.java b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterMergeRegression.java index c83e290..efd1f73 100644 --- a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterMergeRegression.java +++ b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterMergeRegression.java
@@ -50,7 +50,7 @@ // Link against android.jar that contains ReflectiveOperationException. .addLibraryFiles(parameters.getDefaultAndroidJarAbove(AndroidApiLevel.K)) .enableNoVerticalClassMergingAnnotations() - .noMinification(); + .addDontObfuscate(); ProcessResult processResult = testR8Splitter( parameters,
diff --git a/src/test/java/com/android/tools/r8/dexsplitter/R8SplitterInlineToFeature.java b/src/test/java/com/android/tools/r8/dexsplitter/R8SplitterInlineToFeature.java index 6576720..a7fef57 100644 --- a/src/test/java/com/android/tools/r8/dexsplitter/R8SplitterInlineToFeature.java +++ b/src/test/java/com/android/tools/r8/dexsplitter/R8SplitterInlineToFeature.java
@@ -55,7 +55,7 @@ // Link against android.jar that contains ReflectiveOperationException. .addLibraryFiles(parameters.getDefaultAndroidJarAbove(AndroidApiLevel.K)) .enableNoVerticalClassMergingAnnotations() - .noMinification(); + .addDontObfuscate(); ThrowableConsumer<R8TestCompileResult> ensureInlined = r8TestCompileResult -> { // Ensure that isEarly from BaseUtilClass is inlined into the feature
diff --git a/src/test/java/com/android/tools/r8/dexsplitter/SyntheticDistributionTest.java b/src/test/java/com/android/tools/r8/dexsplitter/SyntheticDistributionTest.java index 3dd0858..d0ea744 100644 --- a/src/test/java/com/android/tools/r8/dexsplitter/SyntheticDistributionTest.java +++ b/src/test/java/com/android/tools/r8/dexsplitter/SyntheticDistributionTest.java
@@ -101,7 +101,7 @@ BaseSuperClass.class.getDeclaredMethod( "keptApplyLambda", MyFunction.class, String.class))) .enableInliningAnnotations() - .noMinification() + .addDontObfuscate() // BaseDexClassLoader was introduced at api level 14. .apply(ApiModelingTestHelper::disableOutliningAndStubbing) .setMinApi(parameters.getApiLevel());
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/EnumUnboxingClassStaticizerTest.java b/src/test/java/com/android/tools/r8/enumunboxing/EnumUnboxingClassStaticizerTest.java index d510c33..12dfd1f 100644 --- a/src/test/java/com/android/tools/r8/enumunboxing/EnumUnboxingClassStaticizerTest.java +++ b/src/test/java/com/android/tools/r8/enumunboxing/EnumUnboxingClassStaticizerTest.java
@@ -51,7 +51,7 @@ .assertNoOtherClassesMerged()) .enableNeverClassInliningAnnotations() .enableInliningAnnotations() - .noMinification() // For assertions. + .addDontObfuscate() // For assertions. .addOptionsModification(opt -> enableEnumOptions(opt, enumValueOptimization)) .setMinApi(parameters.getApiLevel()) .compile()
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/EnumUnboxingTestBase.java b/src/test/java/com/android/tools/r8/enumunboxing/EnumUnboxingTestBase.java index c36733b..4690144 100644 --- a/src/test/java/com/android/tools/r8/enumunboxing/EnumUnboxingTestBase.java +++ b/src/test/java/com/android/tools/r8/enumunboxing/EnumUnboxingTestBase.java
@@ -73,4 +73,8 @@ protected static EnumKeepRules[] getAllEnumKeepRules() { return EnumKeepRules.values(); } + + protected static EnumKeepRules[] getStudioEnumKeepRules() { + return new EnumKeepRules[] {EnumKeepRules.STUDIO}; + } }
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/EnumUnboxingVerticalClassMergeTest.java b/src/test/java/com/android/tools/r8/enumunboxing/EnumUnboxingVerticalClassMergeTest.java index f240835..6f53904 100644 --- a/src/test/java/com/android/tools/r8/enumunboxing/EnumUnboxingVerticalClassMergeTest.java +++ b/src/test/java/com/android/tools/r8/enumunboxing/EnumUnboxingVerticalClassMergeTest.java
@@ -43,7 +43,7 @@ .addEnumUnboxingInspector(inspector -> inspector.assertUnboxed(UnboxableEnum.class)) .enableNeverClassInliningAnnotations() .enableInliningAnnotations() - .noMinification() // For assertions. + .addDontObfuscate() // For assertions. .addOptionsModification(opt -> enableEnumOptions(opt, enumValueOptimization)) .setMinApi(parameters.getApiLevel()) .compile()
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/FailingMethodEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/FailingMethodEnumUnboxingTest.java index 0a00994..19aa6fe 100644 --- a/src/test/java/com/android/tools/r8/enumunboxing/FailingMethodEnumUnboxingTest.java +++ b/src/test/java/com/android/tools/r8/enumunboxing/FailingMethodEnumUnboxingTest.java
@@ -65,7 +65,7 @@ .enableInliningAnnotations() .enableNeverClassInliningAnnotations() // TODO(b/173398086): uniqueMethodWithName() does not work with signature changes. - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(this::assertEnumsAsExpected);
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/FieldPutEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/FieldPutEnumUnboxingTest.java index d7627a6..fce366e 100644 --- a/src/test/java/com/android/tools/r8/enumunboxing/FieldPutEnumUnboxingTest.java +++ b/src/test/java/com/android/tools/r8/enumunboxing/FieldPutEnumUnboxingTest.java
@@ -53,7 +53,7 @@ .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) - .noMinification() + .addDontObfuscate() .compile() .inspect( i -> {
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/InstanceFieldsEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/InstanceFieldsEnumUnboxingTest.java index e359c36..a493981 100644 --- a/src/test/java/com/android/tools/r8/enumunboxing/InstanceFieldsEnumUnboxingTest.java +++ b/src/test/java/com/android/tools/r8/enumunboxing/InstanceFieldsEnumUnboxingTest.java
@@ -71,7 +71,7 @@ FailureBoxedInnerEnumField.EnumField.class, FailureUnboxedEnumField.EnumField.class, FailureTooManyUsedFields.EnumField.class)) - .noMinification() + .addDontObfuscate() .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .addKeepRules(enumKeepRules.getKeepRules())
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/InterfaceEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/InterfaceEnumUnboxingTest.java index 3bc5c02..bcf2ec5 100644 --- a/src/test/java/com/android/tools/r8/enumunboxing/InterfaceEnumUnboxingTest.java +++ b/src/test/java/com/android/tools/r8/enumunboxing/InterfaceEnumUnboxingTest.java
@@ -65,7 +65,7 @@ .assertUnboxedIf( !parameters.canUseDefaultAndStaticInterfaceMethods(), FailureDefaultMethodUsed.EnumInterface.class)) - .noMinification() + .addDontObfuscate() .enableNoVerticalClassMergingAnnotations() .enableInliningAnnotations() .enableNeverClassInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/LambdaEnumUnboxingEmptyEnumObjectTest.java b/src/test/java/com/android/tools/r8/enumunboxing/LambdaEnumUnboxingEmptyEnumObjectTest.java index 284f8ac..5f24fbe 100644 --- a/src/test/java/com/android/tools/r8/enumunboxing/LambdaEnumUnboxingEmptyEnumObjectTest.java +++ b/src/test/java/com/android/tools/r8/enumunboxing/LambdaEnumUnboxingEmptyEnumObjectTest.java
@@ -40,7 +40,7 @@ .addKeepMainRule(Main.class) .addKeepRules(enumKeepRules.getKeepRules()) .enableNeverClassInliningAnnotations() - .noMinification() + .addDontObfuscate() .enableNoVerticalClassMergingAnnotations() .enableInliningAnnotations() .addOptionsModification(opt -> enableEnumOptions(opt, enumValueOptimization))
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/LambdaEnumUnboxingEmptyEnumTest.java b/src/test/java/com/android/tools/r8/enumunboxing/LambdaEnumUnboxingEmptyEnumTest.java index 288ace4..14eba8a 100644 --- a/src/test/java/com/android/tools/r8/enumunboxing/LambdaEnumUnboxingEmptyEnumTest.java +++ b/src/test/java/com/android/tools/r8/enumunboxing/LambdaEnumUnboxingEmptyEnumTest.java
@@ -40,7 +40,7 @@ .addKeepMainRule(Main.class) .addKeepRules(enumKeepRules.getKeepRules()) .enableNeverClassInliningAnnotations() - .noMinification() + .addDontObfuscate() .enableNoVerticalClassMergingAnnotations() .enableInliningAnnotations() .addOptionsModification(opt -> enableEnumOptions(opt, enumValueOptimization))
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/SwitchEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/SwitchEnumUnboxingTest.java index 43dec5d..670e3b3 100644 --- a/src/test/java/com/android/tools/r8/enumunboxing/SwitchEnumUnboxingTest.java +++ b/src/test/java/com/android/tools/r8/enumunboxing/SwitchEnumUnboxingTest.java
@@ -49,7 +49,7 @@ .addEnumUnboxingInspector(inspector -> inspector.assertUnboxed(ENUM_CLASS)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() - .noMinification() // For assertions. + .addDontObfuscate() // For assertions. .addOptionsModification(opt -> enableEnumOptions(opt, enumValueOptimization)) .setMinApi(parameters.getApiLevel()) .compile()
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/ValueOfWithoutCastEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/ValueOfWithoutCastEnumUnboxingTest.java new file mode 100644 index 0000000..e213b3b --- /dev/null +++ b/src/test/java/com/android/tools/r8/enumunboxing/ValueOfWithoutCastEnumUnboxingTest.java
@@ -0,0 +1,92 @@ +// 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.enumunboxing; + +import com.android.tools.r8.NeverInline; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.utils.BooleanUtils; +import java.util.List; +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 ValueOfWithoutCastEnumUnboxingTest extends EnumUnboxingTestBase { + + private final TestParameters parameters; + private final boolean enumValueOptimization; + private final EnumKeepRules enumKeepRules; + + @Parameters(name = "{0} valueOpt: {1} keep: {2}") + public static List<Object[]> data() { + return buildParameters( + getTestParameters().withAllRuntimesAndApiLevels().build(), + BooleanUtils.values(), + getStudioEnumKeepRules()); + } + + public ValueOfWithoutCastEnumUnboxingTest( + TestParameters parameters, boolean enumValueOptimization, EnumKeepRules enumKeepRules) { + this.parameters = parameters; + this.enumValueOptimization = enumValueOptimization; + this.enumKeepRules = enumKeepRules; + } + + @Test + public void testEnumUnboxing() throws Exception { + testForR8(parameters.getBackend()) + .addInnerClasses(getClass()) + .addKeepClassAndMembersRules(Main.class) + .addKeepRules(enumKeepRules.getKeepRules()) + .addEnumUnboxingInspector(inspector -> inspector.assertNotUnboxed(MyEnum.class)) + .addOptionsModification(opt -> enableEnumOptions(opt, enumValueOptimization)) + .enableInliningAnnotations() + .setMinApi(parameters.getApiLevel()) + .compile() + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines("A"); + } + + static class Main { + + public static void main(String[] args) { + MyEnum e = System.currentTimeMillis() > 0 ? MyEnum.A : MyEnum.B; + // When the library method optimizer runs, the class argument to Enum.valueOf is still not a + // const-class. Therefore, the library method optimizer cannot insert an assume-dynamic-type + // instruction for the out-value of the call to Enum.valueOf. The argument is optimized into a + // const-class before the enum unboxing analysis runs. The enum unboxer must conclude that the + // enum is not subject to unboxing. + Object o = Enum.valueOf(new ClassInlineCandidate().set(MyEnum.class).get(), e.name()); + escape(o); + } + + // @Keep + static void escape(Object o) { + System.out.println(o); + } + } + + static class ClassInlineCandidate { + + Class<MyEnum> clazz; + + @NeverInline + ClassInlineCandidate set(Class<MyEnum> clazz) { + this.clazz = clazz; + return this; + } + + @NeverInline + Class<MyEnum> get() { + return clazz; + } + } + + enum MyEnum { + A, + B + } +}
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/VirtualMethodsAccessibilityErrorEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/VirtualMethodsAccessibilityErrorEnumUnboxingTest.java index 03e6de9..8cb9018 100644 --- a/src/test/java/com/android/tools/r8/enumunboxing/VirtualMethodsAccessibilityErrorEnumUnboxingTest.java +++ b/src/test/java/com/android/tools/r8/enumunboxing/VirtualMethodsAccessibilityErrorEnumUnboxingTest.java
@@ -59,7 +59,7 @@ }) .transform(); testForR8(parameters.getBackend()) - .noMinification() + .addDontObfuscate() .addProgramClasses(MyEnum.class) .addProgramClassFileData(testClassData) .addKeepMainRule(TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/graph/MissingClassThrowingTest.java b/src/test/java/com/android/tools/r8/graph/MissingClassThrowingTest.java index 14cf693..333ab92 100644 --- a/src/test/java/com/android/tools/r8/graph/MissingClassThrowingTest.java +++ b/src/test/java/com/android/tools/r8/graph/MissingClassThrowingTest.java
@@ -68,7 +68,7 @@ .addProgramClasses(Program.class) .addKeepAllClassesRule() .addKeepAllAttributes() - .noMinification() + .addDontObfuscate() .noTreeShaking() .enableInliningAnnotations() .enableNoHorizontalClassMergingAnnotations()
diff --git a/src/test/java/com/android/tools/r8/graph/invokestatic/InvokeStaticOnInterfaceTest.java b/src/test/java/com/android/tools/r8/graph/invokestatic/InvokeStaticOnInterfaceTest.java index 61d3d32..aaadb51 100644 --- a/src/test/java/com/android/tools/r8/graph/invokestatic/InvokeStaticOnInterfaceTest.java +++ b/src/test/java/com/android/tools/r8/graph/invokestatic/InvokeStaticOnInterfaceTest.java
@@ -81,7 +81,7 @@ .enableInliningAnnotations() .enableNoVerticalClassMergingAnnotations() .addOptionsModification(o -> o.testing.allowInvokeErrors = true) - .noMinification() + .addDontObfuscate() .addKeepMainRule(Main.class) .run(parameters.getRuntime(), Main.class); if (parameters.getRuntime().asCf().isNewerThan(CfVm.JDK8)) {
diff --git a/src/test/java/com/android/tools/r8/internal/Regression127524985.java b/src/test/java/com/android/tools/r8/internal/Regression127524985.java index 009c587..9b88d56 100644 --- a/src/test/java/com/android/tools/r8/internal/Regression127524985.java +++ b/src/test/java/com/android/tools/r8/internal/Regression127524985.java
@@ -68,7 +68,7 @@ testForR8(parameters.getBackend()) .debug() .noTreeShaking() - .noMinification() + .addDontObfuscate() .addKeepAllAttributes() .addKeepRules("-dontwarn") .allowDiagnosticWarningMessages()
diff --git a/src/test/java/com/android/tools/r8/internal/YouTubeCompilationTestBase.java b/src/test/java/com/android/tools/r8/internal/YouTubeCompilationTestBase.java index f280e80..8a15c91 100644 --- a/src/test/java/com/android/tools/r8/internal/YouTubeCompilationTestBase.java +++ b/src/test/java/com/android/tools/r8/internal/YouTubeCompilationTestBase.java
@@ -29,6 +29,7 @@ static final String DEPLOY_JAR = "YouTubeRelease_deploy.jar"; static final String PG_MAP = "YouTubeRelease_proguard.map"; static final String PG_CONF = "YouTubeRelease_proguard.config"; + static final String PG_CONF_EXTRA = "YouTubeRelease_proguard_extra.config"; static final String PG_PROTO_CONF = "YouTubeRelease_proto_safety.pgconf"; static final String PG_MISSING_CLASSES_CONF = "YouTubeRelease_proguard_missing_classes.config"; @@ -61,17 +62,24 @@ return path; } + protected Path getD8DesugaredLibraryJDKLibs() { + Path path = Paths.get(base, "desugar_jdk_libs/d8_desugared_jdk_libs.jar"); + assertTrue(path.toFile().exists()); + return path; + } + protected Path getDesugaredLibraryJDKLibsConfiguration() { Path path = Paths.get(base, "desugar_jdk_libs/desugar_jdk_libs_configuration.jar"); assertTrue(path.toFile().exists()); return path; } - protected List<Path> getDesugaredLibraryKeepRuleFiles() { + protected List<Path> getDesugaredLibraryKeepRuleFiles(Path generatedKeepRules) { ImmutableList<Path> keepRuleFiles = ImmutableList.of( Paths.get(base, "desugar_jdk_libs/base.pgcfg"), - Paths.get(base, "desugar_jdk_libs/minify_desugar_jdk_libs.pgcfg")); + Paths.get(base, "desugar_jdk_libs/minify_desugar_jdk_libs.pgcfg"), + generatedKeepRules); assertTrue(keepRuleFiles.stream().allMatch(keepRuleFile -> keepRuleFile.toFile().exists())); return keepRuleFiles; } @@ -80,7 +88,7 @@ ImmutableList.Builder<Path> builder = ImmutableList.builder(); builder.add(Paths.get(base).resolve(PG_CONF)); builder.add(Paths.get(ToolHelper.PROGUARD_SETTINGS_FOR_INTERNAL_APPS).resolve(PG_CONF)); - for (String name : new String[] {PG_PROTO_CONF, PG_MISSING_CLASSES_CONF}) { + for (String name : new String[] {PG_CONF_EXTRA, PG_PROTO_CONF, PG_MISSING_CLASSES_CONF}) { Path config = Paths.get(base).resolve(name); if (config.toFile().exists()) { builder.add(config);
diff --git a/src/test/java/com/android/tools/r8/internal/YouTubeV1620Test.java b/src/test/java/com/android/tools/r8/internal/YouTubeV1620Test.java deleted file mode 100644 index 56aed18..0000000 --- a/src/test/java/com/android/tools/r8/internal/YouTubeV1620Test.java +++ /dev/null
@@ -1,190 +0,0 @@ -// Copyright (c) 2021, 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.internal; - -import static com.android.tools.r8.ToolHelper.isLocalDevelopment; -import static com.android.tools.r8.ToolHelper.shouldRunSlowTests; -import static com.android.tools.r8.internal.proto.ProtoShrinkingTestBase.assertRewrittenProtoSchemasMatch; -import static com.android.tools.r8.internal.proto.ProtoShrinkingTestBase.keepAllProtosRule; -import static com.android.tools.r8.internal.proto.ProtoShrinkingTestBase.keepDynamicMethodSignatureRule; -import static com.android.tools.r8.internal.proto.ProtoShrinkingTestBase.keepNewMessageInfoSignatureRule; -import static org.hamcrest.CoreMatchers.anyOf; -import static org.hamcrest.CoreMatchers.containsString; -import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeTrue; - -import com.android.tools.r8.CompilationFailedException; -import com.android.tools.r8.L8TestCompileResult; -import com.android.tools.r8.LibraryDesugaringTestConfiguration; -import com.android.tools.r8.LibraryDesugaringTestConfiguration.PresentKeepRuleConsumer; -import com.android.tools.r8.R8FullTestBuilder; -import com.android.tools.r8.R8TestCompileResult; -import com.android.tools.r8.ResourceException; -import com.android.tools.r8.StringResource; -import com.android.tools.r8.TestParameters; -import com.android.tools.r8.TestParametersCollection; -import com.android.tools.r8.ThrowableConsumer; -import com.android.tools.r8.ToolHelper; -import com.android.tools.r8.utils.AndroidApiLevel; -import com.android.tools.r8.utils.Reporter; -import com.android.tools.r8.utils.codeinspector.CodeInspector; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.concurrent.ExecutionException; -import org.junit.After; -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 YouTubeV1620Test extends YouTubeCompilationTestBase { - - private static final int MAX_APPLICATION_SIZE = 29750000; - private static final int MAX_DESUGARED_LIBRARY_SIZE = 425000; - - private final TestParameters parameters; - - private final Path dumpDirectory = Paths.get("YouTubeV1620-" + System.currentTimeMillis()); - private final Reporter reporter = new Reporter(); - - @Parameters(name = "{0}") - public static TestParametersCollection data() { - return getTestParameters().withDefaultDexRuntime().withApiLevel(AndroidApiLevel.L).build(); - } - - public YouTubeV1620Test(TestParameters parameters) { - super(16, 20, parameters.getApiLevel()); - this.parameters = parameters; - } - - @Test - public void test() throws Exception { - assumeTrue(isLocalDevelopment()); - assumeTrue(shouldRunSlowTests()); - - KeepRuleConsumer keepRuleConsumer = new PresentKeepRuleConsumer(); - R8TestCompileResult r8CompileResult = compileApplicationWithR8(keepRuleConsumer); - L8TestCompileResult l8CompileResult = compileDesugaredLibraryWithL8(keepRuleConsumer); - - inspect(r8CompileResult, l8CompileResult); - - if (isLocalDevelopment()) { - dump(r8CompileResult, l8CompileResult); - } - } - - @Test - public void testProtoRewriting() throws Exception { - assumeTrue(shouldRunSlowTests()); - - KeepRuleConsumer keepRuleConsumer = KeepRuleConsumer.emptyConsumer(); - R8TestCompileResult r8CompileResult = - compileApplicationWithR8( - keepRuleConsumer, - builder -> - builder - .addKeepRules( - keepAllProtosRule(), - keepDynamicMethodSignatureRule(), - keepNewMessageInfoSignatureRule()) - .allowCheckDiscardedErrors(true)); - assertRewrittenProtoSchemasMatch( - new CodeInspector(getProgramFiles()), r8CompileResult.inspector()); - } - - @After - public void teardown() { - reporter.failIfPendingErrors(); - } - - private R8TestCompileResult compileApplicationWithR8(KeepRuleConsumer keepRuleConsumer) - throws IOException, CompilationFailedException { - return compileApplicationWithR8(keepRuleConsumer, ThrowableConsumer.empty()); - } - - private R8TestCompileResult compileApplicationWithR8( - KeepRuleConsumer keepRuleConsumer, ThrowableConsumer<R8FullTestBuilder> configuration) - throws IOException, CompilationFailedException { - return testForR8(parameters.getBackend()) - .addProgramFiles(getProgramFiles()) - .addLibraryFiles(getLibraryFileWithoutDesugaredLibrary()) - .addKeepRuleFiles(getKeepRuleFiles()) - .addDontWarn("android.app.Activity$TranslucentConversionListener") - .allowDiagnosticMessages() - .allowUnusedDontWarnPatterns() - .allowUnusedProguardConfigurationRules() - .apply(configuration) - .setMinApi(getApiLevel()) - .enableCoreLibraryDesugaring( - LibraryDesugaringTestConfiguration.builder() - .setKeepRuleConsumer(keepRuleConsumer) - .addDesugaredLibraryConfiguration( - StringResource.fromFile(getDesugaredLibraryConfiguration())) - .build()) - .compile() - .assertAllInfoMessagesMatch( - anyOf( - containsString("Ignoring option: -optimizations"), - containsString("Proguard configuration rule does not match anything"), - containsString("Invalid signature"))) - .apply(this::printProtoStats); - } - - private L8TestCompileResult compileDesugaredLibraryWithL8(KeepRuleConsumer keepRuleConsumer) - throws CompilationFailedException, IOException, ExecutionException { - return testForL8(getApiLevel()) - .setDesugaredLibrarySpecification(getDesugaredLibraryConfiguration()) - .addProgramFiles(getDesugaredLibraryJDKLibs()) - .addGeneratedKeepRules(keepRuleConsumer.get()) - .addKeepRuleFiles(getDesugaredLibraryKeepRuleFiles()) - .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P)) - .compile(); - } - - private void inspect(R8TestCompileResult r8CompileResult, L8TestCompileResult l8CompileResult) - throws IOException, ResourceException { - r8CompileResult.runDex2Oat(parameters.getRuntime()).assertNoVerificationErrors(); - l8CompileResult.runDex2Oat(parameters.getRuntime()).assertNoVerificationErrors(); - - int applicationSize = r8CompileResult.getApp().applicationSize(); - if (applicationSize > MAX_APPLICATION_SIZE) { - reporter.error( - "Expected application size to be <=" - + MAX_APPLICATION_SIZE - + ", but was " - + applicationSize); - } - - int desugaredLibrarySize = l8CompileResult.getApp().applicationSize(); - if (desugaredLibrarySize > MAX_DESUGARED_LIBRARY_SIZE) { - reporter.error( - "Expected desugared library size to be <=" - + MAX_DESUGARED_LIBRARY_SIZE - + ", but was " - + desugaredLibrarySize); - } - - if (isLocalDevelopment()) { - System.out.println("Dex size (application, excluding desugared library): " + applicationSize); - System.out.println("Dex size (desugared library): " + desugaredLibrarySize); - System.out.println("Dex size (total): " + (applicationSize + desugaredLibrarySize)); - } - } - - private void dump(R8TestCompileResult r8CompileResult, L8TestCompileResult l8CompileResult) - throws IOException { - assertTrue(isLocalDevelopment()); - Files.createDirectories(dumpDirectory); - r8CompileResult - .writeToDirectory(dumpDirectory) - .writeProguardMap(dumpDirectory.resolve("mapping.txt")); - l8CompileResult - .writeSingleDexOutputToFile(dumpDirectory.resolve("classes5.dex")) - .writeGeneratedKeepRules(dumpDirectory.resolve("l8-keep.txt")) - .writeProguardMap(dumpDirectory.resolve("l8-mapping.txt")); - } -}
diff --git a/src/test/java/com/android/tools/r8/internal/YouTubeV1719Test.java b/src/test/java/com/android/tools/r8/internal/YouTubeV1719Test.java new file mode 100644 index 0000000..e293b6e --- /dev/null +++ b/src/test/java/com/android/tools/r8/internal/YouTubeV1719Test.java
@@ -0,0 +1,331 @@ +// 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.internal; + +import static com.android.tools.r8.ToolHelper.isLocalDevelopment; +import static com.android.tools.r8.ToolHelper.shouldRunSlowTests; +import static com.android.tools.r8.internal.proto.ProtoShrinkingTestBase.assertRewrittenProtoSchemasMatch; +import static com.android.tools.r8.internal.proto.ProtoShrinkingTestBase.keepAllProtosRule; +import static com.android.tools.r8.internal.proto.ProtoShrinkingTestBase.keepDynamicMethodSignatureRule; +import static com.android.tools.r8.internal.proto.ProtoShrinkingTestBase.keepNewMessageInfoSignatureRule; +import static org.hamcrest.CoreMatchers.anyOf; +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; + +import com.android.tools.r8.CompilationFailedException; +import com.android.tools.r8.D8TestCompileResult; +import com.android.tools.r8.L8TestCompileResult; +import com.android.tools.r8.LibraryDesugaringTestConfiguration; +import com.android.tools.r8.R8FullTestBuilder; +import com.android.tools.r8.R8TestCompileResult; +import com.android.tools.r8.ResourceException; +import com.android.tools.r8.StartupProfileProvider; +import com.android.tools.r8.StringConsumer.FileConsumer; +import com.android.tools.r8.StringResource; +import com.android.tools.r8.TestCompileResult; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.ThrowableConsumer; +import com.android.tools.r8.tracereferences.TraceReferences; +import com.android.tools.r8.tracereferences.TraceReferencesCommand; +import com.android.tools.r8.tracereferences.TraceReferencesKeepRules; +import com.android.tools.r8.utils.AndroidApiLevel; +import com.android.tools.r8.utils.Reporter; +import com.android.tools.r8.utils.codeinspector.CodeInspector; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.concurrent.ExecutionException; +import org.junit.After; +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 YouTubeV1719Test extends YouTubeCompilationTestBase { + + private static final int MAX_APPLICATION_SIZE = 29750000; + private static final int MAX_DESUGARED_LIBRARY_SIZE = 425000; + + private final TestParameters parameters; + + // Location where test artifacts will be dumped when `local_development` is set. + private final Path dumpDirectory = Paths.get("YouTubeV1719-" + System.currentTimeMillis()); + + // By setting this to an actual startup list, YouTube will be build with layout optimizations + // enabled. + private final StartupProfileProvider startupProfileProvider = null; + private final boolean enableMinimalStartupDex = true; + private final boolean enableStartupBoundaryOptimizations = false; + + private final Reporter reporter = new Reporter(); + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withDefaultDexRuntime().withApiLevel(AndroidApiLevel.M).build(); + } + + public YouTubeV1719Test(TestParameters parameters) { + super(17, 19, parameters.getApiLevel()); + this.parameters = parameters; + } + + /** + * Running this test will dump an instrumented version of YouTube in the {@link #dumpDirectory}. + */ + @Test + public void testStartupInstrumentation() throws Exception { + assumeTrue(isLocalDevelopment()); + assumeTrue(shouldRunSlowTests()); + + // Compile the app with instrumentation and core library desugaring enabled. + D8TestCompileResult d8CompileResult = + testForD8() + .addProgramFiles(getProgramFiles()) + .addLibraryFiles(getLibraryFileWithoutDesugaredLibrary()) + .addOptionsModification( + options -> + options + .getStartupInstrumentationOptions() + .setEnableStartupInstrumentation() + .setStartupInstrumentationTag("r8")) + .enableCoreLibraryDesugaring( + LibraryDesugaringTestConfiguration.builder() + .addDesugaredLibraryConfiguration( + StringResource.fromFile(getDesugaredLibraryConfiguration())) + .build()) + .release() + .setMinApi(parameters.getApiLevel()) + .compile(); + + // Compile desugared library using cf backend (without keep rules). + L8TestCompileResult l8CompileResult = compileDesugaredLibraryWithL8(); + + // Generate keep rules for desugared library using trace references. + Path generatedKeepRules = temp.newFile().toPath(); + TraceReferences.run( + TraceReferencesCommand.builder() + .addLibraryFiles(getLibraryFileWithoutDesugaredLibrary()) + .addSourceFiles(d8CompileResult.writeToZip()) + .addTargetFiles(l8CompileResult.writeToZip()) + .setConsumer( + TraceReferencesKeepRules.builder() + .setAllowObfuscation(false) + .setOutputConsumer(new FileConsumer(generatedKeepRules)) + .build()) + .build()); + + // Compile desugared library using the generated keep rules. + R8TestCompileResult l8R8CompileResult = + compileDesugaredLibraryWithR8(l8CompileResult, generatedKeepRules); + + if (isLocalDevelopment()) { + dump(d8CompileResult, l8R8CompileResult); + } + } + + /** + * Running this test will dump an R8 build of YouTube in the {@link #dumpDirectory}, where the + * desugared library keep rules are generated using trace references. + * + * <p>If {@link #startupProfileProvider} is set to a concrete startup list, YouTube will be build + * with layout optimizations enabled. + */ + @Test + public void testR8() throws Exception { + assumeTrue(isLocalDevelopment()); + assumeTrue(shouldRunSlowTests()); + + // Compile app using R8, passing the startup list. + R8TestCompileResult r8CompileResult = + compileApplicationWithR8( + testBuilder -> + testBuilder.addOptionsModification( + options -> { + if (startupProfileProvider != null) { + options + .getStartupOptions() + .setStartupProfileProvider(startupProfileProvider) + .setEnableMinimalStartupDex(enableMinimalStartupDex) + .setEnableStartupBoundaryOptimizations( + enableStartupBoundaryOptimizations); + } + })); + + // Compile desugared library using cf backend (without keep rules). + L8TestCompileResult l8CompileResult = compileDesugaredLibraryWithL8(); + + // Generate keep rules for desugared library using trace references. + Path generatedKeepRules = temp.newFile().toPath(); + TraceReferences.run( + TraceReferencesCommand.builder() + .addLibraryFiles(getLibraryFileWithoutDesugaredLibrary()) + .addSourceFiles(r8CompileResult.writeToZip()) + .addTargetFiles(l8CompileResult.writeToZip()) + .setConsumer( + TraceReferencesKeepRules.builder() + .setAllowObfuscation(false) + .setOutputConsumer(new FileConsumer(generatedKeepRules)) + .build()) + .build()); + + // Compile desugared library using the generated keep rules. + R8TestCompileResult l8R8CompileResult = + compileDesugaredLibraryWithR8(l8CompileResult, generatedKeepRules); + + if (isLocalDevelopment()) { + dump(r8CompileResult, l8R8CompileResult); + } + + inspect(r8CompileResult, l8CompileResult); + } + + /** + * Validates that when all protos are kept and the proto optmization is enabled, the generated + * proto schemas are identical to the proto schemas in the input. + */ + @Test + public void testProtoRewriting() throws Exception { + assumeTrue(shouldRunSlowTests()); + + R8TestCompileResult r8CompileResult = + compileApplicationWithR8( + builder -> + builder + .addKeepRules( + keepAllProtosRule(), + keepDynamicMethodSignatureRule(), + keepNewMessageInfoSignatureRule()) + .allowCheckDiscardedErrors(true)); + assertRewrittenProtoSchemasMatch( + new CodeInspector(getProgramFiles()), r8CompileResult.inspector()); + } + + @After + public void teardown() { + reporter.failIfPendingErrors(); + } + + private R8TestCompileResult compileApplicationWithR8( + ThrowableConsumer<R8FullTestBuilder> configuration) + throws IOException, CompilationFailedException { + return testForR8(parameters.getBackend()) + .addProgramFiles(getProgramFiles()) + .addLibraryFiles(getLibraryFileWithoutDesugaredLibrary()) + .addKeepRuleFiles(getKeepRuleFiles()) + .addDontWarn("android.app.Activity$TranslucentConversionListener") + .apply(configuration) + .apply(this::disableR8StrictMode) + .apply(this::disableR8TestingDefaults) + .setMinApi(getApiLevel()) + .enableCoreLibraryDesugaring( + LibraryDesugaringTestConfiguration.builder() + .addDesugaredLibraryConfiguration( + StringResource.fromFile(getDesugaredLibraryConfiguration())) + .build()) + .compile() + .assertAllInfoMessagesMatch( + anyOf( + containsString("Ignoring option: -optimizations"), + containsString("Proguard configuration rule does not match anything"), + containsString("Invalid signature"))) + .apply(this::printProtoStats); + } + + private L8TestCompileResult compileDesugaredLibraryWithL8() + throws CompilationFailedException, IOException, ExecutionException { + return testForL8(getApiLevel(), Backend.CF) + .setDesugaredLibrarySpecification(getDesugaredLibraryConfiguration()) + .addProgramFiles(getDesugaredLibraryJDKLibs()) + .addLibraryFiles(getLibraryFileWithoutDesugaredLibrary()) + .compile(); + } + + private R8TestCompileResult compileDesugaredLibraryWithR8( + L8TestCompileResult l8CompileResult, Path generatedKeepRules) + throws IOException, CompilationFailedException { + return testForR8(parameters.getBackend()) + .addProgramFiles(l8CompileResult.writeToZip()) + .addLibraryFiles(getLibraryFileWithoutDesugaredLibrary()) + .addKeepRuleFiles(getDesugaredLibraryKeepRuleFiles(generatedKeepRules)) + .apply(this::disableR8StrictMode) + .apply(this::disableR8TestingDefaults) + .setMinApi(parameters.getApiLevel()) + .compile(); + } + + private void inspect(R8TestCompileResult r8CompileResult, L8TestCompileResult l8CompileResult) + throws IOException, ResourceException { + r8CompileResult.runDex2Oat(parameters.getRuntime()).assertNoVerificationErrors(); + l8CompileResult.runDex2Oat(parameters.getRuntime()).assertNoVerificationErrors(); + + int applicationSize = r8CompileResult.getApp().applicationSize(); + if (applicationSize > MAX_APPLICATION_SIZE) { + reporter.error( + "Expected application size to be <=" + + MAX_APPLICATION_SIZE + + ", but was " + + applicationSize); + } + + int desugaredLibrarySize = l8CompileResult.getApp().applicationSize(); + if (desugaredLibrarySize > MAX_DESUGARED_LIBRARY_SIZE) { + reporter.error( + "Expected desugared library size to be <=" + + MAX_DESUGARED_LIBRARY_SIZE + + ", but was " + + desugaredLibrarySize); + } + + if (isLocalDevelopment()) { + System.out.println("Dex size (application, excluding desugared library): " + applicationSize); + System.out.println("Dex size (desugared library): " + desugaredLibrarySize); + System.out.println("Dex size (total): " + (applicationSize + desugaredLibrarySize)); + } + } + + private void dump(TestCompileResult<?, ?> compileResult, R8TestCompileResult l8R8CompileResult) + throws IOException { + assertTrue(isLocalDevelopment()); + Files.createDirectories(dumpDirectory); + + // Dump dex. + compileResult.writeToDirectory(dumpDirectory); + + // Dump mapping. + if (compileResult instanceof R8TestCompileResult) { + R8TestCompileResult r8TestCompileResult = (R8TestCompileResult) compileResult; + r8TestCompileResult.writeProguardMap(dumpDirectory.resolve("mapping.txt")); + } + + // Dump desugared library dex. + int i = 2; + while (true) { + Path desugaredLibraryDexFile = dumpDirectory.resolve("classes" + i + ".dex"); + if (!desugaredLibraryDexFile.toFile().exists()) { + l8R8CompileResult.writeSingleDexOutputToFile(desugaredLibraryDexFile); + break; + } + i++; + } + + // Dump desugared library mapping. + l8R8CompileResult.writeProguardMap(dumpDirectory.resolve("mapping-desugared-library.txt")); + } + + private void disableR8StrictMode(R8FullTestBuilder testBuilder) { + testBuilder + .allowDiagnosticMessages() + .allowUnusedDontWarnPatterns() + .allowUnusedProguardConfigurationRules(); + } + + private void disableR8TestingDefaults(R8FullTestBuilder testBuilder) { + testBuilder.addOptionsModification( + options -> options.horizontalClassMergerOptions().setEnableInterfaceMerging(false)); + } +}
diff --git a/src/test/java/com/android/tools/r8/internal/startup/ChromeStartupTest.java b/src/test/java/com/android/tools/r8/internal/startup/ChromeStartupTest.java new file mode 100644 index 0000000..89b37d0 --- /dev/null +++ b/src/test/java/com/android/tools/r8/internal/startup/ChromeStartupTest.java
@@ -0,0 +1,267 @@ +// 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.internal.startup; + +import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; + +import com.android.tools.r8.ArchiveProgramResourceProvider; +import com.android.tools.r8.DexIndexedConsumer; +import com.android.tools.r8.R8FullTestBuilder; +import com.android.tools.r8.StartupProfileProvider; +import com.android.tools.r8.StringResource; +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.ThrowableConsumer; +import com.android.tools.r8.ToolHelper; +import com.android.tools.r8.utils.AndroidApiLevel; +import com.android.tools.r8.utils.ZipUtils; +import com.android.tools.r8.utils.codeinspector.CodeInspector; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ChromeStartupTest extends TestBase { + + private static AndroidApiLevel apiLevel = AndroidApiLevel.N; + + // Location of dump.zip and startup.txt. + private static Path chromeDirectory = Paths.get("build/chrome/startup"); + + // Location of test artifacts. + private static Path artifactDirectory = Paths.get("build/chrome/startup"); + + // Temporary directory where dump.zip is extracted into. + private static Path dumpDirectory; + + @Parameter(0) + public TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withNoneRuntime().build(); + } + + @BeforeClass + public static void setup() throws IOException { + assumeTrue(ToolHelper.isLocalDevelopment()); + dumpDirectory = getStaticTemp().newFolder().toPath(); + ZipUtils.unzip(chromeDirectory.resolve("dump.zip"), dumpDirectory); + } + + // Outputs the instrumented dex in chrome/instrumented. + @Test + public void buildInstrumentedDex() throws Exception { + buildInstrumentedBase(); + buildInstrumentedChromeSplit(); + } + + private void buildInstrumentedBase() throws Exception { + Files.createDirectories(artifactDirectory.resolve("instrumented/base/dex")); + testForD8() + .addProgramFiles(dumpDirectory.resolve("program.jar")) + .addClasspathFiles(dumpDirectory.resolve("classpath.jar")) + .addLibraryFiles(dumpDirectory.resolve("library.jar")) + .addOptionsModification( + options -> + options + .getStartupInstrumentationOptions() + .setEnableStartupInstrumentation() + .setStartupInstrumentationTag("r8")) + .setMinApi(apiLevel) + .release() + .compile() + .writeToDirectory(artifactDirectory.resolve("instrumented/base/dex")); + } + + private void buildInstrumentedChromeSplit() throws Exception { + Files.createDirectories(artifactDirectory.resolve("instrumented/chrome/dex")); + testForD8() + // The Chrome split is the feature that contains ChromeApplicationImpl. + .addProgramFiles(getChromeSplit()) + .addClasspathFiles(dumpDirectory.resolve("program.jar")) + .addClasspathFiles(dumpDirectory.resolve("classpath.jar")) + .addLibraryFiles(dumpDirectory.resolve("library.jar")) + .addOptionsModification( + options -> + options + .getStartupInstrumentationOptions() + .setEnableStartupInstrumentation() + .setStartupInstrumentationTag("r8")) + .setMinApi(apiLevel) + .release() + .compile() + .inspect( + inspector -> + assertThat( + inspector.clazz("org.chromium.chrome.browser.ChromeApplicationImpl"), + isPresent())) + .writeToDirectory(artifactDirectory.resolve("instrumented/chrome/dex")); + } + + private Path getChromeSplit() { + return getFeatureSplit(9); + } + + private Path getFeatureSplit(int index) { + return dumpDirectory.resolve("feature-" + index + ".jar"); + } + + // Outputs Chrome built using R8 in chrome/default. + @Test + public void buildR8Default() throws Exception { + buildR8(ThrowableConsumer.empty(), artifactDirectory.resolve("default")); + } + + // Outputs Chrome built using R8 with limited class merging in chrome/default-with-patches. + @Test + public void buildR8DefaultWithPatches() throws Exception { + buildR8( + testBuilder -> + testBuilder.addOptionsModification( + options -> options.horizontalClassMergerOptions().setEnableSameFilePolicy(true)), + artifactDirectory.resolve("default-with-patches")); + } + + // Outputs Chrome built using R8 with minimal startup dex and no boundary optimizations in + // chrome/optimized-minimal-nooptimize. + @Test + public void buildR8MinimalStartupDexWithoutBoundaryOptimizations() throws Exception { + boolean enableMinimalStartupDex = true; + boolean enableStartupBoundaryOptimizations = false; + buildR8Startup( + enableMinimalStartupDex, + enableStartupBoundaryOptimizations, + artifactDirectory.resolve("optimized-minimal-nooptimize")); + } + + // Outputs Chrome built using R8 with minimal startup dex and boundary optimizations enabled in + // chrome/optimized-minimal-optimize. + @Test + public void buildR8MinimalStartupDexWithBoundaryOptimizations() throws Exception { + boolean enableMinimalStartupDex = true; + boolean enableStartupBoundaryOptimizations = true; + buildR8Startup( + enableMinimalStartupDex, + enableStartupBoundaryOptimizations, + artifactDirectory.resolve("optimized-minimal-optimize")); + } + + // Outputs Chrome built using R8 with startup layout enabled and no boundary optimizations in + // chrome/optimized-nominimal-nooptimize. + @Test + public void buildR8StartupLayoutWithoutBoundaryOptimizations() throws Exception { + boolean enableMinimalStartupDex = false; + boolean enableStartupBoundaryOptimizations = false; + buildR8Startup( + enableMinimalStartupDex, + enableStartupBoundaryOptimizations, + artifactDirectory.resolve("optimized-nominimal-nooptimize")); + } + + // Outputs Chrome built using R8 with startup layout enabled and no boundary optimizations in + // chrome/optimized-nominimal-optimize. + @Test + public void buildR8StartupLayoutWithBoundaryOptimizations() throws Exception { + boolean enableMinimalStartupDex = false; + boolean enableStartupBoundaryOptimizations = true; + buildR8Startup( + enableMinimalStartupDex, + enableStartupBoundaryOptimizations, + artifactDirectory.resolve("optimized-nominimal-optimize")); + } + + private void buildR8(ThrowableConsumer<R8FullTestBuilder> configuration, Path outDirectory) + throws Exception { + Files.createDirectories(outDirectory.resolve("base/dex")); + Files.createDirectories(outDirectory.resolve("chrome/dex")); + testForR8(Backend.DEX) + .addProgramFiles(dumpDirectory.resolve("program.jar")) + .addClasspathFiles(dumpDirectory.resolve("classpath.jar")) + .addLibraryFiles(dumpDirectory.resolve("library.jar")) + .addKeepRuleFiles(dumpDirectory.resolve("proguard.config")) + .apply( + testBuilder -> { + int i = 1; + boolean seenChromeSplit = false; + for (; i <= 12; i++) { + Path feature = getFeatureSplit(i); + boolean isChromeSplit = feature.equals(getChromeSplit()); + seenChromeSplit |= isChromeSplit; + assertTrue(feature.toFile().exists()); + testBuilder.addFeatureSplit( + featureSplitBuilder -> + featureSplitBuilder + .addProgramResourceProvider( + ArchiveProgramResourceProvider.fromArchive(feature)) + .setProgramConsumer( + isChromeSplit + ? new DexIndexedConsumer.DirectoryConsumer( + outDirectory.resolve("chrome/dex")) + : DexIndexedConsumer.emptyConsumer()) + .build()); + } + assertFalse(dumpDirectory.resolve("feature-" + i + ".jar").toFile().exists()); + assertTrue(seenChromeSplit); + assertThat( + new CodeInspector(getChromeSplit()) + .clazz("org.chromium.chrome.browser.ChromeApplicationImpl"), + isPresent()); + }) + .apply(configuration) + .apply(this::disableR8StrictMode) + .apply(this::disableR8TestingDefaults) + .setMinApi(apiLevel) + .compile() + .writeToDirectory(outDirectory.resolve("base/dex")); + } + + private void buildR8Startup( + boolean enableMinimalStartupDex, + boolean enableStartupBoundaryOptimizations, + Path outDirectory) + throws Exception { + StartupProfileProvider startupProfileProvider = + StringResource.fromFile(chromeDirectory.resolve("startup.txt")) + ::getStringWithRuntimeException; + buildR8( + testBuilder -> + testBuilder.addOptionsModification( + options -> + options + .getStartupOptions() + .setEnableMinimalStartupDex(enableMinimalStartupDex) + .setEnableStartupBoundaryOptimizations(enableStartupBoundaryOptimizations) + .setStartupProfileProvider(startupProfileProvider)), + outDirectory); + } + + private void disableR8StrictMode(R8FullTestBuilder testBuilder) { + testBuilder + .allowDiagnosticMessages() + .allowUnnecessaryDontWarnWildcards() + .allowUnusedDontWarnPatterns() + .allowUnusedProguardConfigurationRules() + .addOptionsModification( + options -> options.getOpenClosedInterfacesOptions().suppressAllOpenInterfaces()); + } + + private void disableR8TestingDefaults(R8FullTestBuilder testBuilder) { + testBuilder.addOptionsModification( + options -> options.horizontalClassMergerOptions().setEnableInterfaceMerging(false)); + } +}
diff --git a/src/test/java/com/android/tools/r8/ir/conversion/StringSwitchConversionFromIfTest.java b/src/test/java/com/android/tools/r8/ir/conversion/StringSwitchConversionFromIfTest.java index bcdd93f..6573810 100644 --- a/src/test/java/com/android/tools/r8/ir/conversion/StringSwitchConversionFromIfTest.java +++ b/src/test/java/com/android/tools/r8/ir/conversion/StringSwitchConversionFromIfTest.java
@@ -55,7 +55,7 @@ .enableInliningAnnotations() // TODO(b/135560746): Add support for treating the keys of a string-switch instruction as an // identifier name string. - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/AlwaysThrowNullTest.java b/src/test/java/com/android/tools/r8/ir/optimize/AlwaysThrowNullTest.java index 684b669..9dcfa24 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/AlwaysThrowNullTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/AlwaysThrowNullTest.java
@@ -243,7 +243,7 @@ .enableInliningAnnotations() .enableMemberValuePropagationAnnotations() .addKeepMainRule(MAIN) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), MAIN) .assertSuccessWithOutput(JAVA_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/MemberValuePropagationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/MemberValuePropagationTest.java index 1433f2e..7d1141c 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/MemberValuePropagationTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/MemberValuePropagationTest.java
@@ -75,7 +75,7 @@ return testForR8(backend) .addProgramFiles(EXAMPLE_JAR) .addKeepRuleFiles(proguardConfig) - .noMinification() + .addDontObfuscate() .addOptionsModification(o -> o.enableClassInlining = false) .compile() .inspector();
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java b/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java index 9b0bb90..e582d84 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java
@@ -66,7 +66,7 @@ .addKeepMainRule(mainClass) .addKeepRules(ImmutableList.of("-keepattributes InnerClasses,Signature,EnclosingMethod")) // All tests are checking if invocations to certain null-check utils are gone. - .noMinification() + .addDontObfuscate() .addOptionsModification( options -> { // Need to increase a little bit to inline System.out.println
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/ObjectsRequireNonNullTest.java b/src/test/java/com/android/tools/r8/ir/optimize/ObjectsRequireNonNullTest.java index 77da418..f40816f 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/ObjectsRequireNonNullTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/ObjectsRequireNonNullTest.java
@@ -136,7 +136,7 @@ .enableInliningAnnotations() .enableMemberValuePropagationAnnotations() .addKeepMainRule(MAIN) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), MAIN) .assertSuccessWithOutput(JAVA_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/R8InliningTest.java b/src/test/java/com/android/tools/r8/ir/optimize/R8InliningTest.java index b7a3474..303bf0c 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/R8InliningTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/R8InliningTest.java
@@ -137,7 +137,7 @@ }) .allowAccessModification(allowAccessModification) .enableProguardTestOptions() - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .applyIf(
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/ShortenLiveRangesOfInstanceGetWithPhiUserRegressionTest.java b/src/test/java/com/android/tools/r8/ir/optimize/ShortenLiveRangesOfInstanceGetWithPhiUserRegressionTest.java new file mode 100644 index 0000000..20b3e58 --- /dev/null +++ b/src/test/java/com/android/tools/r8/ir/optimize/ShortenLiveRangesOfInstanceGetWithPhiUserRegressionTest.java
@@ -0,0 +1,56 @@ +// 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.optimize; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +/** Reproduction of b/241636314. */ +@RunWith(Parameterized.class) +public class ShortenLiveRangesOfInstanceGetWithPhiUserRegressionTest extends TestBase { + + @Parameter(0) + public TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); + } + + @Test + public void test() throws Exception { + testForR8(parameters.getBackend()) + .addInnerClasses(getClass()) + .addKeepMainRule(Main.class) + .setMinApi(parameters.getApiLevel()) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines("0", "1", "2"); + } + + static class Main { + + public final long index; + + Main(long index) { + this.index = index; + } + + public static void main(String[] args) { + Main main = new Main(1); + long index = 0; + do { + System.out.println(index); // Print the value of the phi. + index = main.index; + main = new Main(index + 1); + } while (index < 3); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectPositiveTest.java index f726e4f..2c79f4c 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectPositiveTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectPositiveTest.java
@@ -44,7 +44,7 @@ .enableInliningAnnotations() .enableNeverClassInliningAnnotations() // TODO(b/173398086): uniqueMethodWithName() does not work with argument removal. - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), MAIN) .assertSuccessWithOutputLines("non-null")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfacePositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfacePositiveTest.java index 39f33af..d1a160a 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfacePositiveTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfacePositiveTest.java
@@ -52,7 +52,7 @@ .enableNeverClassInliningAnnotations() .enableNoHorizontalClassMergingAnnotations() // TODO(b/173398086): uniqueMethodWithName() does not work with argument removal. - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), MAIN) .assertSuccessWithOutputLines("non-null")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeStaticPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeStaticPositiveTest.java index 3694dc8..9f01b31 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeStaticPositiveTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeStaticPositiveTest.java
@@ -42,7 +42,7 @@ .addKeepMainRule(MAIN) .enableInliningAnnotations() // TODO(b/173398086): uniqueMethodWithName() does not work with argument removal. - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), MAIN) .assertSuccessWithOutputLines("non-null")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/ConstClassCanonicalizationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/ConstClassCanonicalizationTest.java index 380c5be..5d32d7a 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/ConstClassCanonicalizationTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/ConstClassCanonicalizationTest.java
@@ -214,7 +214,7 @@ .addProgramClassesAndInnerClasses(MAIN) .addKeepMainRule(MAIN) .addKeepAttributeInnerClassesAndEnclosingMethod() - .noMinification() + .addDontObfuscate() .addOptionsModification(InternalOptions::disableNameReflectionOptimization) .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), MAIN)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/IdempotentFunctionCallCanonicalizationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/IdempotentFunctionCallCanonicalizationTest.java index 5c8cfd8..b3e1364 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/IdempotentFunctionCallCanonicalizationTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/IdempotentFunctionCallCanonicalizationTest.java
@@ -242,7 +242,7 @@ .addProgramClasses(MAIN) .enableInliningAnnotations() .addKeepMainRule(MAIN) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getRuntime()) .run(parameters.getRuntime(), MAIN) .assertSuccessWithOutput(JAVA_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/IllegalAccessConstClassTest.java b/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/IllegalAccessConstClassTest.java index 7601389..126c1f0 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/IllegalAccessConstClassTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/IllegalAccessConstClassTest.java
@@ -86,12 +86,11 @@ @Test public void testR8() throws Exception { testForR8(parameters.getBackend()) - .addProgramClassFileData( - IllegalAccessConstClassTestDump.PackagePrivateClassDump.dump()) + .addProgramClassFileData(IllegalAccessConstClassTestDump.PackagePrivateClassDump.dump()) .addProgramClassFileData( IllegalAccessConstClassTestDump.FakePackagePrivateClassConsumerDump.dump()) .addKeepMainRule(MAIN) - .noMinification() + .addDontObfuscate() .addOptionsModification(InternalOptions::disableNameReflectionOptimization) .setMinApi(parameters.getRuntime()) .compile()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/UnresolvableLibraryConstClassTest.java b/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/UnresolvableLibraryConstClassTest.java index 2765bb2..cc65eae 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/UnresolvableLibraryConstClassTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/UnresolvableLibraryConstClassTest.java
@@ -112,7 +112,7 @@ .addLibraryFiles(ToolHelper.getDefaultAndroidJar()) .addProgramClasses(ProgramClass1.class, ProgramClass2.class, ProgramSubClass.class, MAIN) .addKeepMainRule(MAIN) - .noMinification() + .addDontObfuscate() .enableNoVerticalClassMergingAnnotations() .addOptionsModification(InternalOptions::disableNameReflectionOptimization) .setMinApi(parameters.getRuntime())
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/CheckCastDebugTestRunner.java b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/CheckCastDebugTestRunner.java index dc86e78..e398a65 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/CheckCastDebugTestRunner.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/CheckCastDebugTestRunner.java
@@ -53,7 +53,7 @@ .addOptionsModification(options -> options.enableVerticalClassMerging = false) .debug() .enableInliningAnnotations() - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getRuntime()) .compile() .writeToZip(this::setR8Out)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/CheckCastInterfaceArrayTest.java b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/CheckCastInterfaceArrayTest.java index 4431c5a..481bdcd 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/CheckCastInterfaceArrayTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/CheckCastInterfaceArrayTest.java
@@ -43,7 +43,7 @@ .addInnerClasses(CheckCastInterfaceArrayTest.class) .addKeepMainRule(TestClass.class) .setMinApi(parameters.getApiLevel()) - .noMinification() + .addDontObfuscate() .noTreeShaking() .compile() .run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/RemoveCheckCastAfterClassInlining.java b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/RemoveCheckCastAfterClassInlining.java index 53d28eb..1f5c944 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/RemoveCheckCastAfterClassInlining.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/RemoveCheckCastAfterClassInlining.java
@@ -45,7 +45,7 @@ testForR8(parameters.getBackend()) .addProgramClassesAndInnerClasses(Lambda.class) .addKeepMainRule(Lambda.class) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getRuntime()) .compile() .inspector();
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerBuilderWithControlFlowTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerBuilderWithControlFlowTest.java index 44db913..4adf9ef 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerBuilderWithControlFlowTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerBuilderWithControlFlowTest.java
@@ -47,7 +47,7 @@ testForR8(parameters.getBackend()) .addInnerClasses(ClassInlinerBuilderWithControlFlowTest.class) .addKeepMainRule(TestClass.class) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(this::inspect)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerBuilderWithMoreControlFlowTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerBuilderWithMoreControlFlowTest.java index 3778db4..c0277d7 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerBuilderWithMoreControlFlowTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerBuilderWithMoreControlFlowTest.java
@@ -40,7 +40,7 @@ testForR8(parameters.getBackend()) .addInnerClasses(ClassInlinerBuilderWithMoreControlFlowTest.class) .addKeepMainRule(TestClass.class) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(this::inspect)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerSimplePairBuilderTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerSimplePairBuilderTest.java index d9b5cd1..efdaea1 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerSimplePairBuilderTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerSimplePairBuilderTest.java
@@ -61,7 +61,7 @@ .enableAlwaysInliningAnnotations() .enableInliningAnnotations() .enableNoHorizontalClassMergingAnnotations() - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(this::inspect)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerSimplePairBuilderWithMultipleBuildsTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerSimplePairBuilderWithMultipleBuildsTest.java index d23951c..35dbdce 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerSimplePairBuilderWithMultipleBuildsTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerSimplePairBuilderWithMultipleBuildsTest.java
@@ -50,7 +50,7 @@ .addInnerClasses(ClassInlinerSimplePairBuilderWithMultipleBuildsTest.class) .addKeepMainRule(TestClass.class) .enableAlwaysInliningAnnotations() - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(this::inspect)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerStaticGetDirectMonitorTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerStaticGetDirectMonitorTest.java index f6252ea..cd28e2a 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerStaticGetDirectMonitorTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerStaticGetDirectMonitorTest.java
@@ -42,7 +42,7 @@ .addKeepMainRule(TestClass.class) .enableInliningAnnotations() .setMinApi(parameters.getApiLevel()) - .noMinification() + .addDontObfuscate() .compile() .inspect(this::inspect) .run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerStaticGetExtraMethodMonitorTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerStaticGetExtraMethodMonitorTest.java index 0e0b260..23c364e 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerStaticGetExtraMethodMonitorTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerStaticGetExtraMethodMonitorTest.java
@@ -41,7 +41,7 @@ .addKeepMainRule(TestClass.class) .enableInliningAnnotations() .setMinApi(parameters.getApiLevel()) - .noMinification() + .addDontObfuscate() .compile() .inspect(this::inspect) .run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerStaticGetMonitorTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerStaticGetMonitorTest.java index 216f34e..f858a0e 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerStaticGetMonitorTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerStaticGetMonitorTest.java
@@ -41,7 +41,7 @@ .addKeepMainRule(TestClass.class) .enableInliningAnnotations() .setMinApi(parameters.getApiLevel()) - .noMinification() + .addDontObfuscate() .compile() .inspect(this::inspect) .run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerTest.java index 1884e5e..8e5d660 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerTest.java
@@ -99,7 +99,7 @@ .assertMergedInto(CycleReferenceBA.class, Iface1Impl.class) .assertMergedInto(Iface2Impl.class, Iface1Impl.class)) .allowAccessModification() - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), main) .assertSuccessWithOutput(javaOutput); @@ -212,7 +212,7 @@ .addKeepMainRule(main) .addKeepAttributes("LineNumberTable") .allowAccessModification() - .noMinification() + .addDontObfuscate() .run(main) .assertSuccessWithOutput(javaOutput); @@ -254,7 +254,7 @@ o.classInlinerOptions().classInliningInstructionAllowance = 1000; }) .allowAccessModification() - .noMinification() + .addDontObfuscate() .run(main) .assertSuccessWithOutput(javaOutput); @@ -306,7 +306,7 @@ .addKeepAttributes("LineNumberTable") .allowAccessModification() .enableInliningAnnotations() - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), main) .assertSuccessWithOutput(javaOutput);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerTupleBuilderConstructorsTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerTupleBuilderConstructorsTest.java index 187c5f3..179c5ba 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerTupleBuilderConstructorsTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerTupleBuilderConstructorsTest.java
@@ -46,7 +46,7 @@ .addInnerClasses(ClassInlinerTupleBuilderConstructorsTest.class) .addKeepMainRule(TestClass.class) .enableAlwaysClassInlineAnnotations() - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(this::inspect)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/IndirectInstanceOfUserInParentConstructorClassInliningTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/IndirectInstanceOfUserInParentConstructorClassInliningTest.java new file mode 100644 index 0000000..d0e7d73 --- /dev/null +++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/IndirectInstanceOfUserInParentConstructorClassInliningTest.java
@@ -0,0 +1,80 @@ +// 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.optimize.classinliner; + +import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; + +import com.android.tools.r8.NeverInline; +import com.android.tools.r8.NoVerticalClassMerging; +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.utils.codeinspector.CodeInspector; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class IndirectInstanceOfUserInParentConstructorClassInliningTest extends TestBase { + + @Parameter(0) + public TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); + } + + @Test + public void test() throws Exception { + testForR8(parameters.getBackend()) + .addInnerClasses(getClass()) + .addKeepMainRule(Main.class) + .enableInliningAnnotations() + .enableNoVerticalClassMergingAnnotations() + .setMinApi(parameters.getApiLevel()) + .compile() + .inspect(this::inspect) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines("Hello, world!"); + } + + private void inspect(CodeInspector inspector) { + // Verify A and B are absent (due to class inlining). + assertThat(inspector.clazz(Main.class), isPresent()); + assertEquals(1, inspector.allClasses().size()); + } + + static class Main { + + public static void main(String[] args) { + System.out.println(new B().get()); + } + } + + @NoVerticalClassMerging + static class A { + + A() { + if (this instanceof B) { + System.out.print("Hello"); + } else { + throw new RuntimeException(); + } + } + } + + static class B extends A { + + @NeverInline + String get() { + return System.currentTimeMillis() > 0 ? ", world!" : null; + } + } +}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/LibraryOverrideClassInliningTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/LibraryOverrideClassInliningTest.java index 7b68b6d..463efbb 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/LibraryOverrideClassInliningTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/LibraryOverrideClassInliningTest.java
@@ -89,7 +89,7 @@ CodeInspector inspector = testForR8(parameters.getBackend()) .enableInliningAnnotations() - .noMinification() + .addDontObfuscate() .addProgramClasses( Main.class, SimpleLibraryOverride.class, NonSimpleLibraryOverride.class) .addKeepMainRule(Main.class)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/PrivateOverridePublicizerDevirtualizerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/PrivateOverridePublicizerDevirtualizerTest.java index 86739dc..6570849 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/PrivateOverridePublicizerDevirtualizerTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/PrivateOverridePublicizerDevirtualizerTest.java
@@ -53,7 +53,7 @@ .enableNeverClassInliningAnnotations() .addKeepMainRule(Main.class) .allowAccessModification() - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/fields/SwitchOnConstantClassIdAfterBranchPruningTest.java b/src/test/java/com/android/tools/r8/ir/optimize/fields/SwitchOnConstantClassIdAfterBranchPruningTest.java index f3d6a4d..8c029a5 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/fields/SwitchOnConstantClassIdAfterBranchPruningTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/fields/SwitchOnConstantClassIdAfterBranchPruningTest.java
@@ -46,7 +46,7 @@ .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) - .noMinification() + .addDontObfuscate() .compile() .inspect( inspector -> {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/fields/SwitchOnNonConstantClassIdAfterBranchPruningTest.java b/src/test/java/com/android/tools/r8/ir/optimize/fields/SwitchOnNonConstantClassIdAfterBranchPruningTest.java index 1c2705e..88efb9c 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/fields/SwitchOnNonConstantClassIdAfterBranchPruningTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/fields/SwitchOnNonConstantClassIdAfterBranchPruningTest.java
@@ -46,7 +46,7 @@ .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel()) - .noMinification() + .addDontObfuscate() .compile() .inspect( inspector -> {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/DoubleInliningNullCheckTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/DoubleInliningNullCheckTest.java index 94fba01..bf9b044 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/DoubleInliningNullCheckTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/DoubleInliningNullCheckTest.java
@@ -36,7 +36,7 @@ testForR8(parameters.getBackend()) .addInnerClasses(DoubleInliningNullCheckTest.class) .addKeepMainRule(TestClass.class) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), TestClass.class) .assertSuccessWithOutputLines("true")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineLibraryInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineLibraryInterfaceMethodTest.java index 3c76052..634d0a8 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineLibraryInterfaceMethodTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineLibraryInterfaceMethodTest.java
@@ -46,7 +46,7 @@ .addInnerClasses(InlineLibraryInterfaceMethodTest.class) .addKeepMainRule(TestClass.class) .setMinApi(testRuntime) - .noMinification() + .addDontObfuscate() .run(testRuntime, TestClass.class) .assertSuccess() .inspect(
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineSynthesizedLambdaClass.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineSynthesizedLambdaClass.java index 1bd8db6..dbc7c5b 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineSynthesizedLambdaClass.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineSynthesizedLambdaClass.java
@@ -41,7 +41,7 @@ .addProgramClassesAndInnerClasses(Lambda.class) .addKeepMainRule(Lambda.class) .allowAccessModification() - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), Lambda.class) .assertSuccessWithOutput(javaOutput)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/conditionalsimpleinlining/NopInliningConstraintTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/conditionalsimpleinlining/NopInliningConstraintTest.java index dcc572b..c55ea29 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/conditionalsimpleinlining/NopInliningConstraintTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/conditionalsimpleinlining/NopInliningConstraintTest.java
@@ -41,7 +41,7 @@ .enableAlwaysInliningAnnotations() .enableInliningAnnotations() // TODO(b/173398086): uniqueMethodWithName() does not work with argument removal. - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/interfacemethods/InlineDefaultInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/interfacemethods/InlineDefaultInterfaceMethodTest.java index 177353f..247781d 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/interfacemethods/InlineDefaultInterfaceMethodTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/interfacemethods/InlineDefaultInterfaceMethodTest.java
@@ -43,7 +43,7 @@ .setMinApi(parameters.getApiLevel()) .enableNeverClassInliningAnnotations() .enableNoVerticalClassMergingAnnotations() - .noMinification() + .addDontObfuscate() .run(parameters.getRuntime(), TestClass.class) .assertSuccessWithOutput(expectedOutput) .inspector();
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/lambda/LambdaMethodInliningTest.java b/src/test/java/com/android/tools/r8/ir/optimize/lambda/LambdaMethodInliningTest.java index a63addb..b6ca59d 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/lambda/LambdaMethodInliningTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/lambda/LambdaMethodInliningTest.java
@@ -44,7 +44,7 @@ .enableNoVerticalClassMergingAnnotations() .addOptionsModification(options -> options.enableClassInlining = false) // TODO(b/173398086): Horizontal class merging breaks uniqueMethodWithName(). - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(this::inspect)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/logging/CustomLoggingFrameworkRemovalTest.java b/src/test/java/com/android/tools/r8/ir/optimize/logging/CustomLoggingFrameworkRemovalTest.java index b40d47e..c1957f4 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/logging/CustomLoggingFrameworkRemovalTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/logging/CustomLoggingFrameworkRemovalTest.java
@@ -55,7 +55,7 @@ .enableAssumeNoSideEffectsAnnotations() .enableInliningAnnotations() .setMinApi(parameters.getApiLevel()) - .noMinification() + .addDontObfuscate() .compile() .inspect( inspector -> {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/loops/LoopWith1Iterations.java b/src/test/java/com/android/tools/r8/ir/optimize/loops/LoopWith1Iterations.java index dc3ca19..9190a4c 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/loops/LoopWith1Iterations.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/loops/LoopWith1Iterations.java
@@ -34,7 +34,7 @@ .addProgramClasses(Main.class) .addKeepMainRule(Main.class) .enableInliningAnnotations() - .noMinification() + .addDontObfuscate() .compile() .inspect(this::assertLoopRemoved) .run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/loops/LoopWith1IterationsEscape.java b/src/test/java/com/android/tools/r8/ir/optimize/loops/LoopWith1IterationsEscape.java index 07efa85..f8260c0 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/loops/LoopWith1IterationsEscape.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/loops/LoopWith1IterationsEscape.java
@@ -33,7 +33,7 @@ .addProgramClasses(Main.class) .addKeepMainRule(Main.class) .enableInliningAnnotations() - .noMinification() + .addDontObfuscate() .compile() .run(parameters.getRuntime(), Main.class) .assertSuccessWithOutputLines("end 0", "iteration", "end 1");
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/B138912149.java b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/B138912149.java index bee06af..16dbf43a 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/B138912149.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/B138912149.java
@@ -37,16 +37,18 @@ .addInnerClasses(B138912149.class) .addKeepMainRule(TestClass.class) .setMinApi(parameters.getRuntime()) - .noMinification() + .addDontObfuscate() .compile() .run(parameters.getRuntime(), TestClass.class) .assertSuccessWithOutputLines("The end") - .inspect(codeInspector -> { - // All <clinit>s are simplified and shrunk. - codeInspector.forAllClasses(classSubject -> { - assertThat(classSubject.clinit(), not(isPresent())); - }); - }); + .inspect( + codeInspector -> { + // All <clinit>s are simplified and shrunk. + codeInspector.forAllClasses( + classSubject -> { + assertThat(classSubject.clinit(), not(isPresent())); + }); + }); } @Test
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/StaticFieldPropagationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/StaticFieldPropagationTest.java index bd204c7..9a7d252 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/StaticFieldPropagationTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/StaticFieldPropagationTest.java
@@ -31,7 +31,7 @@ .addProgramClasses(TestClass.class, Log.class) .addKeepMainRule(TestClass.class) .enableInliningAnnotations() - .noMinification() + .addDontObfuscate() .run(TestClass.class) .assertSuccessWithOutput(expectedOutput);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/fields/FieldTypeStrengtheningCollisionTest.java b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/fields/FieldTypeStrengtheningCollisionTest.java index 9e5e433..4a7aae0 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/fields/FieldTypeStrengtheningCollisionTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/fields/FieldTypeStrengtheningCollisionTest.java
@@ -12,8 +12,6 @@ import com.android.tools.r8.TestBase; import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestParametersCollection; -import com.android.tools.r8.ir.optimize.membervaluepropagation.fields.FieldTypeStrengtheningTest.A; -import com.android.tools.r8.ir.optimize.membervaluepropagation.fields.FieldTypeStrengtheningTest.Main; import com.android.tools.r8.transformers.ClassFileTransformer.FieldPredicate; import com.android.tools.r8.utils.codeinspector.ClassSubject; import com.android.tools.r8.utils.codeinspector.FieldSubject; @@ -44,7 +42,7 @@ .addKeepRules( "-keep class " + Main.class.getTypeName() + " { " + A.class.getTypeName() + " f; }") .enableInliningAnnotations() - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlinesWithNonNullTest.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlinesWithNonNullTest.java index c4b84a7..696a413 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlinesWithNonNullTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlinesWithNonNullTest.java
@@ -51,7 +51,7 @@ .addKeepMainRule(TestClassWithNonNullOnOneSide.class) .setMinApi(parameters.getApiLevel()) .allowAccessModification() - .noMinification() + .addDontObfuscate() .addOptionsModification( options -> { options.outline.threshold = 2; @@ -72,7 +72,7 @@ .addKeepMainRule(TestClassWithNonNullOnBothSides.class) .setMinApi(parameters.getApiLevel()) .allowAccessModification() - .noMinification() + .addDontObfuscate() .addOptionsModification( options -> { options.outline.threshold = 2;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/arraytypes/OutlinesWithClassArrayTypeArguments.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/arraytypes/OutlinesWithClassArrayTypeArguments.java index 8bd05e0..63aed12 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/arraytypes/OutlinesWithClassArrayTypeArguments.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/arraytypes/OutlinesWithClassArrayTypeArguments.java
@@ -61,7 +61,7 @@ .addInnerClasses(OutlinesWithClassArrayTypeArguments.class) .addKeepMainRule(TestClass.class) .setMinApi(parameters.getApiLevel()) - .noMinification() + .addDontObfuscate() .addOptionsModification( options -> { options.outline.threshold = 2;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/arraytypes/OutlinesWithInterfaceArrayTypeArguments.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/arraytypes/OutlinesWithInterfaceArrayTypeArguments.java index 5a0b120..4f6a822 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/arraytypes/OutlinesWithInterfaceArrayTypeArguments.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/arraytypes/OutlinesWithInterfaceArrayTypeArguments.java
@@ -75,7 +75,7 @@ .addKeepClassAndMembersRules(ClassImplementingIface.class) .addKeepClassAndMembersRules(OtherClassImplementingIface.class) .setMinApi(parameters.getApiLevel()) - .noMinification() + .addDontObfuscate() .addOptionsModification( options -> { options.outline.threshold = 2;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/arraytypes/OutlinesWithPrimitiveArrayTypeArguments.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/arraytypes/OutlinesWithPrimitiveArrayTypeArguments.java index 6334006..2065f83 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/arraytypes/OutlinesWithPrimitiveArrayTypeArguments.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/arraytypes/OutlinesWithPrimitiveArrayTypeArguments.java
@@ -60,7 +60,7 @@ .addInnerClasses(OutlinesWithPrimitiveArrayTypeArguments.class) .addKeepMainRule(TestClass.class) .setMinApi(parameters.getRuntime()) - .noMinification() + .addDontObfuscate() .addOptionsModification( options -> { options.outline.threshold = 2;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/b112247415/B112247415.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/b112247415/B112247415.java index 685d805..9b5e916 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/b112247415/B112247415.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/b112247415/B112247415.java
@@ -82,7 +82,7 @@ CodeInspector inspector = testForR8(parameters.getBackend()) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .addProgramClassesAndInnerClasses(TestClass.class) .addKeepMainRule(TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/b133215941/B133215941.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/b133215941/B133215941.java index 9c8eb76..ee81c79 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/b133215941/B133215941.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/b133215941/B133215941.java
@@ -70,7 +70,7 @@ .addKeepMainRule(TestClass.class) .addKeepClassAndMembersRules(ClassWithStaticMethod.class) .setMinApi(parameters.getApiLevel()) - .noMinification() + .addDontObfuscate() .addOptionsModification(options -> options.outline.threshold = 2) .compile() .inspect(this::validateOutlining)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/classtypes/B134462736.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/classtypes/B134462736.java index 883c62a..9437d1d 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/classtypes/B134462736.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/classtypes/B134462736.java
@@ -69,7 +69,7 @@ .enableConstantArgumentAnnotations() .enableNoMethodStaticizingAnnotations() .setMinApi(parameters.getApiLevel()) - .noMinification() + .addDontObfuscate() .addOptionsModification( options -> { options.outline.threshold = 2;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/primitivetypes/PrimitiveTypesTest.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/primitivetypes/PrimitiveTypesTest.java index 0e8b0ad..8385328 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/primitivetypes/PrimitiveTypesTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/primitivetypes/PrimitiveTypesTest.java
@@ -78,7 +78,7 @@ .addProgramClasses(MyStringBuilder.class) .addKeepMainRule(testClass) .setMinApi(parameters.getApiLevel()) - .noMinification() + .addDontObfuscate() .addOptionsModification( options -> { options.outline.threshold = 2;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/reflection/ForNameTest.java b/src/test/java/com/android/tools/r8/ir/optimize/reflection/ForNameTest.java index 26b927e..2e36ba3 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/reflection/ForNameTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/reflection/ForNameTest.java
@@ -145,7 +145,7 @@ .addKeepMainRule(MAIN) .addKeepAllClassesRule() .addKeepAttributes("EnclosingMethod", "InnerClasses") - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), MAIN); test(result, 4, 0); @@ -157,7 +157,7 @@ .addKeepMainRule(MAIN) .addKeepAllClassesRule() .addKeepAttributes("EnclosingMethod", "InnerClasses") - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), MAIN) .assertSuccessWithOutput(JAVA_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetClassBaseAndSubTest.java b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetClassBaseAndSubTest.java index b5daa52..8190001 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetClassBaseAndSubTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetClassBaseAndSubTest.java
@@ -42,7 +42,7 @@ @Test public void testR8() throws Exception { testForR8(parameters.getBackend()) - .noMinification() + .addDontObfuscate() .addInnerClasses(GetClassBaseAndSubTest.class) .addKeepMainRule(TestClass.class) .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetClassTest.java b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetClassTest.java index 55867a1..908ce00 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetClassTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetClassTest.java
@@ -14,7 +14,6 @@ import com.android.tools.r8.NeverInline; import com.android.tools.r8.NoHorizontalClassMerging; import com.android.tools.r8.TestParameters; -import com.android.tools.r8.utils.InternalOptions; import com.android.tools.r8.utils.ListUtils; import com.android.tools.r8.utils.StringUtils; import com.android.tools.r8.utils.codeinspector.ClassSubject; @@ -215,7 +214,7 @@ .enableInliningAnnotations() .enableNoHorizontalClassMergingAnnotations() .addKeepMainRule(MAIN) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), MAIN) .assertSuccessWithOutput(JAVA_OUTPUT)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java index 9cd0f5f..f265abe 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java
@@ -131,7 +131,7 @@ .enableInliningAnnotations() .enableNoHorizontalClassMergingAnnotations() .addKeepMainRule(main) - .noMinification() + .addDontObfuscate() .addKeepAttributes("InnerClasses", "EnclosingMethod") .addOptionsModification(this::configure) .allowAccessModification() @@ -247,7 +247,7 @@ .enableSideEffectAnnotations() .addKeepMainRule(main) .allowAccessModification() - .noMinification() + .addDontObfuscate() .addOptionsModification(this::configure) .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), main); @@ -286,7 +286,7 @@ .enableMemberValuePropagationAnnotations() .addKeepMainRule(main) .allowAccessModification() - .noMinification() + .addDontObfuscate() .addOptionsModification(this::configure) .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), main) @@ -411,7 +411,7 @@ .enableInliningAnnotations() .addKeepMainRule(main) .allowAccessModification() - .noMinification() + .addDontObfuscate() .addOptionsModification(this::configure) .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), main)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/NameThenLengthTest.java b/src/test/java/com/android/tools/r8/ir/optimize/string/NameThenLengthTest.java index b96ee7f..f49ca5e 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/string/NameThenLengthTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/string/NameThenLengthTest.java
@@ -168,7 +168,7 @@ .addProgramClasses(MAIN) .enableInliningAnnotations() .addKeepMainRule(MAIN) - .noMinification() + .addDontObfuscate() .addOptionsModification(this::configure) .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), MAIN)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/StringBuilderStoredToDeadFieldTest.java b/src/test/java/com/android/tools/r8/ir/optimize/string/StringBuilderStoredToDeadFieldTest.java index 7c27841..c840e13 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/string/StringBuilderStoredToDeadFieldTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/string/StringBuilderStoredToDeadFieldTest.java
@@ -41,7 +41,7 @@ testForR8(parameters.getBackend()) .addInnerClasses(StringBuilderStoredToDeadFieldTest.class) .addKeepMainRule(MAIN) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getRuntime()) .run(parameters.getRuntime(), MAIN) .assertSuccess()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/StringConcatenationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/string/StringConcatenationTest.java index 617fd63..277e1e3 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/string/StringConcatenationTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/string/StringConcatenationTest.java
@@ -229,7 +229,7 @@ .addProgramClasses(MAIN) .enableInliningAnnotations() .addKeepMainRule(MAIN) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), MAIN) .assertSuccessWithOutput(JAVA_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/StringToStringTest.java b/src/test/java/com/android/tools/r8/ir/optimize/string/StringToStringTest.java index a6f314d..b2ecca3 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/string/StringToStringTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/string/StringToStringTest.java
@@ -109,7 +109,7 @@ .enableInliningAnnotations() .addKeepMainRule(MAIN) .setMinApi(parameters.getRuntime()) - .noMinification() + .addDontObfuscate() .run(parameters.getRuntime(), MAIN) .assertSuccessWithOutput(JAVA_OUTPUT); test(result, 0);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/StringValueOfTest.java b/src/test/java/com/android/tools/r8/ir/optimize/string/StringValueOfTest.java index 3ea38e7..dba68cd 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/string/StringValueOfTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/string/StringValueOfTest.java
@@ -113,7 +113,7 @@ .enableMemberValuePropagationAnnotations() .addKeepMainRule(MAIN) .setMinApi(parameters.getApiLevel()) - .noMinification() + .addDontObfuscate() .addOptionsModification(this::configure) .compile() .inspect(
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/switches/SwitchMapWithEnumDependencyTest.java b/src/test/java/com/android/tools/r8/ir/optimize/switches/SwitchMapWithEnumDependencyTest.java index 14d5f18..c533bbb 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/switches/SwitchMapWithEnumDependencyTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/switches/SwitchMapWithEnumDependencyTest.java
@@ -34,7 +34,7 @@ testForR8(parameters.getBackend()) .addInnerClasses(SwitchMapWithEnumDependencyTest.class) .addKeepMainRule(TestClass.class) - .noMinification() + .addDontObfuscate() .enableInliningAnnotations() .setMinApi(parameters.getApiLevel()) .compile();
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/switches/SwitchMapWithMissingFieldTest.java b/src/test/java/com/android/tools/r8/ir/optimize/switches/SwitchMapWithMissingFieldTest.java index 707eb10..5489745 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/switches/SwitchMapWithMissingFieldTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/switches/SwitchMapWithMissingFieldTest.java
@@ -48,7 +48,7 @@ .setClassDescriptor(descriptor(IncompleteEnum.class)) .transform()) .addKeepMainRule(TestClass.class) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/switches/SwitchMapWithSubtypesTest.java b/src/test/java/com/android/tools/r8/ir/optimize/switches/SwitchMapWithSubtypesTest.java index 7bc82e8..d9180bd 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/switches/SwitchMapWithSubtypesTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/switches/SwitchMapWithSubtypesTest.java
@@ -36,7 +36,7 @@ testForR8(parameters.getBackend()) .addInnerClasses(SwitchMapWithSubtypesTest.class) .addKeepMainRule(TestClass.class) - .noMinification() + .addDontObfuscate() .enableInliningAnnotations() .setMinApi(parameters.getApiLevel()) .compile();
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/switches/SwitchMapWithUnexpectedFieldTest.java b/src/test/java/com/android/tools/r8/ir/optimize/switches/SwitchMapWithUnexpectedFieldTest.java index 167cd47..ec3c1ed 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/switches/SwitchMapWithUnexpectedFieldTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/switches/SwitchMapWithUnexpectedFieldTest.java
@@ -54,7 +54,7 @@ .setClassDescriptor(descriptor(CompleteEnum.class)) .transform()) .addKeepMainRule(TestClass.class) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InvokeMethodWithReceiverOptimizationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InvokeMethodWithReceiverOptimizationTest.java index eca11f0..55889a3 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InvokeMethodWithReceiverOptimizationTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InvokeMethodWithReceiverOptimizationTest.java
@@ -68,7 +68,7 @@ options.callSiteOptimizationOptions().setEnabled(enableArgumentPropagation)) // TODO(b/120764902): The calls to getOriginalName() below does not work in presence of // argument removal. - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), TestClass.class) .assertSuccessWithOutput(expected)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/ParameterRewritingTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/ParameterRewritingTest.java index ee595ce..17d3ccc 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/ParameterRewritingTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/ParameterRewritingTest.java
@@ -56,7 +56,7 @@ .enableInliningAnnotations() .enableNoHorizontalClassMergingAnnotations() .addOptionsModification(options -> options.enableClassInlining = false) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), TestClass.class) .assertSuccessWithOutput(expected)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/VoidReturnTypeRewritingTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/VoidReturnTypeRewritingTest.java index 16c8f61..831330d 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/VoidReturnTypeRewritingTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/VoidReturnTypeRewritingTest.java
@@ -61,7 +61,7 @@ .enableNoVerticalClassMergingAnnotations() .enableNoHorizontalClassMergingAnnotations() .addOptionsModification(options -> options.enableClassInlining = false) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), TestClass.class) .assertSuccessWithOutput(expected)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/EffectivelyUnusedNullableArgumentTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/EffectivelyUnusedNullableArgumentTest.java index f01e7b7..0f5b122 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/EffectivelyUnusedNullableArgumentTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/EffectivelyUnusedNullableArgumentTest.java
@@ -42,7 +42,7 @@ .enableInliningAnnotations() .enableNeverClassInliningAnnotations() // TODO(b/173398086): uniqueMethodWithName() does not work with argument changes. - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAndUninstantiatedTypesTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAndUninstantiatedTypesTest.java index 7ca05fb..96577a4 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAndUninstantiatedTypesTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAndUninstantiatedTypesTest.java
@@ -38,7 +38,7 @@ testForR8(parameters.getBackend()) .addInnerClasses(UnusedAndUninstantiatedTypesTest.class) .addKeepMainRule(Main.class) - .noMinification() + .addDontObfuscate() .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedinterfaces/UnusedInterfaceRemovalPackageBoundaryTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedinterfaces/UnusedInterfaceRemovalPackageBoundaryTest.java index 9c4046d..2ea0223 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/unusedinterfaces/UnusedInterfaceRemovalPackageBoundaryTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedinterfaces/UnusedInterfaceRemovalPackageBoundaryTest.java
@@ -47,7 +47,7 @@ .enableNeverClassInliningAnnotations() .enableNoVerticalClassMergingAnnotations() .setMinApi(parameters.getApiLevel()) - .noMinification() + .addDontObfuscate() .compile() .inspect( inspector -> {
diff --git a/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java b/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java index 5759deb..5cdae5d 100644 --- a/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java +++ b/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
@@ -262,7 +262,7 @@ .allowAccessModification(allowAccessModification) .allowDiagnosticWarningMessages() .enableProguardTestOptions() - .noMinification() + .addDontObfuscate() .setMinApi(testParameters.getApiLevel()) .apply(configuration) .compile()
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinDuplicateAnnotationTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinDuplicateAnnotationTest.java index f2792a4..6f65db0 100644 --- a/src/test/java/com/android/tools/r8/kotlin/KotlinDuplicateAnnotationTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/KotlinDuplicateAnnotationTest.java
@@ -80,7 +80,7 @@ .addProgramFiles(compiledJars.getForConfiguration(kotlinc, targetVersion)) .addKeepMainRule(MAIN) .addKeepRules(KEEP_RULES) - .noMinification() + .addDontObfuscate() .addOptionsModification(optionsModifier) .compile(); fail("Expect to fail"); @@ -97,7 +97,7 @@ .addProgramFiles(compiledJars.getForConfiguration(kotlinc, targetVersion)) .addKeepMainRule(MAIN) .addKeepRules(KEEP_RULES) - .noMinification() + .addDontObfuscate() .addOptionsModification(optionsModifier) .compile() .assertNoMessages();
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinIntrinsicsInlineChainTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinIntrinsicsInlineChainTest.java index f9e965c..011cc58 100644 --- a/src/test/java/com/android/tools/r8/kotlin/KotlinIntrinsicsInlineChainTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/KotlinIntrinsicsInlineChainTest.java
@@ -61,7 +61,7 @@ .allowAccessModification(allowAccessModification) .allowDiagnosticWarningMessages() .setMinApi(parameters.getApiLevel()) - .noMinification() + .addDontObfuscate() .compile() .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists.")) .run(parameters.getRuntime(), MAIN, "foobar")
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinIntrinsicsInlineTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinIntrinsicsInlineTest.java index 6d64e37..a664d59 100644 --- a/src/test/java/com/android/tools/r8/kotlin/KotlinIntrinsicsInlineTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/KotlinIntrinsicsInlineTest.java
@@ -63,7 +63,7 @@ "-keepclasseswithmembers class " + MAIN + "{", " public static *** *(...);", "}")) .allowAccessModification(allowAccessModification) .allowDiagnosticWarningMessages() - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists.")) @@ -118,7 +118,7 @@ "}")) .allowAccessModification(allowAccessModification) .allowDiagnosticWarningMessages() - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
diff --git a/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinReflectionLibTest.java b/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinReflectionLibTest.java index c53700b..0a93f62 100644 --- a/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinReflectionLibTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinReflectionLibTest.java
@@ -4,6 +4,7 @@ package com.android.tools.r8.kotlin; import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_1_3_72; +import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_1_7_0; import com.android.tools.r8.KotlinTestBase; import com.android.tools.r8.KotlinTestParameters; @@ -56,6 +57,8 @@ .addKeepAttributes(ProguardKeepAttributes.ENCLOSING_METHOD) .allowUnusedDontWarnKotlinReflectJvmInternal(kotlinc.isNot(KOTLINC_1_3_72)) .allowUnusedProguardConfigurationRules(kotlinc.isNot(KOTLINC_1_3_72)) + .allowUnusedDontWarnJavaLangClassValue( + kotlinc.getCompilerVersion().isGreaterThan(KOTLINC_1_7_0)) .apply(testBuilderConsumer) .compile() .apply(compileResultBuilder) @@ -64,7 +67,7 @@ @Test public void testAsIs() throws Exception { - test(builder -> builder.noMinification().addDontOptimize().noTreeShaking()); + test(builder -> builder.addDontObfuscate().addDontOptimize().noTreeShaking()); } @Test @@ -74,7 +77,7 @@ @Test public void testDontShrinkAndDontObfuscate() throws Exception { - test(builder -> builder.noMinification().noTreeShaking()); + test(builder -> builder.addDontObfuscate().noTreeShaking()); } @Test @@ -98,7 +101,7 @@ @Test public void testDontObfuscate() throws Exception { - test(TestShrinkerBuilder::noMinification); + test(TestShrinkerBuilder::addDontObfuscate); } }
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KStyleKotlinLambdaMergingWithEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KStyleKotlinLambdaMergingWithEnumUnboxingTest.java index b4abfb6..a3e5c28 100644 --- a/src/test/java/com/android/tools/r8/kotlin/lambda/KStyleKotlinLambdaMergingWithEnumUnboxingTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KStyleKotlinLambdaMergingWithEnumUnboxingTest.java
@@ -51,7 +51,7 @@ .allowDiagnosticWarningMessages() .enableInliningAnnotations() .enableNeverClassInliningAnnotations() - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionFunctionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionFunctionTest.java index 7a37728..619f4a1 100644 --- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionFunctionTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionFunctionTest.java
@@ -12,10 +12,12 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; import com.android.tools.r8.KotlinTestParameters; import com.android.tools.r8.TestParameters; import com.android.tools.r8.shaking.ProguardKeepAttributes; +import com.android.tools.r8.utils.Box; import com.android.tools.r8.utils.StringUtils; import com.android.tools.r8.utils.codeinspector.ClassSubject; import com.android.tools.r8.utils.codeinspector.CodeInspector; @@ -179,6 +181,43 @@ .assertSuccessWithOutput(EXPECTED); } + @Test + public void testMetadataInExtensionFunction_renamedKotlinSources() throws Exception { + assumeTrue(kotlinc.getCompilerVersion().isGreaterThanOrEqualTo(KOTLINC_1_4_20)); + Box<String> renamedKtHolder = new Box<>(); + Path libJar = + testForR8(parameters.getBackend()) + .addClasspathFiles(kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinAnnotationJar()) + .addProgramFiles(extLibJarMap.getForConfiguration(kotlinc, targetVersion)) + // Keep the B class and its interface (which has the doStuff method). + .addKeepRules("-keep class **.B") + .addKeepRules("-keep class **.I { <methods>; }") + // Keep Super, but allow minification. + .addKeepRules("-keep,allowobfuscation class **.Super") + // Keep the BKt extension function which requires metadata + // to be called with Kotlin syntax from other kotlin code. + .addKeepRules("-keep,allowobfuscation class **.BKt { <methods>; }") + .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS) + .addKeepAttributes(ProguardKeepAttributes.SIGNATURE) + .addKeepAttributes(ProguardKeepAttributes.INNER_CLASSES) + .addKeepAttributes(ProguardKeepAttributes.ENCLOSING_METHOD) + .compile() + .inspect( + inspector -> { + ClassSubject clazz = inspector.clazz(PKG + ".extension_function_lib.BKt"); + assertThat(clazz, isPresentAndRenamed()); + renamedKtHolder.set(clazz.getFinalName()); + }) + .writeToZip(); + + kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion) + .addClasspathFiles(libJar) + .addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/extension_function_app", "main")) + .setOutputPath(temp.newFolder().toPath()) + // TODO(b/242289529): Expect that we can compile without errors. + .compile(true); + } + private void inspectRenamed(CodeInspector inspector) { String superClassName = PKG + ".extension_function_lib.Super"; String bClassName = PKG + ".extension_function_lib.B";
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePrunedObjectsTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePrunedObjectsTest.java index 8532cf9..26d9934 100644 --- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePrunedObjectsTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePrunedObjectsTest.java
@@ -81,7 +81,7 @@ .addKeepClassAndMembersRules(PKG_LIB + ".SubUser") .addKeepRuntimeVisibleAnnotations() .enableProguardTestOptions() - .noMinification() + .addDontObfuscate() .compile() .inspect(this::checkPruned) .writeToZip();
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataStripTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataStripTest.java index baf09cc..d74e3d2 100644 --- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataStripTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataStripTest.java
@@ -4,6 +4,7 @@ package com.android.tools.r8.kotlin.metadata; import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_1_3_72; +import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_1_7_0; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed; @@ -57,6 +58,8 @@ .allowDiagnosticWarningMessages() .setMinApi(parameters.getApiLevel()) .allowUnusedDontWarnKotlinReflectJvmInternal(kotlinc.isNot(KOTLINC_1_3_72)) + .allowUnusedDontWarnJavaLangClassValue( + kotlinc.getCompilerVersion().isGreaterThan(KOTLINC_1_7_0)) .compile() .assertNoErrorMessages() .apply(KotlinMetadataTestBase::verifyExpectedWarningsFromKotlinReflectAndStdLib)
diff --git a/src/test/java/com/android/tools/r8/kotlin/optimize/switches/KotlinEnumSwitchTest.java b/src/test/java/com/android/tools/r8/kotlin/optimize/switches/KotlinEnumSwitchTest.java index b14aeb4..0963963 100644 --- a/src/test/java/com/android/tools/r8/kotlin/optimize/switches/KotlinEnumSwitchTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/optimize/switches/KotlinEnumSwitchTest.java
@@ -60,7 +60,7 @@ options.enableEnumSwitchMapRemoval = enableSwitchMapRemoval; }) .setMinApi(parameters.getApiLevel()) - .noMinification() + .addDontObfuscate() .allowDiagnosticWarningMessages() .compile() .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
diff --git a/src/test/java/com/android/tools/r8/kotlin/reflection/ReflectiveConstructionWithInlineClassTest.java b/src/test/java/com/android/tools/r8/kotlin/reflection/ReflectiveConstructionWithInlineClassTest.java index 3b9e678..6273755 100644 --- a/src/test/java/com/android/tools/r8/kotlin/reflection/ReflectiveConstructionWithInlineClassTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/reflection/ReflectiveConstructionWithInlineClassTest.java
@@ -100,6 +100,12 @@ .setMinApi(parameters.getApiLevel()) .addKeepMainRule(MAIN_CLASS) .addKeepClassAndMembersRules(PKG + ".Data") + // TODO(b/242158616): Figure out why this is necessary. + .applyIf( + kotlinc.getCompilerVersion().isGreaterThan(KotlinCompilerVersion.KOTLINC_1_7_0), + b -> + b.addKeepClassAndMembersRules( + "kotlin.reflect.jvm.internal.ClassValueCache$initClassValue$1")) .addKeepEnumsRule() .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS) .allowDiagnosticMessages()
diff --git a/src/test/java/com/android/tools/r8/kotlin/stringplus/StringPlusTest.java b/src/test/java/com/android/tools/r8/kotlin/stringplus/StringPlusTest.java index d189806..b3ba245 100644 --- a/src/test/java/com/android/tools/r8/kotlin/stringplus/StringPlusTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/stringplus/StringPlusTest.java
@@ -85,7 +85,7 @@ .allowDiagnosticWarningMessages() .addKeepMainRule(MAIN) .addKeepRules("-keep class " + MAIN + "{ void keepFor*(...); }") - .noMinification() + .addDontObfuscate() .compile() .inspect( inspector -> {
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainDexInliningSpuriousRootTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainDexInliningSpuriousRootTest.java index 3290031..47bd62e 100644 --- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainDexInliningSpuriousRootTest.java +++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainDexInliningSpuriousRootTest.java
@@ -84,7 +84,7 @@ .enableInliningAnnotations() .enableNoHorizontalClassMergingAnnotations() .setMinApi(parameters.getApiLevel()) - .noMinification() + .addDontObfuscate() .allowDiagnosticMessages() .compileWithExpectedDiagnostics( diagnostics ->
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainDexInliningWithTracingTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainDexInliningWithTracingTest.java index bb3b81c..50e65c9 100644 --- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainDexInliningWithTracingTest.java +++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainDexInliningWithTracingTest.java
@@ -85,7 +85,7 @@ .collectMainDexClasses() .enableInliningAnnotations() .enableNoHorizontalClassMergingAnnotations() - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .allowDiagnosticMessages() .compileWithExpectedDiagnostics(
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListMergeInRootTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListMergeInRootTest.java index 9451f9a..45df36d 100644 --- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListMergeInRootTest.java +++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListMergeInRootTest.java
@@ -42,7 +42,7 @@ .enableNeverClassInliningAnnotations() .enableNoHorizontalClassMergingAnnotations() .enableInliningAnnotations() - .noMinification() + .addDontObfuscate() .addMainDexRules( "-keep class " + Main.class.getTypeName() + " { public static void main(***); }") .addOptionsModification(
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListOutputTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListOutputTest.java index 2dd90c1..5bc57ba 100644 --- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListOutputTest.java +++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListOutputTest.java
@@ -100,7 +100,7 @@ testForR8(Backend.DEX) .addProgramClasses(HelloWorldMain.class) .noTreeShaking() - .noMinification() + .addDontObfuscate() .setMinApi(AndroidApiLevel.K) .addMainDexRuleFiles(mainDexRules) .setMainDexListConsumer(new FileConsumer(mainDexListOutput))
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java index f375004..8f1833a 100644 --- a/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java +++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
@@ -393,7 +393,7 @@ .apply(configuration) .assumeAllMethodsMayHaveSideEffects() .setMinApi(minSdk) - .noMinification() + .addDontObfuscate() .noTreeShaking() .addDontOptimize() .setMainDexListConsumer(ToolHelper.consumeString(r8MainDexListOutput::set))
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexWithSynthesizedClassesTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexWithSynthesizedClassesTest.java index 16dc8db..84d8eca 100644 --- a/src/test/java/com/android/tools/r8/maindexlist/MainDexWithSynthesizedClassesTest.java +++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexWithSynthesizedClassesTest.java
@@ -174,7 +174,7 @@ .addOptionsModification(o -> o.minimalMainDex = true) .addMainDexListClasses(TestClass.class) .addMainDexListFiles(mainDexFile) - .noMinification() + .addDontObfuscate() .noTreeShaking() .allowDiagnosticWarningMessages() .compileWithExpectedDiagnostics(
diff --git a/src/test/java/com/android/tools/r8/maindexlist/checkdiscard/MainDexListCheckDiscard.java b/src/test/java/com/android/tools/r8/maindexlist/checkdiscard/MainDexListCheckDiscard.java index 125c364..3f1fb69 100644 --- a/src/test/java/com/android/tools/r8/maindexlist/checkdiscard/MainDexListCheckDiscard.java +++ b/src/test/java/com/android/tools/r8/maindexlist/checkdiscard/MainDexListCheckDiscard.java
@@ -55,7 +55,7 @@ .addMainDexRules(keepMainProguardConfiguration(HelloWorldMain.class)) .addMainDexRules(checkDiscardRule) .noTreeShaking() - .noMinification() + .addDontObfuscate() .compile(); }
diff --git a/src/test/java/com/android/tools/r8/maindexlist/whyareyoukeeping/MainDexListWhyAreYouKeeping.java b/src/test/java/com/android/tools/r8/maindexlist/whyareyoukeeping/MainDexListWhyAreYouKeeping.java index c4a616c..0aafb8d 100644 --- a/src/test/java/com/android/tools/r8/maindexlist/whyareyoukeeping/MainDexListWhyAreYouKeeping.java +++ b/src/test/java/com/android/tools/r8/maindexlist/whyareyoukeeping/MainDexListWhyAreYouKeeping.java
@@ -86,7 +86,7 @@ R8FullTestBuilder builder = testForR8(Backend.DEX) .noTreeShaking() - .noMinification() + .addDontObfuscate() .setMinApi(AndroidApiLevel.K) .addProgramClasses(CLASSES) .addMainDexRules(keepMainProguardConfiguration(HelloWorldMain.class))
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeAlphaRenamingTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeAlphaRenamingTest.java new file mode 100644 index 0000000..a3f010d --- /dev/null +++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeAlphaRenamingTest.java
@@ -0,0 +1,55 @@ +// 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.mappingcompose; + +import static org.junit.Assert.assertEquals; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.naming.ClassNameMapper; +import com.android.tools.r8.naming.MappingComposer; +import com.android.tools.r8.utils.StringUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ComposeAlphaRenamingTest extends TestBase { + + @Parameter() public TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withNoneRuntime().build(); + } + + private static final String mapping = + StringUtils.unixLines( + "a -> b:", + " int a -> b", + " void a() -> b", + "b -> a:", + " int b -> a", + " void b() -> a"); + private static final String mappingResult = + StringUtils.unixLines( + "a -> a:", + " int a -> a", + " void a() -> a", + "b -> b:", + " int b -> b", + " void b() -> b"); + + @Test + public void testCompose() throws Exception { + ClassNameMapper mappingForFoo = ClassNameMapper.mapperFromString(mapping); + ClassNameMapper mappingForBar = ClassNameMapper.mapperFromString(mapping); + String composed = MappingComposer.compose(mappingForFoo, mappingForBar); + assertEquals(mappingResult, composed); + } +}
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeChangeLineNumberTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeChangeLineNumberTest.java new file mode 100644 index 0000000..b1ff980 --- /dev/null +++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeChangeLineNumberTest.java
@@ -0,0 +1,45 @@ +// 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.mappingcompose; + +import static org.junit.Assert.assertEquals; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.naming.ClassNameMapper; +import com.android.tools.r8.naming.MappingComposer; +import com.android.tools.r8.utils.StringUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ComposeChangeLineNumberTest extends TestBase { + + @Parameter() public TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withNoneRuntime().build(); + } + + private static final String mappingFoo = + StringUtils.unixLines("com.foo -> a:", " 1:1:void m():42:42 -> m"); + private static final String mappingBar = + StringUtils.unixLines("a -> b:", " 2:2:void m():1:1 -> m"); + private static final String mappingResult = + StringUtils.unixLines("com.foo -> b:", " 2:2:void m():42:42 -> m"); + + @Test + public void testCompose() throws Exception { + ClassNameMapper mappingForFoo = ClassNameMapper.mapperFromString(mappingFoo); + ClassNameMapper mappingForBar = ClassNameMapper.mapperFromString(mappingBar); + String composed = MappingComposer.compose(mappingForFoo, mappingForBar); + assertEquals(mappingResult, composed); + } +}
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeChangeMethodAndLineNumberTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeChangeMethodAndLineNumberTest.java new file mode 100644 index 0000000..c0fe2b7 --- /dev/null +++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeChangeMethodAndLineNumberTest.java
@@ -0,0 +1,45 @@ +// 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.mappingcompose; + +import static org.junit.Assert.assertEquals; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.naming.ClassNameMapper; +import com.android.tools.r8.naming.MappingComposer; +import com.android.tools.r8.utils.StringUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ComposeChangeMethodAndLineNumberTest extends TestBase { + + @Parameter() public TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withNoneRuntime().build(); + } + + private static final String mappingFoo = + StringUtils.unixLines("com.foo -> a:", " 1:1:void m1():42:42 -> m2"); + private static final String mappingBar = + StringUtils.unixLines("a -> b:", " 2:2:void m2():1:1 -> m3"); + private static final String mappingResult = + StringUtils.unixLines("com.foo -> b:", " 2:2:void m1():42:42 -> m3"); + + @Test + public void testCompose() throws Exception { + ClassNameMapper mappingForFoo = ClassNameMapper.mapperFromString(mappingFoo); + ClassNameMapper mappingForBar = ClassNameMapper.mapperFromString(mappingBar); + String composed = MappingComposer.compose(mappingForFoo, mappingForBar); + assertEquals(mappingResult, composed); + } +}
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeChangeMethodTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeChangeMethodTest.java new file mode 100644 index 0000000..83026e6 --- /dev/null +++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeChangeMethodTest.java
@@ -0,0 +1,44 @@ +// 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.mappingcompose; + +import static org.junit.Assert.assertEquals; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.naming.ClassNameMapper; +import com.android.tools.r8.naming.MappingComposer; +import com.android.tools.r8.utils.StringUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ComposeChangeMethodTest extends TestBase { + + @Parameter() public TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withNoneRuntime().build(); + } + + private static final String mappingFoo = + StringUtils.unixLines("com.foo -> a:", " void f1() -> f2"); + private static final String mappingBar = StringUtils.unixLines("a -> b:", " void f2() -> f3"); + private static final String mappingResult = + StringUtils.unixLines("com.foo -> b:", " void f1() -> f3"); + + @Test + public void testCompose() throws Exception { + ClassNameMapper mappingForFoo = ClassNameMapper.mapperFromString(mappingFoo); + ClassNameMapper mappingForBar = ClassNameMapper.mapperFromString(mappingBar); + String composed = MappingComposer.compose(mappingForFoo, mappingForBar); + assertEquals(mappingResult, composed); + } +}
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeDifferentMethodTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeDifferentMethodTest.java new file mode 100644 index 0000000..a145c17 --- /dev/null +++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeDifferentMethodTest.java
@@ -0,0 +1,48 @@ +// 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.mappingcompose; + +import static org.junit.Assert.assertEquals; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.naming.ClassNameMapper; +import com.android.tools.r8.naming.MappingComposer; +import com.android.tools.r8.utils.StringUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ComposeDifferentMethodTest extends TestBase { + + @Parameter() public TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withNoneRuntime().build(); + } + + // Here we are testing that a shrinker could have changed the method signature. Since we have no + // right hand side mapping we have no other choice than to map the naming through. This would not + // be ok if we had overloads but any shrinker should put in line numbering for those. + private static final String mappingFoo = + StringUtils.unixLines("com.foo -> a:", " void f1(int) -> f2"); + private static final String mappingBar = + StringUtils.unixLines("a -> b:", " int f2(boolean) -> f3"); + private static final String mappingResult = + StringUtils.unixLines("com.foo -> b:", " void f1(int) -> f3"); + + @Test + public void testCompose() throws Exception { + ClassNameMapper mappingForFoo = ClassNameMapper.mapperFromString(mappingFoo); + ClassNameMapper mappingForBar = ClassNameMapper.mapperFromString(mappingBar); + String composed = MappingComposer.compose(mappingForFoo, mappingForBar); + assertEquals(mappingResult, composed); + } +}
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeDifferentMethodWithLineNumberTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeDifferentMethodWithLineNumberTest.java new file mode 100644 index 0000000..a9b4d44 --- /dev/null +++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeDifferentMethodWithLineNumberTest.java
@@ -0,0 +1,47 @@ +// 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.mappingcompose; + +import static org.junit.Assert.assertEquals; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.naming.ClassNameMapper; +import com.android.tools.r8.naming.MappingComposer; +import com.android.tools.r8.utils.StringUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ComposeDifferentMethodWithLineNumberTest extends TestBase { + + @Parameter() public TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withNoneRuntime().build(); + } + + private static final String mappingFoo = + StringUtils.unixLines( + "com.foo -> a:", " 1:1:int f1(boolean) -> f2", " 2:2:void f1(int) -> f2"); + private static final String mappingBar = + StringUtils.unixLines("a -> b:", " 8:8:void f2(boolean):2:2 -> f3"); + private static final String mappingResult = + StringUtils.unixLines( + "com.foo -> b:", " 1:1:int f1(boolean) -> f2", " 8:8:void f1(int) -> f3"); + + @Test + public void testCompose() throws Exception { + ClassNameMapper mappingForFoo = ClassNameMapper.mapperFromString(mappingFoo); + ClassNameMapper mappingForBar = ClassNameMapper.mapperFromString(mappingBar); + String composed = MappingComposer.compose(mappingForFoo, mappingForBar); + assertEquals(mappingResult, composed); + } +}
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeDistinctClassesTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeDistinctClassesTest.java new file mode 100644 index 0000000..e226de7 --- /dev/null +++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeDistinctClassesTest.java
@@ -0,0 +1,41 @@ +// 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.mappingcompose; + +import static org.junit.Assert.assertEquals; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.naming.ClassNameMapper; +import com.android.tools.r8.naming.MappingComposer; +import com.android.tools.r8.utils.StringUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ComposeDistinctClassesTest extends TestBase { + + @Parameter() public TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withNoneRuntime().build(); + } + + private static final String mappingFoo = StringUtils.unixLines("com.foo -> a:"); + private static final String mappingBar = StringUtils.unixLines("com.bar -> b:"); + + @Test + public void testCompose() throws Exception { + ClassNameMapper mappingForFoo = ClassNameMapper.mapperFromString(mappingFoo); + ClassNameMapper mappingForBar = ClassNameMapper.mapperFromString(mappingBar); + String composed = MappingComposer.compose(mappingForFoo, mappingForBar); + assertEquals(mappingBar + mappingFoo, composed); + } +}
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeDuplicateClassMappingTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeDuplicateClassMappingTest.java new file mode 100644 index 0000000..cd2c32d --- /dev/null +++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeDuplicateClassMappingTest.java
@@ -0,0 +1,48 @@ +// 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.mappingcompose; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.naming.ClassNameMapper; +import com.android.tools.r8.naming.MappingComposeException; +import com.android.tools.r8.naming.MappingComposer; +import com.android.tools.r8.utils.StringUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ComposeDuplicateClassMappingTest extends TestBase { + + @Parameter() public TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withNoneRuntime().build(); + } + + private static final String mappingFoo = StringUtils.unixLines("com.foo -> b:"); + private static final String mappingBar = StringUtils.unixLines("a -> b:"); + + @Test + public void testCompose() throws Exception { + ClassNameMapper mappingForFoo = ClassNameMapper.mapperFromString(mappingFoo); + ClassNameMapper mappingForBar = ClassNameMapper.mapperFromString(mappingBar); + MappingComposeException mappingComposeException = + assertThrows( + MappingComposeException.class, + () -> MappingComposer.compose(mappingForFoo, mappingForBar)); + assertEquals( + "Duplicate class mapping. Both 'com.foo' and 'a' maps to 'b'.", + mappingComposeException.getMessage()); + } +}
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeFieldNameTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeFieldNameTest.java new file mode 100644 index 0000000..0834ed7 --- /dev/null +++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeFieldNameTest.java
@@ -0,0 +1,44 @@ +// 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.mappingcompose; + +import static org.junit.Assert.assertEquals; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.naming.ClassNameMapper; +import com.android.tools.r8.naming.MappingComposer; +import com.android.tools.r8.utils.StringUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ComposeFieldNameTest extends TestBase { + + @Parameter() public TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withNoneRuntime().build(); + } + + private static final String mappingFoo = + StringUtils.unixLines("com.foo -> a:", " int f1 -> f2"); + private static final String mappingBar = StringUtils.unixLines("a -> b:", " int f2 -> f3"); + private static final String mappingResult = + StringUtils.unixLines("com.foo -> b:", " int f1 -> f3"); + + @Test + public void testCompose() throws Exception { + ClassNameMapper mappingForFoo = ClassNameMapper.mapperFromString(mappingFoo); + ClassNameMapper mappingForBar = ClassNameMapper.mapperFromString(mappingBar); + String composed = MappingComposer.compose(mappingForFoo, mappingForBar); + assertEquals(mappingResult, composed); + } +}
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeFieldWithAmbiguousTypeTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeFieldWithAmbiguousTypeTest.java new file mode 100644 index 0000000..d4fedec --- /dev/null +++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeFieldWithAmbiguousTypeTest.java
@@ -0,0 +1,49 @@ +// 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.mappingcompose; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.naming.ClassNameMapper; +import com.android.tools.r8.naming.MappingComposeException; +import com.android.tools.r8.naming.MappingComposer; +import com.android.tools.r8.utils.StringUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ComposeFieldWithAmbiguousTypeTest extends TestBase { + + @Parameter() public TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withNoneRuntime().build(); + } + + private static final String mappingFoo = + StringUtils.unixLines("com.foo -> a:", " int f1 -> f2"); + private static final String mappingBar = StringUtils.unixLines("a -> b:", " bool f2 -> f3"); + + @Test + public void testCompose() throws Exception { + ClassNameMapper mappingForFoo = ClassNameMapper.mapperFromString(mappingFoo); + ClassNameMapper mappingForBar = ClassNameMapper.mapperFromString(mappingBar); + MappingComposeException mappingComposeException = + assertThrows( + MappingComposeException.class, + () -> MappingComposer.compose(mappingForFoo, mappingForBar)); + assertEquals( + "Unable to compose field naming 'bool f2 -> f3' since the original type has changed.", + mappingComposeException.getMessage()); + } +}
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeHelpers.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeHelpers.java new file mode 100644 index 0000000..61656a3 --- /dev/null +++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeHelpers.java
@@ -0,0 +1,12 @@ +// 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.mappingcompose; + +public class ComposeHelpers { + + public static String doubleToSingleQuote(String str) { + return str.replace("\"", "'"); + } +}
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeInlineFollowedByLineNumberChangeTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeInlineFollowedByLineNumberChangeTest.java new file mode 100644 index 0000000..79bae0b --- /dev/null +++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeInlineFollowedByLineNumberChangeTest.java
@@ -0,0 +1,53 @@ +// 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.mappingcompose; + +import static org.junit.Assert.assertEquals; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.naming.ClassNameMapper; +import com.android.tools.r8.naming.MappingComposer; +import com.android.tools.r8.utils.StringUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ComposeInlineFollowedByLineNumberChangeTest extends TestBase { + + @Parameter() public TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withNoneRuntime().build(); + } + + private static final String mappingFoo = + StringUtils.unixLines( + "com.foo -> a:", + " 1:1:void inlinee2():42:42 -> x", + " 1:1:void foo.bar.baz.inlinee1():41 -> x", + " 1:1:void caller():40 -> x"); + private static final String mappingBar = + StringUtils.unixLines("a -> b:", " 2:2:void x():1:1 -> y"); + private static final String mappingResult = + StringUtils.unixLines( + "com.foo -> b:", + " 2:2:void inlinee2():42:42 -> y", + " 2:2:void foo.bar.baz.inlinee1():41 -> y", + " 2:2:void caller():40 -> y"); + + @Test + public void testCompose() throws Exception { + ClassNameMapper mappingForFoo = ClassNameMapper.mapperFromString(mappingFoo); + ClassNameMapper mappingForBar = ClassNameMapper.mapperFromString(mappingBar); + String composed = MappingComposer.compose(mappingForFoo, mappingForBar); + assertEquals(mappingResult, composed); + } +}
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeMapVersionTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeMapVersionTest.java new file mode 100644 index 0000000..bbc6c01 --- /dev/null +++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeMapVersionTest.java
@@ -0,0 +1,48 @@ +// 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.mappingcompose; + +import static com.android.tools.r8.mappingcompose.ComposeHelpers.doubleToSingleQuote; +import static org.junit.Assert.assertEquals; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.naming.ClassNameMapper; +import com.android.tools.r8.naming.MappingComposer; +import com.android.tools.r8.utils.StringUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ComposeMapVersionTest extends TestBase { + + @Parameter() public TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withNoneRuntime().build(); + } + + private static final String mappingFoo = + StringUtils.unixLines( + "# { id: 'com.android.tools.r8.mapping', version: '1.0' }", "com.foo -> a:"); + private static final String mappingBar = + StringUtils.unixLines("# { id: 'com.android.tools.r8.mapping', version: '2.0' }", "a -> b:"); + private static final String mappingResult = + StringUtils.unixLines( + "# {'id':'com.android.tools.r8.mapping','version':'2.0'}", "com.foo -> b:"); + + @Test + public void testCompose() throws Exception { + ClassNameMapper mappingForFoo = ClassNameMapper.mapperFromString(mappingFoo); + ClassNameMapper mappingForBar = ClassNameMapper.mapperFromString(mappingBar); + String composed = MappingComposer.compose(mappingForFoo, mappingForBar); + assertEquals(mappingResult, doubleToSingleQuote(composed)); + } +}
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlineTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlineTest.java new file mode 100644 index 0000000..98f1cd5 --- /dev/null +++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlineTest.java
@@ -0,0 +1,74 @@ +// 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.mappingcompose; + +import static com.android.tools.r8.mappingcompose.ComposeHelpers.doubleToSingleQuote; +import static org.junit.Assert.assertNotEquals; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.naming.ClassNameMapper; +import com.android.tools.r8.naming.MappingComposer; +import com.android.tools.r8.utils.StringUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ComposeOutlineTest extends TestBase { + + @Parameter() public TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); + } + + private static final String mappingFoo = + StringUtils.unixLines( + "# { id: 'com.android.tools.r8.mapping', version: '2.0' }", + "outline.Class -> a:", + " 1:2:int some.inlinee():75:76 -> a", + " 1:2:int outline():0 -> a", + " # { 'id':'com.android.tools.r8.outline' }", + "outline.Callsite -> x:", + " 4:4:int outlineCaller(int):23 -> s", + " 5:5:int foo.bar.baz.outlineCaller(int):98:98 -> s", + " 5:5:int outlineCaller(int):24 -> s", + " 27:27:int outlineCaller(int):0:0 -> s", + " # { 'id':'com.android.tools.r8.outlineCallsite', 'positions': { '1': 4, '2': 5 } }"); + private static final String mappingBar = + StringUtils.unixLines( + "a -> b:", + " 4:5:int a():1:2 -> m", + "x -> c:", + " 8:9:int s(int):4:5 -> o", + " 42:42:int s(int):27:27 -> o"); + private static final String mappingResult = + StringUtils.unixLines( + "# {'id':'com.android.tools.r8.mapping','version':'2.0'}", + "outline.Callsite -> c:", + " 8:8:int outlineCaller(int):23 -> o", + " 9:9:int foo.bar.baz.outlineCaller(int):98:98 -> o", + " 9:9:int outlineCaller(int):24 -> o", + " 42:42:int outlineCaller(int):0:0 -> o", + " # { 'id':'com.android.tools.r8.outlineCallsite', 'positions': { '4': 8, '5': 9 } }", + "outline.Class -> b:", + " 4:5:int some.inlinee():75:76 -> m", + " 4:5:int outline():0 -> m", + " # {'id':'com.android.tools.r8.outline'}"); + + @Test + public void testCompose() throws Exception { + ClassNameMapper mappingForFoo = ClassNameMapper.mapperFromString(mappingFoo); + ClassNameMapper mappingForBar = ClassNameMapper.mapperFromString(mappingBar); + String composed = MappingComposer.compose(mappingForFoo, mappingForBar); + // TODO(b/242682464): Update this test when the link has been added to the mapping information. + assertNotEquals(mappingResult, doubleToSingleQuote(composed)); + } +}
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeRewriteFrameTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeRewriteFrameTest.java new file mode 100644 index 0000000..cae1f89 --- /dev/null +++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeRewriteFrameTest.java
@@ -0,0 +1,64 @@ +// 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.mappingcompose; + +import static com.android.tools.r8.mappingcompose.ComposeHelpers.doubleToSingleQuote; +import static org.junit.Assert.assertEquals; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.naming.ClassNameMapper; +import com.android.tools.r8.naming.MappingComposer; +import com.android.tools.r8.utils.StringUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ComposeRewriteFrameTest extends TestBase { + + @Parameter() public TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withNoneRuntime().build(); + } + + private static final String mappingFoo = + StringUtils.unixLines( + "# { id: 'com.android.tools.r8.mapping', version: '2.0' }", + "my.CustomException -> a:", + "foo.Bar -> x:", + " 4:4:void other.Class.inlinee():23:23 -> a", + " 4:4:void caller(other.Class):7 -> a", + " # { id: 'com.android.tools.r8.rewriteFrame', " + + "conditions: ['throws(La;)'], actions: ['removeInnerFrames(1)'] }"); + private static final String mappingBar = + StringUtils.unixLines( + "# { id: 'com.android.tools.r8.mapping', version: '2.0' }", + "a -> b:", + "x -> c:", + " 8:8:void a(Other.Class):4:4 -> m"); + private static final String mappingResult = + StringUtils.unixLines( + "# {'id':'com.android.tools.r8.mapping','version':'2.0'}", + "foo.Bar -> c:", + " 8:8:void other.Class.inlinee():23:23 -> m", + " 8:8:void caller(other.Class):7 -> m", + " # {'id':'com.android.tools.r8.rewriteFrame','conditions':['throws(Lb;)']," + + "'actions':['removeInnerFrames(1)']}", + "my.CustomException -> b:"); + + @Test + public void testCompose() throws Exception { + ClassNameMapper mappingForFoo = ClassNameMapper.mapperFromString(mappingFoo); + ClassNameMapper mappingForBar = ClassNameMapper.mapperFromString(mappingBar); + String composed = MappingComposer.compose(mappingForFoo, mappingForBar); + assertEquals(mappingResult, doubleToSingleQuote(composed)); + } +}
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeSourceFileTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeSourceFileTest.java new file mode 100644 index 0000000..9ec3ec6 --- /dev/null +++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeSourceFileTest.java
@@ -0,0 +1,51 @@ +// 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.mappingcompose; + +import static com.android.tools.r8.mappingcompose.ComposeHelpers.doubleToSingleQuote; +import static org.junit.Assert.assertEquals; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.naming.ClassNameMapper; +import com.android.tools.r8.naming.MappingComposer; +import com.android.tools.r8.utils.StringUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ComposeSourceFileTest extends TestBase { + + @Parameter() public TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withNoneRuntime().build(); + } + + private static final String mappingFoo = + StringUtils.unixLines("com.foo -> a:", " # {'id':'sourceFile','fileName':'Foo.kt'}"); + private static final String mappingBar = + StringUtils.unixLines( + "com.bar -> c:", " # {'id':'sourceFile','fileName':'Bar.kt'}", "a -> b:"); + private static final String mappingResult = + StringUtils.unixLines( + "com.bar -> c:", + "# {'id':'sourceFile','fileName':'Bar.kt'}", + "com.foo -> b:", + "# {'id':'sourceFile','fileName':'Foo.kt'}"); + + @Test + public void testCompose() throws Exception { + ClassNameMapper mappingForFoo = ClassNameMapper.mapperFromString(mappingFoo); + ClassNameMapper mappingForBar = ClassNameMapper.mapperFromString(mappingBar); + String composed = MappingComposer.compose(mappingForFoo, mappingForBar); + assertEquals(mappingResult, doubleToSingleQuote(composed)); + } +}
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeSplitRangeStartTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeSplitRangeStartTest.java new file mode 100644 index 0000000..82cb66d --- /dev/null +++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeSplitRangeStartTest.java
@@ -0,0 +1,57 @@ +// 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.mappingcompose; + +import static org.junit.Assert.assertEquals; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.naming.ClassNameMapper; +import com.android.tools.r8.naming.MappingComposer; +import com.android.tools.r8.utils.StringUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ComposeSplitRangeStartTest extends TestBase { + + @Parameter() public TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withNoneRuntime().build(); + } + + private static final String mappingFoo = + StringUtils.unixLines( + "com.foo -> a:", " 1:5:void m():41:45 -> x", " 6:10:void m():56:60 -> x"); + private static final String mappingBar = + StringUtils.unixLines( + "a -> b:", + " 11:12:void x():1:2 -> y", + " 13:17:void x():3:7 -> y", + " 18:24:void x():8:8 -> y", + " 25:26:void x():9:10 -> y"); + private static final String mappingResult = + StringUtils.unixLines( + "com.foo -> b:", + " 11:12:void m():41:42 -> y", + " 13:15:void m():43:45 -> y", + " 16:17:void m():56:57 -> y", + " 18:24:void m():58:58 -> y", + " 25:26:void m():59:60 -> y"); + + @Test + public void testCompose() throws Exception { + ClassNameMapper mappingForFoo = ClassNameMapper.mapperFromString(mappingFoo); + ClassNameMapper mappingForBar = ClassNameMapper.mapperFromString(mappingBar); + String composed = MappingComposer.compose(mappingForFoo, mappingForBar); + assertEquals(mappingResult, composed); + } +}
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeSyntheticTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeSyntheticTest.java new file mode 100644 index 0000000..20585e9 --- /dev/null +++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeSyntheticTest.java
@@ -0,0 +1,71 @@ +// 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.mappingcompose; + +import static com.android.tools.r8.mappingcompose.ComposeHelpers.doubleToSingleQuote; +import static org.junit.Assert.assertEquals; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.naming.ClassNameMapper; +import com.android.tools.r8.naming.MappingComposer; +import com.android.tools.r8.utils.StringUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ComposeSyntheticTest extends TestBase { + + @Parameter() public TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withNoneRuntime().build(); + } + + private static final String mappingFoo = + StringUtils.unixLines( + "# { id: 'com.android.tools.r8.mapping', version: '1.0' }", + "com.foo -> a:", + "# { id: 'com.android.tools.r8.synthesized' }", + " int f -> a", + " # { id: 'com.android.tools.r8.synthesized' }", + " void m() -> b", + " # { id: 'com.android.tools.r8.synthesized' }"); + private static final String mappingBar = + StringUtils.unixLines( + "# { id: 'com.android.tools.r8.mapping', version: '1.0' }", + "a -> b:", + " int a -> b", + "com.bar -> c:", + "# { id: 'com.android.tools.r8.synthesized' }", + " void bar() -> a", + " # { id: 'com.android.tools.r8.synthesized' }"); + private static final String mappingResult = + StringUtils.unixLines( + "# {'id':'com.android.tools.r8.mapping','version':'1.0'}", + "com.bar -> c:", + "# {'id':'com.android.tools.r8.synthesized'}", + " void bar() -> a", + " # {'id':'com.android.tools.r8.synthesized'}", + "com.foo -> b:", + "# {'id':'com.android.tools.r8.synthesized'}", + " int f -> b", + // TODO(b/242673239): When fixed, we should emit synthetized info here as well. + " void m() -> b", + " # {'id':'com.android.tools.r8.synthesized'}"); + + @Test + public void testCompose() throws Exception { + ClassNameMapper mappingForFoo = ClassNameMapper.mapperFromString(mappingFoo); + ClassNameMapper mappingForBar = ClassNameMapper.mapperFromString(mappingBar); + String composed = MappingComposer.compose(mappingForFoo, mappingForBar); + assertEquals(mappingResult, doubleToSingleQuote(composed)); + } +}
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingRemoveInterfaceBridgeWithSubTypeTest.java b/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingRemoveInterfaceBridgeWithSubTypeTest.java index 25674a2..4551dbe 100644 --- a/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingRemoveInterfaceBridgeWithSubTypeTest.java +++ b/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingRemoveInterfaceBridgeWithSubTypeTest.java
@@ -56,7 +56,7 @@ .enableNoVerticalClassMergingAnnotations() .addHorizontallyMergedClassesInspector( HorizontallyMergedClassesInspector::assertNoClassesMerged) - .noMinification() + .addDontObfuscate() .run(parameters.getRuntime(), newMainTypeName) .assertSuccessWithOutputLines("B::foo") .inspect(
diff --git a/src/test/java/com/android/tools/r8/naming/ClassNameMinifierOriginalClassNameTest.java b/src/test/java/com/android/tools/r8/naming/ClassNameMinifierOriginalClassNameTest.java index 779eb8a..bd76317 100644 --- a/src/test/java/com/android/tools/r8/naming/ClassNameMinifierOriginalClassNameTest.java +++ b/src/test/java/com/android/tools/r8/naming/ClassNameMinifierOriginalClassNameTest.java
@@ -74,7 +74,7 @@ .addProgramClasses(Main.class) .setMinApi(parameters.getApiLevel()) .addKeepMainRule(Main.class) - .noMinification() + .addDontObfuscate() .addClasspathClasses(A.class, B.class) .addApplyMapping(libraryCompileResult.getProguardMap()) .compile() @@ -94,7 +94,7 @@ .addProgramClasses(MainWithReferenceToNotMapped.class) .setMinApi(parameters.getApiLevel()) .addKeepMainRule(MainWithReferenceToNotMapped.class) - .noMinification() + .addDontObfuscate() .addClasspathClasses(A.class, B.class) .addApplyMapping(libraryCompileResult.getProguardMap()) .allowDiagnosticWarningMessages()
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterDevirtualizationTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterDevirtualizationTest.java index 5b13f6b..efb32a2 100644 --- a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterDevirtualizationTest.java +++ b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterDevirtualizationTest.java
@@ -127,7 +127,7 @@ testForR8(parameters.getBackend()) .noTreeShaking() - .noMinification() + .addDontObfuscate() .addProgramClasses(PROGRAM_CLASSES) .addApplyMapping(libraryResult.getProguardMap()) .addClasspathClasses(CLASSPATH_CLASSES) @@ -160,7 +160,7 @@ testForR8(parameters.getBackend()) .noTreeShaking() - .noMinification() + .addDontObfuscate() .addProgramClasses(PROGRAM_CLASSES) .addApplyMapping(libraryResult.getProguardMap()) .addClasspathClasses(CLASSPATH_CLASSES)
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterHorizontalMergingFieldTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterHorizontalMergingFieldTest.java index 98ead74..3311270 100644 --- a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterHorizontalMergingFieldTest.java +++ b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterHorizontalMergingFieldTest.java
@@ -104,7 +104,7 @@ testForR8(parameters.getBackend()) .noTreeShaking() - .noMinification() + .addDontObfuscate() .addProgramClasses(PROGRAM_CLASSES) .addApplyMapping(libraryResult.getProguardMap()) .addLibraryClasses(LIBRARY_CLASSES)
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterHorizontalMergingMethodTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterHorizontalMergingMethodTest.java index e101caa..ac2e989 100644 --- a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterHorizontalMergingMethodTest.java +++ b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterHorizontalMergingMethodTest.java
@@ -110,7 +110,7 @@ testForR8(backend) .noTreeShaking() - .noMinification() + .addDontObfuscate() .addProgramClasses(PROGRAM_CLASSES) .addApplyMapping(libraryResult.getProguardMap()) .addLibraryClasses(LIBRARY_CLASSES)
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingFieldTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingFieldTest.java index a7a51fd..0fe35cb 100644 --- a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingFieldTest.java +++ b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingFieldTest.java
@@ -90,7 +90,7 @@ testForR8(backend) .noTreeShaking() - .noMinification() + .addDontObfuscate() .addProgramClasses(PROGRAM_CLASSES) .addApplyMapping(libraryResult.getProguardMap()) .addLibraryClasses(LIBRARY_CLASSES)
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingMethodTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingMethodTest.java index 198fcde..609465f 100644 --- a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingMethodTest.java +++ b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingMethodTest.java
@@ -135,7 +135,7 @@ throws CompilationFailedException { return testForR8(staticTemp, backend) .noTreeShaking() - .noMinification() + .addDontObfuscate() .addProgramClasses(PROGRAM_CLASSES) .addApplyMapping(proguardMap) .addLibraryClasses(LIBRARY_CLASSES)
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingInterfaceInvokeTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingInterfaceInvokeTest.java index b4b6807..8c7e804 100644 --- a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingInterfaceInvokeTest.java +++ b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingInterfaceInvokeTest.java
@@ -73,7 +73,7 @@ testForR8(parameters.getBackend()) .addClasspathClasses(classPathClasses) .addProgramClasses(TestApp.class) - .noMinification() + .addDontObfuscate() .noTreeShaking() .addApplyMapping(libraryResult.getProguardMap()) .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingVirtualInvokeTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingVirtualInvokeTest.java index 84a7f62..ff9f9b4 100644 --- a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingVirtualInvokeTest.java +++ b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingVirtualInvokeTest.java
@@ -157,7 +157,7 @@ libraryCompileResult.writeToZip(outPath); testForR8(parameters.getBackend()) .noTreeShaking() - .noMinification() + .addDontObfuscate() .addProgramClasses(PROGRAM_CLASSES) .addApplyMapping(libraryCompileResult.getProguardMap()) .addClasspathClasses(LIBRARY_CLASSES)
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/shared/NameClashTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/shared/NameClashTest.java index 3466e21..5d1c231 100644 --- a/src/test/java/com/android/tools/r8/naming/applymapping/shared/NameClashTest.java +++ b/src/test/java/com/android/tools/r8/naming/applymapping/shared/NameClashTest.java
@@ -139,7 +139,7 @@ .addKeepMainRule(MAIN) .addKeepRules("-applymapping " + mappingFile) .noTreeShaking() - .noMinification() + .addDontObfuscate() .compile() .run(MAIN) .assertSuccessWithOutput(EXPECTED_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/naming/arraytypes/ArrayTypesTest.java b/src/test/java/com/android/tools/r8/naming/arraytypes/ArrayTypesTest.java index 8100e16..031571e 100644 --- a/src/test/java/com/android/tools/r8/naming/arraytypes/ArrayTypesTest.java +++ b/src/test/java/com/android/tools/r8/naming/arraytypes/ArrayTypesTest.java
@@ -102,7 +102,7 @@ .addProgramClassFileData(generateTestClass()) .addKeepMainRule(Main.class) .addKeepRules("-applymapping " + mappingFile.toAbsolutePath()) - .noMinification() + .addDontObfuscate() .noTreeShaking() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/naming/signature/SignatureOfMergedClassesTest.java b/src/test/java/com/android/tools/r8/naming/signature/SignatureOfMergedClassesTest.java index 7511e28..5f58326 100644 --- a/src/test/java/com/android/tools/r8/naming/signature/SignatureOfMergedClassesTest.java +++ b/src/test/java/com/android/tools/r8/naming/signature/SignatureOfMergedClassesTest.java
@@ -61,7 +61,7 @@ .addKeepClassRules(InterfaceToKeep.class, ImplI.class, K.class) .addKeepAttributes("Signature, InnerClasses, EnclosingMethod, *Annotation*") .setMinApi(parameters.getApiLevel()) - .noMinification() + .addDontObfuscate() .addOptionsModification( internalOptions -> { internalOptions.enableUnusedInterfaceRemoval = false; @@ -92,7 +92,7 @@ .addKeepClassRules(InterfaceToKeep.class) .addKeepAttributes("Signature, InnerClasses, EnclosingMethod, *Annotation*") .setMinApi(parameters.getApiLevel()) - .noMinification() + .addDontObfuscate() .addOptionsModification( internalOptions -> { internalOptions.enableUnusedInterfaceRemoval = false;
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/CheckNotZeroMethodWithArgumentRemovalTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/CheckNotZeroMethodWithArgumentRemovalTest.java index 3685b5c..20b82f0 100644 --- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/CheckNotZeroMethodWithArgumentRemovalTest.java +++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/CheckNotZeroMethodWithArgumentRemovalTest.java
@@ -39,7 +39,7 @@ .addEnumUnboxingInspector(inspector -> inspector.assertUnboxed(MyEnum.class)) .enableInliningAnnotations() // TODO(b/173398086): uniqueMethodWithName() does not work with argument removal. - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ConsistentMethodRenamingWithArgumentRemovalAndStaticizingTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ConsistentMethodRenamingWithArgumentRemovalAndStaticizingTest.java new file mode 100644 index 0000000..e8daac4 --- /dev/null +++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ConsistentMethodRenamingWithArgumentRemovalAndStaticizingTest.java
@@ -0,0 +1,78 @@ +// 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.optimize.argumentpropagation; + +import com.android.tools.r8.NeverClassInline; +import com.android.tools.r8.NeverInline; +import com.android.tools.r8.NoHorizontalClassMerging; +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +/** Reproduction of b/241426917. */ +@RunWith(Parameterized.class) +public class ConsistentMethodRenamingWithArgumentRemovalAndStaticizingTest extends TestBase { + + @Parameter(0) + public TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); + } + + @Test + public void test() throws Exception { + testForR8(parameters.getBackend()) + .addInnerClasses(getClass()) + .addKeepMainRule(Main.class) + .enableInliningAnnotations() + .enableNeverClassInliningAnnotations() + .enableNoHorizontalClassMergingAnnotations() + .setMinApi(parameters.getApiLevel()) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines("A.m()", "B.m()"); + } + + static class Main { + + public static void main(String[] args) { + String used = System.currentTimeMillis() > 0 ? "A.m()" : null; + new A().m(used); + + String unused = null; + B.m(unused); + } + } + + // To force A and B into the same strongly connected component. + static class Parent {} + + @NeverClassInline + @NoHorizontalClassMerging + static class A extends Parent { + + // Will have its receiver argument removed (i.e., the method is staticized). + @NeverInline + void m(String used) { + System.out.println(used); + } + } + + @NoHorizontalClassMerging + static class B extends Parent { + + // Will have its first argument removed. + @NeverInline + static void m(String unused) { + System.out.println("B.m()"); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ConstantReturnAfterArgumentPropagationTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ConstantReturnAfterArgumentPropagationTest.java index ba07988..3e410db 100644 --- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ConstantReturnAfterArgumentPropagationTest.java +++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ConstantReturnAfterArgumentPropagationTest.java
@@ -38,7 +38,7 @@ .addKeepMainRule(Main.class) .enableInliningAnnotations() // TODO(b/173398086): uniqueMethodWithName() does not work with argument removal. - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ConstantUnboxedEnumArgumentTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ConstantUnboxedEnumArgumentTest.java index 7c4f463..562c3b5 100644 --- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ConstantUnboxedEnumArgumentTest.java +++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ConstantUnboxedEnumArgumentTest.java
@@ -41,7 +41,7 @@ .addEnumUnboxingInspector(inspector -> inspector.assertUnboxed(MyEnum.class)) .enableInliningAnnotations() // TODO(b/173398086): uniqueMethodWithName() does not work with argument removal. - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/EffectivelyFinalCompanionMethodsTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/EffectivelyFinalCompanionMethodsTest.java index 67af262..86ab638 100644 --- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/EffectivelyFinalCompanionMethodsTest.java +++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/EffectivelyFinalCompanionMethodsTest.java
@@ -42,7 +42,7 @@ .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .enableNoHorizontalClassMergingAnnotations() - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/MixedArgumentRemovalAndEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/MixedArgumentRemovalAndEnumUnboxingTest.java index 71d2f1c..65c3ce8 100644 --- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/MixedArgumentRemovalAndEnumUnboxingTest.java +++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/MixedArgumentRemovalAndEnumUnboxingTest.java
@@ -41,7 +41,7 @@ .addEnumUnboxingInspector(inspector -> inspector.assertUnboxed(MyEnum.class)) .enableInliningAnnotations() // TODO(b/173398086): uniqueMethodWithName() does not work with argument removal. - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/MonomorphicMethodWithUnusedReturnValueTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/MonomorphicMethodWithUnusedReturnValueTest.java index d7130ef..0df2eff 100644 --- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/MonomorphicMethodWithUnusedReturnValueTest.java +++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/MonomorphicMethodWithUnusedReturnValueTest.java
@@ -38,7 +38,7 @@ .addKeepMainRule(Main.class) .enableInliningAnnotations() // TODO(b/173398086): uniqueMethodWithName() does not work with proto changes. - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ParameterTypeStrengtheningTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ParameterTypeStrengtheningTest.java index 91abde9..42d8535 100644 --- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ParameterTypeStrengtheningTest.java +++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ParameterTypeStrengtheningTest.java
@@ -42,7 +42,7 @@ .enableNeverClassInliningAnnotations() .enableNoHorizontalClassMergingAnnotations() // TODO(b/173398086): uniqueMethodWithName() does not work with argument changes. - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/PolymorphicMethodWithUnusedReturnValueTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/PolymorphicMethodWithUnusedReturnValueTest.java index e8007c3..fcf44bb 100644 --- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/PolymorphicMethodWithUnusedReturnValueTest.java +++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/PolymorphicMethodWithUnusedReturnValueTest.java
@@ -40,7 +40,7 @@ .enableNoHorizontalClassMergingAnnotations() .enableNoVerticalClassMergingAnnotations() // TODO(b/173398086): uniqueMethodWithName() does not work with proto changes. - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ReturnTypeStrengtheningTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ReturnTypeStrengtheningTest.java index 89dccdb..b1faa74 100644 --- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ReturnTypeStrengtheningTest.java +++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ReturnTypeStrengtheningTest.java
@@ -44,7 +44,7 @@ .enableInliningAnnotations() .enableNoVerticalClassMergingAnnotations() // TODO(b/173398086): uniqueMethodWithName() does not work with argument changes. - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/StaticMethodWithConstantArgumentTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/StaticMethodWithConstantArgumentTest.java index 9b1429f..cee9ab5 100644 --- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/StaticMethodWithConstantArgumentTest.java +++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/StaticMethodWithConstantArgumentTest.java
@@ -41,7 +41,7 @@ .addKeepMainRule(Main.class) .enableInliningAnnotations() // TODO(b/173398086): uniqueMethodWithName() does not work with argument removal. - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/StaticMethodWithConstantArgumentThroughCallChainTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/StaticMethodWithConstantArgumentThroughCallChainTest.java index e33fe2a..1764b30 100644 --- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/StaticMethodWithConstantArgumentThroughCallChainTest.java +++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/StaticMethodWithConstantArgumentThroughCallChainTest.java
@@ -41,7 +41,7 @@ .addKeepMainRule(Main.class) .enableInliningAnnotations() // TODO(b/173398086): uniqueMethodWithName() does not work with argument removal. - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/UnboxedEnumUserInMethodWithConstantArgumentTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/UnboxedEnumUserInMethodWithConstantArgumentTest.java index 9a991c2..dd93e33 100644 --- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/UnboxedEnumUserInMethodWithConstantArgumentTest.java +++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/UnboxedEnumUserInMethodWithConstantArgumentTest.java
@@ -41,7 +41,7 @@ .addEnumUnboxingInspector(inspector -> inspector.assertUnboxed(MyEnum.class)) .enableInliningAnnotations() // TODO(b/173398086): uniqueMethodWithName() does not work with argument removal. - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/UpwardsArgumentPropagationToResolvedMethodTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/UpwardsArgumentPropagationToResolvedMethodTest.java index dd1d2d2..993ca6b 100644 --- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/UpwardsArgumentPropagationToResolvedMethodTest.java +++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/UpwardsArgumentPropagationToResolvedMethodTest.java
@@ -46,7 +46,7 @@ .enableNeverClassInliningAnnotations() .enableNoHorizontalClassMergingAnnotations() // TODO(b/173398086): uniqueMethodWithName() does not work with argument removal. - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(
diff --git a/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithKeptMethodTest.java b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithKeptMethodTest.java index 5f30d86..12d62c9 100644 --- a/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithKeptMethodTest.java +++ b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithKeptMethodTest.java
@@ -41,7 +41,7 @@ .enableInliningAnnotations() .enableNoHorizontalClassMergingAnnotations() // TODO(b/173398086): uniqueMethodWithName() does not work with proto changes. - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(
diff --git a/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithLibraryOverrideTest.java b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithLibraryOverrideTest.java index 31a766e..1e6a4e5 100644 --- a/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithLibraryOverrideTest.java +++ b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithLibraryOverrideTest.java
@@ -40,7 +40,7 @@ .addKeepMainRule(Main.class) .enableInliningAnnotations() // TODO(b/173398086): uniqueMethodWithName() does not work with proto changes. - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(
diff --git a/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithParameterAnnotationsTest.java b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithParameterAnnotationsTest.java index 37bfc73..e4507b5 100644 --- a/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithParameterAnnotationsTest.java +++ b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithParameterAnnotationsTest.java
@@ -47,7 +47,7 @@ .enableInliningAnnotations() .enableNoHorizontalClassMergingAnnotations() // TODO(b/173398086): uniqueMethodWithName() does not work with proto changes. - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(
diff --git a/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithVirtualMethodCollisionTest.java b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithVirtualMethodCollisionTest.java index 0e63441..de0dfe3 100644 --- a/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithVirtualMethodCollisionTest.java +++ b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithVirtualMethodCollisionTest.java
@@ -41,7 +41,7 @@ .enableInliningAnnotations() .enableNoVerticalClassMergingAnnotations() // TODO(b/173398086): uniqueMethodWithName() does not work with proto changes. - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(
diff --git a/src/test/java/com/android/tools/r8/regress/Regress181837660.java b/src/test/java/com/android/tools/r8/regress/Regress181837660.java index d1275c8..0ce8797 100644 --- a/src/test/java/com/android/tools/r8/regress/Regress181837660.java +++ b/src/test/java/com/android/tools/r8/regress/Regress181837660.java
@@ -98,7 +98,7 @@ testBuilder // Link against android.jar that contains ReflectiveOperationException. .addLibraryFiles(parameters.getDefaultAndroidJarAbove(AndroidApiLevel.K)) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()); }
diff --git a/src/test/java/com/android/tools/r8/regress/Regress241478253.java b/src/test/java/com/android/tools/r8/regress/Regress241478253.java new file mode 100644 index 0000000..8a11afd --- /dev/null +++ b/src/test/java/com/android/tools/r8/regress/Regress241478253.java
@@ -0,0 +1,65 @@ +// 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.regress; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class Regress241478253 extends TestBase { + + static final String EXPECTED = "In the Bar"; + + private final TestParameters parameters; + + @Parameterized.Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withDexRuntimes().withAllApiLevels().build(); + } + + public Regress241478253(TestParameters parameters) { + this.parameters = parameters; + } + + @Test + public void testR8() throws Exception { + testForR8(parameters.getBackend()) + .addProgramClasses(Foo.class, Bar.class) + .addKeepMainRule(Foo.class) + .setMinApi(parameters.getApiLevel()) + .run(parameters.getRuntime(), Foo.class) + .assertSuccessWithOutputLines(EXPECTED); + testForR8(parameters.getBackend()) + .debug() + .addProgramClasses(Foo.class, Bar.class) + .addKeepMainRule(Foo.class) + .setMinApi(parameters.getApiLevel()) + .run(parameters.getRuntime(), Foo.class) + .assertSuccessWithOutputLines(EXPECTED); + } + + public static class Foo { + + @SuppressWarnings("unchecked") + public static void main(String[] args) { + try { + Class<Bar> impl = + (Class<Bar>) Class.forName("com.android.tools.r8.regress.Regress241478253$Bar"); + impl.getDeclaredConstructor().newInstance(); + } catch (Exception ignored) { + throw new RuntimeException(ignored); + } + } + } + + public static class Bar { + public Bar() { + System.out.println("In the Bar"); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/regress/b151964517/ConstStringWithMonitorTest.java b/src/test/java/com/android/tools/r8/regress/b151964517/ConstStringWithMonitorTest.java index c37953b..31fcbef 100644 --- a/src/test/java/com/android/tools/r8/regress/b151964517/ConstStringWithMonitorTest.java +++ b/src/test/java/com/android/tools/r8/regress/b151964517/ConstStringWithMonitorTest.java
@@ -27,7 +27,7 @@ public void regress() throws Exception { testForR8(parameters.getBackend()) .addInnerClasses(ConstStringWithMonitorTest.class) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .allowAccessModification() .addKeepMainRule(TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/regress/b158429654/InliningNonAccessible.java b/src/test/java/com/android/tools/r8/regress/b158429654/InliningNonAccessible.java index dfed133..9cebb80 100644 --- a/src/test/java/com/android/tools/r8/regress/b158429654/InliningNonAccessible.java +++ b/src/test/java/com/android/tools/r8/regress/b158429654/InliningNonAccessible.java
@@ -32,7 +32,7 @@ .addProgramClasses(OuterAbstract.class, OuterImpl.class, InnerClass.class) .addProgramClasses(Main.class) .addKeepMainRule(Main.class) - .noMinification() + .addDontObfuscate() .run(parameters.getRuntime(), Main.class) .assertSuccessWithOutputLines("42"); }
diff --git a/src/test/java/com/android/tools/r8/regress/b158432019/StaticizerSyntheticUseTest.java b/src/test/java/com/android/tools/r8/regress/b158432019/StaticizerSyntheticUseTest.java index e07f8f1..8fde692 100644 --- a/src/test/java/com/android/tools/r8/regress/b158432019/StaticizerSyntheticUseTest.java +++ b/src/test/java/com/android/tools/r8/regress/b158432019/StaticizerSyntheticUseTest.java
@@ -42,7 +42,7 @@ .addProgramClasses(Singleton.class, Main.class, Sam.class, A.class) .addKeepClassAndMembersRules(Main.class) .setMinApi(parameters.getApiLevel()) - .noMinification() + .addDontObfuscate() .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/regress/b63935662/Regress63935662.java b/src/test/java/com/android/tools/r8/regress/b63935662/Regress63935662.java index ced781f..a3ce92b 100644 --- a/src/test/java/com/android/tools/r8/regress/b63935662/Regress63935662.java +++ b/src/test/java/com/android/tools/r8/regress/b63935662/Regress63935662.java
@@ -36,7 +36,7 @@ testBuilder .addKeepRuleFiles() .allowAccessModification() - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .run(parameters.getRuntime(), mainClass)
diff --git a/src/test/java/com/android/tools/r8/regress/b69825683/Regress69825683Test.java b/src/test/java/com/android/tools/r8/regress/b69825683/Regress69825683Test.java index eb1e0bf..e0a469c 100644 --- a/src/test/java/com/android/tools/r8/regress/b69825683/Regress69825683Test.java +++ b/src/test/java/com/android/tools/r8/regress/b69825683/Regress69825683Test.java
@@ -55,7 +55,7 @@ " synthetic void <init>(...);", "}") .addOptionsModification(options -> options.enableClassInlining = false) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), outer) // Run code to check that the constructor with synthetic class as argument is present. @@ -82,7 +82,7 @@ "-assumemayhavesideeffects class " + clazz.getName() + " {", " void <init>(...);", "}") - .noMinification() + .addDontObfuscate() .addOptionsModification(o -> o.enableClassInlining = false) .setMinApi(parameters.getApiLevel()) // Run code to check that the constructor with synthetic class as argument is present.
diff --git a/src/test/java/com/android/tools/r8/regress/b76025099/B76025099.java b/src/test/java/com/android/tools/r8/regress/b76025099/B76025099.java index e179440..79eadb7 100644 --- a/src/test/java/com/android/tools/r8/regress/b76025099/B76025099.java +++ b/src/test/java/com/android/tools/r8/regress/b76025099/B76025099.java
@@ -62,7 +62,7 @@ testForProguard() .addProgramFiles(ToolHelper.getClassFilesForTestPackage(Main.class.getPackage())) .addKeepMainRule(Main.class) - .noMinification() + .addDontObfuscate() .compile(); if (parameters.isDexRuntime()) { @@ -86,7 +86,7 @@ .addProgramFiles(ToolHelper.getClassFilesForTestPackage(Main.class.getPackage())) .addKeepMainRule(Main.class) .enableNoVerticalClassMergingAnnotations() - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(this::verifyFieldAccess)
diff --git a/src/test/java/com/android/tools/r8/regress/b78493232/Regress78493232_WithPhi.java b/src/test/java/com/android/tools/r8/regress/b78493232/Regress78493232_WithPhi.java index 7028257..b2b9dad 100644 --- a/src/test/java/com/android/tools/r8/regress/b78493232/Regress78493232_WithPhi.java +++ b/src/test/java/com/android/tools/r8/regress/b78493232/Regress78493232_WithPhi.java
@@ -90,7 +90,7 @@ .addProgramClassFileData(CLASS_BYTES) .allowDiagnosticWarningMessages() .treeShaking(treeShake) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .addOptionsModification(options -> options.testing.readInputStackMaps = false) .addKeepMainRule(MAIN)
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageDontObfuscateTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageDontObfuscateTest.java index 39b3d43..658822d 100644 --- a/src/test/java/com/android/tools/r8/repackage/RepackageDontObfuscateTest.java +++ b/src/test/java/com/android/tools/r8/repackage/RepackageDontObfuscateTest.java
@@ -61,7 +61,7 @@ .apply(this::configureRepackaging) .addInliningAnnotations() .addDontWarn(RepackageDontObfuscateTest.class) - .noMinification() + .addDontObfuscate() .compile() .inspect( inspector -> { @@ -106,7 +106,7 @@ .addKeepMainRule(Main.class) .enableInliningAnnotations() .apply(this::configureRepackaging) - .noMinification() + .addDontObfuscate() .compile(); }
diff --git a/src/test/java/com/android/tools/r8/resolution/SingleTargetExecutionTest.java b/src/test/java/com/android/tools/r8/resolution/SingleTargetExecutionTest.java index 4726fe4..12b9676 100644 --- a/src/test/java/com/android/tools/r8/resolution/SingleTargetExecutionTest.java +++ b/src/test/java/com/android/tools/r8/resolution/SingleTargetExecutionTest.java
@@ -69,7 +69,7 @@ @Test public void testR8() throws Exception { testForR8(parameters.getBackend()) - .noMinification() + .addDontObfuscate() .addProgramClasses(CLASSES) .addProgramClassFileData(ASM_CLASSES) .addKeepMainRule(Main.class)
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/ProgramAndLibraryDefinitionTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/ProgramAndLibraryDefinitionTest.java index 8494f39..e76a5b6 100644 --- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/ProgramAndLibraryDefinitionTest.java +++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/ProgramAndLibraryDefinitionTest.java
@@ -72,7 +72,7 @@ .addDontWarn(A.class, B.class) .addKeepMainRule(Main.class) .addOptionsModification(options -> options.loadAllClassDefinitions = true) - .noMinification() + .addDontObfuscate() .allowUnusedDontWarnPatterns(); byte[] libraryA = getAFromClassTestParam(this.aInLibrary); addIfNotNull(libraryA, testBuilder::addLibraryClassFileData);
diff --git a/src/test/java/com/android/tools/r8/retrace/KotlinInlineFunctionInSameFileRetraceTests.java b/src/test/java/com/android/tools/r8/retrace/KotlinInlineFunctionInSameFileRetraceTests.java index 3d3331b..8eb9f47 100644 --- a/src/test/java/com/android/tools/r8/retrace/KotlinInlineFunctionInSameFileRetraceTests.java +++ b/src/test/java/com/android/tools/r8/retrace/KotlinInlineFunctionInSameFileRetraceTests.java
@@ -99,7 +99,7 @@ .setMode(CompilationMode.RELEASE) .addKeepMainRule(MAIN) .allowDiagnosticWarningMessages() - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
diff --git a/src/test/java/com/android/tools/r8/rewrite/ScriptEngineTest.java b/src/test/java/com/android/tools/r8/rewrite/ScriptEngineTest.java index 33394dd..8a6035c 100644 --- a/src/test/java/com/android/tools/r8/rewrite/ScriptEngineTest.java +++ b/src/test/java/com/android/tools/r8/rewrite/ScriptEngineTest.java
@@ -84,7 +84,7 @@ } }) // TODO(b/136633154): This should work both with and without -dontobfuscate. - .noMinification() + .addDontObfuscate() // TODO(b/136633154): This should work both with and without -dontshrink. .noTreeShaking() .compile()
diff --git a/src/test/java/com/android/tools/r8/rewrite/ServiceLoaderRewritingTest.java b/src/test/java/com/android/tools/r8/rewrite/ServiceLoaderRewritingTest.java index cd7964f..76fe6b6 100644 --- a/src/test/java/com/android/tools/r8/rewrite/ServiceLoaderRewritingTest.java +++ b/src/test/java/com/android/tools/r8/rewrite/ServiceLoaderRewritingTest.java
@@ -282,7 +282,7 @@ .addKeepMainRule(EscapingRunner.class) .enableInliningAnnotations() .setMinApi(parameters.getApiLevel()) - .noMinification() + .addDontObfuscate() .addDataEntryResources( DataEntryResource.fromBytes( StringUtils.lines(ServiceImpl.class.getTypeName()).getBytes(),
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/RemoveAssertionsTest.java b/src/test/java/com/android/tools/r8/rewrite/assertions/RemoveAssertionsTest.java index 837b449..e5e3b29 100644 --- a/src/test/java/com/android/tools/r8/rewrite/assertions/RemoveAssertionsTest.java +++ b/src/test/java/com/android/tools/r8/rewrite/assertions/RemoveAssertionsTest.java
@@ -190,7 +190,7 @@ .addKeepMainRule(ClassWithAssertions.class) .addOptionsModification(o -> o.inlinerOptions().enableInlining = false) .allowAccessModification() - .noMinification() + .addDontObfuscate() .setMinApi(minApi) .compile(); } @@ -202,7 +202,7 @@ .addProgramClasses(ClassWithAssertions.class) .debug() .noTreeShaking() - .noMinification() + .addDontObfuscate() .addAssertionsConfiguration(transformation) .compile(); } @@ -226,7 +226,7 @@ .setMinApi(AndroidApiLevel.B) .debug() .noTreeShaking() - .noMinification() + .addDontObfuscate() .setMinApi(minApi) .compile(); } @@ -355,7 +355,7 @@ .debug() .setMinApi(minApi) .noTreeShaking() - .noMinification() + .addDontObfuscate() .compile() .writeToZip();
diff --git a/src/test/java/com/android/tools/r8/rewrite/logarguments/LogArgumentsTest.java b/src/test/java/com/android/tools/r8/rewrite/logarguments/LogArgumentsTest.java index 3e69d0b..8f37d3d 100644 --- a/src/test/java/com/android/tools/r8/rewrite/logarguments/LogArgumentsTest.java +++ b/src/test/java/com/android/tools/r8/rewrite/logarguments/LogArgumentsTest.java
@@ -36,7 +36,7 @@ .addOptionsModification( options -> options.logArgumentsFilter = ImmutableList.of(qualifiedMethodName)) .assumeAllMethodsMayHaveSideEffects() - .noMinification() + .addDontObfuscate() .noTreeShaking() .run(TestStatic.class) .getStdOut(); @@ -57,7 +57,7 @@ .addOptionsModification( options -> options.logArgumentsFilter = ImmutableList.of(qualifiedMethodName)) .assumeAllMethodsMayHaveSideEffects() - .noMinification() + .addDontObfuscate() .noTreeShaking() .run(TestInstance.class) .getStdOut();
diff --git a/src/test/java/com/android/tools/r8/rewrite/staticvalues/inlibraries/StaticLibraryValuesChangeTest.java b/src/test/java/com/android/tools/r8/rewrite/staticvalues/inlibraries/StaticLibraryValuesChangeTest.java index 16691d8..dc1d864 100644 --- a/src/test/java/com/android/tools/r8/rewrite/staticvalues/inlibraries/StaticLibraryValuesChangeTest.java +++ b/src/test/java/com/android/tools/r8/rewrite/staticvalues/inlibraries/StaticLibraryValuesChangeTest.java
@@ -83,11 +83,12 @@ .addProgramClasses(TestMain.class) .addLibraryFiles(ToolHelper.getDefaultAndroidJar()) // Compile TestMain with R8 using the second version of LibraryClass as library. - .addLibraryProvider(PreloadedClassFileProvider.fromClassData( - DescriptorUtils.javaTypeToDescriptor(LibraryClass.class.getName()), - compileTimeLibrary.buildClasses().get(0))) + .addLibraryProvider( + PreloadedClassFileProvider.fromClassData( + DescriptorUtils.javaTypeToDescriptor(LibraryClass.class.getName()), + compileTimeLibrary.buildClasses().get(0))) .noTreeShaking() - .noMinification() + .addDontObfuscate() .compile() // Merge the compiled TestMain with the runtime version of LibraryClass. .addRunClasspathFiles(lib)
diff --git a/src/test/java/com/android/tools/r8/shaking/FunctionTest.java b/src/test/java/com/android/tools/r8/shaking/FunctionTest.java index 39169a1..eda629d 100644 --- a/src/test/java/com/android/tools/r8/shaking/FunctionTest.java +++ b/src/test/java/com/android/tools/r8/shaking/FunctionTest.java
@@ -43,7 +43,7 @@ testForR8(parameters.getBackend()) .addKeepMainRule(TestClass.class) .noTreeShaking() - .noMinification() + .addDontObfuscate() .enableInliningAnnotations() .addInnerClasses(FunctionTest.class) .run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/shaking/ParameterTypeTest.java b/src/test/java/com/android/tools/r8/shaking/ParameterTypeTest.java index eeb91af..e38943c 100644 --- a/src/test/java/com/android/tools/r8/shaking/ParameterTypeTest.java +++ b/src/test/java/com/android/tools/r8/shaking/ParameterTypeTest.java
@@ -314,7 +314,7 @@ options.inlinerOptions().enableInlining = false; options.callSiteOptimizationOptions().setEnabled(enableArgumentPropagation); }) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(
diff --git a/src/test/java/com/android/tools/r8/shaking/addconfigurationdebugging/ConfigurationDebuggingTest.java b/src/test/java/com/android/tools/r8/shaking/addconfigurationdebugging/ConfigurationDebuggingTest.java index c7630ba..ac46b3f 100644 --- a/src/test/java/com/android/tools/r8/shaking/addconfigurationdebugging/ConfigurationDebuggingTest.java +++ b/src/test/java/com/android/tools/r8/shaking/addconfigurationdebugging/ConfigurationDebuggingTest.java
@@ -109,7 +109,7 @@ .addProgramClasses(BaseClass.class, UninstantiatedClass.class, TestClass.class) .addKeepRules("-addconfigurationdebugging") .addKeepRules("-keep class **.TestClass { <init>(); }") - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(this::inspect)
diff --git a/src/test/java/com/android/tools/r8/shaking/annotations/AnnotationsOnTargetedMethodTest.java b/src/test/java/com/android/tools/r8/shaking/annotations/AnnotationsOnTargetedMethodTest.java index d737c41..35dace2 100644 --- a/src/test/java/com/android/tools/r8/shaking/annotations/AnnotationsOnTargetedMethodTest.java +++ b/src/test/java/com/android/tools/r8/shaking/annotations/AnnotationsOnTargetedMethodTest.java
@@ -90,7 +90,7 @@ .enableNeverClassInliningAnnotations() .enableNoHorizontalClassMergingAnnotations() .enableNoVerticalClassMergingAnnotations() - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), TestClass.class) .assertSuccessWithOutput(
diff --git a/src/test/java/com/android/tools/r8/shaking/annotations/SerializedNameAlternateTest.java b/src/test/java/com/android/tools/r8/shaking/annotations/SerializedNameAlternateTest.java index de259e5..7d2173f 100644 --- a/src/test/java/com/android/tools/r8/shaking/annotations/SerializedNameAlternateTest.java +++ b/src/test/java/com/android/tools/r8/shaking/annotations/SerializedNameAlternateTest.java
@@ -91,7 +91,7 @@ " @" + SerializedName.class.getTypeName() + " <fields>;", "}") .setMinApi(parameters.getApiLevel()) - .noMinification() + .addDontObfuscate() .run(parameters.getRuntime(), Main.class); checkRunResult(result); } @@ -107,7 +107,7 @@ .addKeepMainRule(Main.class) .addKeepClassRules(Foo.class) .addKeepClassRules(SerializedName.class) - .noMinification() + .addDontObfuscate() .addKeepRules("-dontwarn") .run(parameters.getRuntime(), Main.class); checkRunResult(result);
diff --git a/src/test/java/com/android/tools/r8/shaking/array/DeadArrayLengthTest.java b/src/test/java/com/android/tools/r8/shaking/array/DeadArrayLengthTest.java index 03d5aa6..a4ba893 100644 --- a/src/test/java/com/android/tools/r8/shaking/array/DeadArrayLengthTest.java +++ b/src/test/java/com/android/tools/r8/shaking/array/DeadArrayLengthTest.java
@@ -78,7 +78,7 @@ .addKeepMainRule(MAIN) .enableInliningAnnotations() .enableMemberValuePropagationAnnotations() - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), MAIN) .assertSuccessWithOutput(EXPECTED_OUTPUT)
diff --git a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationTest.java b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationTest.java index b73fc3e..5d95ca0 100644 --- a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationTest.java +++ b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationTest.java
@@ -153,7 +153,7 @@ options -> options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging)) .enableInliningAnnotations() - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), MAIN) .assertSuccessWithOutput(config.expectedOutput(enableHorizontalClassMerging));
diff --git a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationWithSuperCallTest.java b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationWithSuperCallTest.java index fa8d22b..a97890a 100644 --- a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationWithSuperCallTest.java +++ b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationWithSuperCallTest.java
@@ -76,7 +76,7 @@ .addInnerClasses(AssumenosideeffectsPropagationWithSuperCallTest.class) .addKeepMainRule(MAIN) .addKeepRules(config.getKeepRules()) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), MAIN) .assertSuccessWithOutput(config.expectedOutput(parameters));
diff --git a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationWithoutMatchingDefinitionTest.java b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationWithoutMatchingDefinitionTest.java index e4edf08..ad79ff7 100644 --- a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationWithoutMatchingDefinitionTest.java +++ b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationWithoutMatchingDefinitionTest.java
@@ -52,7 +52,7 @@ "-assumenosideeffects class * implements " + LoggerInterface.class.getTypeName() + " {", " *** debug(...);", "}") - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getRuntime()) .run(parameters.getRuntime(), MAIN) .assertSuccessWithOutput(OUTPUT_WITHOUT_LOGGING)
diff --git a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsVisibleMethodsTest.java b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsVisibleMethodsTest.java index 6b053ee..73151e0 100644 --- a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsVisibleMethodsTest.java +++ b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsVisibleMethodsTest.java
@@ -156,7 +156,7 @@ .addProgramClasses(ProgramBase.class, ProgramSub.class, MAIN) .addKeepMainRule(MAIN) .addKeepRules(config.getKeepRule()) - .noMinification() + .addDontObfuscate() .enableNoVerticalClassMergingAnnotations() .enableNeverClassInliningAnnotations() .enableInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsWithMultipleTargetsTest.java b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsWithMultipleTargetsTest.java index daaacb2..41311d2 100644 --- a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsWithMultipleTargetsTest.java +++ b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsWithMultipleTargetsTest.java
@@ -98,7 +98,7 @@ .enableInliningAnnotations() .addKeepMainRule(MAIN) .addKeepRules(config.getKeepRule()) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getRuntime()) .run(parameters.getRuntime(), MAIN) .assertSuccessWithOutput(TestConfig.OUTPUT_WITHOUT_INFO)
diff --git a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsWithoutMatchingDefinitionTest.java b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsWithoutMatchingDefinitionTest.java index 010af23..0bd97f8 100644 --- a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsWithoutMatchingDefinitionTest.java +++ b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsWithoutMatchingDefinitionTest.java
@@ -114,7 +114,7 @@ .addProgramClasses(MAIN) .addKeepMainRule(MAIN) .addKeepRules(config.getKeepRule()) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getRuntime()) .compile() .addRunClasspathFiles(parameters.isDexRuntime() ? libDexPath : libJarPath)
diff --git a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsWithoutReturnValueTest.java b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsWithoutReturnValueTest.java index 3596b42..352a53c 100644 --- a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsWithoutReturnValueTest.java +++ b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsWithoutReturnValueTest.java
@@ -73,7 +73,7 @@ .enableInliningAnnotations() .addKeepMainRule(MAIN) .addKeepRules(config.getKeepRules()) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getRuntime()) .compile() .inspect(this::verifyDebugMethodIsRemoved)
diff --git a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/StringBuildersAfterAssumenosideeffectsTest.java b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/StringBuildersAfterAssumenosideeffectsTest.java index b80febc..ca28f14 100644 --- a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/StringBuildersAfterAssumenosideeffectsTest.java +++ b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/StringBuildersAfterAssumenosideeffectsTest.java
@@ -50,7 +50,7 @@ "-assumenosideeffects class * implements " + TestLogger.class.getTypeName() + " {", " void info(...);", "}") - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), MAIN) .assertSuccessWithOutput(EXPECTED)
diff --git a/src/test/java/com/android/tools/r8/shaking/assumevalues/AssumevaluesWithMultipleTargetsTest.java b/src/test/java/com/android/tools/r8/shaking/assumevalues/AssumevaluesWithMultipleTargetsTest.java index eb205d0..a6d7d67 100644 --- a/src/test/java/com/android/tools/r8/shaking/assumevalues/AssumevaluesWithMultipleTargetsTest.java +++ b/src/test/java/com/android/tools/r8/shaking/assumevalues/AssumevaluesWithMultipleTargetsTest.java
@@ -159,7 +159,7 @@ .enableInliningAnnotations() .addKeepMainRule(MAIN) .addKeepRules(config.getKeepRule()) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getRuntime()) .run(parameters.getRuntime(), MAIN) .assertSuccessWithOutput(TestConfig.OUTPUT_WITH_FULL_REPLACEMENT)
diff --git a/src/test/java/com/android/tools/r8/shaking/attributes/InnerClassesSimpleTest.java b/src/test/java/com/android/tools/r8/shaking/attributes/InnerClassesSimpleTest.java index 0474186..41de889 100644 --- a/src/test/java/com/android/tools/r8/shaking/attributes/InnerClassesSimpleTest.java +++ b/src/test/java/com/android/tools/r8/shaking/attributes/InnerClassesSimpleTest.java
@@ -41,7 +41,7 @@ .addKeepMainRule(Main.class) .addKeepPackageNamesRule(getClass().getPackage()) .noTreeShaking() - .applyIf(!minify, TestShrinkerBuilder::noMinification) + .applyIf(!minify, TestShrinkerBuilder::addDontObfuscate) .compile() .writeToZip(); testForR8(parameters.getBackend())
diff --git a/src/test/java/com/android/tools/r8/shaking/b136698023/LibraryBridgeTest.java b/src/test/java/com/android/tools/r8/shaking/b136698023/LibraryBridgeTest.java index baba02c..45286b6 100644 --- a/src/test/java/com/android/tools/r8/shaking/b136698023/LibraryBridgeTest.java +++ b/src/test/java/com/android/tools/r8/shaking/b136698023/LibraryBridgeTest.java
@@ -101,7 +101,7 @@ .addProgramClasses(ICloneable.class, BaseOrdinaryClone.class, MainWithOrdinaryClone.class) .addKeepClassAndMembersRules(ICloneable.class) .addKeepMainRule(MainWithOrdinaryClone.class) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), MainWithOrdinaryClone.class) .assertSuccessWithOutputThatMatches(containsString(BaseOrdinaryClone.class.getTypeName())); @@ -114,7 +114,7 @@ .addProgramClasses(XCloneable.class, Model.class, Main.class, Base.class) .addKeepClassAndMembersRules(XCloneable.class, Base.class) .addKeepMainRule(Main.class) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), Main.class) .assertSuccessWithOutputThatMatches(containsString(Model.class.getTypeName())); @@ -127,7 +127,7 @@ .addProgramClasses(XCloneable.class, ModelImpl.class, MainImpl.class, Base.class) .addKeepClassAndMembersRules(XCloneable.class, Base.class) .addKeepMainRule(MainImpl.class) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), MainImpl.class) .assertSuccessWithOutputThatMatches(containsString(Model.class.getTypeName())); @@ -149,7 +149,7 @@ .addKeepClassAndMembersRules(XCloneable.class) .addKeepMainRule(Main.class) .setMinApi(parameters.getApiLevel()) - .noMinification() + .addDontObfuscate() .compile() .addRunClasspathFiles(library.writeToZip()) .run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/shaking/b136698023/ProgramInterfaceNotImplementedTest.java b/src/test/java/com/android/tools/r8/shaking/b136698023/ProgramInterfaceNotImplementedTest.java index 0d41b96..970dd1e 100644 --- a/src/test/java/com/android/tools/r8/shaking/b136698023/ProgramInterfaceNotImplementedTest.java +++ b/src/test/java/com/android/tools/r8/shaking/b136698023/ProgramInterfaceNotImplementedTest.java
@@ -127,7 +127,7 @@ .addProgramClasses(I.class, clazz, main) .addKeepClassAndMembersRules(I.class) .addKeepMainRule(main) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getRuntime()) .run(parameters.getRuntime(), main) .assertSuccessWithOutputThatMatches(containsString(clazz.getTypeName())) @@ -155,7 +155,7 @@ .addKeepClassAndMembersRules(I.class) .addKeepMainRule(MainD.class) .setMinApi(parameters.getRuntime()) - .noMinification() + .addDontObfuscate() .compile() .addRunClasspathFiles(library.writeToZip()) .run(parameters.getRuntime(), MainD.class)
diff --git a/src/test/java/com/android/tools/r8/shaking/b169045091/B169045091.java b/src/test/java/com/android/tools/r8/shaking/b169045091/B169045091.java index e8f8091..fdec859 100644 --- a/src/test/java/com/android/tools/r8/shaking/b169045091/B169045091.java +++ b/src/test/java/com/android/tools/r8/shaking/b169045091/B169045091.java
@@ -59,7 +59,7 @@ .enableInliningAnnotations() .enableNoVerticalClassMergingAnnotations() .setMinApi(parameters.getApiLevel()) - .noMinification() + .addDontObfuscate() .compile() .run(parameters.getRuntime(), TestClass.class) .assertSuccessWithOutputLines("Hello world!");
diff --git a/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceInitializedByImplementationTest.java b/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceInitializedByImplementationTest.java index dcb962b..eecee11 100644 --- a/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceInitializedByImplementationTest.java +++ b/src/test/java/com/android/tools/r8/shaking/clinit/InterfaceInitializedByImplementationTest.java
@@ -46,7 +46,7 @@ .enableInliningAnnotations() .enableNoMethodStaticizingAnnotations() .setMinApi(parameters.getApiLevel()) - .noMinification() + .addDontObfuscate() .compile() .inspect(this::inspect) .run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/shaking/defaultmethods/DefaultMethodsTest.java b/src/test/java/com/android/tools/r8/shaking/defaultmethods/DefaultMethodsTest.java index 0a54cf8..ae783ee 100644 --- a/src/test/java/com/android/tools/r8/shaking/defaultmethods/DefaultMethodsTest.java +++ b/src/test/java/com/android/tools/r8/shaking/defaultmethods/DefaultMethodsTest.java
@@ -51,7 +51,7 @@ .setMinApi(parameters.getApiLevel()) .addKeepMainRule(TestClass.class) .addKeepRules(additionalKeepRules) - .noMinification() + .addDontObfuscate() .compile() .inspect(inspection); }
diff --git a/src/test/java/com/android/tools/r8/shaking/definitelynull/DefinitelyNullTest.java b/src/test/java/com/android/tools/r8/shaking/definitelynull/DefinitelyNullTest.java index c736dc1..8431fcb 100644 --- a/src/test/java/com/android/tools/r8/shaking/definitelynull/DefinitelyNullTest.java +++ b/src/test/java/com/android/tools/r8/shaking/definitelynull/DefinitelyNullTest.java
@@ -49,7 +49,7 @@ } testForR8(parameters.getBackend()) // Disable minification so that A still refers to A given on the classpath below. - .noMinification() + .addDontObfuscate() .addProgramClasses(TestClass.class, A.class) .addKeepMainRule(TestClass.class) .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java index e00615a..48f0372 100644 --- a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java +++ b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java
@@ -82,7 +82,7 @@ throws Exception { CodeInspector inspector = testForR8Compat(parameters.getBackend(), forceProguardCompatibility) - .noMinification() + .addDontObfuscate() .allowAccessModification() .addProgramClasses(mainClass, mentionedClass) .addKeepMainRule(mainClass)
diff --git a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/keepinterface/CompatKeepInterfaceAsInstantiatedTest.java b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/keepinterface/CompatKeepInterfaceAsInstantiatedTest.java index 38a6b4f..c68e841 100644 --- a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/keepinterface/CompatKeepInterfaceAsInstantiatedTest.java +++ b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/keepinterface/CompatKeepInterfaceAsInstantiatedTest.java
@@ -130,7 +130,7 @@ .applyIf( builder.isProguardTestBuilder(), b -> b.addDontWarn(CompatKeepInterfaceAsInstantiatedTest.class)) - .noMinification() + .addDontObfuscate() .addProgramClasses(main, Foo.class) .addKeepMainRule(main) .compile()
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedTypeBaseTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedTypeBaseTest.java index a482eee..385f32f 100644 --- a/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedTypeBaseTest.java +++ b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedTypeBaseTest.java
@@ -104,7 +104,7 @@ getConditionForProguardIfRule(), "-keep class " + Unused.class.getTypeName(), getAdditionalKeepRules()) - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .apply(this::configure) .run(parameters.getRuntime(), getTestClass())
diff --git a/src/test/java/com/android/tools/r8/shaking/methods/interfaces/DefaultInterfaceMethodsTest.java b/src/test/java/com/android/tools/r8/shaking/methods/interfaces/DefaultInterfaceMethodsTest.java index f75f7bd..aa1fe71 100644 --- a/src/test/java/com/android/tools/r8/shaking/methods/interfaces/DefaultInterfaceMethodsTest.java +++ b/src/test/java/com/android/tools/r8/shaking/methods/interfaces/DefaultInterfaceMethodsTest.java
@@ -72,7 +72,7 @@ .addKeepMethodRules(J.class, "void foo()") .addOptionsModification( internalOptions -> internalOptions.enableVerticalClassMerging = false) - .noMinification() + .addDontObfuscate() .compile(); // TODO(b/144269679): We should be able to compile and run this. testForR8(parameters.getBackend())
diff --git a/src/test/java/com/android/tools/r8/shaking/methods/interfaces/InterfaceDefaultMethodKeptTest.java b/src/test/java/com/android/tools/r8/shaking/methods/interfaces/InterfaceDefaultMethodKeptTest.java index b7b517b..91f4153 100644 --- a/src/test/java/com/android/tools/r8/shaking/methods/interfaces/InterfaceDefaultMethodKeptTest.java +++ b/src/test/java/com/android/tools/r8/shaking/methods/interfaces/InterfaceDefaultMethodKeptTest.java
@@ -95,7 +95,7 @@ .setMinApi(parameters.getApiLevel()) .addKeepMethodRules(A.class, "void <init>()", "void foo()") .addKeepMethodRules(B.class, "void <init>()", "void foo()") - .noMinification() + .addDontObfuscate() .compile() .inspect( codeInspector -> {
diff --git a/src/test/java/com/android/tools/r8/shaking/methods/interfaces/MultipleTargetTest.java b/src/test/java/com/android/tools/r8/shaking/methods/interfaces/MultipleTargetTest.java index 7e11e46..1fdd5d1 100644 --- a/src/test/java/com/android/tools/r8/shaking/methods/interfaces/MultipleTargetTest.java +++ b/src/test/java/com/android/tools/r8/shaking/methods/interfaces/MultipleTargetTest.java
@@ -54,7 +54,7 @@ .addProgramClasses(Top.class, Left.class, Right.class, Bottom.class) .setMinApi(parameters.getApiLevel()) .addKeepMethodRules(Bottom.class, "java.lang.String name()") - .noMinification() + .addDontObfuscate() .compile(); // TODO(b/144269679): We should be able to compile and run this. testForR8(parameters.getBackend())
diff --git a/src/test/java/com/android/tools/r8/shaking/modifiers/SyntheticAndBridgeModifiersTest.java b/src/test/java/com/android/tools/r8/shaking/modifiers/SyntheticAndBridgeModifiersTest.java index 4ef106c..6570f3f 100644 --- a/src/test/java/com/android/tools/r8/shaking/modifiers/SyntheticAndBridgeModifiersTest.java +++ b/src/test/java/com/android/tools/r8/shaking/modifiers/SyntheticAndBridgeModifiersTest.java
@@ -27,28 +27,30 @@ testForProguard() .addProgramClasses(CLASSES) .addKeepRules(keepRules) - .noMinification() + .addDontObfuscate() .compile() .disassemble() - .inspect(inspector -> { - ClassSubject clazz = - inspector.clazz(SyntheticAndBridgeModifiersTestClass.TestClass.class); - assertThat(clazz, isPresent()); - classConsumer.accept(clazz); - }); + .inspect( + inspector -> { + ClassSubject clazz = + inspector.clazz(SyntheticAndBridgeModifiersTestClass.TestClass.class); + assertThat(clazz, isPresent()); + classConsumer.accept(clazz); + }); testForR8(Backend.DEX) .addProgramClasses(CLASSES) .addKeepRules(keepRules) - .noMinification() + .addDontObfuscate() .compile() .disassemble() - .inspect(inspector -> { - ClassSubject clazz = - inspector.clazz(SyntheticAndBridgeModifiersTestClass.TestClass.class); - assertThat(clazz, isPresent()); - classConsumer.accept(clazz); - }); + .inspect( + inspector -> { + ClassSubject clazz = + inspector.clazz(SyntheticAndBridgeModifiersTestClass.TestClass.class); + assertThat(clazz, isPresent()); + classConsumer.accept(clazz); + }); } private long methodsWithNameStartingWith(ClassSubject clazz, String prefix) {
diff --git a/src/test/java/com/android/tools/r8/shaking/negatedrules/NegatedKeepRulesTest.java b/src/test/java/com/android/tools/r8/shaking/negatedrules/NegatedKeepRulesTest.java index 0468d27..57e37fe 100644 --- a/src/test/java/com/android/tools/r8/shaking/negatedrules/NegatedKeepRulesTest.java +++ b/src/test/java/com/android/tools/r8/shaking/negatedrules/NegatedKeepRulesTest.java
@@ -333,7 +333,7 @@ return testBuilder .addProgramClasses(A.class, B.class, C.class, D.class, FooBar.class, BarBar.class) .setMinApi(AndroidApiLevel.B) - .noMinification() + .addDontObfuscate() .compile(); }
diff --git a/src/test/java/com/android/tools/r8/shaking/negatedrules/NegatedMethodArgumentTest.java b/src/test/java/com/android/tools/r8/shaking/negatedrules/NegatedMethodArgumentTest.java index b4d6576..2fabb47 100644 --- a/src/test/java/com/android/tools/r8/shaking/negatedrules/NegatedMethodArgumentTest.java +++ b/src/test/java/com/android/tools/r8/shaking/negatedrules/NegatedMethodArgumentTest.java
@@ -76,7 +76,7 @@ .addKeepMainRule(TestClass.class) .addKeepRules("-keep class * { void setX(!%); }") .addKeepRules("-dontwarn **.NegatedMethodArgumentTest") - .noMinification() + .addDontObfuscate() .run(parameters.getRuntime(), TestClass.class) .inspect( inspector -> { @@ -94,7 +94,7 @@ .addKeepMainRule(TestClass.class) .addKeepRules("-keep class * { void setX(!**.*P1); }") .addKeepRules("-dontwarn **.NegatedMethodArgumentTest") - .noMinification() + .addDontObfuscate() .run(parameters.getRuntime(), TestClass.class) .inspect( inspector -> {
diff --git a/src/test/java/com/android/tools/r8/shaking/proxy/ProxiesTest.java b/src/test/java/com/android/tools/r8/shaking/proxy/ProxiesTest.java index 047a109..75b74e6 100644 --- a/src/test/java/com/android/tools/r8/shaking/proxy/ProxiesTest.java +++ b/src/test/java/com/android/tools/r8/shaking/proxy/ProxiesTest.java
@@ -67,7 +67,7 @@ o.enableDevirtualization = false; }) .enableAlwaysInliningAnnotations() - .noMinification() + .addDontObfuscate() .setMinApi(parameters.getApiLevel()) .compile() .inspect(inspection)
diff --git a/src/test/java/com/android/tools/r8/softverification/TestInstanceFieldWithOtherMembers.java b/src/test/java/com/android/tools/r8/softverification/TestInstanceFieldWithOtherMembers.java new file mode 100644 index 0000000..b13476d --- /dev/null +++ b/src/test/java/com/android/tools/r8/softverification/TestInstanceFieldWithOtherMembers.java
@@ -0,0 +1,186 @@ +// 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.softverification; + +public class TestInstanceFieldWithOtherMembers { + + public static String run() { + return run(null); + } + + public static String run(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + System.out.println(missingClass.instanceField); + } + if (System.currentTimeMillis() == 0) { + System.out.println(missingClass.instanceField); + } + String currentString = "foobar"; + for (int i = 0; i < 10; i++) { + currentString = "foobar" + (i + currentString.length()); + } + return currentString; + } + + public static String run1(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run2(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run3(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run4(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run5(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run6(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run7(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run8(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run9(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run10(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run11(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run12(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run13(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run14(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run15(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run16(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run17(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run18(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run19(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run20(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } +}
diff --git a/src/test/java/com/android/tools/r8/softverification/TestRunner.java b/src/test/java/com/android/tools/r8/softverification/TestRunner.java index dbe5ab1..a29ad21 100644 --- a/src/test/java/com/android/tools/r8/softverification/TestRunner.java +++ b/src/test/java/com/android/tools/r8/softverification/TestRunner.java
@@ -41,12 +41,18 @@ measure.start("StaticField"); TestStaticField.run(); sb.append(measure.stop()); + measure.start("StaticFieldWithOtherMembers"); + TestStaticFieldWithOtherMembers.run(); + sb.append(measure.stop()); measure.start("StaticMethod"); TestStaticMethod.run(); sb.append(measure.stop()); measure.start("InstanceField"); TestInstanceField.run(); sb.append(measure.stop()); + measure.start("InstanceFieldWithOtherMembers"); + TestInstanceFieldWithOtherMembers.run(); + sb.append(measure.stop()); measure.start("HashCode"); TestHashCode.run(); sb.append(measure.stop());
diff --git a/src/test/java/com/android/tools/r8/softverification/TestRunnerBuilder.java b/src/test/java/com/android/tools/r8/softverification/TestRunnerBuilder.java index c3f91db..c842e42 100644 --- a/src/test/java/com/android/tools/r8/softverification/TestRunnerBuilder.java +++ b/src/test/java/com/android/tools/r8/softverification/TestRunnerBuilder.java
@@ -72,9 +72,10 @@ .build(); } - private static final Path ANDROID_STUDIO_LIB_PATH = Paths.get("PATH_TO_PROJECT/libs/library.jar"); + private static final Path ANDROID_STUDIO_LIB_PATH = + Paths.get("path-to-project/app/libs/library.jar"); - private static final int COUNT = 800; + private static final int COUNT = 400; private static final List<Class<?>> referenceClasses = ImmutableList.of( @@ -86,8 +87,10 @@ TestTypeReference.class, TestNewInstance.class, TestStaticField.class, + TestStaticFieldWithOtherMembers.class, TestStaticMethod.class, TestInstanceField.class, + TestInstanceFieldWithOtherMembers.class, TestInstanceMethod.class, TestHashCode.class, TestTryCatch.class);
diff --git a/src/test/java/com/android/tools/r8/softverification/TestStaticFieldWithOtherMembers.java b/src/test/java/com/android/tools/r8/softverification/TestStaticFieldWithOtherMembers.java new file mode 100644 index 0000000..be3d6b0 --- /dev/null +++ b/src/test/java/com/android/tools/r8/softverification/TestStaticFieldWithOtherMembers.java
@@ -0,0 +1,182 @@ +// 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.softverification; + +public class TestStaticFieldWithOtherMembers { + + public static String run() { + if (System.currentTimeMillis() == 0) { + System.out.println(MissingClass.staticField); + } + if (System.currentTimeMillis() == 0) { + System.out.println(MissingClass.staticField); + } + String currentString = "foobar"; + for (int i = 0; i < 10; i++) { + currentString = "foobar" + (i + currentString.length()); + } + return currentString; + } + + public static String run1(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run2(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run3(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run4(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run5(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run6(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run7(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run8(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run9(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run10(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run11(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run12(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run13(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run14(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run15(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run16(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run17(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run18(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run19(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } + + public static String run20(MissingClass missingClass) { + if (System.currentTimeMillis() == 0) { + missingClass.instanceMethod(); + return "foo"; + } + return "bar"; + } +}
diff --git a/src/test/java/com/android/tools/r8/startup/MinimalStartupDexTest.java b/src/test/java/com/android/tools/r8/startup/MinimalStartupDexTest.java index a433265..35df0b6 100644 --- a/src/test/java/com/android/tools/r8/startup/MinimalStartupDexTest.java +++ b/src/test/java/com/android/tools/r8/startup/MinimalStartupDexTest.java
@@ -15,7 +15,6 @@ import com.android.tools.r8.experimental.startup.StartupItem; import com.android.tools.r8.references.ClassReference; import com.android.tools.r8.references.MethodReference; -import com.android.tools.r8.startup.StartupSyntheticPlacementTest.Main; import com.android.tools.r8.startup.utils.StartupTestingUtils; import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.codeinspector.ClassSubject; @@ -49,7 +48,8 @@ List<StartupItem<ClassReference, MethodReference, ?>> startupList = new ArrayList<>(); testForD8(parameters.getBackend()) .addInnerClasses(getClass()) - .apply(StartupTestingUtils.enableStartupInstrumentationUsingLogcat(parameters)) + .apply( + StartupTestingUtils.enableStartupInstrumentationForOriginalAppUsingLogcat(parameters)) .release() .setMinApi(parameters.getApiLevel()) .compile()
diff --git a/src/test/java/com/android/tools/r8/startup/StartupInstrumentationTest.java b/src/test/java/com/android/tools/r8/startup/StartupInstrumentationTest.java index 07f4487..bc0292f 100644 --- a/src/test/java/com/android/tools/r8/startup/StartupInstrumentationTest.java +++ b/src/test/java/com/android/tools/r8/startup/StartupInstrumentationTest.java
@@ -53,8 +53,8 @@ .addInnerClasses(getClass()) .applyIf( logcat, - StartupTestingUtils.enableStartupInstrumentationUsingLogcat(parameters), - StartupTestingUtils.enableStartupInstrumentationUsingFile(parameters)) + StartupTestingUtils.enableStartupInstrumentationForOriginalAppUsingLogcat(parameters), + StartupTestingUtils.enableStartupInstrumentationForOriginalAppUsingFile(parameters)) .release() .setMinApi(parameters.getApiLevel()) .compile()
diff --git a/src/test/java/com/android/tools/r8/startup/StartupSyntheticPlacementTest.java b/src/test/java/com/android/tools/r8/startup/StartupSyntheticPlacementTest.java index 0cce865..179810b 100644 --- a/src/test/java/com/android/tools/r8/startup/StartupSyntheticPlacementTest.java +++ b/src/test/java/com/android/tools/r8/startup/StartupSyntheticPlacementTest.java
@@ -11,12 +11,16 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import com.android.tools.r8.D8TestCompileResult; +import com.android.tools.r8.R8TestCompileResult; import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestCompilerBuilder; import com.android.tools.r8.TestParameters; import com.android.tools.r8.experimental.startup.StartupClass; import com.android.tools.r8.experimental.startup.StartupItem; import com.android.tools.r8.experimental.startup.StartupMethod; import com.android.tools.r8.graph.DexProgramClass; +import com.android.tools.r8.ir.desugar.LambdaClass; import com.android.tools.r8.references.ClassReference; import com.android.tools.r8.references.MethodReference; import com.android.tools.r8.references.Reference; @@ -26,8 +30,11 @@ import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.BooleanUtils; import com.android.tools.r8.utils.MethodReferenceUtils; +import com.android.tools.r8.utils.codeinspector.ClassSubject; import com.android.tools.r8.utils.codeinspector.CodeInspector; +import com.android.tools.r8.utils.codeinspector.MethodSubject; import com.google.common.collect.ImmutableList; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -64,35 +71,89 @@ } @Test - public void test() throws Exception { + public void testLayoutUsingD8() throws Exception { + // First build the app using R8. + R8TestCompileResult r8CompileResult = + testForR8(parameters.getBackend()) + .addInnerClasses(getClass()) + .addKeepMainRule(Main.class) + .addKeepClassAndMembersRules(A.class, B.class, C.class) + .addDontOptimize() + .setMinApi(parameters.getApiLevel()) + .compile(); + + // Verify that the build works. + r8CompileResult + .run(parameters.getRuntime(), Main.class, Boolean.toString(useLambda)) + .assertSuccessWithOutputLines(getExpectedOutput()); + + Path optimizedApp = r8CompileResult.writeToZip(); + + // Then instrument the app to generate a startup list for the minified app. List<StartupItem<ClassReference, MethodReference, ?>> startupList = new ArrayList<>(); testForD8(parameters.getBackend()) - .addInnerClasses(getClass()) - .apply(StartupTestingUtils.enableStartupInstrumentationUsingLogcat(parameters)) + .addProgramFiles(optimizedApp) + .apply( + StartupTestingUtils.enableStartupInstrumentationForOptimizedAppUsingLogcat(parameters)) .release() .setMinApi(parameters.getApiLevel()) .compile() .addRunClasspathFiles(StartupTestingUtils.getAndroidUtilLog(temp)) .run(parameters.getRuntime(), Main.class, Boolean.toString(useLambda)) .apply(StartupTestingUtils.removeStartupListFromStdout(startupList::add)) - .assertSuccessWithOutputLines(getExpectedOutput()); - assertEquals(getExpectedStartupList(), startupList); + .assertSuccessWithOutputLines(getExpectedOutput()) + .apply( + runResult -> + assertEquals( + getExpectedStartupList(r8CompileResult.inspector(), false), startupList)); + // Finally rebuild the minified app using D8 and the startup list. + testForD8(parameters.getBackend()) + .addProgramFiles(optimizedApp) + .apply( + testBuilder -> + configureStartupOptions(testBuilder, r8CompileResult.inspector(), startupList)) + .release() + .setMinApi(parameters.getApiLevel()) + .compile() + .inspectMultiDex( + r8CompileResult.writeProguardMap(), this::inspectPrimaryDex, this::inspectSecondaryDex) + .run(parameters.getRuntime(), Main.class, Boolean.toString(useLambda)) + .assertSuccessWithOutputLines(getExpectedOutput()); + } + + @Test + public void testLayoutUsingR8() throws Exception { + // First generate a startup list for the original app. + List<StartupItem<ClassReference, MethodReference, ?>> startupList = new ArrayList<>(); + D8TestCompileResult instrumentationCompileResult = + testForD8(parameters.getBackend()) + .addInnerClasses(getClass()) + .apply( + StartupTestingUtils.enableStartupInstrumentationForOriginalAppUsingLogcat( + parameters)) + .release() + .setMinApi(parameters.getApiLevel()) + .compile(); + + instrumentationCompileResult + .addRunClasspathFiles(StartupTestingUtils.getAndroidUtilLog(temp)) + .run(parameters.getRuntime(), Main.class, Boolean.toString(useLambda)) + .apply(StartupTestingUtils.removeStartupListFromStdout(startupList::add)) + .assertSuccessWithOutputLines(getExpectedOutput()) + .apply( + runResult -> + assertEquals(getExpectedStartupList(runResult.inspector(), true), startupList)); + + // Then build the app using the startup list that is based on original names. testForR8(parameters.getBackend()) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) .addKeepClassAndMembersRules(A.class, B.class, C.class) - .addOptionsModification( - options -> { - options - .getStartupOptions() - .setEnableMinimalStartupDex(enableMinimalStartupDex) - .setEnableStartupCompletenessCheckForTesting(enableStartupCompletenessCheck); - options - .getTestingOptions() - .setMixedSectionLayoutStrategyInspector(getMixedSectionLayoutInspector()); - }) - .apply(testBuilder -> StartupTestingUtils.setStartupConfiguration(testBuilder, startupList)) + .apply( + testBuilder -> + configureStartupOptions( + testBuilder, instrumentationCompileResult.inspector(), startupList)) .setMinApi(parameters.getApiLevel()) .compile() .inspectMultiDex(this::inspectPrimaryDex, this::inspectSecondaryDex) @@ -103,12 +164,32 @@ runResult -> runResult.assertSuccessWithOutputLines(getExpectedOutput())); } + private void configureStartupOptions( + TestCompilerBuilder<?, ?, ?, ?, ?> testBuilder, + CodeInspector inspector, + List<StartupItem<ClassReference, MethodReference, ?>> startupList) { + testBuilder + .addOptionsModification( + options -> { + options + .getStartupOptions() + .setEnableMinimalStartupDex(enableMinimalStartupDex) + .setEnableStartupCompletenessCheckForTesting(enableStartupCompletenessCheck); + options + .getTestingOptions() + .setMixedSectionLayoutStrategyInspector( + getMixedSectionLayoutInspector(inspector)); + }) + .apply(ignore -> StartupTestingUtils.setStartupConfiguration(testBuilder, startupList)); + } + private List<String> getExpectedOutput() { return ImmutableList.of("A", "B", "C"); } - private List<StartupItem<ClassReference, MethodReference, ?>> getExpectedStartupList() - throws NoSuchMethodException { + @SuppressWarnings("unchecked") + private List<StartupItem<ClassReference, MethodReference, ?>> getExpectedStartupList( + CodeInspector inspector, boolean isStartupListForOriginalApp) throws NoSuchMethodException { ImmutableList.Builder<StartupItem<ClassReference, MethodReference, ?>> builder = ImmutableList.builder(); builder.add( @@ -132,11 +213,56 @@ Reference.methodFromMethod(B.class.getDeclaredMethod("b", boolean.class))) .build()); if (useLambda) { + if (isStartupListForOriginalApp) { + builder.add( + StartupClass.referenceBuilder() + .setClassReference(Reference.classFromClass(B.class)) + .setSynthetic() + .build()); + } else { + ClassSubject bClassSubject = inspector.clazz(B.class); + + MethodSubject syntheticLambdaAccessorMethod = + bClassSubject.uniqueMethodThatMatches( + method -> + method + .getOriginalName() + .startsWith(LambdaClass.R8_LAMBDA_ACCESSOR_METHOD_PREFIX)); + assertThat(syntheticLambdaAccessorMethod, isPresent()); + + ClassSubject externalSyntheticLambdaClassSubject = + inspector.clazz(getSyntheticLambdaClassReference()); + assertThat(externalSyntheticLambdaClassSubject, isPresent()); + + ClassReference externalSyntheticLambdaClassReference = + externalSyntheticLambdaClassSubject.getFinalReference(); + + builder.add( + StartupClass.referenceBuilder() + .setClassReference(externalSyntheticLambdaClassReference) + .build(), + StartupMethod.referenceBuilder() + .setMethodReference( + MethodReferenceUtils.instanceConstructor(externalSyntheticLambdaClassReference)) + .build(), + StartupMethod.referenceBuilder() + .setMethodReference( + Reference.method( + externalSyntheticLambdaClassReference, + "accept", + ImmutableList.of(Reference.classFromClass(Object.class)), + null)) + .build(), + StartupMethod.referenceBuilder() + .setMethodReference( + Reference.method( + Reference.classFromClass(B.class), + syntheticLambdaAccessorMethod.getFinalName(), + ImmutableList.of(Reference.classFromClass(Object.class)), + null)) + .build()); + } builder.add( - StartupClass.referenceBuilder() - .setClassReference(Reference.classFromClass(B.class)) - .setSynthetic() - .build(), StartupMethod.referenceBuilder() .setMethodReference( Reference.methodFromMethod(B.class.getDeclaredMethod("lambda$b$0", Object.class))) @@ -152,7 +278,10 @@ return builder.build(); } - private List<ClassReference> getExpectedClassDataLayout(int virtualFile) { + private List<ClassReference> getExpectedClassDataLayout( + CodeInspector inspector, int virtualFile) { + ClassSubject syntheticLambdaClassSubject = inspector.clazz(getSyntheticLambdaClassReference()); + // The synthetic lambda should only be placed alongside its synthetic context (B) if it is used. // Otherwise, it should be last, or in the second dex file if compiling with minimal startup. ImmutableList.Builder<ClassReference> layoutBuilder = ImmutableList.builder(); @@ -162,23 +291,24 @@ Reference.classFromClass(A.class), Reference.classFromClass(B.class)); if (useLambda) { - layoutBuilder.add(getSyntheticLambdaClassReference()); + layoutBuilder.add(syntheticLambdaClassSubject.getFinalReference()); } layoutBuilder.add(Reference.classFromClass(C.class)); } if (!useLambda) { if (!enableMinimalStartupDex || virtualFile == 1) { - layoutBuilder.add(getSyntheticLambdaClassReference()); + layoutBuilder.add(syntheticLambdaClassSubject.getFinalReference()); } } return layoutBuilder.build(); } - private MixedSectionLayoutInspector getMixedSectionLayoutInspector() { + private MixedSectionLayoutInspector getMixedSectionLayoutInspector(CodeInspector inspector) { return new MixedSectionLayoutInspector() { @Override public void inspectClassDataLayout(int virtualFile, Collection<DexProgramClass> layout) { - assertThat(layout, isEqualToClassDataLayout(getExpectedClassDataLayout(virtualFile))); + assertThat( + layout, isEqualToClassDataLayout(getExpectedClassDataLayout(inspector, virtualFile))); } }; }
diff --git a/src/test/java/com/android/tools/r8/startup/StartupSyntheticWithoutContextTest.java b/src/test/java/com/android/tools/r8/startup/StartupSyntheticWithoutContextTest.java index 13c7ca7..b9ceea2 100644 --- a/src/test/java/com/android/tools/r8/startup/StartupSyntheticWithoutContextTest.java +++ b/src/test/java/com/android/tools/r8/startup/StartupSyntheticWithoutContextTest.java
@@ -64,7 +64,8 @@ List<StartupItem<ClassReference, MethodReference, ?>> startupList = new ArrayList<>(); testForD8(parameters.getBackend()) .addInnerClasses(getClass()) - .apply(StartupTestingUtils.enableStartupInstrumentationUsingLogcat(parameters)) + .apply( + StartupTestingUtils.enableStartupInstrumentationForOriginalAppUsingLogcat(parameters)) .release() .setMinApi(parameters.getApiLevel()) .compile()
diff --git a/src/test/java/com/android/tools/r8/startup/utils/StartupTestingUtils.java b/src/test/java/com/android/tools/r8/startup/utils/StartupTestingUtils.java index ae31fe8..ec7e59f 100644 --- a/src/test/java/com/android/tools/r8/startup/utils/StartupTestingUtils.java +++ b/src/test/java/com/android/tools/r8/startup/utils/StartupTestingUtils.java
@@ -10,14 +10,15 @@ import com.android.tools.r8.CompilationFailedException; import com.android.tools.r8.D8TestBuilder; import com.android.tools.r8.D8TestRunResult; -import com.android.tools.r8.R8TestBuilder; +import com.android.tools.r8.StartupProfileProvider; import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestCompilerBuilder; import com.android.tools.r8.TestParameters; import com.android.tools.r8.ThrowableConsumer; -import com.android.tools.r8.experimental.startup.StartupConfiguration; import com.android.tools.r8.experimental.startup.StartupConfigurationParser; import com.android.tools.r8.experimental.startup.StartupItem; -import com.android.tools.r8.experimental.startup.StartupOptions; +import com.android.tools.r8.experimental.startup.StartupProfile; +import com.android.tools.r8.experimental.startup.instrumentation.StartupInstrumentationOptions; import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexType; @@ -40,25 +41,54 @@ private static String startupInstrumentationTag = "startup"; - public static ThrowableConsumer<D8TestBuilder> enableStartupInstrumentationUsingFile( - TestParameters parameters) { - return testBuilder -> enableStartupInstrumentation(testBuilder, parameters, false); + private enum AppVariant { + ORIGINAL, + OPTIMIZED; + + boolean isOriginal() { + return this == ORIGINAL; + } } - public static ThrowableConsumer<D8TestBuilder> enableStartupInstrumentationUsingLogcat( - TestParameters parameters) { - return testBuilder -> enableStartupInstrumentation(testBuilder, parameters, true); + public static ThrowableConsumer<D8TestBuilder> + enableStartupInstrumentationForOriginalAppUsingFile(TestParameters parameters) { + return testBuilder -> + enableStartupInstrumentation(testBuilder, parameters, AppVariant.ORIGINAL, false); + } + + public static ThrowableConsumer<D8TestBuilder> + enableStartupInstrumentationForOriginalAppUsingLogcat(TestParameters parameters) { + return testBuilder -> + enableStartupInstrumentation(testBuilder, parameters, AppVariant.ORIGINAL, true); + } + + public static ThrowableConsumer<D8TestBuilder> + enableStartupInstrumentationForOptimizedAppUsingFile(TestParameters parameters) { + return testBuilder -> + enableStartupInstrumentation(testBuilder, parameters, AppVariant.OPTIMIZED, false); + } + + public static ThrowableConsumer<D8TestBuilder> + enableStartupInstrumentationForOptimizedAppUsingLogcat(TestParameters parameters) { + return testBuilder -> + enableStartupInstrumentation(testBuilder, parameters, AppVariant.OPTIMIZED, true); } private static void enableStartupInstrumentation( - D8TestBuilder testBuilder, TestParameters parameters, boolean logcat) throws IOException { + D8TestBuilder testBuilder, TestParameters parameters, AppVariant appVariant, boolean logcat) + throws IOException { testBuilder .addOptionsModification( options -> { - StartupOptions startupOptions = - options.getStartupOptions().setEnableStartupInstrumentation(); + StartupInstrumentationOptions startupInstrumentationOptions = + options + .getStartupInstrumentationOptions() + .setEnableStartupInstrumentation() + .setEnableGeneralizationOfSyntheticsToSyntheticContext( + appVariant.isOriginal()); if (logcat) { - startupOptions.setStartupInstrumentationTag(startupInstrumentationTag); + startupInstrumentationOptions.setStartupInstrumentationTag( + startupInstrumentationTag); } }) .addLibraryFiles(parameters.getDefaultRuntimeLibrary()) @@ -113,13 +143,13 @@ } public static void setStartupConfiguration( - R8TestBuilder<?> testBuilder, + TestCompilerBuilder<?, ?, ?, ?, ?> testBuilder, List<StartupItem<ClassReference, MethodReference, ?>> startupItems) { testBuilder.addOptionsModification( options -> { DexItemFactory dexItemFactory = options.dexItemFactory(); - StartupConfiguration startupConfiguration = - StartupConfiguration.builder() + StartupProfile startupProfile = + StartupProfile.builder() .apply( builder -> startupItems.forEach( @@ -127,7 +157,8 @@ builder.addStartupItem( convertStartupItemToDex(startupItem, dexItemFactory)))) .build(); - options.getStartupOptions().setStartupConfiguration(startupConfiguration); + StartupProfileProvider startupProfileProvider = startupProfile::serializeToString; + options.getStartupOptions().setStartupProfileProvider(startupProfileProvider); }); }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeMatchers.java b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeMatchers.java index 50a77fe..db36bbc 100644 --- a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeMatchers.java +++ b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeMatchers.java
@@ -4,8 +4,8 @@ package com.android.tools.r8.utils.codeinspector; -import com.android.tools.r8.graph.DexField; import com.android.tools.r8.graph.DexMethod; +import com.android.tools.r8.references.FieldReference; import java.util.Arrays; import java.util.List; import java.util.function.Predicate; @@ -20,7 +20,10 @@ if (!targetSubject.isPresent()) { throw new IllegalArgumentException(); } - DexField target = targetSubject.getField().getReference(); + return accessesField(targetSubject.getField().getReference().asFieldReference()); + } + + public static Matcher<MethodSubject> accessesField(FieldReference target) { return new TypeSafeMatcher<MethodSubject>() { @Override protected boolean matchesSafely(MethodSubject subject) { @@ -35,7 +38,7 @@ @Override public void describeTo(Description description) { - description.appendText("accesses field `" + target.toSourceString() + "`"); + description.appendText("accesses field `" + target.toString() + "`"); } @Override @@ -232,7 +235,8 @@ }; } - public static Predicate<InstructionSubject> isFieldAccessWithTarget(DexField target) { - return instruction -> instruction.isFieldAccess() && instruction.getField() == target; + public static Predicate<InstructionSubject> isFieldAccessWithTarget(FieldReference target) { + return instruction -> + instruction.isFieldAccess() && instruction.getField().asFieldReference().equals(target); } }
diff --git a/third_party/android_jar/lib-master.tar.gz.sha1 b/third_party/android_jar/lib-master.tar.gz.sha1 new file mode 100644 index 0000000..717d805 --- /dev/null +++ b/third_party/android_jar/lib-master.tar.gz.sha1
@@ -0,0 +1 @@ +a759a6727431a73b4f461ed40aa5bfbc79ebc172 \ No newline at end of file
diff --git a/third_party/bundletool/bundletool-1.11.0.tar.gz.sha1 b/third_party/bundletool/bundletool-1.11.0.tar.gz.sha1 new file mode 100644 index 0000000..15286b5 --- /dev/null +++ b/third_party/bundletool/bundletool-1.11.0.tar.gz.sha1
@@ -0,0 +1 @@ +0df683c4962e31e12db4bc264d3ed99a9b91d31c \ No newline at end of file
diff --git a/third_party/openjdk/desugar_jdk_libs_11.tar.gz.sha1 b/third_party/openjdk/desugar_jdk_libs_11.tar.gz.sha1 index 0f2a679..6d54f29 100644 --- a/third_party/openjdk/desugar_jdk_libs_11.tar.gz.sha1 +++ b/third_party/openjdk/desugar_jdk_libs_11.tar.gz.sha1
@@ -1 +1 @@ -cec0d3cf2655ac9c77410ddf87a7b4e5900858a5 \ No newline at end of file +cbd86c3d046d227e71e8157742b3a1f2e4abcd8e \ No newline at end of file
diff --git a/tools/linux/README.art-versions b/tools/linux/README.art-versions index 02e81cd..94d78e1 100644 --- a/tools/linux/README.art-versions +++ b/tools/linux/README.art-versions
@@ -42,6 +42,29 @@ <continue with repo sync as above> +art-master (Currently Android U) +-------------------------------- +Build from master, build spec included. Art at 31b98e9ce8fbb56c3507c8e7718881efa1ce9f63. + +repo sync -cq -j24 +source build/envsetup.sh +lunch aosp_redfin-userdebug +m -j48 +m -j48 build-art +m -j48 test-art-host +repo manifest -r -o build_spec.xml + +Collected into tools/linux/host/art-master. The "host" path element is checked +by the script for running Art. + + cd <r8 checkout> + scripts/update-host-art.sh \ + --android-checkout <...>/android/tm-dev \ + --art-dir host/art-master \ + --android-product redfin + +(cd tools/linux/host; upload_to_google_storage.py -a --bucket r8-deps art-master) + art-13 (Android T) ------------------ Build from tm-dev commit 442e1091f39417c692d91609af05e58af60d8e2b.
diff --git a/tools/linux/host/art-master.tar.gz.sha1 b/tools/linux/host/art-master.tar.gz.sha1 new file mode 100644 index 0000000..096aa8c --- /dev/null +++ b/tools/linux/host/art-master.tar.gz.sha1
@@ -0,0 +1 @@ +7c795b752ba1edce6c3e9e11d837d31eb78043a3 \ No newline at end of file
diff --git a/tools/r8_release.py b/tools/r8_release.py index 56828c0..f7f0c15 100755 --- a/tools/r8_release.py +++ b/tools/r8_release.py
@@ -389,9 +389,9 @@ result = re.search(version_match_regexp, line) if result: match_count = match_count + 1 - if match_count != 3: + if match_count != 4: print(("Could not find the previous -dev release string to replace in " + - "METADATA. Expected to find is mentioned 3 times. Please update %s " + + "METADATA. Expected to find is mentioned 4 times. Please update %s " + "manually and run again with options --google3 " + "--use-existing-work-branch.") % metadata_path) sys.exit(1)
diff --git a/tools/run_on_app_dump.py b/tools/run_on_app_dump.py index 4f22dc5..4d19948 100755 --- a/tools/run_on_app_dump.py +++ b/tools/run_on_app_dump.py
@@ -54,6 +54,7 @@ 'skip_recompilation': False, 'compiler_properties': [], 'internal': False, + 'golem_duration': None, } # This below does not work in python3 defaults.update(fields.items()) @@ -362,6 +363,7 @@ 'url': 'https://github.com/android/compose-samples', 'revision': '779cf9e187b8ee2c6b620b2abb4524719b3f10f8', 'folder': 'android/compose-samples/crane', + 'golem_duration': 240 }), # TODO(b/173167253): Check if monkey testing works. App({ @@ -1062,6 +1064,13 @@ print_indented( 'StandardBenchmark(name, [Metric.RunTimeRaw, Metric.CodeSize]);', indentation + 4) + if app.golem_duration != None: + print_indented( + 'final timeout = const Duration(seconds: %s);' % app.golem_duration, + indentation) + print_indented( + 'ExecutionManagement.addTimeoutConstraint' + '(timeout, benchmark: benchmark);', indentation) app_gz = os.path.join(utils.OPENSOURCE_DUMPS_DIR, app.folder + '.tar.gz') name = 'appResource' add_golem_resource(indentation, app_gz, name)
diff --git a/tools/startup/adb_utils.py b/tools/startup/adb_utils.py index 2369aa7..60a7ee3 100755 --- a/tools/startup/adb_utils.py +++ b/tools/startup/adb_utils.py
@@ -14,6 +14,7 @@ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +import profile_utils import utils DEVNULL=subprocess.DEVNULL @@ -56,6 +57,24 @@ cmd = create_adb_cmd('shell am broadcast -a %s %s' % (action, component), device_id) return subprocess.check_output(cmd).decode('utf-8').strip().splitlines() +def build_apks_from_bundle(bundle, output, overwrite=False): + print('Building %s' % bundle) + cmd = [ + 'java', '-jar', utils.BUNDLETOOL_JAR, + 'build-apks', + '--bundle=%s' % bundle, + '--output=%s' % output] + if overwrite: + cmd.append('--overwrite') + subprocess.check_call(cmd, stdout=DEVNULL, stderr=DEVNULL) + +def capture_screen(target, device_id=None): + print('Taking screenshot to %s' % target) + tmp = '/sdcard/screencap.png' + cmd = create_adb_cmd('shell screencap -p %s' % tmp, device_id) + subprocess.check_call(cmd, stdout=DEVNULL, stderr=DEVNULL) + pull(tmp, target, device_id) + def create_adb_cmd(arguments, device_id=None): assert isinstance(arguments, list) or isinstance(arguments, str) cmd = ['adb'] @@ -135,8 +154,7 @@ with utils.TempDir() as temp: source = get_profile_path(app_id) target = os.path.join(temp, 'primary.prof') - cmd = create_adb_cmd('pull %s %s' % (source, target), device_id) - subprocess.check_call(cmd, stdout=DEVNULL, stderr=DEVNULL) + pull(source, target, device_id) with open(target, 'rb') as f: return f.read() @@ -182,38 +200,13 @@ def get_classes_and_methods_from_app_profile(app_id, device_id=None): apk_path = get_apk_path(app_id, device_id) profile_path = get_profile_path(app_id) - - # Generates a list of class and method descriptors, prefixed with one or more - # flags 'H' (hot), 'S' (startup), 'P' (post startup). - # - # Example: - # - # HSPLandroidx/compose/runtime/ComposerImpl;->updateValue(Ljava/lang/Object;)V - # HSPLandroidx/compose/runtime/ComposerImpl;->updatedNodeCount(I)I - # HLandroidx/compose/runtime/ComposerImpl;->validateNodeExpected()V - # PLandroidx/compose/runtime/CompositionImpl;->applyChanges()V - # HLandroidx/compose/runtime/ComposerKt;->findLocation(Ljava/util/List;I)I - # Landroidx/compose/runtime/ComposerImpl; - # - # See also https://developer.android.com/studio/profile/baselineprofiles. cmd = create_adb_cmd( 'shell profman --dump-classes-and-methods' ' --profile-file=%s --apk=%s --dex-location=%s' % (profile_path, apk_path, apk_path), device_id) stdout = subprocess.check_output(cmd).decode('utf-8').strip() lines = stdout.splitlines() - classes_and_methods = [] - flags_to_name = { 'H': 'hot', 'S': 'startup', 'P': 'post_startup' } - for line in lines: - flags = { 'hot': False, 'startup': False, 'post_startup': False } - while line[0] in flags_to_name: - flag_abbreviation = line[0] - flag_name = flags_to_name.get(flag_abbreviation) - flags[flag_name] = True - line = line[1:] - assert line.startswith('L') - classes_and_methods.append({ 'descriptor': line, 'flags': flags }) - return classes_and_methods + return profile_utils.parse_art_profile(lines) def get_screen_off_timeout(device_id=None): cmd = create_adb_cmd( @@ -229,6 +222,33 @@ stdout = subprocess.check_output(cmd).decode('utf-8') assert 'Success' in stdout +def install_apks(apks, device_id=None, max_attempts=3): + print('Installing %s' % apks) + cmd = [ + 'java', '-jar', utils.BUNDLETOOL_JAR, + 'install-apks', + '--apks=%s' % apks] + if device_id is not None: + cmd.append('--device-id=%s' % device_id) + for i in range(max_attempts): + process_result = subprocess.run(cmd, capture_output=True) + stdout = process_result.stdout.decode('utf-8') + stderr = process_result.stderr.decode('utf-8') + if process_result.returncode == 0: + return + print('Failed to install %s' % apks) + print('Stdout: %s' % stdout) + print('Stderr: %s' % stderr) + print('Retrying...') + raise Exception('Unable to install apks in %s attempts' % max_attempts) + +def install_bundle(bundle, device_id=None): + print('Installing %s' % bundle) + with utils.TempDir() as temp: + apks = os.path.join(temp, 'Bundle.apks') + build_apks_from_bundle(bundle, apks) + install_apks(apks, device_id) + def install_profile(app_id, device_id=None): # This assumes that the profileinstaller library has been added to the app, # https://developer.android.com/jetpack/androidx/releases/profileinstaller. @@ -267,7 +287,7 @@ total_time_str = line.removeprefix('TotalTime: ') assert total_time_str.isdigit() result['total_time'] = int(total_time_str) - assert not wait_for_activity_to_launch or 'total_time' in result + assert not wait_for_activity_to_launch or 'total_time' in result, lines return result def navigate_to_home_screen(device_id=None): @@ -288,6 +308,10 @@ } return teardown_options +def pull(source, target, device_id=None): + cmd = create_adb_cmd('pull %s %s' % (source, target), device_id) + subprocess.check_call(cmd, stdout=DEVNULL, stderr=DEVNULL) + def root(device_id=None): cmd = create_adb_cmd('root', device_id) subprocess.check_call(cmd, stdout=DEVNULL, stderr=DEVNULL) @@ -364,6 +388,8 @@ def parse_options(argv): result = argparse.ArgumentParser(description='Run adb utils.') + result.add_argument('--capture-screen', + help='Capture screen to given file') result.add_argument('--device-id', help='Device id (e.g., emulator-5554).') result.add_argument('--device-pin', @@ -385,6 +411,8 @@ def main(argv): (options, args) = parse_options(argv) + if options.capture_screen: + capture_screen(options.capture_screen, options.device_id) if options.ensure_screen_off: ensure_screen_off(options.device_id) elif options.get_screen_state:
diff --git a/tools/startup/generate_startup_descriptors.py b/tools/startup/generate_startup_descriptors.py index d4a33d0..ee3f27a 100755 --- a/tools/startup/generate_startup_descriptors.py +++ b/tools/startup/generate_startup_descriptors.py
@@ -4,15 +4,22 @@ # BSD-style license that can be found in the LICENSE file. import adb_utils +import profile_utils import argparse import os import sys import time -def extend_startup_descriptors(startup_descriptors, iteration, options): +class Device: + + def __init__(self, device_id, device_pin): + self.device_id = device_id + self.device_pin = device_pin + +def extend_startup_descriptors(startup_descriptors, iteration, device, options): (logcat, profile, profile_classes_and_methods) = \ - generate_startup_profile(options) + generate_startup_profile(device, options) if options.logcat: write_tmp_logcat(logcat, iteration, options) current_startup_descriptors = get_r8_startup_descriptors_from_logcat( @@ -22,47 +29,48 @@ write_tmp_profile_classes_and_methods( profile_classes_and_methods, iteration, options) current_startup_descriptors = \ - transform_classes_and_methods_to_r8_startup_descriptors( - profile_classes_and_methods, options) + profile_utils.transform_art_profile_to_r8_startup_list( + profile_classes_and_methods) write_tmp_startup_descriptors(current_startup_descriptors, iteration, options) new_startup_descriptors = add_r8_startup_descriptors( startup_descriptors, current_startup_descriptors) - number_of_new_startup_descriptors = len(new_startup_descriptors) - len(startup_descriptors) + number_of_new_startup_descriptors = \ + len(new_startup_descriptors) - len(startup_descriptors) if options.out is not None: print( 'Found %i new startup descriptors in iteration %i' % (number_of_new_startup_descriptors, iteration + 1)) return new_startup_descriptors -def generate_startup_profile(options): +def generate_startup_profile(device, options): logcat = None profile = None profile_classes_and_methods = None if options.use_existing_profile: # Verify presence of profile. - adb_utils.check_app_has_profile_data(options.app_id, options.device_id) - profile = adb_utils.get_profile_data(options.app_id, options.device_id) + adb_utils.check_app_has_profile_data(options.app_id, device.device_id) + profile = adb_utils.get_profile_data(options.app_id, device.device_id) profile_classes_and_methods = \ adb_utils.get_classes_and_methods_from_app_profile( - options.app_id, options.device_id) + options.app_id, device.device_id) else: # Unlock device. tear_down_options = adb_utils.prepare_for_interaction_with_device( - options.device_id, options.device_pin) + device.device_id, device.device_pin) logcat_process = None if options.logcat: # Clear logcat and start capturing logcat. - adb_utils.clear_logcat(options.device_id) + adb_utils.clear_logcat(device.device_id) logcat_process = adb_utils.start_logcat( - options.device_id, format='tag', filter='r8:I ActivityTaskManager:I *:S') + device.device_id, format='tag', filter='r8:I ActivityTaskManager:I *:S') else: # Clear existing profile data. - adb_utils.clear_profile_data(options.app_id, options.device_id) + adb_utils.clear_profile_data(options.app_id, device.device_id) # Launch activity to generate startup profile on device. adb_utils.launch_activity( - options.app_id, options.main_activity, options.device_id) + options.app_id, options.main_activity, device.device_id) # Wait for activity startup. time.sleep(options.startup_duration) @@ -72,16 +80,16 @@ logcat = adb_utils.stop_logcat(logcat_process) else: # Capture startup profile. - adb_utils.capture_app_profile_data(options.app_id, options.device_id) - profile = adb_utils.get_profile_data(options.app_id, options.device_id) + adb_utils.capture_app_profile_data(options.app_id, device.device_id) + profile = adb_utils.get_profile_data(options.app_id, device.device_id) profile_classes_and_methods = \ adb_utils.get_classes_and_methods_from_app_profile( - options.app_id, options.device_id) + options.app_id, device.device_id) # Shutdown app. - adb_utils.stop_app(options.app_id, options.device_id) + adb_utils.stop_app(options.app_id, device.device_id) adb_utils.teardown_after_interaction_with_device( - tear_down_options, options.device_id) + tear_down_options, device.device_id) return (logcat, profile, profile_classes_and_methods) @@ -161,16 +169,6 @@ def report_unrecognized_logcat_line(line): print('Unrecognized line in logcat: %s' % line) -def transform_classes_and_methods_to_r8_startup_descriptors( - classes_and_methods, options): - startup_descriptors = [] - for class_or_method in classes_and_methods: - descriptor = class_or_method.get('descriptor') - flags = class_or_method.get('flags') - if should_include_startup_descriptor(descriptor, flags, options): - startup_descriptors.append(descriptor) - return startup_descriptors - def add_r8_startup_descriptors(old_startup_descriptors, startup_descriptors_to_add): new_startup_descriptors = {} if len(old_startup_descriptors) == 0: @@ -252,15 +250,14 @@ def write_tmp_profile_classes_and_methods( profile_classes_and_methods, iteration, options): def item_to_string(item): - descriptor = item.get('descriptor') - flags = item.get('flags') + (descriptor, flags) = item return '%s%s%s%s' % ( 'H' if flags.get('hot') else '', 'S' if flags.get('startup') else '', 'P' if flags.get('post_startup') else '', descriptor) write_tmp_textual_artifact( - profile_classes_and_methods, + profile_classes_and_methods.items(), iteration, options, 'profile.txt', @@ -296,14 +293,20 @@ result = argparse.ArgumentParser( description='Generate a perfetto trace file.') result.add_argument('--apk', - help='Path to the APK') + help='Path to the .apk') + result.add_argument('--apks', + help='Path to the .apks') result.add_argument('--app-id', help='The application ID of interest', required=True) + result.add_argument('--bundle', + help='Path to the .aab') result.add_argument('--device-id', - help='Device id (e.g., emulator-5554).') + help='Device id (e.g., emulator-5554).', + action='append') result.add_argument('--device-pin', - help='Device pin code (e.g., 1234)') + help='Device pin code (e.g., 1234)', + action='append') result.add_argument('--logcat', action='store_true', default=False) @@ -348,24 +351,52 @@ action='store_true', default=False) options, args = result.parse_known_args(argv) + + # Read the device pins. + device_pins = options.device_pin or [] + del options.device_pin + + # Convert the device ids and pins into a list of devices. + options.devices = [] + if options.device_id is None: + # Assume a single device is attached. + options.devices.append( + Device(None, device_pins[0] if len(device_pins) > 0 else None)) + else: + for i in range(len(options.device_id)): + device_id = options.device_id[i] + device_pin = device_pins[i] if i < len(device_pins) else None + options.devices.append(Device(device_id, device_pin)) + del options.device_id + + paths = [ + path for path in [options.apk, options.apks, options.bundle] + if path is not None] + assert len(paths) <= 1, 'Expected at most one .apk, .apks, or .aab file.' assert options.main_activity is not None or options.use_existing_profile, \ 'Argument --main-activity is required except when running with ' \ '--use-existing-profile.' + return options, args -def main(argv): - (options, args) = parse_options(argv) - adb_utils.root(options.device_id) +def run_on_device(device, options, startup_descriptors): + adb_utils.root(device.device_id) if options.apk: - adb_utils.uninstall(options.app_id, options.device_id) - adb_utils.install(options.apk, options.device_id) - startup_descriptors = {} + adb_utils.uninstall(options.app_id, device.device_id) + adb_utils.install(options.apk, device.device_id) + elif options.apks: + adb_utils.uninstall(options.app_id, device.device_id) + adb_utils.install_apks(options.apks, device.device_id) + elif options.bundle: + adb_utils.uninstall(options.app_id, device.device_id) + adb_utils.install_bundle(options.bundle, device.device_id) if options.until_stable: iteration = 0 stable_iterations = 0 while True: old_startup_descriptors = startup_descriptors - startup_descriptors = extend_startup_descriptors(old_startup_descriptors, iteration, options) + startup_descriptors = extend_startup_descriptors( + old_startup_descriptors, iteration, device, options) diff = len(startup_descriptors) - len(old_startup_descriptors) if diff == 0: stable_iterations = stable_iterations + 1 @@ -376,7 +407,15 @@ iteration = iteration + 1 else: for iteration in range(options.iterations): - startup_descriptors = extend_startup_descriptors(startup_descriptors, iteration, options) + startup_descriptors = extend_startup_descriptors( + startup_descriptors, iteration, device, options) + return startup_descriptors + +def main(argv): + (options, args) = parse_options(argv) + startup_descriptors = {} + for device in options.devices: + startup_descriptors = run_on_device(device, options, startup_descriptors) if options.out is not None: with open(options.out, 'w') as f: for startup_descriptor, flags in startup_descriptors.items():
diff --git a/tools/startup/measure_startup.py b/tools/startup/measure_startup.py index 04076ec..e00797c 100755 --- a/tools/startup/measure_startup.py +++ b/tools/startup/measure_startup.py
@@ -47,15 +47,15 @@ teardown_options['previous_screen_off_timeout'], options.device_id) -def run_all(apk, options, tmp_dir): +def run_all(apk_or_apks, options, tmp_dir): # Launch app while collecting information. data_total = {} for iteration in range(1, options.iterations + 1): print('Starting iteration %i' % iteration) out_dir = os.path.join(options.out_dir, str(iteration)) - teardown_options = setup_for_run(apk, out_dir, options) + teardown_options = setup_for_run(apk_or_apks, out_dir, options) data = run(out_dir, options, tmp_dir) - teardown_for_run(options, teardown_options) + teardown_for_run(out_dir, options, teardown_options) add_data(data_total, data) print('Result:') print(data) @@ -76,12 +76,17 @@ data_summary['%s_med' % key] = statistics.median(value) return data_summary -def setup_for_run(apk, out_dir, options): +def setup_for_run(apk_or_apks, out_dir, options): adb_utils.root(options.device_id) print('Installing') adb_utils.uninstall(options.app_id, options.device_id) - adb_utils.install(apk, options.device_id) + if apk_or_apks['apk']: + adb_utils.install(apk_or_apks['apk'], options.device_id) + else: + assert apk_or_apks['apks'] + adb_utils.install_apks(apk_or_apks['apks'], options.device_id) + os.makedirs(out_dir, exist_ok=True) # AOT compile. @@ -119,9 +124,13 @@ adb_utils.drop_caches(options.device_id) return teardown_options -def teardown_for_run(options, teardown_options): +def teardown_for_run(out_dir, options, teardown_options): assert adb_utils.get_screen_state(options.device_id).is_on_and_unlocked() + if options.capture_screen: + target = os.path.join(out_dir, 'screen.png') + adb_utils.capture_screen(target, options.device_id) + if options.cooldown > 0: adb_utils.teardown_after_interaction_with_device( teardown_options, options.device_id) @@ -246,8 +255,15 @@ default=False, action='store_true') result.add_argument('--apk', - help='Path to the APK', - required=True) + help='Path to the .apk') + result.add_argument('--apks', + help='Path to the .apks') + result.add_argument('--bundle', + help='Path to the .aab') + result.add_argument('--capture-screen', + help='Take a screenshot after each test', + default=False, + action='store_true') result.add_argument('--cooldown', help='Seconds to wait before running each iteration', default=0, @@ -282,8 +298,23 @@ type=int) options, args = result.parse_known_args(argv) setattr(options, 'perfetto', not options.no_perfetto) + + paths = [ + path for path in [options.apk, options.apks, options.bundle] + if path is not None] + assert len(paths) == 1, 'Expected exactly one .apk, .apks, or .aab file.' + + # Build .apks file up front to avoid building the bundle upon each install. + if options.bundle: + os.makedirs(options.out_dir, exist_ok=True) + options.apks = os.path.join(options.out_dir, 'Bundle.apks') + adb_utils.build_apks_from_bundle( + options.bundle, options.apks, overwrite=True) + del options.bundle + # Profile is only used with --aot. assert options.aot or not options.baseline_profile + return options, args def global_setup(options): @@ -308,10 +339,13 @@ def main(argv): (options, args) = parse_options(argv) with utils.TempDir() as tmp_dir: - apk = apk_utils.add_baseline_profile_to_apk( - options.apk, options.baseline_profile, tmp_dir) + apk_or_apks = { 'apk': options.apk, 'apks': options.apks } + if options.baseline_profile: + assert not options.apks, 'Unimplemented' + apk_or_apks['apk'] = apk_utils.add_baseline_profile_to_apk( + options.apk, options.baseline_profile, tmp_dir) teardown_options = global_setup(options) - run_all(apk, options, tmp_dir) + run_all(apk_or_apks, options, tmp_dir) global_teardown(options, teardown_options) if __name__ == '__main__':
diff --git a/tools/startup/profile_utils.py b/tools/startup/profile_utils.py new file mode 100755 index 0000000..0e69397 --- /dev/null +++ b/tools/startup/profile_utils.py
@@ -0,0 +1,105 @@ +#!/usr/bin/env python3 +# 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. + +import argparse +import sys + +COMPANION_CLASS_SUFFIX = '$-CC' +EXTERNAL_SYNTHETIC_SUFFIX = '$$ExternalSynthetic' +SYNTHETIC_PREFIX = 'S' + +# Parses a list of class and method descriptors, prefixed with one or more flags +# 'H' (hot), 'S' (startup), 'P' (post startup). +# +# Example: +# +# HSPLandroidx/compose/runtime/ComposerImpl;->updateValue(Ljava/lang/Object;)V +# HSPLandroidx/compose/runtime/ComposerImpl;->updatedNodeCount(I)I +# HLandroidx/compose/runtime/ComposerImpl;->validateNodeExpected()V +# PLandroidx/compose/runtime/CompositionImpl;->applyChanges()V +# HLandroidx/compose/runtime/ComposerKt;->findLocation(Ljava/util/List;I)I +# Landroidx/compose/runtime/ComposerImpl; +# +# See also https://developer.android.com/studio/profile/baselineprofiles. +def parse_art_profile(lines): + art_profile = {} + flags_to_name = { 'H': 'hot', 'S': 'startup', 'P': 'post_startup' } + for line in lines: + line = line.strip() + if not line: + continue + flags = { 'hot': False, 'startup': False, 'post_startup': False } + while line[0] in flags_to_name: + flag_abbreviation = line[0] + flag_name = flags_to_name.get(flag_abbreviation) + flags[flag_name] = True + line = line[1:] + assert line.startswith('L') + descriptor = line + art_profile[descriptor] = flags + return art_profile + +def transform_art_profile_to_r8_startup_list(art_profile): + r8_startup_list = {} + for startup_descriptor, flags in art_profile.items(): + transformed_startup_descriptor = transform_synthetic_descriptor( + startup_descriptor) + r8_startup_list[transformed_startup_descriptor] = { + 'conditional_startup': False, + 'post_startup': flags['post_startup'], + 'startup': flags['startup'] + } + return r8_startup_list + +def transform_synthetic_descriptor(descriptor): + companion_class_index = descriptor.find(COMPANION_CLASS_SUFFIX) + if companion_class_index >= 0: + return SYNTHETIC_PREFIX + descriptor[0:companion_class_index] + ';' + external_synthetic_index = descriptor.find(EXTERNAL_SYNTHETIC_SUFFIX) + if external_synthetic_index >= 0: + return SYNTHETIC_PREFIX + descriptor[0:external_synthetic_index] + ';' + return descriptor + +def filter_r8_startup_list(r8_startup_list, options): + filtered_r8_startup_list = {} + for startup_descriptor, flags in r8_startup_list.items(): + if not options.include_post_startup \ + and flags.get('post_startup') \ + and not flags.get('startup'): + continue + filtered_r8_startup_list[startup_descriptor] = flags + return filtered_r8_startup_list + +def parse_options(argv): + result = argparse.ArgumentParser( + description='Utilities for converting an ART profile into an R8 startup ' + 'list.') + result.add_argument('--art-profile', help='Path to the ART profile') + result.add_argument('--include-post-startup', + help='Include post startup classes and methods in the R8 ' + 'startup list', + action='store_true', + default=False) + result.add_argument('--out', help='Where to store the R8 startup list') + options, args = result.parse_known_args(argv) + return options, args + +def main(argv): + (options, args) = parse_options(argv) + with open(options.art_profile, 'r') as f: + art_profile = parse_art_profile(f.read().splitlines()) + r8_startup_list = transform_art_profile_to_r8_startup_list(art_profile) + filtered_r8_startup_list = filter_r8_startup_list(r8_startup_list, options) + if options.out is not None: + with open(options.out, 'w') as f: + for startup_descriptor, flags in filtered_r8_startup_list.items(): + f.write(startup_descriptor) + f.write('\n') + else: + for startup_descriptor, flags in filtered_r8_startup_list.items(): + print(startup_descriptor) + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:]))
diff --git a/tools/utils.py b/tools/utils.py index ecd172c..9bd518f 100644 --- a/tools/utils.py +++ b/tools/utils.py
@@ -23,6 +23,8 @@ TOOLS_DIR = defines.TOOLS_DIR REPO_ROOT = defines.REPO_ROOT THIRD_PARTY = defines.THIRD_PARTY +BUNDLETOOL_JAR_DIR = os.path.join(THIRD_PARTY, 'bundletool/bundletool-1.11.0') +BUNDLETOOL_JAR = os.path.join(BUNDLETOOL_JAR_DIR, 'bundletool-all-1.11.0.jar') ANDROID_SDK = os.path.join(THIRD_PARTY, 'android_sdk') MEMORY_USE_TMP_FILE = 'memory_use.tmp' DEX_SEGMENTS_RESULT_PATTERN = re.compile('- ([^:]+): ([0-9]+)')