Merge commit '685a8c81f5387eb165566f7ec48a79241b3d35d0' into dev-release
diff --git a/.gitignore b/.gitignore index 80c9662..07f90a7 100644 --- a/.gitignore +++ b/.gitignore
@@ -262,6 +262,8 @@ tools/*/art-9.0.0.tar.gz tools/*/art-10.0.0 tools/*/art-10.0.0.tar.gz +tools/*/host/art-12.0.0-beta4 +tools/*/host/art-12.0.0-beta4.tar.gz tools/*/art.tar.gz tools/*/dalvik tools/*/dalvik-4.0.4
diff --git a/build.gradle b/build.gradle index 4a8dd81..8b0525f 100644 --- a/build.gradle +++ b/build.gradle
@@ -361,6 +361,7 @@ "linux/art-8.1.0", "linux/art-9.0.0", "linux/art-10.0.0", + "linux/host/art-12.0.0-beta4", "linux/dalvik", "linux/dalvik-4.0.4", "${osString}/dx",
diff --git a/infra/config/global/cr-buildbucket.cfg b/infra/config/global/cr-buildbucket.cfg index 9fe678c..85170a7 100644 --- a/infra/config/global/cr-buildbucket.cfg +++ b/infra/config/global/cr-buildbucket.cfg
@@ -390,6 +390,24 @@ } } builders { + name: "linux-android-12.0.0" + mixins: "linux" + mixins: "normal" + recipe { + properties: "tool:r8" + properties: "dex_vm:12.0.0" + } + } + builders { + name: "linux-android-12.0.0_release" + mixins: "linux" + mixins: "normal" + recipe { + properties: "tool:r8" + properties: "dex_vm:12.0.0" + } + } + builders { name: "linux-internal" mixins: "linux" mixins: "internal"
diff --git a/infra/config/global/generated/cr-buildbucket.cfg b/infra/config/global/generated/cr-buildbucket.cfg index b881778..c105138 100644 --- a/infra/config/global/generated/cr-buildbucket.cfg +++ b/infra/config/global/generated/cr-buildbucket.cfg
@@ -347,6 +347,50 @@ service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com" } builders { + name: "linux-android=12.0.0" + swarming_host: "chrome-swarming.appspot.com" + swarming_tags: "vpython:native-python-wrapper" + dimensions: "cores:8" + dimensions: "cpu:x86-64" + dimensions: "normal:true" + dimensions: "os:Ubuntu-16.04" + dimensions: "pool:luci.r8.ci" + recipe { + name: "rex" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" + cipd_version: "refs/heads/master" + properties_j: "builder_group:\"internal.client.r8\"" + properties_j: "test_options:[\"--dex_vm=12.0.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]" + } + priority: 26 + execution_timeout_secs: 21600 + expiration_secs: 126000 + build_numbers: YES + service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com" + } + builders { + name: "linux-android=12.0.0_release" + swarming_host: "chrome-swarming.appspot.com" + swarming_tags: "vpython:native-python-wrapper" + dimensions: "cores:8" + dimensions: "cpu:x86-64" + dimensions: "normal:true" + dimensions: "os:Ubuntu-16.04" + dimensions: "pool:luci.r8.ci" + recipe { + name: "rex" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" + cipd_version: "refs/heads/master" + properties_j: "builder_group:\"internal.client.r8\"" + properties_j: "test_options:[\"--dex_vm=12.0.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]" + } + priority: 26 + execution_timeout_secs: 21600 + expiration_secs: 126000 + build_numbers: YES + service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com" + } + builders { name: "linux-android=8.1.0" swarming_host: "chrome-swarming.appspot.com" swarming_tags: "vpython:native-python-wrapper"
diff --git a/infra/config/global/generated/luci-milo.cfg b/infra/config/global/generated/luci-milo.cfg index 58474a2..7ffcae6 100644 --- a/infra/config/global/generated/luci-milo.cfg +++ b/infra/config/global/generated/luci-milo.cfg
@@ -186,6 +186,16 @@ short_name: "android=10.0.0_release" } builders { + name: "buildbucket/luci.r8.ci/linux-android=12.0.0" + category: "R8" + short_name: "android=12.0.0" + } + builders { + name: "buildbucket/luci.r8.ci/linux-android=12.0.0_release" + category: "R8 release" + short_name: "android=12.0.0_release" + } + builders { name: "buildbucket/luci.r8.ci/windows" category: "R8" short_name: "windows"
diff --git a/infra/config/global/generated/luci-notify.cfg b/infra/config/global/generated/luci-notify.cfg index c441677..25f83b5 100644 --- a/infra/config/global/generated/luci-notify.cfg +++ b/infra/config/global/generated/luci-notify.cfg
@@ -180,6 +180,30 @@ } builders { bucket: "ci" + name: "linux-android=12.0.0" + repository: "https://r8.googlesource.com/r8" + } +} +notifiers { + notifications { + on_failure: true + on_new_failure: true + notify_blamelist {} + } + builders { + bucket: "ci" + name: "linux-android=12.0.0_release" + repository: "https://r8.googlesource.com/r8" + } +} +notifiers { + notifications { + on_failure: true + on_new_failure: true + notify_blamelist {} + } + builders { + bucket: "ci" name: "linux-android=8.1.0" repository: "https://r8.googlesource.com/r8" }
diff --git a/infra/config/global/generated/luci-scheduler.cfg b/infra/config/global/generated/luci-scheduler.cfg index b4ee1f0..e915f53 100644 --- a/infra/config/global/generated/luci-scheduler.cfg +++ b/infra/config/global/generated/luci-scheduler.cfg
@@ -155,6 +155,24 @@ } } job { + id: "linux-android=12.0.0" + acl_sets: "ci" + buildbucket { + server: "cr-buildbucket.appspot.com" + bucket: "luci.r8.ci" + builder: "linux-android=12.0.0" + } +} +job { + id: "linux-android=12.0.0_release" + acl_sets: "ci" + buildbucket { + server: "cr-buildbucket.appspot.com" + bucket: "luci.r8.ci" + builder: "linux-android=12.0.0_release" + } +} +job { id: "linux-android=8.1.0" acl_sets: "ci" buildbucket { @@ -372,6 +390,7 @@ triggers: "linux-android-6.0.1_release" triggers: "linux-android-7.0.0_release" triggers: "linux-android=10.0.0_release" + triggers: "linux-android=12.0.0_release" triggers: "linux-android=8.1.0_release" triggers: "linux-android=9.0.0_release" triggers: "linux-d8_jctf_release" @@ -399,6 +418,7 @@ triggers: "linux-android-6.0.1" triggers: "linux-android-7.0.0" triggers: "linux-android=10.0.0" + triggers: "linux-android=12.0.0" triggers: "linux-android=8.1.0" triggers: "linux-android=9.0.0" triggers: "linux-d8_jctf"
diff --git a/infra/config/global/luci-milo.cfg b/infra/config/global/luci-milo.cfg index 8218353..3c2ad37 100644 --- a/infra/config/global/luci-milo.cfg +++ b/infra/config/global/luci-milo.cfg
@@ -76,6 +76,11 @@ short_name: "10.0.0" } builders { + name: "buildbucket/luci.r8.ci/linux-android-12.0.0" + category: "R8" + short_name: "12.0.0" + } + builders { name: "buildbucket/luci.r8.ci/linux-internal" category: "R8" short_name: "internal" @@ -186,6 +191,11 @@ short_name: "10.0.0" } builders { + name: "buildbucket/luci.r8.ci/linux-android-12.0.0_release" + category: "R8 release" + short_name: "12.0.0" + } + builders { name: "buildbucket/luci.r8.ci/linux-internal_release" category: "R8 release" short_name: "internal"
diff --git a/infra/config/global/luci-notify.cfg b/infra/config/global/luci-notify.cfg index 92b76f3..1e0eb27 100644 --- a/infra/config/global/luci-notify.cfg +++ b/infra/config/global/luci-notify.cfg
@@ -124,6 +124,16 @@ repository: "https://r8.googlesource.com/r8" } builders { + name: "linux-android-12.0.0" + bucket: "ci" + repository: "https://r8.googlesource.com/r8" + } + builders { + name: "linux-android-12.0.0_release" + bucket: "ci" + repository: "https://r8.googlesource.com/r8" + } + builders { name: "linux-internal" bucket: "ci" repository: "https://r8.googlesource.com/r8"
diff --git a/infra/config/global/luci-scheduler.cfg b/infra/config/global/luci-scheduler.cfg index 4bd0b89..f585e8d 100644 --- a/infra/config/global/luci-scheduler.cfg +++ b/infra/config/global/luci-scheduler.cfg
@@ -39,6 +39,7 @@ triggers: "linux-android-8.1.0" triggers: "linux-android-9.0.0" triggers: "linux-android-10.0.0" + triggers: "linux-android-12.0.0" triggers: "linux-run-on-app-dump" triggers: "linux-internal" triggers: "linux-jctf" @@ -91,6 +92,7 @@ triggers: "linux-android-8.1.0_release" triggers: "linux-android-9.0.0_release" triggers: "linux-android-10.0.0_release" + triggers: "linux-android-12.0.0_release" triggers: "linux-internal_release" triggers: "linux-jctf_release" triggers: "r8cf-linux-jctf_release" @@ -529,6 +531,34 @@ } job { + id: "linux-android-12.0.0" + acl_sets: "default" + triggering_policy: { + kind: GREEDY_BATCHING + max_concurrent_invocations: 6 + } + buildbucket { + server: "cr-buildbucket.appspot.com" + bucket: "luci.r8.ci" + builder: "linux-android-12.0.0" + } +} + +job { + id: "linux-android-12.0.0_release" + acl_sets: "default" + triggering_policy: { + max_batch_size: 1 + max_concurrent_invocations: 3 + } + buildbucket { + server: "cr-buildbucket.appspot.com" + bucket: "luci.r8.ci" + builder: "linux-android-12.0.0_release" + } +} + +job { id: "linux-internal" acl_sets: "default" buildbucket {
diff --git a/infra/config/global/main.star b/infra/config/global/main.star index e78b09a..beda63e 100755 --- a/infra/config/global/main.star +++ b/infra/config/global/main.star
@@ -237,6 +237,8 @@ ["--dex_vm=9.0.0", "--all_tests"]) r8_tester_with_default("linux-android=10.0.0", ["--dex_vm=10.0.0", "--all_tests"]) +r8_tester_with_default("linux-android=12.0.0", + ["--dex_vm=12.0.0", "--all_tests"]) r8_tester_with_default("windows", ["--all_tests"], dimensions=get_dimensions(windows=True))
diff --git a/scripts/update-host-art.sh b/scripts/update-host-art.sh index 76572e0..58165cd 100755 --- a/scripts/update-host-art.sh +++ b/scripts/update-host-art.sh
@@ -109,11 +109,15 @@ # dalvikvm32 or dalvikvm64). cp $ANDROID_HOST_BUILD/bin/dalvikvm $DEST/bin cp $ANDROID_HOST_BUILD/bin/dex2oat $DEST/bin +if [ -e $ANDROID_HOST_BUILD/bin/dex2oat64 ] + then cp $ANDROID_HOST_BUILD/bin/dex2oat64 $DEST/bin +fi if [ -e $ANDROID_HOST_BUILD/bin/patchoat ] # File patchoat does not exist on Q anymore. then cp $ANDROID_HOST_BUILD/bin/patchoat $DEST/bin fi + # Required framework files. mkdir -p $DEST/framework cp -R $ANDROID_HOST_BUILD/framework/* $DEST/framework @@ -127,15 +131,32 @@ # Image files required for dex2oat of actual android apps. We need an actual android product # image containing framework classes to verify the code against. mkdir -p $DEST/product/$ANDROID_PRODUCT/system/framework -cp -r $ANDROID_TARGET_BUILD/product/$ANDROID_PRODUCT/system/framework/* $DEST/product/$ANDROID_PRODUCT/system/framework +cp -rL $ANDROID_TARGET_BUILD/product/$ANDROID_PRODUCT/system/framework/* $DEST/product/$ANDROID_PRODUCT/system/framework # Required auxillary files. -if [ -e $ANDROID_HOST_BUILD/usr/icu ]; then - mkdir -p $DEST/usr/icu - cp -r $ANDROID_HOST_BUILD/usr/icu/* $DEST/usr/icu +if [ -e $ANDROID_HOST_BUILD/apex ]; then + mkdir -p $DEST/apex + cp -rL $ANDROID_HOST_BUILD/apex/* $DEST/apex + if [ -e $ANDROID_HOST_BUILD/com.android.i18n ]; then + mkdir -p $DEST/com.android.i18n + cp -r $ANDROID_HOST_BUILD/com.android.i18n/* $DEST/com.android.i18n + fi + if [ -e $ANDROID_HOST_BUILD/com.android.tzdata ]; then + mkdir -p $DEST/com.android.tzdata + cp -r $ANDROID_HOST_BUILD/com.android.tzdata/* $DEST/com.android.tzdata + fi + if [ -e $ANDROID_HOST_BUILD/usr ]; then + mkdir -p $DEST/usr + cp -r $ANDROID_HOST_BUILD/usr/* $DEST/usr + fi else - mkdir -p $DEST/com.android.runtime/etc/icu/ - cp -r $ANDROID_HOST_BUILD/com.android.runtime/etc/icu/* $DEST/com.android.runtime/etc/icu/ + if [ -e $ANDROID_HOST_BUILD/usr/icu ]; then + mkdir -p $DEST/usr/icu + cp -r $ANDROID_HOST_BUILD/usr/icu/* $DEST/usr/icu + else + mkdir -p $DEST/com.android.runtime/etc/icu/ + cp -r $ANDROID_HOST_BUILD/com.android.runtime/etc/icu/* $DEST/com.android.runtime/etc/icu/ + fi fi # Update links for vdex files for Android P and later. @@ -166,3 +187,4 @@ echo "Now run" echo "(cd $DEST_ROOT; upload_to_google_storage.py -a --bucket r8-deps $ART_DIR)" +echo "NOTE; If $ART_DIR has several directory elements adjust accordingly." \ No newline at end of file
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java index af8aa34..e7efbfa 100644 --- a/src/main/java/com/android/tools/r8/R8Command.java +++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -872,6 +872,7 @@ internal.enableClassStaticizer = false; internal.outline.enabled = false; internal.enableEnumUnboxing = false; + internal.callSiteOptimizationOptions().disableOptimization(); } if (!internal.isShrinking()) {
diff --git a/src/main/java/com/android/tools/r8/cf/CfVerifierTool.java b/src/main/java/com/android/tools/r8/cf/CfVerifierTool.java index 7bf11e0..524b6bc 100644 --- a/src/main/java/com/android/tools/r8/cf/CfVerifierTool.java +++ b/src/main/java/com/android/tools/r8/cf/CfVerifierTool.java
@@ -25,6 +25,7 @@ builder.addProgramFile(Paths.get(arg)); } InternalOptions options = new InternalOptions(); + options.testing.verifyInputs = true; DexApplication dexApplication = new ApplicationReader(builder.build(), options, Timing.empty()).read(); AppView<AppInfo> appView = AppView.createForD8(AppInfo.createInitialAppInfo(dexApplication));
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java index 31d40bb..b231b6e 100644 --- a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java +++ b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
@@ -142,6 +142,11 @@ if (shouldDump) { dumpApplication(); } + + if (options.testing.verifyInputs) { + inputApp.validateInputs(); + } + timing.begin("DexApplication.read"); final LazyLoadedDexApplication.Builder builder = DexApplication.builder(options, timing, resolver);
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java b/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java index e6db3e1..30a1c04 100644 --- a/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java +++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
@@ -688,15 +688,21 @@ } public MethodResolutionResult resolveMethodOnClass(DexMethod method, DexClass clazz) { + return resolveMethodOnClass(clazz, method.getProto(), method.getName()); + } + + public MethodResolutionResult resolveMethodOnClass( + DexClass clazz, DexProto methodProto, DexString methodName) { assert checkIfObsolete(); assert !clazz.isInterface(); // Step 2: - MethodResolutionResult result = resolveMethodOnClassStep2(clazz, method, clazz); + MethodResolutionResult result = + resolveMethodOnClassStep2(clazz, methodProto, methodName, clazz); if (result != null) { return result; } // Finally Step 3: - return resolveMethodStep3(clazz, method); + return resolveMethodStep3(clazz, methodProto, methodName); } /** @@ -705,16 +711,19 @@ * 5.4.3.3 of the JVM Spec</a>. */ private MethodResolutionResult resolveMethodOnClassStep2( - DexClass clazz, DexMethod method, DexClass initialResolutionHolder) { + DexClass clazz, + DexProto methodProto, + DexString methodName, + DexClass initialResolutionHolder) { // Pt. 1: Signature polymorphic method check. // See also <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.9"> // Section 2.9 of the JVM Spec</a>. - DexEncodedMethod result = clazz.lookupSignaturePolymorphicMethod(method.name, dexItemFactory()); + DexEncodedMethod result = clazz.lookupSignaturePolymorphicMethod(methodName, dexItemFactory()); if (result != null) { return new SingleResolutionResult(initialResolutionHolder, clazz, result); } // Pt 2: Find a method that matches the descriptor. - result = clazz.lookupMethod(method); + result = clazz.lookupMethod(methodProto, methodName); if (result != null) { // If the resolved method is private, then it can only be accessed if the symbolic reference // that initiated the resolution was the type at which the method resolved on. If that is not @@ -730,7 +739,8 @@ if (clazz.superType != null) { DexClass superClass = definitionFor(clazz.superType); if (superClass != null) { - return resolveMethodOnClassStep2(superClass, method, initialResolutionHolder); + return resolveMethodOnClassStep2( + superClass, methodProto, methodName, initialResolutionHolder); } } return null; @@ -742,35 +752,45 @@ * 5.4.3.3 of the JVM Spec</a>. As this is the same for interfaces and classes, we share one * implementation. */ - private MethodResolutionResult resolveMethodStep3(DexClass clazz, DexMethod method) { + private MethodResolutionResult resolveMethodStep3( + DexClass clazz, DexProto methodProto, DexString methodName) { MaximallySpecificMethodsBuilder builder = new MaximallySpecificMethodsBuilder(); - resolveMethodStep3Helper(method, clazz, builder); + resolveMethodStep3Helper(methodProto, methodName, clazz, builder); return builder.resolve(clazz); } // Non-private lookup (ie, not resolution) to find interface targets. DexClassAndMethod lookupMaximallySpecificTarget(DexClass clazz, DexMethod method) { MaximallySpecificMethodsBuilder builder = new MaximallySpecificMethodsBuilder(); - resolveMethodStep3Helper(method, clazz, builder); + resolveMethodStep3Helper(method.getProto(), method.getName(), clazz, builder); return builder.lookup(); } // Non-private lookup (ie, not resolution) to find interface targets. DexClassAndMethod lookupMaximallySpecificTarget(LambdaDescriptor lambda, DexMethod method) { MaximallySpecificMethodsBuilder builder = new MaximallySpecificMethodsBuilder(); - resolveMethodStep3Helper(method, dexItemFactory().objectType, lambda.interfaces, builder); + resolveMethodStep3Helper( + method.getProto(), + method.getName(), + dexItemFactory().objectType, + lambda.interfaces, + builder); return builder.lookup(); } /** Helper method that builds the set of maximally specific methods. */ private void resolveMethodStep3Helper( - DexMethod method, DexClass clazz, MaximallySpecificMethodsBuilder builder) { + DexProto methodProto, + DexString methodName, + DexClass clazz, + MaximallySpecificMethodsBuilder builder) { resolveMethodStep3Helper( - method, clazz.superType, Arrays.asList(clazz.interfaces.values), builder); + methodProto, methodName, clazz.superType, Arrays.asList(clazz.interfaces.values), builder); } private void resolveMethodStep3Helper( - DexMethod method, + DexProto methodProto, + DexString methodName, DexType superType, List<DexType> interfaces, MaximallySpecificMethodsBuilder builder) { @@ -781,20 +801,20 @@ continue; } assert definition.isInterface(); - DexEncodedMethod result = definition.lookupMethod(method); + DexEncodedMethod result = definition.lookupMethod(methodProto, methodName); if (isMaximallySpecificCandidate(result)) { // The candidate is added and doing so will prohibit shadowed methods from being in the set. builder.addCandidate(definition, result, this); } else { // Look at the super-interfaces of this class and keep searching. - resolveMethodStep3Helper(method, definition, builder); + resolveMethodStep3Helper(methodProto, methodName, definition, builder); } } // Now look at indirect super interfaces. if (superType != null) { DexClass superClass = definitionFor(superType); if (superClass != null) { - resolveMethodStep3Helper(method, superClass, builder); + resolveMethodStep3Helper(methodProto, methodName, superClass, builder); } } } @@ -860,7 +880,7 @@ } // Step 3: Look for maximally-specific superinterface methods or any interface definition. // This is the same for classes and interfaces. - return resolveMethodStep3(definition, desc); + return resolveMethodStep3(definition, desc.getProto(), desc.getName()); } /**
diff --git a/src/main/java/com/android/tools/r8/graph/CfCode.java b/src/main/java/com/android/tools/r8/graph/CfCode.java index 0213b0e..0a7c0e5 100644 --- a/src/main/java/com/android/tools/r8/graph/CfCode.java +++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -741,15 +741,20 @@ firstLabel = new CfLabel(); newInstructions.add(firstLabel); } - newInstructions.add(new CfPosition(firstLabel, callerPosition)); + boolean seenPosition = false; for (CfInstruction instruction : instructions) { if (instruction.isPosition()) { + seenPosition = true; CfPosition oldPosition = instruction.asPosition(); newInstructions.add( new CfPosition( oldPosition.getLabel(), oldPosition.getPosition().withOutermostCallerPosition(callerPosition))); } else { + if (!instruction.isLabel() && !seenPosition) { + newInstructions.add(new CfPosition(firstLabel, callerPosition)); + seenPosition = true; + } newInstructions.add(instruction); } }
diff --git a/src/main/java/com/android/tools/r8/graph/DexCallSite.java b/src/main/java/com/android/tools/r8/graph/DexCallSite.java index 9cb4704..3aa03da 100644 --- a/src/main/java/com/android/tools/r8/graph/DexCallSite.java +++ b/src/main/java/com/android/tools/r8/graph/DexCallSite.java
@@ -102,6 +102,14 @@ return application.getCallSite(name, desc, bootstrapMethod, bootstrapArgs); } + public List<DexValue> getBootstrapArgs() { + return bootstrapArgs; + } + + public DexProto getMethodProto() { + return methodProto; + } + @Override public DexCallSite self() { return this;
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java index e4d00aa..d3a63f6 100644 --- a/src/main/java/com/android/tools/r8/graph/DexClass.java +++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -588,6 +588,10 @@ return methodCollection.getMethod(method); } + public DexEncodedMethod lookupMethod(DexProto methodProto, DexString methodName) { + return methodCollection.getMethod(methodProto, methodName); + } + /** Find method in this class matching {@param method}. */ public DexEncodedMethod lookupMethod(Predicate<DexEncodedMethod> predicate) { return methodCollection.getMethod(predicate);
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 6daff01..2b8a186 100644 --- a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java +++ b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
@@ -6,7 +6,6 @@ import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull; import static com.android.tools.r8.ir.analysis.type.Nullability.maybeNull; import static com.android.tools.r8.kotlin.KotlinMetadataUtils.getNoKotlinInfo; -import static com.android.tools.r8.utils.AndroidApiLevelUtils.MIN_API_LEVEL; import com.android.tools.r8.dex.MixedSectionCollection; import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature; @@ -17,7 +16,6 @@ import com.android.tools.r8.ir.code.Instruction; import com.android.tools.r8.ir.code.TypeAndLocalInfoSupplier; import com.android.tools.r8.ir.optimize.info.DefaultFieldOptimizationInfo; -import com.android.tools.r8.ir.optimize.info.DefaultFieldOptimizationWithMinApiInfo; import com.android.tools.r8.ir.optimize.info.FieldOptimizationInfo; import com.android.tools.r8.ir.optimize.info.MutableFieldOptimizationInfo; import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple; @@ -45,7 +43,7 @@ /** Generic signature information if the attribute is present in the input */ private FieldTypeSignature genericSignature; - private FieldOptimizationInfo optimizationInfo; + private FieldOptimizationInfo optimizationInfo = DefaultFieldOptimizationInfo.getInstance(); private KotlinFieldLevelInfo kotlinMemberInfo = getNoKotlinInfo(); private static void specify(StructuralSpecification<DexEncodedField, ?> spec) { @@ -98,20 +96,11 @@ boolean deprecated, boolean d8R8Synthesized, AndroidApiLevel apiLevel) { - super(field, annotations, d8R8Synthesized); + super(field, annotations, d8R8Synthesized, apiLevel); this.accessFlags = accessFlags; this.staticValue = staticValue; this.deprecated = deprecated; this.genericSignature = genericSignature; - if (apiLevel == AndroidApiLevel.UNKNOWN) { - optimizationInfo = DefaultFieldOptimizationInfo.getInstance(); - } else if (apiLevel == MIN_API_LEVEL) { - optimizationInfo = DefaultFieldOptimizationWithMinApiInfo.getInstance(); - } else { - MutableFieldOptimizationInfo optimizationInfo = new MutableFieldOptimizationInfo(); - this.optimizationInfo = optimizationInfo; - optimizationInfo.setApiReferenceLevelForDefinition(apiLevel); - } assert genericSignature != null; assert GenericSignatureUtils.verifyNoDuplicateGenericDefinitions(genericSignature, annotations); } @@ -148,8 +137,8 @@ } @Override - public AndroidApiLevel getApiReferenceLevel(AndroidApiLevel minApiLevel) { - return optimizationInfo.getApiReferenceLevelForDefinition(minApiLevel); + public AndroidApiLevel getApiLevel() { + return getApiLevelForDefinition(); } public synchronized MutableFieldOptimizationInfo getMutableOptimizationInfo() { @@ -162,10 +151,6 @@ optimizationInfo = info; } - public void setMinApiOptimizationInfo(DefaultFieldOptimizationWithMinApiInfo info) { - optimizationInfo = info; - } - @Override public KotlinFieldLevelInfo getKotlinInfo() { return kotlinMemberInfo; @@ -400,6 +385,7 @@ private FieldAccessFlags accessFlags; private FieldTypeSignature genericSignature; private DexValue staticValue; + private AndroidApiLevel apiLevel; private FieldOptimizationInfo optimizationInfo; private boolean deprecated; private boolean d8R8Synthesized; @@ -413,6 +399,7 @@ genericSignature = from.getGenericSignature(); annotations = from.annotations(); staticValue = from.staticValue; + apiLevel = from.getApiLevel(); optimizationInfo = from.optimizationInfo.isMutableOptimizationInfo() ? from.optimizationInfo.asMutableFieldOptimizationInfo().mutableCopy() @@ -468,7 +455,7 @@ staticValue, deprecated, d8R8Synthesized, - AndroidApiLevel.UNKNOWN); + apiLevel); dexEncodedField.optimizationInfo = optimizationInfo; buildConsumer.accept(dexEncodedField); return dexEncodedField;
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 c1ce2f5..da3c5ff 100644 --- a/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java +++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java
@@ -20,12 +20,20 @@ // set. private final boolean d8R8Synthesized; + /** apiLevelForDefinition describes the api level needed for knowing all types */ + private AndroidApiLevel apiLevelForDefinition; + private final R reference; - public DexEncodedMember(R reference, DexAnnotationSet annotations, boolean d8R8Synthesized) { + public DexEncodedMember( + R reference, + DexAnnotationSet annotations, + boolean d8R8Synthesized, + AndroidApiLevel apiLevelForDefinition) { super(annotations); this.reference = reference; this.d8R8Synthesized = d8R8Synthesized; + this.apiLevelForDefinition = apiLevelForDefinition; } public abstract KotlinMemberLevelInfo getKotlinInfo(); @@ -85,7 +93,15 @@ public abstract MemberOptimizationInfo<?> getOptimizationInfo(); - public abstract AndroidApiLevel getApiReferenceLevel(AndroidApiLevel minApiLevel); + public abstract AndroidApiLevel getApiLevel(); + + public AndroidApiLevel getApiLevelForDefinition() { + return apiLevelForDefinition; + } + + public void setApiLevelForDefinition(AndroidApiLevel apiLevelForDefinition) { + this.apiLevelForDefinition = apiLevelForDefinition; + } @Override public final boolean equals(Object other) {
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 cb44ff9..c2b204e 100644 --- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java +++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -11,7 +11,6 @@ import static com.android.tools.r8.graph.DexEncodedMethod.CompilationState.PROCESSED_NOT_INLINING_CANDIDATE; import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull; import static com.android.tools.r8.kotlin.KotlinMetadataUtils.getNoKotlinInfo; -import static com.android.tools.r8.utils.AndroidApiLevelUtils.MIN_API_LEVEL; import static com.android.tools.r8.utils.ConsumerUtils.emptyConsumer; import com.android.tools.r8.cf.CfVersion; @@ -57,7 +56,6 @@ import com.android.tools.r8.ir.optimize.NestUtils; import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo; import com.android.tools.r8.ir.optimize.info.DefaultMethodOptimizationInfo; -import com.android.tools.r8.ir.optimize.info.DefaultMethodOptimizationWithMinApiInfo; import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo; import com.android.tools.r8.ir.optimize.info.MutableMethodOptimizationInfo; import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple; @@ -158,9 +156,12 @@ // TODO(b/128967328): towards finer-grained inlining constraints, // we need to maintain a set of states with (potentially different) contexts. private CompilationState compilationState = CompilationState.NOT_PROCESSED; - private MethodOptimizationInfo optimizationInfo = DefaultMethodOptimizationInfo.DEFAULT_INSTANCE; + private MethodOptimizationInfo optimizationInfo = DefaultMethodOptimizationInfo.getInstance(); private CallSiteOptimizationInfo callSiteOptimizationInfo = CallSiteOptimizationInfo.bottom(); private CfVersion classFileVersion; + /** The apiLevelForCode describes the api level needed for knowing all references in the code */ + private AndroidApiLevel apiLevelForCode; + private KotlinMethodLevelInfo kotlinMemberInfo = getNoKotlinInfo(); /** Generic signature information if the attribute is present in the input */ private MethodTypeSignature genericSignature; @@ -316,28 +317,18 @@ AndroidApiLevel apiLevelForDefinition, AndroidApiLevel apiLevelForCode, boolean deprecated) { - super(method, annotations, d8R8Synthesized); + super(method, annotations, d8R8Synthesized, apiLevelForDefinition); this.accessFlags = accessFlags; this.deprecated = deprecated; this.genericSignature = genericSignature; this.parameterAnnotationsList = parameterAnnotationsList; this.code = code; this.classFileVersion = classFileVersion; - if (apiLevelForDefinition == AndroidApiLevel.UNKNOWN - && apiLevelForCode == AndroidApiLevel.UNKNOWN) { - optimizationInfo = DefaultMethodOptimizationInfo.getInstance(); - } else if (apiLevelForDefinition == MIN_API_LEVEL && apiLevelForCode == MIN_API_LEVEL) { - optimizationInfo = DefaultMethodOptimizationWithMinApiInfo.getInstance(); - } else { - MutableMethodOptimizationInfo optimizationInfo = - DefaultMethodOptimizationInfo.getInstance().toMutableOptimizationInfo(); - optimizationInfo.setApiReferenceLevelForDefinition(apiLevelForDefinition); - optimizationInfo.setApiReferenceLevelForCode(apiLevelForCode); - this.optimizationInfo = optimizationInfo; - } + this.apiLevelForCode = apiLevelForCode; assert accessFlags != null; assert code == null || !shouldNotHaveCode(); assert parameterAnnotationsList != null; + assert apiLevelForCode != null && apiLevelForDefinition != null; } public static DexEncodedMethod toMethodDefinitionOrNull(DexClassAndMethod method) { @@ -1117,11 +1108,17 @@ } public DexEncodedMethod toMethodThatLogsError(AppView<?> appView) { - if (appView.options().isGeneratingDex()) { - return toMethodThatLogsErrorDexCode(appView.dexItemFactory()); - } else { - return toMethodThatLogsErrorCfCode(appView.dexItemFactory()); - } + Builder builder = + builder(this) + .setCode( + appView.options().isGeneratingClassFiles() + ? toCfCodeThatLogsError(appView.dexItemFactory()) + : toDexCodeThatLogsError(appView.dexItemFactory())) + .setIsLibraryMethodOverrideIf( + belongsToVirtualPool() && !isLibraryMethodOverride().isUnknown(), + isLibraryMethodOverride()); + setObsolete(); + return builder.build(); } public static void setDebugInfoWithFakeThisParameter(Code code, int arity, AppView<?> appView) { @@ -1136,8 +1133,8 @@ cfCode.addFakeThisParameter(appView.dexItemFactory()); } } - - private DexEncodedMethod toMethodThatLogsErrorDexCode(DexItemFactory itemFactory) { + + private DexCode toDexCodeThatLogsError(DexItemFactory itemFactory) { checkIfObsolete(); Signature signature = MethodSignature.fromDexMethod(getReference()); DexString message = @@ -1158,23 +1155,18 @@ exceptionType, itemFactory.createProto(itemFactory.voidType, itemFactory.stringType), itemFactory.constructorMethodName); - DexCode code = - generateCodeFromTemplate( - 2, - 2, - new ConstString(0, tag), - new ConstString(1, message), - new InvokeStatic(2, logMethod, 0, 1, 0, 0, 0), - new NewInstance(0, exceptionType), - new InvokeDirect(2, exceptionInitMethod, 0, 1, 0, 0, 0), - new Throw(0)); - Builder builder = builder(this); - builder.setCode(code); - setObsolete(); - return builder.build(); + return generateCodeFromTemplate( + 2, + 2, + new ConstString(0, tag), + new ConstString(1, message), + new InvokeStatic(2, logMethod, 0, 1, 0, 0, 0), + new NewInstance(0, exceptionType), + new InvokeDirect(2, exceptionInitMethod, 0, 1, 0, 0, 0), + new Throw(0)); } - private DexEncodedMethod toMethodThatLogsErrorCfCode(DexItemFactory itemFactory) { + private CfCode toCfCodeThatLogsError(DexItemFactory itemFactory) { checkIfObsolete(); Signature signature = MethodSignature.fromDexMethod(getReference()); DexString message = @@ -1219,18 +1211,13 @@ .add(new CfConstString(message)) .add(new CfInvoke(Opcodes.INVOKESPECIAL, exceptionInitMethod, false)) .add(new CfThrow()); - CfCode code = - new CfCode( - getReference().holder, - 3, - locals, - instructionBuilder.build(), - Collections.emptyList(), - Collections.emptyList()); - Builder builder = builder(this); - builder.setCode(code); - setObsolete(); - return builder.build(); + return new CfCode( + getReference().holder, + 3, + locals, + instructionBuilder.build(), + Collections.emptyList(), + Collections.emptyList()); } public DexEncodedMethod toTypeSubstitutedMethod(DexMethod method) { @@ -1328,7 +1315,10 @@ .getHolderType() .isInterface(definitions))) .build()) - .modifyAccessFlags(MethodAccessFlags::setBridge)) + .modifyAccessFlags(MethodAccessFlags::setBridge) + .setIsLibraryMethodOverrideIf( + !isStatic() && !isLibraryMethodOverride().isUnknown(), + isLibraryMethodOverride())) .build(); } @@ -1431,18 +1421,19 @@ return optimizationInfo; } - public AndroidApiLevel getApiReferenceLevelForDefinition(AndroidApiLevel minApiLevel) { - return optimizationInfo.getApiReferenceLevelForDefinition(minApiLevel); + public AndroidApiLevel getApiLevelForCode() { + return apiLevelForCode; } - public AndroidApiLevel getApiReferenceLevelForCode(AndroidApiLevel minApiLevel) { - return optimizationInfo.getApiReferenceLevelForCode(minApiLevel); + public void setApiLevelForCode(AndroidApiLevel apiLevel) { + assert apiLevel != null; + this.apiLevelForCode = apiLevel; } @Override - public AndroidApiLevel getApiReferenceLevel(AndroidApiLevel minApiLevel) { - return getApiReferenceLevelForDefinition(minApiLevel) - .max(getApiReferenceLevelForCode(minApiLevel)); + public AndroidApiLevel getApiLevel() { + return (isAbstract() ? AndroidApiLevel.B : getApiLevelForCode()) + .max(getApiLevelForDefinition()); } public synchronized MutableMethodOptimizationInfo getMutableOptimizationInfo() { @@ -1457,11 +1448,6 @@ optimizationInfo = info; } - public void setMinApiOptimizationInfo(DefaultMethodOptimizationWithMinApiInfo info) { - checkIfObsolete(); - optimizationInfo = info; - } - public synchronized void abandonCallSiteOptimizationInfo() { checkIfObsolete(); callSiteOptimizationInfo = CallSiteOptimizationInfo.abandoned(); @@ -1525,6 +1511,8 @@ private MethodOptimizationInfo optimizationInfo = DefaultMethodOptimizationInfo.getInstance(); private KotlinMethodLevelInfo kotlinInfo = getNoKotlinInfo(); private CfVersion classFileVersion = null; + private AndroidApiLevel apiLevelForDefinition = null; + private AndroidApiLevel apiLevelForCode = null; private boolean d8R8Synthesized = false; private Consumer<DexEncodedMethod> buildConsumer = ConsumerUtils.emptyConsumer(); @@ -1542,6 +1530,8 @@ genericSignature = from.getGenericSignature(); annotations = from.annotations(); code = from.getCode(); + apiLevelForDefinition = from.getApiLevelForDefinition(); + apiLevelForCode = from.getApiLevelForCode(); optimizationInfo = from.getOptimizationInfo().isMutableOptimizationInfo() ? from.getOptimizationInfo().asMutableMethodOptimizationInfo().mutableCopy() @@ -1732,6 +1722,8 @@ assert parameterAnnotations != null; assert parameterAnnotations.isEmpty() || parameterAnnotations.size() == method.proto.parameters.size(); + assert apiLevelForDefinition != null; + assert apiLevelForCode != null; DexEncodedMethod result = new DexEncodedMethod( method, @@ -1742,8 +1734,8 @@ code, d8R8Synthesized, classFileVersion, - AndroidApiLevel.UNKNOWN, - AndroidApiLevel.UNKNOWN); + apiLevelForDefinition, + apiLevelForCode); result.setKotlinMemberInfo(kotlinInfo); result.compilationState = compilationState; result.optimizationInfo = optimizationInfo; @@ -1758,5 +1750,15 @@ this.genericSignature = methodSignature; return this; } + + public Builder setApiLevelForDefinition(AndroidApiLevel apiLevelForDefinition) { + this.apiLevelForDefinition = apiLevelForDefinition; + return this; + } + + public Builder setApiLevelForCode(AndroidApiLevel apiLevelForCode) { + this.apiLevelForCode = apiLevelForCode; + return this; + } } }
diff --git a/src/main/java/com/android/tools/r8/graph/DexMethod.java b/src/main/java/com/android/tools/r8/graph/DexMethod.java index 5a109e7..c5cb0ff 100644 --- a/src/main/java/com/android/tools/r8/graph/DexMethod.java +++ b/src/main/java/com/android/tools/r8/graph/DexMethod.java
@@ -228,7 +228,15 @@ @Override public boolean match(DexMethod method) { - return method.name == name && method.proto == proto; + return match(method.getProto(), method.getName()); + } + + public boolean match(DexMethodSignature method) { + return match(method.getProto(), method.getName()); + } + + public boolean match(DexProto methodProto, DexString methodName) { + return proto == methodProto && name == methodName; } @Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexMethodSignature.java b/src/main/java/com/android/tools/r8/graph/DexMethodSignature.java index 8b2fcc4..74d464f 100644 --- a/src/main/java/com/android/tools/r8/graph/DexMethodSignature.java +++ b/src/main/java/com/android/tools/r8/graph/DexMethodSignature.java
@@ -4,9 +4,13 @@ package com.android.tools.r8.graph; +import com.android.tools.r8.utils.structural.StructuralItem; +import com.android.tools.r8.utils.structural.StructuralMapping; +import com.android.tools.r8.utils.structural.StructuralSpecification; import java.util.Objects; -public class DexMethodSignature { +public class DexMethodSignature implements StructuralItem<DexMethodSignature> { + private final DexProto proto; private final DexString name; @@ -21,14 +25,31 @@ this.name = name; } - public DexProto getProto() { - return proto; + public int getArity() { + return proto.getArity(); } public DexString getName() { return name; } + public DexProto getProto() { + return proto; + } + + public DexType getReturnType() { + return proto.returnType; + } + + @Override + public StructuralMapping<DexMethodSignature> getStructuralMapping() { + return DexMethodSignature::specify; + } + + private static void specify(StructuralSpecification<DexMethodSignature, ?> spec) { + spec.withItem(DexMethodSignature::getName).withItem(DexMethodSignature::getProto); + } + public DexMethodSignature withName(DexString name) { return new DexMethodSignature(proto, name); } @@ -58,12 +79,9 @@ return Objects.hash(proto, name); } - public DexType getReturnType() { - return proto.returnType; - } - - public int getArity() { - return proto.getArity(); + @Override + public DexMethodSignature self() { + return this; } @Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java index 8a3f39a..e297bd4 100644 --- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java +++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -4,7 +4,7 @@ package com.android.tools.r8.graph; import static com.android.tools.r8.kotlin.KotlinMetadataUtils.getNoKotlinInfo; -import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabled; +import static com.android.tools.r8.utils.AndroidApiLevel.minApiLevelIfEnabledOrUnknown; import static com.google.common.base.Predicates.alwaysTrue; import com.android.tools.r8.ProgramResource; @@ -827,7 +827,7 @@ AppView<?> appView, BiFunction<DexReference, AndroidApiLevel, AndroidApiLevel> apiLevelLookup) { // The api level of a class is the max level of it's members, super class and interfaces. - AndroidApiLevel computedApiLevel = getApiLevelIfEnabled(appView, Function.identity()); + AndroidApiLevel computedApiLevel = minApiLevelIfEnabledOrUnknown(appView); for (DexType superType : allImmediateSupertypes()) { computedApiLevel = apiLevelLookup.apply(superType, computedApiLevel); if (computedApiLevel == AndroidApiLevel.UNKNOWN) { @@ -838,9 +838,9 @@ } public AndroidApiLevel getMembersApiReferenceLevel(AppView<?> appView) { - AndroidApiLevel memberLevel = getApiLevelIfEnabled(appView, Function.identity()); + AndroidApiLevel memberLevel = minApiLevelIfEnabledOrUnknown(appView); for (DexEncodedMember<?, ?> member : members()) { - memberLevel = memberLevel.max(getApiLevelIfEnabled(appView, member::getApiReferenceLevel)); + memberLevel = memberLevel.max(member.getApiLevel()); if (memberLevel == AndroidApiLevel.UNKNOWN) { return AndroidApiLevel.UNKNOWN; }
diff --git a/src/main/java/com/android/tools/r8/graph/FieldResolutionResult.java b/src/main/java/com/android/tools/r8/graph/FieldResolutionResult.java index 62b62b9..03627d7 100644 --- a/src/main/java/com/android/tools/r8/graph/FieldResolutionResult.java +++ b/src/main/java/com/android/tools/r8/graph/FieldResolutionResult.java
@@ -66,6 +66,10 @@ return false; } + public boolean isFailedResolution() { + return false; + } + public DexClass getInitialResolutionHolder() { return null; } @@ -163,6 +167,11 @@ public boolean isFailedOrUnknownResolution() { return true; } + + @Override + public boolean isFailedResolution() { + return true; + } } /**
diff --git a/src/main/java/com/android/tools/r8/graph/GraphLens.java b/src/main/java/com/android/tools/r8/graph/GraphLens.java index 8da7519..37dea58 100644 --- a/src/main/java/com/android/tools/r8/graph/GraphLens.java +++ b/src/main/java/com/android/tools/r8/graph/GraphLens.java
@@ -681,7 +681,11 @@ continue; } DexMethod originalMethod = getOriginalMethodSignature(method.getReference()); - assert originalMethods.contains(originalMethod); + assert originalMethods.contains(originalMethod) + : "Method could not be mapped back: " + + method.toSourceString() + + ", originalMethod: " + + originalMethod.toSourceString(); } }
diff --git a/src/main/java/com/android/tools/r8/graph/ImmediateProgramSubtypingInfo.java b/src/main/java/com/android/tools/r8/graph/ImmediateProgramSubtypingInfo.java index ac08e3f..fa003ea 100644 --- a/src/main/java/com/android/tools/r8/graph/ImmediateProgramSubtypingInfo.java +++ b/src/main/java/com/android/tools/r8/graph/ImmediateProgramSubtypingInfo.java
@@ -63,6 +63,24 @@ }); } + public void forEachImmediateProgramSuperClass( + DexProgramClass clazz, Consumer<? super DexProgramClass> consumer) { + forEachImmediateProgramSuperClassMatching(clazz, alwaysTrue(), consumer); + } + + public void forEachImmediateProgramSuperClassMatching( + DexProgramClass clazz, + Predicate<? super DexProgramClass> predicate, + Consumer<? super DexProgramClass> consumer) { + clazz.forEachImmediateSupertype( + supertype -> { + DexProgramClass superclass = asProgramClassOrNull(appView.definitionFor(supertype)); + if (superclass != null && predicate.test(superclass)) { + consumer.accept(superclass); + } + }); + } + public void forEachImmediateSubClass( DexProgramClass clazz, Consumer<? super DexProgramClass> consumer) { forEachImmediateSubClassMatching(clazz, alwaysTrue(), consumer);
diff --git a/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java b/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java index 7e67c3b..6930912 100644 --- a/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java +++ b/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java
@@ -249,9 +249,21 @@ } @Override - DexEncodedMethod getMethod(DexMethod method) { - DexEncodedMethod result = getDirectMethod(method); - return result == null ? getVirtualMethod(method) : result; + DexEncodedMethod getMethod(DexProto methodProto, DexString methodName) { + DexEncodedMethod directMethod = internalGetMethod(methodProto, methodName, directMethods); + return directMethod == null + ? internalGetMethod(methodProto, methodName, virtualMethods) + : directMethod; + } + + private static DexEncodedMethod internalGetMethod( + DexProto methodProto, DexString methodName, DexEncodedMethod[] methods) { + for (DexEncodedMethod method : methods) { + if (method.getReference().match(methodProto, methodName)) { + return method; + } + } + return null; } @Override
diff --git a/src/main/java/com/android/tools/r8/graph/MethodCollection.java b/src/main/java/com/android/tools/r8/graph/MethodCollection.java index 3509b8c..3dc2b58 100644 --- a/src/main/java/com/android/tools/r8/graph/MethodCollection.java +++ b/src/main/java/com/android/tools/r8/graph/MethodCollection.java
@@ -160,7 +160,11 @@ } public DexEncodedMethod getMethod(DexMethod method) { - return backing.getMethod(method); + return backing.getMethod(method.getProto(), method.getName()); + } + + public DexEncodedMethod getMethod(DexProto methodProto, DexString methodName) { + return backing.getMethod(methodProto, methodName); } public DexEncodedMethod getMethod(Predicate<DexEncodedMethod> predicate) {
diff --git a/src/main/java/com/android/tools/r8/graph/MethodCollectionBacking.java b/src/main/java/com/android/tools/r8/graph/MethodCollectionBacking.java index 301352a..90fbf1f 100644 --- a/src/main/java/com/android/tools/r8/graph/MethodCollectionBacking.java +++ b/src/main/java/com/android/tools/r8/graph/MethodCollectionBacking.java
@@ -68,7 +68,7 @@ // Lookup methods. - abstract DexEncodedMethod getMethod(DexMethod method); + abstract DexEncodedMethod getMethod(DexProto methodProto, DexString methodName); abstract DexEncodedMethod getDirectMethod(DexMethod method);
diff --git a/src/main/java/com/android/tools/r8/graph/MethodMapBacking.java b/src/main/java/com/android/tools/r8/graph/MethodMapBacking.java index a7d3c45..8f705d4 100644 --- a/src/main/java/com/android/tools/r8/graph/MethodMapBacking.java +++ b/src/main/java/com/android/tools/r8/graph/MethodMapBacking.java
@@ -5,67 +5,59 @@ import com.android.tools.r8.utils.Box; import com.android.tools.r8.utils.IteratorUtils; -import com.android.tools.r8.utils.MethodSignatureEquivalence; import com.android.tools.r8.utils.TraversalContinuation; -import com.google.common.base.Equivalence.Wrapper; import com.google.common.collect.Lists; -import it.unimi.dsi.fastutil.objects.Object2ReferenceLinkedOpenHashMap; -import it.unimi.dsi.fastutil.objects.Object2ReferenceMap; -import it.unimi.dsi.fastutil.objects.Object2ReferenceRBTreeMap; import java.util.ArrayList; import java.util.Collection; -import java.util.Comparator; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.TreeMap; import java.util.function.Function; import java.util.function.Predicate; public class MethodMapBacking extends MethodCollectionBacking { - private Object2ReferenceMap<Wrapper<DexMethod>, DexEncodedMethod> methodMap; + private Map<DexMethodSignature, DexEncodedMethod> methodMap; public MethodMapBacking() { this(createMap()); } - private MethodMapBacking(Object2ReferenceMap<Wrapper<DexMethod>, DexEncodedMethod> methodMap) { + private MethodMapBacking(Map<DexMethodSignature, DexEncodedMethod> methodMap) { this.methodMap = methodMap; } public static MethodMapBacking createSorted() { - Comparator<Wrapper<DexMethod>> comparator = Comparator.comparing(Wrapper::get); - return new MethodMapBacking(new Object2ReferenceRBTreeMap<>(comparator)); + return new MethodMapBacking(new TreeMap<>()); } - private static Object2ReferenceMap<Wrapper<DexMethod>, DexEncodedMethod> createMap() { + private static Map<DexMethodSignature, DexEncodedMethod> createMap() { // Maintain a linked map so the output order remains a deterministic function of the input. - return new Object2ReferenceLinkedOpenHashMap<>(); + return new HashMap<>(); } - private static Object2ReferenceMap<Wrapper<DexMethod>, DexEncodedMethod> createMap(int capacity) { + private static Map<DexMethodSignature, DexEncodedMethod> createMap(int capacity) { // Maintain a linked map so the output order remains a deterministic function of the input. - return new Object2ReferenceLinkedOpenHashMap<>(capacity); + return new HashMap<>(capacity); } - private Wrapper<DexMethod> wrap(DexMethod method) { - return MethodSignatureEquivalence.get().wrap(method); - } - - private void replace(Wrapper<DexMethod> existingKey, DexEncodedMethod method) { - if (existingKey.get().match(method)) { + private void replace(DexMethodSignature existingKey, DexEncodedMethod method) { + if (method.getReference().match(existingKey)) { methodMap.put(existingKey, method); } else { methodMap.remove(existingKey); - methodMap.put(wrap(method.getReference()), method); + methodMap.put(method.getSignature(), method); } } @Override boolean verify() { methodMap.forEach( - (key, method) -> { - assert key.get().match(method); + (signature, method) -> { + assert method.getReference().match(signature); }); return true; } @@ -97,7 +89,7 @@ @Override TraversalContinuation traverse(Function<DexEncodedMethod, TraversalContinuation> fn) { - for (Entry<Wrapper<DexMethod>, DexEncodedMethod> entry : methodMap.object2ReferenceEntrySet()) { + for (Entry<DexMethodSignature, DexEncodedMethod> entry : methodMap.entrySet()) { TraversalContinuation result = fn.apply(entry.getValue()); if (result.shouldBreak()) { return result; @@ -122,8 +114,8 @@ } @Override - DexEncodedMethod getMethod(DexMethod method) { - return methodMap.get(wrap(method)); + DexEncodedMethod getMethod(DexProto methodProto, DexString methodName) { + return methodMap.get(new DexMethodSignature(methodProto, methodName)); } private DexEncodedMethod getMethod(Predicate<DexEncodedMethod> predicate) { @@ -141,7 +133,7 @@ @Override DexEncodedMethod getDirectMethod(DexMethod method) { - DexEncodedMethod definition = getMethod(method); + DexEncodedMethod definition = getMethod(method.getProto(), method.getName()); return definition != null && belongsToDirectPool(definition) ? definition : null; } @@ -153,7 +145,7 @@ @Override DexEncodedMethod getVirtualMethod(DexMethod method) { - DexEncodedMethod definition = getMethod(method); + DexEncodedMethod definition = getMethod(method.getProto(), method.getName()); return definition != null && belongsToVirtualPool(definition) ? definition : null; } @@ -165,7 +157,7 @@ @Override void addMethod(DexEncodedMethod method) { - Wrapper<DexMethod> key = wrap(method.getReference()); + DexMethodSignature key = method.getSignature(); DexEncodedMethod old = methodMap.put(key, method); assert old == null; } @@ -208,12 +200,12 @@ @Override DexEncodedMethod removeMethod(DexMethod method) { - return methodMap.remove(wrap(method)); + return methodMap.remove(method.getSignature()); } @Override void removeMethods(Set<DexEncodedMethod> methods) { - methods.forEach(method -> methodMap.remove(wrap(method.getReference()))); + methods.forEach(method -> methodMap.remove(method.getSignature())); } @Override @@ -224,17 +216,16 @@ if (methods == null) { methods = DexEncodedMethod.EMPTY_ARRAY; } - Object2ReferenceMap<Wrapper<DexMethod>, DexEncodedMethod> newMap = - createMap(size() + methods.length); + Map<DexMethodSignature, DexEncodedMethod> newMap = createMap(size() + methods.length); forEachMethod( method -> { if (belongsToVirtualPool(method)) { - newMap.put(wrap(method.getReference()), method); + newMap.put(method.getSignature(), method); } }); for (DexEncodedMethod method : methods) { assert belongsToDirectPool(method); - newMap.put(wrap(method.getReference()), method); + newMap.put(method.getSignature(), method); } methodMap = newMap; } @@ -247,17 +238,16 @@ if (methods == null) { methods = DexEncodedMethod.EMPTY_ARRAY; } - Object2ReferenceMap<Wrapper<DexMethod>, DexEncodedMethod> newMap = - createMap(size() + methods.length); + Map<DexMethodSignature, DexEncodedMethod> newMap = createMap(size() + methods.length); forEachMethod( method -> { if (belongsToDirectPool(method)) { - newMap.put(wrap(method.getReference()), method); + newMap.put(method.getSignature(), method); } }); for (DexEncodedMethod method : methods) { assert belongsToVirtualPool(method); - newMap.put(wrap(method.getReference()), method); + newMap.put(method.getSignature(), method); } methodMap = newMap; } @@ -325,7 +315,7 @@ DexMethod method, Function<DexEncodedMethod, DexEncodedMethod> replacement, Predicate<DexEncodedMethod> predicate) { - Wrapper<DexMethod> key = wrap(method); + DexMethodSignature key = method.getSignature(); DexEncodedMethod existing = methodMap.get(key); if (existing == null || !predicate.test(existing)) { return null; @@ -339,7 +329,7 @@ @Override DexEncodedMethod replaceDirectMethodWithVirtualMethod( DexMethod method, Function<DexEncodedMethod, DexEncodedMethod> replacement) { - Wrapper<DexMethod> key = wrap(method); + DexMethodSignature key = method.getSignature(); DexEncodedMethod existing = methodMap.get(key); if (existing == null || belongsToVirtualPool(existing)) { return null; @@ -359,7 +349,7 @@ private boolean verifyVirtualizedMethods(Set<DexEncodedMethod> methods) { for (DexEncodedMethod method : methods) { assert belongsToVirtualPool(method); - assert methodMap.get(wrap(method.getReference())) == method; + assert methodMap.get(method.getSignature()) == method; } return true; }
diff --git a/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java b/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java index aadd446..f1e8ae1 100644 --- a/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java +++ b/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java
@@ -80,6 +80,10 @@ return false; } + public boolean isClassNotFoundResult() { + return false; + } + /** Returns non-null if isFailedResolution() is true, otherwise null. */ public FailedResolutionResult asFailedResolution() { return null; @@ -94,6 +98,10 @@ return null; } + public ProgramMethod getResolvedProgramMethod() { + return null; + } + @Override public DexClassAndMethod getResolutionPair() { return null; @@ -188,6 +196,7 @@ return resolvedMethod; } + @Override public ProgramMethod getResolvedProgramMethod() { return resolvedHolder.isProgramClass() ? new ProgramMethod(resolvedHolder.asProgramClass(), resolvedMethod) @@ -846,6 +855,11 @@ private ClassNotFoundResult() { // Intentionally left empty. } + + @Override + public boolean isClassNotFoundResult() { + return true; + } } public abstract static class FailedResolutionWithCausingMethods extends FailedResolutionResult {
diff --git a/src/main/java/com/android/tools/r8/graph/TreeFixerBase.java b/src/main/java/com/android/tools/r8/graph/TreeFixerBase.java index d09c3f5..f3670f3 100644 --- a/src/main/java/com/android/tools/r8/graph/TreeFixerBase.java +++ b/src/main/java/com/android/tools/r8/graph/TreeFixerBase.java
@@ -208,7 +208,10 @@ // inner class attributes. boolean innerClassAttributeChanged = newInnerClassType != innerClassType || newOuterClassType != outerClassType; - if (innerClassAttributeChanged && innerClassType != null && outerClassType != null) { + if (innerClassAttributeChanged + && innerClassType != null + && outerClassType != null + && innerClassAttribute.getInnerName() != null) { String innerClassName = DescriptorUtils.getInnerClassName( newOuterClassType.toDescriptorString(), newInnerClassType.toDescriptorString()); @@ -217,10 +220,8 @@ } else { // If run without treeshaking and the outer type is missing we are not pruning the // relationship. - // TODO(b/196503304): Enable the below asserts when resolved. - assert !appView.options().isTreeShakingEnabled() || true; - // assert appView.appInfo().definitionForWithoutExistenceAssert(newOuterClassType) == - // null; + assert !appView.options().isTreeShakingEnabled(); + assert appView.appInfo().definitionForWithoutExistenceAssert(newOuterClassType) == null; } } newInnerClassAttributes.add(
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java index b4615df..9da5368 100644 --- a/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java +++ b/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
@@ -6,18 +6,11 @@ import com.android.tools.r8.androidapi.AndroidApiReferenceLevelCache; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexEncodedMember; -import com.android.tools.r8.graph.DexEncodedMethod; -import com.android.tools.r8.graph.DexMember; +import com.android.tools.r8.graph.DexClassAndMember; import com.android.tools.r8.graph.LookupTarget; import com.android.tools.r8.graph.ProgramDefinition; import com.android.tools.r8.graph.ProgramField; import com.android.tools.r8.graph.ProgramMethod; -import com.android.tools.r8.ir.optimize.info.DefaultFieldOptimizationWithMinApiInfo; -import com.android.tools.r8.ir.optimize.info.DefaultMethodOptimizationInfo; -import com.android.tools.r8.ir.optimize.info.DefaultMethodOptimizationWithMinApiInfo; -import com.android.tools.r8.ir.optimize.info.MemberOptimizationInfo; -import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo; import com.android.tools.r8.shaking.DefaultEnqueuerUseRegistry; import com.android.tools.r8.utils.AndroidApiLevel; @@ -35,14 +28,12 @@ @Override public void processNewlyLiveField(ProgramField field, ProgramDefinition context) { - setApiLevelForMemberDefinition( - field.getDefinition(), computeApiLevelForReferencedTypes(field.getReference())); + computeApiLevelForDefinition(field); } @Override public void processNewlyLiveMethod(ProgramMethod method, ProgramDefinition context) { - setApiLevelForMemberDefinition( - method.getDefinition(), computeApiLevelForReferencedTypes(method.getReference())); + computeApiLevelForDefinition(method); } @Override @@ -55,71 +46,35 @@ .tracedMethodApiLevelCallback .accept(method.getMethodReference(), registry.getMaxApiReferenceLevel()); } - setApiLevelForMemberDefinition( - method.getDefinition(), computeApiLevelForReferencedTypes(method.getReference())); - setApiLevelForCode(method.getDefinition(), registry.getMaxApiReferenceLevel()); + computeApiLevelForDefinition(method); + method.getDefinition().setApiLevelForCode(registry.getMaxApiReferenceLevel()); } @Override public void notifyMarkMethodAsTargeted(ProgramMethod method) { - setApiLevelForMemberDefinition(method.getDefinition(), minApiLevel); + computeApiLevelForDefinition(method); } @Override public void notifyMarkFieldAsReachable(ProgramField field) { - setApiLevelForMemberDefinition(field.getDefinition(), minApiLevel); + computeApiLevelForDefinition(field); } @Override public void notifyMarkVirtualDispatchTargetAsLive(LookupTarget target) { target.accept( - dexClassAndMethod -> { - setApiLevelForMemberDefinition(dexClassAndMethod.getDefinition(), minApiLevel); - }, + this::computeApiLevelForDefinition, lookupLambdaTarget -> { // The implementation method will be assigned an api level when visited. }); } - private void setApiLevelForMemberDefinition( - DexEncodedMember<?, ?> member, AndroidApiLevel apiLevel) { - // To not have mutable update information for all members that all has min api level we - // swap the default optimization info for one with that marks the api level to be min api. - MemberOptimizationInfo<?> optimizationInfo = member.getOptimizationInfo(); - if (!optimizationInfo.isMutableOptimizationInfo() && apiLevel == minApiLevel) { - member.accept( - field -> { - field.setMinApiOptimizationInfo(DefaultFieldOptimizationWithMinApiInfo.getInstance()); - }, - method -> { - method.setMinApiOptimizationInfo(DefaultMethodOptimizationWithMinApiInfo.getInstance()); - }); - } else { - AndroidApiLevel maxApiLevel = - optimizationInfo.hasApiReferenceLevelForDefinition() - ? apiLevel.max(optimizationInfo.getApiReferenceLevelForDefinition(minApiLevel)) - : apiLevel; - member.accept( - field -> { - field.getMutableOptimizationInfo().setApiReferenceLevelForDefinition(maxApiLevel); - }, - method -> { - method.getMutableOptimizationInfo().setApiReferenceLevelForDefinition(maxApiLevel); - }); - } - } - - private void setApiLevelForCode(DexEncodedMethod method, AndroidApiLevel apiLevel) { - MethodOptimizationInfo optimizationInfo = method.getOptimizationInfo(); - assert optimizationInfo != DefaultMethodOptimizationInfo.getInstance(); - if (!optimizationInfo.isMutableOptimizationInfo() && apiLevel == minApiLevel) { - assert optimizationInfo == DefaultMethodOptimizationWithMinApiInfo.getInstance(); - return; - } - method.getMutableOptimizationInfo().setApiReferenceLevelForCode(apiLevel); - } - - private AndroidApiLevel computeApiLevelForReferencedTypes(DexMember<?, ?> member) { - return member.computeApiLevelForReferencedTypes(appView, referenceLevelCache::lookupMax); + private void computeApiLevelForDefinition(DexClassAndMember<?, ?> member) { + member + .getDefinition() + .setApiLevelForDefinition( + member + .getReference() + .computeApiLevelForReferencedTypes(appView, referenceLevelCache::lookupMax)); } }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java index a772278..43a2c8a 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
@@ -4,7 +4,7 @@ package com.android.tools.r8.horizontalclassmerging; -import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabledForNewMember; +import static com.android.tools.r8.utils.AndroidApiLevel.minApiLevelIfEnabledOrUnknown; import static com.google.common.base.Predicates.not; import com.android.tools.r8.graph.AppInfoWithClassHierarchy; @@ -45,7 +45,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.function.Function; /** * The class merger is responsible for moving methods from the sources in {@link ClassMerger#group} @@ -141,8 +140,8 @@ classInitializerMerger.getCode(syntheticMethodReference), DexEncodedMethod.D8_R8_SYNTHESIZED, classInitializerMerger.getCfVersion(), - getApiLevelIfEnabledForNewMember(appView, ignored -> apiReferenceLevel), - getApiLevelIfEnabledForNewMember(appView, ignored -> apiReferenceLevel)); + apiReferenceLevel, + apiReferenceLevel); classMethodsBuilder.addDirectMethod(definition); // In case we didn't synthesize CF code, we register the class initializer for conversion to dex @@ -230,7 +229,7 @@ null, deprecated, d8R8Synthesized, - getApiLevelIfEnabledForNewMember(appView, Function.identity())); + minApiLevelIfEnabledOrUnknown(appView)); // For the $r8$classId synthesized fields, we try to over-approximate the set of values it may // have. For example, for a merge group of size 4, we may compute the set {0, 2, 3}, if the
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java index adc89fc..d6ae971 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java
@@ -5,7 +5,6 @@ package com.android.tools.r8.horizontalclassmerging; import static com.android.tools.r8.dex.Constants.TEMPORARY_INSTANCE_INITIALIZER_PREFIX; -import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabledForNewMember; import com.android.tools.r8.cf.CfVersion; import com.android.tools.r8.dex.Constants; @@ -372,10 +371,8 @@ getNewCode(newMethodReference, syntheticMethodReference, needsClassId, extraNulls), true, getNewClassFileVersion(), - getApiLevelIfEnabledForNewMember( - appView, representativeMethod::getApiReferenceLevelForDefinition), - getApiLevelIfEnabledForNewMember( - appView, representativeMethod::getApiReferenceLevelForCode)); + representativeMethod.getApiLevelForDefinition(), + representativeMethod.getApiLevelForCode()); classMethodsBuilder.addDirectMethod(newInstanceInitializer); if (mode.isFinal()) {
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java index 87a3211..be6a5a2 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
@@ -4,8 +4,6 @@ package com.android.tools.r8.horizontalclassmerging; -import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabledForNewMember; - import com.android.tools.r8.cf.CfVersion; import com.android.tools.r8.graph.AppInfoWithClassHierarchy; import com.android.tools.r8.graph.AppView; @@ -289,10 +287,8 @@ synthesizedCode, true, classFileVersion, - getApiLevelIfEnabledForNewMember( - appView, representativeMethod::getApiReferenceLevelForDefinition), - getApiLevelIfEnabledForNewMember( - appView, representativeMethod::getApiReferenceLevelForCode)); + representativeMethod.getApiLevelForDefinition(), + representativeMethod.getApiLevelForCode()); if (!representative.getDefinition().isLibraryMethodOverride().isUnknown()) { newMethod.setLibraryMethodOverride(representative.getDefinition().isLibraryMethodOverride()); }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java index cff4480..3251db1 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java
@@ -4,7 +4,7 @@ package com.android.tools.r8.horizontalclassmerging.code; -import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabled; +import static com.android.tools.r8.utils.AndroidApiLevel.minApiLevelIfEnabledOrUnknown; import static java.lang.Integer.max; import com.android.tools.r8.cf.CfVersion; @@ -104,12 +104,8 @@ assert !classInitializers.isEmpty(); return ListUtils.fold( classInitializers, - appView.options().apiModelingOptions().enableApiCallerIdentification - ? appView.options().minApiLevel - : AndroidApiLevel.UNKNOWN, - (accApiLevel, method) -> - accApiLevel.max( - getApiLevelIfEnabled(appView, method.getDefinition()::getApiReferenceLevel))); + minApiLevelIfEnabledOrUnknown(appView), + (accApiLevel, method) -> accApiLevel.max(method.getDefinition().getApiLevel())); } public static class Builder {
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 083c27f..9e83183 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
@@ -140,6 +140,16 @@ } @Override + public ClassTypeElement joinNullability(Nullability nullability) { + return getOrCreateVariant(nullability().join(nullability)); + } + + @Override + public ClassTypeElement meetNullability(Nullability nullability) { + return getOrCreateVariant(nullability().meet(nullability)); + } + + @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append(nullability);
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicType.java b/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicType.java index 12d1c4c..5db6f54 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicType.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicType.java
@@ -7,6 +7,7 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.ir.code.Value; import com.android.tools.r8.shaking.AppInfoWithLiveness; +import java.util.Objects; /** * Represents the runtime type of a reference value. This type may be more precise than the value's @@ -27,18 +28,40 @@ this.dynamicUpperBoundType = dynamicUpperBoundType; } - public static DynamicType create(Value value, AppView<AppInfoWithLiveness> appView) { - assert value.getType().isReferenceType(); - TypeElement dynamicUpperBoundType = value.getDynamicUpperBoundType(appView); - ClassTypeElement dynamicLowerBoundType = value.getDynamicLowerBoundType(appView); + public static DynamicType create( + AppView<AppInfoWithLiveness> appView, + TypeElement dynamicUpperBoundType, + ClassTypeElement dynamicLowerBoundType) { + if (dynamicUpperBoundType.isBottom()) { + return bottom(); + } + if (dynamicUpperBoundType.isTop()) { + return unknown(); + } if (dynamicLowerBoundType != null) { assert dynamicUpperBoundType.isClassType(); + assert dynamicUpperBoundType.nullability() == dynamicLowerBoundType.nullability(); + if (dynamicUpperBoundType.equals(dynamicLowerBoundType)) { + return createExact(dynamicLowerBoundType); + } return DynamicTypeWithLowerBound.create( appView, dynamicUpperBoundType.asClassType(), dynamicLowerBoundType); } return new DynamicType(dynamicUpperBoundType); } + public static DynamicType createExact(ClassTypeElement exactDynamicType) { + return new ExactDynamicType(exactDynamicType); + } + + public static DynamicType create(Value value, AppView<AppInfoWithLiveness> appView) { + assert value.getType().isReferenceType(); + TypeElement dynamicUpperBoundType = value.getDynamicUpperBoundType(appView); + ClassTypeElement dynamicLowerBoundType = + value.getDynamicLowerBoundType(appView, dynamicUpperBoundType.nullability()); + return create(appView, dynamicUpperBoundType, dynamicLowerBoundType); + } + public static DynamicType bottom() { return BOTTOM; } @@ -59,21 +82,61 @@ return null; } + public boolean isBottom() { + return getDynamicUpperBoundType().isBottom(); + } + public boolean isTrivial(TypeElement staticType) { - return staticType == getDynamicUpperBoundType() || isUnknown(); + return staticType.equals(getDynamicUpperBoundType()) || isUnknown(); } public boolean isUnknown() { return getDynamicUpperBoundType().isTop(); } + public DynamicType join(AppView<AppInfoWithLiveness> appView, DynamicType dynamicType) { + if (isBottom()) { + return dynamicType; + } + if (dynamicType.isBottom() || equals(dynamicType)) { + return this; + } + if (isUnknown() || dynamicType.isUnknown()) { + return unknown(); + } + TypeElement upperBoundType = + getDynamicUpperBoundType().join(dynamicType.getDynamicUpperBoundType(), appView); + ClassTypeElement lowerBoundType = meetDynamicLowerBound(appView, dynamicType); + if (upperBoundType.equals(getDynamicUpperBoundType()) + && Objects.equals(lowerBoundType, getDynamicLowerBoundType())) { + return this; + } + return create(appView, upperBoundType, lowerBoundType); + } + + private ClassTypeElement meetDynamicLowerBound( + AppView<AppInfoWithLiveness> appView, DynamicType dynamicType) { + if (!hasDynamicLowerBoundType() || !dynamicType.hasDynamicLowerBoundType()) { + return null; + } + ClassTypeElement lowerBoundType = getDynamicLowerBoundType(); + ClassTypeElement otherLowerBoundType = dynamicType.getDynamicLowerBoundType(); + if (lowerBoundType.lessThanOrEqualUpToNullability(otherLowerBoundType, appView)) { + return lowerBoundType.joinNullability(otherLowerBoundType.nullability()); + } + if (otherLowerBoundType.lessThanOrEqualUpToNullability(lowerBoundType, appView)) { + return otherLowerBoundType.joinNullability(lowerBoundType.nullability()); + } + return null; + } + @Override public boolean equals(Object other) { if (other == null || getClass() != other.getClass()) { return false; } - DynamicType assumption = (DynamicType) other; - return dynamicUpperBoundType == assumption.dynamicUpperBoundType; + DynamicType dynamicType = (DynamicType) other; + return dynamicUpperBoundType.equals(dynamicType.dynamicUpperBoundType); } @Override
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicTypeWithLowerBound.java b/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicTypeWithLowerBound.java index ae61ee3..400f99e 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicTypeWithLowerBound.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicTypeWithLowerBound.java
@@ -15,16 +15,21 @@ DynamicTypeWithLowerBound( ClassTypeElement dynamicUpperBoundType, ClassTypeElement dynamicLowerBoundType) { super(dynamicUpperBoundType); + assert !dynamicUpperBoundType.equals(dynamicLowerBoundType); this.dynamicLowerBoundType = dynamicLowerBoundType; } - public static DynamicTypeWithLowerBound create( + static DynamicTypeWithLowerBound create( AppView<AppInfoWithLiveness> appView, ClassTypeElement dynamicUpperBoundType, ClassTypeElement dynamicLowerBoundType) { + assert dynamicUpperBoundType != null; + assert dynamicLowerBoundType != null; + assert dynamicUpperBoundType.nullability() == dynamicLowerBoundType.nullability(); assert appView .appInfo() - .isSubtype(dynamicLowerBoundType.getClassType(), dynamicUpperBoundType.getClassType()); + .isStrictSubtypeOf( + dynamicLowerBoundType.getClassType(), dynamicUpperBoundType.getClassType()); return new DynamicTypeWithLowerBound(dynamicUpperBoundType, dynamicLowerBoundType); } @@ -48,9 +53,9 @@ if (other == null || getClass() != other.getClass()) { return false; } - DynamicTypeWithLowerBound assumption = (DynamicTypeWithLowerBound) other; - return getDynamicUpperBoundType() == assumption.getDynamicUpperBoundType() - && getDynamicLowerBoundType() == assumption.getDynamicLowerBoundType(); + DynamicTypeWithLowerBound dynamicType = (DynamicTypeWithLowerBound) other; + return getDynamicUpperBoundType().equals(dynamicType.getDynamicUpperBoundType()) + && getDynamicLowerBoundType().equals(dynamicType.getDynamicLowerBoundType()); } @Override
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/ExactDynamicType.java b/src/main/java/com/android/tools/r8/ir/analysis/type/ExactDynamicType.java new file mode 100644 index 0000000..a6061d9 --- /dev/null +++ b/src/main/java/com/android/tools/r8/ir/analysis/type/ExactDynamicType.java
@@ -0,0 +1,41 @@ +// 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.ir.analysis.type; + +public class ExactDynamicType extends DynamicType { + + ExactDynamicType(ClassTypeElement exactDynamicType) { + super(exactDynamicType); + } + + @Override + public boolean hasDynamicLowerBoundType() { + return true; + } + + @Override + public ClassTypeElement getDynamicLowerBoundType() { + return getDynamicUpperBoundType().asClassType(); + } + + @Override + public boolean isTrivial(TypeElement staticType) { + return false; + } + + @Override + public boolean equals(Object other) { + if (other == null || getClass() != other.getClass()) { + return false; + } + ExactDynamicType dynamicType = (ExactDynamicType) other; + return getDynamicUpperBoundType().equals(dynamicType.getDynamicUpperBoundType()); + } + + @Override + public int hashCode() { + return getDynamicLowerBoundType().hashCode(); + } +}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/Nullability.java b/src/main/java/com/android/tools/r8/ir/analysis/type/Nullability.java index 26b9030..e45ac9a 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/type/Nullability.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/type/Nullability.java
@@ -29,6 +29,10 @@ private Nullability() {} + public boolean isBottom() { + return this == BOTTOM; + } + public boolean isDefinitelyNull() { return this == DEFINITELY_NULL; }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/ReferenceTypeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/ReferenceTypeElement.java index c150cfd..3577c72 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/type/ReferenceTypeElement.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/type/ReferenceTypeElement.java
@@ -78,6 +78,10 @@ return getOrCreateVariant(nullability.meet(Nullability.definitelyNotNull())); } + public TypeElement asDefinitelyNull() { + return getOrCreateVariant(Nullability.definitelyNull()); + } + public TypeElement asDefinitelyNotNull() { return getOrCreateVariant(Nullability.definitelyNotNull()); } @@ -86,6 +90,14 @@ return getOrCreateVariant(Nullability.maybeNull()); } + public ReferenceTypeElement joinNullability(Nullability nullability) { + return getOrCreateVariant(nullability().join(nullability)); + } + + public ReferenceTypeElement meetNullability(Nullability nullability) { + return getOrCreateVariant(nullability().meet(nullability)); + } + @Override public boolean isReferenceType() { return true;
diff --git a/src/main/java/com/android/tools/r8/ir/code/Assume.java b/src/main/java/com/android/tools/r8/ir/code/Assume.java index 3a51eec..f25c73b 100644 --- a/src/main/java/com/android/tools/r8/ir/code/Assume.java +++ b/src/main/java/com/android/tools/r8/ir/code/Assume.java
@@ -311,6 +311,8 @@ } public boolean verifyCorrectnessOfValues(Value dest, Value src, AppView<?> appView) { + assert !dynamicUpperBoundType.isBottom(); + assert !dynamicUpperBoundType.isTop(); assert dynamicUpperBoundType.lessThanOrEqualUpToNullability(src.getType(), appView); return true; }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Value.java b/src/main/java/com/android/tools/r8/ir/code/Value.java index ce8efd1..4df7f91 100644 --- a/src/main/java/com/android/tools/r8/ir/code/Value.java +++ b/src/main/java/com/android/tools/r8/ir/code/Value.java
@@ -23,6 +23,7 @@ import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.type.ClassTypeElement; import com.android.tools.r8.ir.analysis.type.DynamicType; +import com.android.tools.r8.ir.analysis.type.Nullability; import com.android.tools.r8.ir.analysis.type.TypeElement; import com.android.tools.r8.ir.analysis.value.AbstractValue; import com.android.tools.r8.ir.analysis.value.UnknownValue; @@ -1136,13 +1137,18 @@ } public ClassTypeElement getDynamicLowerBoundType(AppView<AppInfoWithLiveness> appView) { + return getDynamicLowerBoundType(appView, Nullability.maybeNull()); + } + + public ClassTypeElement getDynamicLowerBoundType( + AppView<AppInfoWithLiveness> appView, Nullability maxNullability) { // If it is a final or effectively-final class type, then we know the lower bound. if (getType().isClassType()) { ClassTypeElement classType = getType().asClassType(); DexType type = classType.getClassType(); DexClass clazz = appView.definitionFor(type); if (clazz != null && clazz.isEffectivelyFinal(appView)) { - return classType; + return classType.meetNullability(maxNullability); } } @@ -1151,25 +1157,32 @@ return null; } - Instruction definition = root.definition; + Instruction definition = root.getDefinition(); if (definition.isNewInstance()) { - DexType type = definition.asNewInstance().clazz; + DexType type = definition.asNewInstance().getType(); DexClass clazz = appView.definitionFor(type); if (clazz != null && !clazz.isInterface()) { - return ClassTypeElement.create(type, definitelyNotNull(), appView); + assert !maxNullability.isBottom(); + return TypeElement.fromDexType(type, definitelyNotNull(), appView).asClassType(); } return null; } // Try to find an alias of the receiver, which is defined by an instruction of the type Assume. Value aliasedValue = - getSpecificAliasedValue(value -> value.definition.isAssumeWithDynamicTypeAssumption()); + getSpecificAliasedValue(value -> value.getDefinition().isAssumeWithDynamicTypeAssumption()); if (aliasedValue != null) { - ClassTypeElement lattice = - aliasedValue.definition.asAssume().getDynamicTypeAssumption().getDynamicLowerBoundType(); - return lattice != null && type.isDefinitelyNotNull() && lattice.isNullable() - ? lattice.asMeetWithNotNull() - : lattice; + ClassTypeElement aliasedValueType = + aliasedValue + .getDefinition() + .asAssume() + .getDynamicTypeAssumption() + .getDynamicLowerBoundType(); + if (aliasedValueType != null) { + aliasedValueType = aliasedValueType.meetNullability(getType().nullability()); + assert aliasedValueType.nullability().lessThanOrEqual(maxNullability); + return aliasedValueType; + } } return null;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/ClassConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/ClassConverter.java index 3129b82..2a30a23 100644 --- a/src/main/java/com/android/tools/r8/ir/conversion/ClassConverter.java +++ b/src/main/java/com/android/tools/r8/ir/conversion/ClassConverter.java
@@ -13,7 +13,9 @@ import com.android.tools.r8.ir.desugar.CfClassDesugaringEventConsumer.D8CfClassDesugaringEventConsumer; import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer; import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer.D8CfInstructionDesugaringEventConsumer; +import com.android.tools.r8.ir.desugar.CfL8ClassSynthesizerEventConsumer; import com.android.tools.r8.utils.ThreadUtils; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Sets; import java.util.ArrayList; import java.util.List; @@ -53,6 +55,17 @@ throws ExecutionException { List<DexProgramClass> classes = appView.appInfo().classes(); + if (appView.options().isDesugaredLibraryCompilation()) { + CfL8ClassSynthesizerEventConsumer l8ClassSynthesizerEventConsumer = + new CfL8ClassSynthesizerEventConsumer(); + converter.l8ClassSynthesis(executorService, l8ClassSynthesizerEventConsumer); + classes = + ImmutableList.<DexProgramClass>builder() + .addAll(classes) + .addAll(l8ClassSynthesizerEventConsumer.getSynthesizedClasses()) + .build(); + } + D8CfClassDesugaringEventConsumer classDesugaringEventConsumer = CfClassDesugaringEventConsumer.createForD8(methodProcessor); converter.desugarClassesForD8(classes, classDesugaringEventConsumer, executorService); @@ -76,11 +89,6 @@ D8CfInstructionDesugaringEventConsumer instructionDesugaringEventConsumer = CfInstructionDesugaringEventConsumer.createForD8(methodProcessor); - // TODO(b/191656218): Move upfront the loop and use maybe the class event consumer. - if (appView.options().isDesugaredLibraryCompilation()) { - converter.ensureWrappersForL8(instructionDesugaringEventConsumer); - } - // Process the wave and wait for all IR processing to complete. methodProcessor.newWave(); ThreadUtils.processItems(
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java index 73ef0f1..8595ecd 100644 --- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java +++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -49,6 +49,8 @@ import com.android.tools.r8.ir.desugar.CfInstructionDesugaringCollection; import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer; import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer.D8CfInstructionDesugaringEventConsumer; +import com.android.tools.r8.ir.desugar.CfL8ClassSynthesizerCollection; +import com.android.tools.r8.ir.desugar.CfL8ClassSynthesizerEventConsumer; import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringCollection; import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer; import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer.D8CfPostProcessingDesugaringEventConsumer; @@ -355,13 +357,6 @@ D8NestBasedAccessDesugaring::clearNestAttributes); } - public void ensureWrappersForL8( - D8CfInstructionDesugaringEventConsumer instructionDesugaringEventConsumer) { - assert appView.options().isDesugaredLibraryCompilation(); - instructionDesugaring.withDesugaredLibraryAPIConverter( - converter -> converter.ensureWrappersForL8(instructionDesugaringEventConsumer)); - } - private void staticizeClasses( OptimizationFeedback feedback, ExecutorService executorService, GraphLens applied) throws ExecutionException { @@ -414,11 +409,11 @@ reportNestDesugarDependencies(); clearNestAttributes(); - application = commitPendingSyntheticItems(appView, application); + application = commitPendingSyntheticItemsD8(appView, application); postProcessingDesugaringForD8(methodProcessor, executor); - application = commitPendingSyntheticItems(appView, application); + application = commitPendingSyntheticItemsD8(appView, application); // Build a new application with jumbo string info, Builder<?> builder = application.builder().setHighestSortingString(highestSortingString); @@ -437,7 +432,7 @@ appView.appInfo().getMainDexInfo())); } - private DexApplication commitPendingSyntheticItems( + private DexApplication commitPendingSyntheticItemsD8( AppView<AppInfo> appView, DexApplication application) { if (appView.getSyntheticItems().hasPendingSyntheticClasses()) { appView.setAppInfo( @@ -449,6 +444,23 @@ return application; } + private static void commitPendingSyntheticItemsR8(AppView<AppInfoWithLiveness> appView) { + if (appView.getSyntheticItems().hasPendingSyntheticClasses()) { + appView.setAppInfo( + appView + .appInfo() + .rebuildWithLiveness(appView.getSyntheticItems().commit(appView.appInfo().app()))); + } + } + + public void l8ClassSynthesis( + ExecutorService executorService, + CfL8ClassSynthesizerEventConsumer l8ClassSynthesizerEventConsumer) + throws ExecutionException { + new CfL8ClassSynthesizerCollection(appView, instructionDesugaring.getRetargetingInfo()) + .synthesizeClasses(executorService, l8ClassSynthesizerEventConsumer); + } + private void postProcessingDesugaringForD8( D8MethodProcessor methodProcessor, ExecutorService executorService) throws ExecutionException { @@ -726,6 +738,9 @@ // lenses with code rewriting are added. appView.clearCodeRewritings(); + // Commit synthetics from the primary optimization pass. + commitPendingSyntheticItemsR8(appView); + // Analyze the data collected by the argument propagator, use the analysis result to update // the parameter optimization infos, and rewrite the application. appView.withArgumentPropagator( @@ -797,12 +812,8 @@ // Commit synthetics before creating a builder (otherwise the builder will not include the // synthetics.) - if (appView.getSyntheticItems().hasPendingSyntheticClasses()) { - appView.setAppInfo( - appView - .appInfo() - .rebuildWithLiveness(appView.getSyntheticItems().commit(appView.appInfo().app()))); - } + commitPendingSyntheticItemsR8(appView); + // Build a new application with jumbo string info. Builder<?> builder = appView.appInfo().app().builder(); builder.setHighestSortingString(highestSortingString); @@ -1538,7 +1549,7 @@ printMethod(code, "IR after idempotent function call canonicalization (SSA)", previous); // Insert code to log arguments if requested. - if (options.methodMatchesLogArgumentsFilter(method)) { + if (options.methodMatchesLogArgumentsFilter(method) && !method.isProcessed()) { codeRewriter.logArgumentTypes(method, code); assert code.isConsistentSSA(); }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java index 0b29d90..6eda99c 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
@@ -6,7 +6,6 @@ import com.android.tools.r8.graph.AppInfoWithClassHierarchy; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexClass; import com.android.tools.r8.graph.DexClasspathClass; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexReference; @@ -15,8 +14,8 @@ import com.android.tools.r8.ir.conversion.ClassConverterResult; import com.android.tools.r8.ir.conversion.D8MethodProcessor; import com.android.tools.r8.ir.desugar.backports.BackportedMethodDesugaringEventConsumer; -import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverterEventConsumer; -import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterInstructionEventConsumer; +import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterInstructionEventConsumer; +import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryAPIConverterEventConsumer; import com.android.tools.r8.ir.desugar.invokespecial.InvokeSpecialBridgeInfo; import com.android.tools.r8.ir.desugar.invokespecial.InvokeSpecialToSelfDesugaringEventConsumer; import com.android.tools.r8.ir.desugar.itf.InterfaceMethodDesugaringEventConsumer; @@ -70,11 +69,6 @@ return new CfInstructionDesugaringEventConsumer() { @Override - public void acceptWrapperProgramClass(DexProgramClass clazz) { - assert false; - } - - @Override public void acceptWrapperClasspathClass(DexClasspathClass clazz) { assert false; } @@ -85,21 +79,11 @@ } @Override - public void acceptDesugaredLibraryRetargeterDispatchProgramClass(DexProgramClass clazz) { - assert false; - } - - @Override public void acceptDesugaredLibraryRetargeterDispatchClasspathClass(DexClasspathClass clazz) { assert false; } @Override - public void acceptInterfaceInjection(DexProgramClass clazz, DexClass newInterface) { - assert false; - } - - @Override public void acceptThrowMethod(ProgramMethod method, ProgramMethod context) { assert false; } @@ -154,6 +138,11 @@ public void acceptTwrCloseResourceMethod(ProgramMethod closeMethod, ProgramMethod context) { assert false; } + + @Override + public void acceptCompanionClassClinit(ProgramMethod method) { + assert false; + } }; } @@ -171,21 +160,11 @@ } @Override - public void acceptDesugaredLibraryRetargeterDispatchProgramClass(DexProgramClass clazz) { - methodProcessor.scheduleDesugaredMethodsForProcessing(clazz.programMethods()); - } - - @Override public void acceptDesugaredLibraryRetargeterDispatchClasspathClass(DexClasspathClass clazz) { // Intentionally empty. } @Override - public void acceptInterfaceInjection(DexProgramClass clazz, DexClass newInterface) { - // Intentionally empty. - } - - @Override public void acceptBackportedMethod(ProgramMethod backportedMethod, ProgramMethod context) { methodProcessor.scheduleMethodForProcessing(backportedMethod, this); } @@ -247,11 +226,6 @@ } @Override - public void acceptWrapperProgramClass(DexProgramClass clazz) { - methodProcessor.scheduleDesugaredMethodsForProcessing(clazz.programMethods()); - } - - @Override public void acceptWrapperClasspathClass(DexClasspathClass clazz) { // Intentionally empty. } @@ -261,6 +235,11 @@ methodProcessor.scheduleDesugaredMethodForProcessing(method); } + @Override + public void acceptCompanionClassClinit(ProgramMethod method) { + methodProcessor.scheduleDesugaredMethodForProcessing(method); + } + public List<ProgramMethod> finalizeDesugaring( AppView<?> appView, ClassConverterResult.Builder classConverterResultBuilder) { List<ProgramMethod> needsProcessing = new ArrayList<>(); @@ -342,22 +321,16 @@ } @Override - public void acceptDesugaredLibraryRetargeterDispatchProgramClass(DexProgramClass clazz) { - // Called only in Desugared library compilation which is D8. - assert false; - } - - @Override - public void acceptInterfaceInjection(DexProgramClass clazz, DexClass newInterface) { - additions.injectInterface(clazz, newInterface); - } - - @Override public void acceptDesugaredLibraryRetargeterDispatchClasspathClass(DexClasspathClass clazz) { additions.addLiveClasspathClass(clazz); } @Override + public void acceptCompanionClassClinit(ProgramMethod method) { + // TODO(b/183998768): Update this once desugaring is moved to the enqueuer. + } + + @Override public void acceptRecordClass(DexProgramClass recordClass) { // This is called each time an instruction or a class is found to require the record class. assert false : "TODO(b/179146128): To be implemented"; @@ -380,12 +353,6 @@ } @Override - public void acceptWrapperProgramClass(DexProgramClass clazz) { - // Called only in Desugared library compilation which is D8. - assert false; - } - - @Override public void acceptWrapperClasspathClass(DexClasspathClass clazz) { additions.addLiveClasspathClass(clazz); }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfL8ClassSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/CfL8ClassSynthesizer.java new file mode 100644 index 0000000..2eefa63 --- /dev/null +++ b/src/main/java/com/android/tools/r8/ir/desugar/CfL8ClassSynthesizer.java
@@ -0,0 +1,10 @@ +// 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.ir.desugar; + +public interface CfL8ClassSynthesizer { + + void synthesizeClasses(CfL8ClassSynthesizerEventConsumer eventConsumer); +}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfL8ClassSynthesizerCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/CfL8ClassSynthesizerCollection.java new file mode 100644 index 0000000..9accf26 --- /dev/null +++ b/src/main/java/com/android/tools/r8/ir/desugar/CfL8ClassSynthesizerCollection.java
@@ -0,0 +1,43 @@ +// 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.ir.desugar; + +import com.android.tools.r8.graph.AppView; +import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterL8Synthesizer; +import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizer; +import com.android.tools.r8.ir.desugar.desugaredlibrary.RetargetingInfo; +import com.android.tools.r8.ir.desugar.itf.EmulatedInterfaceSynthesizer; +import com.android.tools.r8.utils.ThreadUtils; +import java.util.ArrayList; +import java.util.Collection; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; + +public class CfL8ClassSynthesizerCollection { + + private Collection<CfL8ClassSynthesizer> synthesizers = new ArrayList<>(); + + public CfL8ClassSynthesizerCollection(AppView<?> appView, RetargetingInfo retargetingInfo) { + assert appView.options().isDesugaredLibraryCompilation(); + EmulatedInterfaceSynthesizer emulatedInterfaceSynthesizer = + EmulatedInterfaceSynthesizer.create(appView); + if (emulatedInterfaceSynthesizer != null) { + synthesizers.add(emulatedInterfaceSynthesizer); + } + DesugaredLibraryRetargeterL8Synthesizer retargeterL8Synthesizer = + DesugaredLibraryRetargeterL8Synthesizer.create(appView, retargetingInfo); + if (retargeterL8Synthesizer != null) { + synthesizers.add(retargeterL8Synthesizer); + } + synthesizers.add(new DesugaredLibraryWrapperSynthesizer(appView)); + } + + public void synthesizeClasses( + ExecutorService executorService, CfL8ClassSynthesizerEventConsumer eventConsumer) + throws ExecutionException { + ThreadUtils.processItems( + synthesizers, synthesizer -> synthesizer.synthesizeClasses(eventConsumer), executorService); + } +}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfL8ClassSynthesizerEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/CfL8ClassSynthesizerEventConsumer.java new file mode 100644 index 0000000..5e41810 --- /dev/null +++ b/src/main/java/com/android/tools/r8/ir/desugar/CfL8ClassSynthesizerEventConsumer.java
@@ -0,0 +1,40 @@ +// 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.ir.desugar; + +import com.android.tools.r8.graph.DexProgramClass; +import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterL8SynthesizerEventConsumer; +import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer; +import com.android.tools.r8.ir.desugar.itf.EmulatedInterfaceSynthesizerEventConsumer; +import com.google.common.collect.Sets; +import java.util.Set; + +public class CfL8ClassSynthesizerEventConsumer + implements EmulatedInterfaceSynthesizerEventConsumer, + DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer, + DesugaredLibraryRetargeterL8SynthesizerEventConsumer { + + private Set<DexProgramClass> synthesizedClasses = Sets.newConcurrentHashSet(); + + @Override + public void acceptEmulatedInterface(DexProgramClass clazz) { + synthesizedClasses.add(clazz); + } + + @Override + public void acceptWrapperProgramClass(DexProgramClass clazz) { + synthesizedClasses.add(clazz); + } + + @Override + public void acceptDesugaredLibraryRetargeterDispatchProgramClass(DexProgramClass clazz) { + synthesizedClasses.add(clazz); + } + + public Set<DexProgramClass> getSynthesizedClasses() { + return synthesizedClasses; + } + +}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringCollection.java index e539861..2d99720 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringCollection.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringCollection.java
@@ -53,7 +53,8 @@ InterfaceMethodProcessorFacade interfaceMethodProcessorFacade, RetargetingInfo retargetingInfo) { ArrayList<CfPostProcessingDesugaring> desugarings = new ArrayList<>(); - if (!appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember().isEmpty()) { + if (!appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember().isEmpty() + && !appView.options().isDesugaredLibraryCompilation()) { desugarings.add(new DesugaredLibraryRetargeterPostProcessor(appView, retargetingInfo)); } if (interfaceMethodProcessorFacade != null) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringEventConsumer.java index d0b798b..95407f8 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringEventConsumer.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringEventConsumer.java
@@ -8,8 +8,8 @@ import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.conversion.D8MethodProcessor; -import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverterEventConsumer.DesugaredLibraryAPIConverterPostProcessingEventConsumer; -import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterInstructionEventConsumer.DesugaredLibraryRetargeterPostProcessingEventConsumer; +import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterPostProcessingEventConsumer; +import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryAPICallbackSynthesizorEventConsumer; import com.android.tools.r8.ir.desugar.itf.InterfaceProcessingDesugaringEventConsumer; import com.android.tools.r8.shaking.Enqueuer.SyntheticAdditions; import com.android.tools.r8.utils.collections.ProgramMethodSet; @@ -23,7 +23,7 @@ public abstract class CfPostProcessingDesugaringEventConsumer implements DesugaredLibraryRetargeterPostProcessingEventConsumer, InterfaceProcessingDesugaringEventConsumer, - DesugaredLibraryAPIConverterPostProcessingEventConsumer { + DesugaredLibraryAPICallbackSynthesizorEventConsumer { public static D8CfPostProcessingDesugaringEventConsumer createForD8( D8MethodProcessor methodProcessor) { @@ -38,6 +38,7 @@ public static class D8CfPostProcessingDesugaringEventConsumer extends CfPostProcessingDesugaringEventConsumer { + private final D8MethodProcessor methodProcessor; // Methods cannot be processed directly because we cannot add method to classes while // concurrently processing other methods. @@ -48,11 +49,6 @@ } @Override - public void acceptDesugaredLibraryRetargeterDispatchProgramClass(DexProgramClass clazz) { - methodsToReprocess.addAll(clazz.programMethods()); - } - - @Override public void acceptDesugaredLibraryRetargeterDispatchClasspathClass(DexClasspathClass clazz) { // Intentionally empty. } @@ -73,11 +69,6 @@ } @Override - public void acceptEmulatedInterfaceMethod(ProgramMethod method) { - methodsToReprocess.add(method); - } - - @Override public void finalizeDesugaring() throws ExecutionException { assert methodProcessor.verifyNoPendingMethodProcessing(); methodProcessor.newWave(); @@ -89,10 +80,16 @@ public void acceptAPIConversionCallback(ProgramMethod method) { methodsToReprocess.add(method); } + + @Override + public void acceptWrapperClasspathClass(DexClasspathClass clazz) { + // Intentionally empty. + } } public static class R8PostProcessingDesugaringEventConsumer extends CfPostProcessingDesugaringEventConsumer { + private final SyntheticAdditions additions; R8PostProcessingDesugaringEventConsumer(SyntheticAdditions additions) { @@ -105,11 +102,6 @@ } @Override - public void acceptDesugaredLibraryRetargeterDispatchProgramClass(DexProgramClass clazz) { - additions.addLiveMethods(clazz.programMethods()); - } - - @Override public void acceptInterfaceInjection(DexProgramClass clazz, DexClass newInterface) { additions.injectInterface(clazz, newInterface); } @@ -130,13 +122,13 @@ } @Override - public void acceptEmulatedInterfaceMethod(ProgramMethod method) { - assert false : "TODO(b/183998768): Support Interface processing in R8"; + public void acceptAPIConversionCallback(ProgramMethod method) { + additions.addLiveMethod(method); } @Override - public void acceptAPIConversionCallback(ProgramMethod method) { - additions.addLiveMethod(method); + public void acceptWrapperClasspathClass(DexClasspathClass clazz) { + additions.addLiveClasspathClass(clazz); } } }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java index 88f451b..61e6828 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
@@ -5,7 +5,6 @@ package com.android.tools.r8.ir.desugar; import static com.android.tools.r8.ir.desugar.lambda.ForcefullyMovedLambdaMethodConsumer.emptyForcefullyMovedLambdaMethodConsumer; -import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabledForNewMember; import static com.android.tools.r8.utils.ConsumerUtils.emptyConsumer; import com.android.tools.r8.dex.Constants; @@ -40,11 +39,11 @@ import com.android.tools.r8.ir.optimize.info.OptimizationFeedback; import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple; import com.android.tools.r8.synthesis.SyntheticProgramClassBuilder; +import com.android.tools.r8.utils.AndroidApiLevel; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.function.Consumer; -import java.util.function.Function; /** * Represents lambda class generated for a lambda descriptor in context of lambda instantiation @@ -109,7 +108,7 @@ this.lambdaField = !stateless ? null : factory.createField(type, type, factory.lambdaInstanceFieldName); - // Synthesize the program class one all fields are set. + // Synthesize the program class once all fields are set. synthesizeLambdaClass(builder); } @@ -244,7 +243,8 @@ null, deprecated, d8R8Synthesized, - getApiLevelIfEnabledForNewMember(appView, Function.identity()))); + // The api level is computed when tracing. + AndroidApiLevel.minApiLevelIfEnabledOrUnknown(appView))); } builder.setInstanceFields(fields); } @@ -270,7 +270,8 @@ DexValueNull.NULL, deprecated, d8R8Synthesized, - getApiLevelIfEnabledForNewMember(appView, Function.identity())))); + // The api level is computed when tracing. + AndroidApiLevel.minApiLevelIfEnabledOrUnknown(appView)))); } }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPICallbackSynthesizor.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPICallbackSynthesizor.java index cfcb9b0..3e0143a 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPICallbackSynthesizor.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPICallbackSynthesizor.java
@@ -19,8 +19,8 @@ import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaring; import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer; -import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverterEventConsumer.DesugaredLibraryAPIConverterPostProcessingEventConsumer; -import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APIConverterWrapperCfCodeProvider; +import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryAPICallbackSynthesizorEventConsumer; +import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APICallbackWrapperCfCodeProvider; import com.android.tools.r8.utils.OptionalBool; import com.android.tools.r8.utils.WorkList; import com.google.common.collect.Sets; @@ -190,17 +190,16 @@ private ProgramMethod generateCallbackMethod( DexEncodedMethod originalMethod, DexProgramClass clazz, - DesugaredLibraryAPIConverterPostProcessingEventConsumer eventConsumer) { + DesugaredLibraryAPICallbackSynthesizorEventConsumer eventConsumer) { DexMethod methodToInstall = methodWithVivifiedTypeInSignature(originalMethod.getReference(), clazz.type, appView); CfCode cfCode = - new APIConverterWrapperCfCodeProvider( + new APICallbackWrapperCfCodeProvider( appView, originalMethod.getReference(), - null, wrapperSynthesizor, clazz.isInterface(), - null) + eventConsumer) .generateCfCode(); DexEncodedMethod newMethod = wrapperSynthesizor.newSynthesizedMethod(methodToInstall, originalMethod, cfCode); @@ -209,11 +208,8 @@ newMethod.setLibraryMethodOverride(OptionalBool.TRUE); } ProgramMethod callback = new ProgramMethod(clazz, newMethod); - if (eventConsumer != null) { - eventConsumer.acceptAPIConversionCallback(callback); - } else { - assert appView.enableWholeProgramOptimizations(); - } + assert eventConsumer != null; + eventConsumer.acceptAPIConversionCallback(callback); return callback; }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverter.java index ebab39e..be8ac84 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverter.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverter.java
@@ -34,6 +34,7 @@ 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.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryClasspathWrapperSynthesizeEventConsumer; import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter; import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APIConversionCfCodeProvider; import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind; @@ -241,12 +242,6 @@ DexProto newProto = appView.dexItemFactory().createProto(newReturnType, newParameters); return appView.dexItemFactory().createMethod(holder, newProto, originalMethod.name); } - - public void ensureWrappersForL8(CfInstructionDesugaringEventConsumer eventConsumer) { - assert appView.options().isDesugaredLibraryCompilation(); - wrapperSynthesizor.ensureWrappersForL8(eventConsumer); - } - public void generateTrackingWarnings() { generateTrackDesugaredAPIWarnings(trackedAPIs, "", appView); } @@ -324,7 +319,8 @@ } private DexMethod computeReturnConversion( - DexMethod invokedMethod, DesugaredLibraryAPIConverterEventConsumer eventConsumer) { + DexMethod invokedMethod, + DesugaredLibraryClasspathWrapperSynthesizeEventConsumer eventConsumer) { DexType returnType = invokedMethod.proto.returnType; if (wrapperSynthesizor.shouldConvert(returnType, invokedMethod)) { DexType newReturnType = DesugaredLibraryAPIConverter.vivifiedTypeFor(returnType, appView); @@ -335,7 +331,8 @@ } private DexMethod[] computeParameterConversions( - DexMethod invokedMethod, DesugaredLibraryAPIConverterEventConsumer eventConsumer) { + DexMethod invokedMethod, + DesugaredLibraryClasspathWrapperSynthesizeEventConsumer eventConsumer) { DexMethod[] parameterConversions = new DexMethod[invokedMethod.getArity()]; DexType[] parameters = invokedMethod.proto.parameters.values; for (int i = 0; i < parameters.length; i++) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverterEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverterEventConsumer.java deleted file mode 100644 index 7af64bb..0000000 --- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverterEventConsumer.java +++ /dev/null
@@ -1,23 +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.ir.desugar.desugaredlibrary; - -import com.android.tools.r8.graph.DexClasspathClass; -import com.android.tools.r8.graph.DexProgramClass; -import com.android.tools.r8.graph.ProgramMethod; - -public interface DesugaredLibraryAPIConverterEventConsumer { - - void acceptWrapperProgramClass(DexProgramClass clazz); - - void acceptWrapperClasspathClass(DexClasspathClass clazz); - - void acceptAPIConversion(ProgramMethod method); - - interface DesugaredLibraryAPIConverterPostProcessingEventConsumer { - - void acceptAPIConversionCallback(ProgramMethod method); - } -}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeter.java index a4c9b12..8a59f14 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeter.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeter.java
@@ -28,6 +28,7 @@ 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.desugar.desugaredlibrary.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterInstructionEventConsumer; import com.android.tools.r8.utils.collections.DexClassAndMethodSet; import java.util.Collection; import java.util.Collections;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterInstructionEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterInstructionEventConsumer.java deleted file mode 100644 index ae7630d..0000000 --- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterInstructionEventConsumer.java +++ /dev/null
@@ -1,25 +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.ir.desugar.desugaredlibrary; - -import com.android.tools.r8.graph.DexClass; -import com.android.tools.r8.graph.DexClasspathClass; -import com.android.tools.r8.graph.DexProgramClass; -import com.android.tools.r8.graph.ProgramMethod; - -public interface DesugaredLibraryRetargeterInstructionEventConsumer { - - void acceptDesugaredLibraryRetargeterDispatchProgramClass(DexProgramClass clazz); - - void acceptDesugaredLibraryRetargeterDispatchClasspathClass(DexClasspathClass clazz); - - void acceptInterfaceInjection(DexProgramClass clazz, DexClass newInterface); - - interface DesugaredLibraryRetargeterPostProcessingEventConsumer - extends DesugaredLibraryRetargeterInstructionEventConsumer { - - void acceptForwardingMethod(ProgramMethod method); - } -}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterL8Synthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterL8Synthesizer.java new file mode 100644 index 0000000..dad4cd6 --- /dev/null +++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterL8Synthesizer.java
@@ -0,0 +1,43 @@ +// 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.ir.desugar.desugaredlibrary; + +import com.android.tools.r8.graph.AppView; +import com.android.tools.r8.graph.DexClassAndMethod; +import com.android.tools.r8.ir.desugar.CfL8ClassSynthesizer; +import com.android.tools.r8.ir.desugar.CfL8ClassSynthesizerEventConsumer; +import com.android.tools.r8.utils.collections.DexClassAndMethodSet; + +public class DesugaredLibraryRetargeterL8Synthesizer implements CfL8ClassSynthesizer { + + private final AppView<?> appView; + private final DesugaredLibraryRetargeterSyntheticHelper syntheticHelper; + private final DexClassAndMethodSet emulatedDispatchMethods; + + public static DesugaredLibraryRetargeterL8Synthesizer create( + AppView<?> appView, RetargetingInfo retargetingInfo) { + assert appView.options().isDesugaredLibraryCompilation(); + if (retargetingInfo == null || retargetingInfo.getEmulatedDispatchMethods().isEmpty()) { + assert appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember().isEmpty(); + return null; + } + return new DesugaredLibraryRetargeterL8Synthesizer(appView, retargetingInfo); + } + + public DesugaredLibraryRetargeterL8Synthesizer( + AppView<?> appView, RetargetingInfo retargetingInfo) { + this.appView = appView; + this.syntheticHelper = new DesugaredLibraryRetargeterSyntheticHelper(appView); + emulatedDispatchMethods = retargetingInfo.getEmulatedDispatchMethods(); + } + + @Override + public void synthesizeClasses(CfL8ClassSynthesizerEventConsumer eventConsumer) { + assert !emulatedDispatchMethods.isEmpty(); + for (DexClassAndMethod emulatedDispatchMethod : emulatedDispatchMethods) { + syntheticHelper.ensureProgramEmulatedHolderDispatchMethod( + emulatedDispatchMethod, eventConsumer); + } + } +}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterPostProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterPostProcessor.java index 64d3cc6..b6200cb 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterPostProcessor.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterPostProcessor.java
@@ -15,7 +15,7 @@ import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaring; import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer; -import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterInstructionEventConsumer.DesugaredLibraryRetargeterPostProcessingEventConsumer; +import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterPostProcessingEventConsumer; import com.android.tools.r8.utils.OptionalBool; import com.android.tools.r8.utils.collections.DexClassAndMethodSet; import com.google.common.collect.Maps; @@ -49,11 +49,8 @@ CfPostProcessingDesugaringEventConsumer eventConsumer, ExecutorService executorService) throws ExecutionException { - if (appView.options().isDesugaredLibraryCompilation()) { - ensureEmulatedDispatchMethodsSynthesized(eventConsumer); - } else { - ensureInterfacesAndForwardingMethodsSynthesized(programClasses, eventConsumer); - } + assert !appView.options().isDesugaredLibraryCompilation(); + ensureInterfacesAndForwardingMethodsSynthesized(programClasses, eventConsumer); } private void ensureInterfacesAndForwardingMethodsSynthesized( @@ -150,17 +147,6 @@ return desugaringForwardingMethod; } - private void ensureEmulatedDispatchMethodsSynthesized( - DesugaredLibraryRetargeterInstructionEventConsumer eventConsumer) { - assert appView.options().isDesugaredLibraryCompilation(); - if (emulatedDispatchMethods.isEmpty()) { - return; - } - for (DexClassAndMethod emulatedDispatchMethod : emulatedDispatchMethods) { - syntheticHelper.ensureEmulatedHolderDispatchMethod(emulatedDispatchMethod, eventConsumer); - } - } - private void reportInvalidLibrarySupertype( DexLibraryClass libraryClass, DexClassAndMethodSet retarget) { DexClass dexClass = appView.definitionFor(libraryClass.superType);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterSynthesizerEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterSynthesizerEventConsumer.java new file mode 100644 index 0000000..fab6f10 --- /dev/null +++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterSynthesizerEventConsumer.java
@@ -0,0 +1,28 @@ +// 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.ir.desugar.desugaredlibrary; + +import com.android.tools.r8.graph.DexClass; +import com.android.tools.r8.graph.DexClasspathClass; +import com.android.tools.r8.graph.DexProgramClass; +import com.android.tools.r8.graph.ProgramMethod; + +public interface DesugaredLibraryRetargeterSynthesizerEventConsumer { + + interface DesugaredLibraryRetargeterL8SynthesizerEventConsumer { + void acceptDesugaredLibraryRetargeterDispatchProgramClass(DexProgramClass clazz); + } + + interface DesugaredLibraryRetargeterInstructionEventConsumer { + void acceptDesugaredLibraryRetargeterDispatchClasspathClass(DexClasspathClass clazz); + } + + interface DesugaredLibraryRetargeterPostProcessingEventConsumer + extends DesugaredLibraryRetargeterInstructionEventConsumer { + void acceptInterfaceInjection(DexProgramClass clazz, DexClass newInterface); + + void acceptForwardingMethod(ProgramMethod method); + } +}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterSyntheticHelper.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterSyntheticHelper.java index 02eb59b..9569c61 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterSyntheticHelper.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterSyntheticHelper.java
@@ -11,6 +11,8 @@ import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.MethodAccessFlags; +import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterInstructionEventConsumer; +import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterL8SynthesizerEventConsumer; import com.android.tools.r8.ir.synthetic.EmulateInterfaceSyntheticCfCodeProvider; import com.android.tools.r8.synthesis.SyntheticClassBuilder; import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind; @@ -28,91 +30,99 @@ public DexClass ensureEmulatedHolderDispatchMethod( DexClassAndMethod emulatedDispatchMethod, DesugaredLibraryRetargeterInstructionEventConsumer eventConsumer) { - assert eventConsumer != null || appView.enableWholeProgramOptimizations(); + assert eventConsumer != null; + if (appView.options().isDesugaredLibraryCompilation()) { + return appView + .getSyntheticItems() + .getExistingFixedClass( + SyntheticKind.RETARGET_CLASS, emulatedDispatchMethod.getHolder(), appView); + } DexClass interfaceClass = ensureEmulatedInterfaceDispatchMethod(emulatedDispatchMethod, eventConsumer); DexMethod itfMethod = interfaceClass.lookupMethod(emulatedDispatchMethod.getReference()).getReference(); - DexClass holderDispatch; - if (appView.options().isDesugaredLibraryCompilation()) { - holderDispatch = - appView - .getSyntheticItems() - .ensureFixedClass( - SyntheticKind.RETARGET_CLASS, - emulatedDispatchMethod.getHolder(), - appView, - classBuilder -> - buildHolderDispatchMethod(classBuilder, emulatedDispatchMethod, itfMethod), - clazz -> { - if (eventConsumer != null) { - eventConsumer.acceptDesugaredLibraryRetargeterDispatchProgramClass(clazz); - } - }); - } else { - ClasspathOrLibraryClass context = - emulatedDispatchMethod.getHolder().asClasspathOrLibraryClass(); - assert context != null; - holderDispatch = - appView - .getSyntheticItems() - .ensureFixedClasspathClass( - SyntheticKind.RETARGET_CLASS, - context, - appView, - classBuilder -> - buildHolderDispatchMethod(classBuilder, emulatedDispatchMethod, itfMethod), - clazz -> { - if (eventConsumer != null) { - eventConsumer.acceptDesugaredLibraryRetargeterDispatchClasspathClass(clazz); - } - }); - } - rewriteType(holderDispatch.type); - return holderDispatch; + ClasspathOrLibraryClass context = + emulatedDispatchMethod.getHolder().asClasspathOrLibraryClass(); + assert context != null; + return appView + .getSyntheticItems() + .ensureFixedClasspathClass( + SyntheticKind.RETARGET_CLASS, + context, + appView, + classBuilder -> + buildHolderDispatchMethod(classBuilder, emulatedDispatchMethod, itfMethod), + clazz -> { + eventConsumer.acceptDesugaredLibraryRetargeterDispatchClasspathClass(clazz); + rewriteType(clazz.type); + }); + } + + public void ensureProgramEmulatedHolderDispatchMethod( + DexClassAndMethod emulatedDispatchMethod, + DesugaredLibraryRetargeterL8SynthesizerEventConsumer eventConsumer) { + assert eventConsumer != null; + assert appView.options().isDesugaredLibraryCompilation(); + DexClass interfaceClass = + ensureEmulatedInterfaceDispatchMethod(emulatedDispatchMethod, eventConsumer); + DexMethod itfMethod = + interfaceClass.lookupMethod(emulatedDispatchMethod.getReference()).getReference(); + appView + .getSyntheticItems() + .ensureFixedClass( + SyntheticKind.RETARGET_CLASS, + emulatedDispatchMethod.getHolder(), + appView, + classBuilder -> + buildHolderDispatchMethod(classBuilder, emulatedDispatchMethod, itfMethod), + clazz -> { + eventConsumer.acceptDesugaredLibraryRetargeterDispatchProgramClass(clazz); + rewriteType(clazz.type); + }); } public DexClass ensureEmulatedInterfaceDispatchMethod( DexClassAndMethod emulatedDispatchMethod, DesugaredLibraryRetargeterInstructionEventConsumer eventConsumer) { - assert eventConsumer != null || appView.enableWholeProgramOptimizations(); - DexClass interfaceDispatch; + assert eventConsumer != null; if (appView.options().isDesugaredLibraryCompilation()) { - interfaceDispatch = - appView - .getSyntheticItems() - .ensureFixedClass( - SyntheticKind.RETARGET_INTERFACE, - emulatedDispatchMethod.getHolder(), - appView, - classBuilder -> - buildInterfaceDispatchMethod(classBuilder, emulatedDispatchMethod), - clazz -> { - if (eventConsumer != null) { - eventConsumer.acceptDesugaredLibraryRetargeterDispatchProgramClass(clazz); - } - }); - } else { - ClasspathOrLibraryClass context = - emulatedDispatchMethod.getHolder().asClasspathOrLibraryClass(); - assert context != null; - interfaceDispatch = - appView - .getSyntheticItems() - .ensureFixedClasspathClass( - SyntheticKind.RETARGET_INTERFACE, - context, - appView, - classBuilder -> - buildInterfaceDispatchMethod(classBuilder, emulatedDispatchMethod), - clazz -> { - if (eventConsumer != null) { - eventConsumer.acceptDesugaredLibraryRetargeterDispatchClasspathClass(clazz); - } - }); + return appView + .getSyntheticItems() + .getExistingFixedClass( + SyntheticKind.RETARGET_INTERFACE, emulatedDispatchMethod.getHolder(), appView); } - rewriteType(interfaceDispatch.type); - return interfaceDispatch; + ClasspathOrLibraryClass context = + emulatedDispatchMethod.getHolder().asClasspathOrLibraryClass(); + assert context != null; + return appView + .getSyntheticItems() + .ensureFixedClasspathClass( + SyntheticKind.RETARGET_INTERFACE, + context, + appView, + classBuilder -> buildInterfaceDispatchMethod(classBuilder, emulatedDispatchMethod), + clazz -> { + eventConsumer.acceptDesugaredLibraryRetargeterDispatchClasspathClass(clazz); + rewriteType(clazz.type); + }); + } + + public DexClass ensureEmulatedInterfaceDispatchMethod( + DexClassAndMethod emulatedDispatchMethod, + DesugaredLibraryRetargeterL8SynthesizerEventConsumer eventConsumer) { + assert appView.options().isDesugaredLibraryCompilation(); + assert eventConsumer != null; + return appView + .getSyntheticItems() + .ensureFixedClass( + SyntheticKind.RETARGET_INTERFACE, + emulatedDispatchMethod.getHolder(), + appView, + classBuilder -> buildInterfaceDispatchMethod(classBuilder, emulatedDispatchMethod), + clazz -> { + eventConsumer.acceptDesugaredLibraryRetargeterDispatchProgramClass(clazz); + rewriteType(clazz.type); + }); } private void buildInterfaceDispatchMethod( @@ -149,14 +159,16 @@ .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic()) .setCode( methodSig -> - new EmulateInterfaceSyntheticCfCodeProvider( - methodSig.getHolderType(), - emulatedDispatchMethod.getHolderType(), - desugarMethod, - itfMethod, - Collections.emptyList(), - appView) - .generateCfCode()); + appView.options().isDesugaredLibraryCompilation() + ? new EmulateInterfaceSyntheticCfCodeProvider( + methodSig.getHolderType(), + emulatedDispatchMethod.getHolderType(), + desugarMethod, + itfMethod, + Collections.emptyList(), + appView) + .generateCfCode() + : null); }); }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryWrapperSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryWrapperSynthesizer.java index 2605672..3e21feb 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryWrapperSynthesizer.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryWrapperSynthesizer.java
@@ -11,7 +11,6 @@ import com.android.tools.r8.graph.Code; import com.android.tools.r8.graph.DexAnnotationSet; import com.android.tools.r8.graph.DexClass; -import com.android.tools.r8.graph.DexClassAndMethod; import com.android.tools.r8.graph.DexClasspathClass; import com.android.tools.r8.graph.DexEncodedField; import com.android.tools.r8.graph.DexEncodedMethod; @@ -19,13 +18,17 @@ import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexProgramClass; +import com.android.tools.r8.graph.DexProto; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.FieldAccessFlags; import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature; import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature; import com.android.tools.r8.graph.MethodAccessFlags; import com.android.tools.r8.graph.ParameterAnnotationsList; -import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.ir.desugar.CfL8ClassSynthesizer; +import com.android.tools.r8.ir.desugar.CfL8ClassSynthesizerEventConsumer; +import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryClasspathWrapperSynthesizeEventConsumer; +import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer; import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APIConverterConstructorCfCodeProvider; import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APIConverterThrowRuntimeExceptionCfCodeProvider; import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APIConverterVivifiedWrapperCfCodeProvider; @@ -39,12 +42,12 @@ import com.google.common.collect.Sets; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Consumer; import java.util.function.Function; // I am responsible for the generation of wrappers used to call library APIs when desugaring @@ -90,14 +93,14 @@ // return new j$....BiFunction$-WRP(wrappedValue); // } // } -public class DesugaredLibraryWrapperSynthesizer { +public class DesugaredLibraryWrapperSynthesizer implements CfL8ClassSynthesizer { private final AppView<?> appView; private final DexItemFactory factory; private final ConcurrentHashMap<DexType, List<DexEncodedMethod>> allImplementedMethodsCache = new ConcurrentHashMap<>(); - DesugaredLibraryWrapperSynthesizer(AppView<?> appView) { + public DesugaredLibraryWrapperSynthesizer(AppView<?> appView) { this.appView = appView; this.factory = appView.dexItemFactory(); } @@ -122,20 +125,49 @@ DexType type, DexType srcType, DexType destType, - DesugaredLibraryAPIConverterEventConsumer eventConsumer) { + DesugaredLibraryClasspathWrapperSynthesizeEventConsumer eventConsumer) { + DexMethod customConversion = getCustomConversion(type, srcType, destType); + if (customConversion != null) { + return customConversion; + } + assert canGenerateWrapper(type) : type; + DexClass clazz = getValidClassToWrap(type); + WrapperConversions wrapperConversions = ensureWrappers(clazz, eventConsumer); + DexMethod conversion = + type == srcType + ? wrapperConversions.getConversion() + : wrapperConversions.getVivifiedConversion(); + assert srcType == conversion.getArgumentType(0, true); + assert destType == conversion.getReturnType(); + return conversion; + } + + public DexMethod getExistingProgramConversionMethod( + DexType type, DexType srcType, DexType destType) { + DexMethod customConversion = getCustomConversion(type, srcType, destType); + if (customConversion != null) { + return customConversion; + } + WrapperConversions wrapperConversions = + getExistingProgramWrapperConversions(getValidClassToWrap(type)); + DexMethod conversion = + type == srcType + ? wrapperConversions.getConversion() + : wrapperConversions.getVivifiedConversion(); + assert srcType == conversion.getArgumentType(0, true); + return conversion; + } + + private DexMethod getCustomConversion(DexType type, DexType srcType, DexType destType) { // ConversionType holds the methods "rewrittenType convert(type)" and the other way around. // But everything is going to be rewritten, so we need to use vivifiedType and type". DexType conversionHolder = appView.options().desugaredLibraryConfiguration.getCustomConversions().get(type); - if (conversionHolder == null) { - conversionHolder = - type == srcType - ? ensureTypeWrapper(type, eventConsumer) - : ensureVivifiedTypeWrapper(type, eventConsumer); + if (conversionHolder != null) { + return factory.createMethod( + conversionHolder, factory.createProto(destType, srcType), factory.convertMethodName); } - assert conversionHolder != null; - return factory.createMethod( - conversionHolder, factory.createProto(destType, srcType), factory.convertMethodName); + return null; } private boolean canConvert(DexType type) { @@ -165,16 +197,6 @@ return appView.options().desugaredLibraryConfiguration.getWrapperConversions().contains(type); } - private DexType ensureTypeWrapper( - DexType type, DesugaredLibraryAPIConverterEventConsumer eventConsumer) { - return ensureWrappers(type, eventConsumer).getWrapper().type; - } - - private DexType ensureVivifiedTypeWrapper( - DexType type, DesugaredLibraryAPIConverterEventConsumer eventConsumer) { - return ensureWrappers(type, eventConsumer).getVivifiedWrapper().type; - } - private DexClass getValidClassToWrap(DexType type) { DexClass dexClass = appView.definitionFor(type); // The dexClass should be a library class, so it cannot be null. @@ -188,102 +210,78 @@ return DesugaredLibraryAPIConverter.vivifiedTypeFor(type, appView); } - static class Wrappers { - private final DexClass wrapper; - private final DexClass vivifiedWrapper; + static class WrapperConversions { - Wrappers(DexClass wrapper, DexClass vivifiedWrapper) { - this.wrapper = wrapper; - this.vivifiedWrapper = vivifiedWrapper; + private final DexMethod conversion; + private final DexMethod vivifiedConversion; + + WrapperConversions(DexMethod conversion, DexMethod vivifiedConversion) { + this.conversion = conversion; + this.vivifiedConversion = vivifiedConversion; } - public DexClass getWrapper() { - return wrapper; + public DexMethod getConversion() { + return conversion; } - public DexClass getVivifiedWrapper() { - return vivifiedWrapper; + public DexMethod getVivifiedConversion() { + return vivifiedConversion; } } - private Wrappers ensureWrappers( - DexType type, DesugaredLibraryAPIConverterEventConsumer eventConsumer) { - assert canGenerateWrapper(type) : type; - DexClass dexClass = getValidClassToWrap(type); - return ensureWrappers(dexClass, ignored -> {}, eventConsumer); - } - - private Wrappers ensureWrappers( - DexClass context, - Consumer<DexClasspathClass> creationCallback, - DesugaredLibraryAPIConverterEventConsumer eventConsumer) { - DexType type = context.type; - DexClass wrapper; - DexClass vivifiedWrapper; + private WrapperConversions ensureWrappers( + DexClass context, DesugaredLibraryClasspathWrapperSynthesizeEventConsumer eventConsumer) { + assert eventConsumer != null; if (context.isProgramClass()) { - assert appView.options().isDesugaredLibraryCompilation(); - DexProgramClass programContext = context.asProgramClass(); - wrapper = - ensureProgramWrapper( - SyntheticKind.WRAPPER, - vivifiedTypeFor(type), - type, - programContext, - eventConsumer, - wrapperField -> - synthesizeVirtualMethodsForTypeWrapper( - programContext, wrapperField, eventConsumer)); - vivifiedWrapper = - ensureProgramWrapper( - SyntheticKind.VIVIFIED_WRAPPER, - type, - vivifiedTypeFor(type), - programContext, - eventConsumer, - wrapperField -> - synthesizeVirtualMethodsForVivifiedTypeWrapper( - programContext, wrapperField, eventConsumer)); - DexField wrapperField = getWrapperUniqueField(wrapper); - DexField vivifiedWrapperField = getWrapperUniqueField(vivifiedWrapper); - ensureProgramConversionMethod( - SyntheticKind.WRAPPER, programContext, wrapperField, vivifiedWrapperField); - ensureProgramConversionMethod( - SyntheticKind.VIVIFIED_WRAPPER, programContext, vivifiedWrapperField, wrapperField); - } else { - assert context.isNotProgramClass(); - ClasspathOrLibraryClass classpathOrLibraryContext = context.asClasspathOrLibraryClass(); - wrapper = - ensureClasspathWrapper( - SyntheticKind.WRAPPER, - vivifiedTypeFor(type), - type, - classpathOrLibraryContext, - creationCallback, - eventConsumer, - wrapperField -> - synthesizeVirtualMethodsForTypeWrapper(context, wrapperField, eventConsumer)); - vivifiedWrapper = - ensureClasspathWrapper( - SyntheticKind.VIVIFIED_WRAPPER, - type, - vivifiedTypeFor(type), - classpathOrLibraryContext, - creationCallback, - eventConsumer, - wrapperField -> - synthesizeVirtualMethodsForVivifiedTypeWrapper( - context, wrapperField, eventConsumer)); - DexField wrapperField = getWrapperUniqueField(wrapper); - DexField vivifiedWrapperField = getWrapperUniqueField(vivifiedWrapper); - ensureClasspathConversionMethod( - SyntheticKind.WRAPPER, classpathOrLibraryContext, wrapperField, vivifiedWrapperField); - ensureClasspathConversionMethod( - SyntheticKind.VIVIFIED_WRAPPER, - classpathOrLibraryContext, - vivifiedWrapperField, - wrapperField); + return getExistingProgramWrapperConversions(context); } - return new Wrappers(wrapper, vivifiedWrapper); + assert context.isNotProgramClass(); + ClasspathOrLibraryClass classpathOrLibraryContext = context.asClasspathOrLibraryClass(); + DexType type = context.type; + DexType vivifiedType = vivifiedTypeFor(type); + DexClass wrapper = + ensureClasspathWrapper( + SyntheticKind.WRAPPER, + vivifiedType, + type, + classpathOrLibraryContext, + eventConsumer, + wrapperField -> synthesizeVirtualMethodsForTypeWrapper(context, wrapperField)); + DexClass vivifiedWrapper = + ensureClasspathWrapper( + SyntheticKind.VIVIFIED_WRAPPER, + type, + vivifiedType, + classpathOrLibraryContext, + eventConsumer, + wrapperField -> synthesizeVirtualMethodsForVivifiedTypeWrapper(context, wrapperField)); + return new WrapperConversions( + getConversion(wrapper, vivifiedType, type), + getConversion(vivifiedWrapper, type, vivifiedType)); + } + + private WrapperConversions getExistingProgramWrapperConversions(DexClass context) { + DexClass vivifiedWrapper; + DexClass wrapper; + assert appView.options().isDesugaredLibraryCompilation(); + wrapper = getExistingProgramWrapper(context, SyntheticKind.WRAPPER); + vivifiedWrapper = getExistingProgramWrapper(context, SyntheticKind.VIVIFIED_WRAPPER); + DexField wrapperField = getWrapperUniqueField(wrapper); + DexField vivifiedWrapperField = getWrapperUniqueField(vivifiedWrapper); + return new WrapperConversions( + getConversion(wrapper, vivifiedWrapperField.type, wrapperField.type), + getConversion(vivifiedWrapper, wrapperField.type, vivifiedWrapperField.type)); + } + + private DexProgramClass getExistingProgramWrapper(DexClass context, SyntheticKind kind) { + return appView.getSyntheticItems().getExistingFixedClass(kind, context, appView); + } + + private DexMethod getConversion(DexClass wrapper, DexType returnType, DexType argType) { + DexMethod convertMethod = + factory.createMethod( + wrapper.type, factory.createProto(returnType, argType), factory.convertMethodName); + return wrapper.lookupDirectMethod(convertMethod).getReference(); } private DexEncodedField getWrapperUniqueEncodedField(DexClass wrapper) { @@ -300,8 +298,9 @@ DexType wrappingType, DexType wrappedType, DexProgramClass programContext, - DesugaredLibraryAPIConverterEventConsumer eventConsumer, - Function<DexEncodedField, DexEncodedMethod[]> virtualMethodProvider) { + DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer eventConsumer) { + assert appView.options().isDesugaredLibraryCompilation(); + assert eventConsumer != null; return appView .getSyntheticItems() .ensureFixedClass( @@ -311,13 +310,7 @@ builder -> buildWrapper(wrappingType, wrappedType, programContext, builder), // The creation of virtual methods may require new wrappers, this needs to happen // once the wrapper is created to avoid infinite recursion. - wrapper -> { - if (eventConsumer != null) { - eventConsumer.acceptWrapperProgramClass(wrapper); - } - wrapper.setVirtualMethods( - virtualMethodProvider.apply(getWrapperUniqueEncodedField(wrapper))); - }); + eventConsumer::acceptWrapperProgramClass); } private DexClasspathClass ensureClasspathWrapper( @@ -325,101 +318,84 @@ DexType wrappingType, DexType wrappedType, ClasspathOrLibraryClass classpathOrLibraryContext, - Consumer<DexClasspathClass> creationCallback, - DesugaredLibraryAPIConverterEventConsumer eventConsumer, - Function<DexEncodedField, DexEncodedMethod[]> virtualMethodProvider) { + DesugaredLibraryClasspathWrapperSynthesizeEventConsumer eventConsumer, + Function<DexEncodedField, Collection<DexEncodedMethod>> virtualMethodProvider) { + assert eventConsumer != null; return appView .getSyntheticItems() .ensureFixedClasspathClass( kind, classpathOrLibraryContext, appView, - builder -> - buildWrapper( - wrappingType, wrappedType, classpathOrLibraryContext.asDexClass(), builder), - // The creation of virtual methods may require new wrappers, this needs to happen - // once the wrapper is created to avoid infinite recursion. - wrapper -> { - if (eventConsumer != null) { - eventConsumer.acceptWrapperClasspathClass(wrapper); - } - wrapper.setVirtualMethods( - virtualMethodProvider.apply(getWrapperUniqueEncodedField(wrapper))); - creationCallback.accept(wrapper); - }); + builder -> { + DexEncodedField wrapperField = + buildWrapper( + wrappingType, wrappedType, classpathOrLibraryContext.asDexClass(), builder); + builder.addMethod( + methodBuilder -> + buildConversionMethod( + methodBuilder, factory.createProto(wrappingType, wrappedType), null)); + builder.setVirtualMethods(virtualMethodProvider.apply(wrapperField)); + }, + eventConsumer::acceptWrapperClasspathClass); } - private ProgramMethod ensureProgramConversionMethod( - SyntheticKind kind, - DexProgramClass context, - DexField wrapperField, - DexField reverseWrapperField) { - return appView + private void getExistingProgramConversionMethod( + SyntheticKind kind, DexProgramClass context, DexClass wrapper, DexClass reverseWrapper) { + DexField wrapperField = getWrapperUniqueField(wrapper); + DexField reverseWrapperField = getWrapperUniqueField(reverseWrapper); + DexProto proto = factory.createProto(reverseWrapperField.type, wrapperField.type); + appView .getSyntheticItems() .ensureFixedClassMethod( factory.convertMethodName, - factory.createProto(reverseWrapperField.type, wrapperField.type), - kind, - context, - appView, - ignored -> {}, - methodBuilder -> - buildConversionMethod(methodBuilder, wrapperField, reverseWrapperField, context)); - } - - private DexClassAndMethod ensureClasspathConversionMethod( - SyntheticKind kind, - ClasspathOrLibraryClass context, - DexField wrapperField, - DexField reverseWrapperField) { - return appView - .getSyntheticItems() - .ensureFixedClasspathClassMethod( - factory.convertMethodName, - factory.createProto(reverseWrapperField.type, wrapperField.type), + proto, kind, context, appView, ignored -> {}, methodBuilder -> buildConversionMethod( - methodBuilder, wrapperField, reverseWrapperField, context.asDexClass())); + methodBuilder, + proto, + computeProgramConversionMethodCode( + wrapperField, reverseWrapperField, context))); } private boolean isInvalidWrapper(DexClass clazz) { return Iterables.any(allImplementedMethods(clazz), DexEncodedMethod::isFinal); } - private void buildConversionMethod( - SyntheticMethodBuilder methodBuilder, - DexField wrapperField, - DexField reverseWrapperField, - DexClass context) { - CfCode cfCode; + private CfCode computeProgramConversionMethodCode( + DexField wrapperField, DexField reverseWrapperField, DexClass context) { if (isInvalidWrapper(context)) { - cfCode = - new APIConverterThrowRuntimeExceptionCfCodeProvider( - appView, - factory.createString( - "Unsupported conversion for " - + context.type - + ". See compilation time warnings for more details."), - wrapperField.holder) - .generateCfCode(); - } else { - cfCode = - new APIConverterWrapperConversionCfCodeProvider( - appView, reverseWrapperField, wrapperField) - .generateCfCode(); + return new APIConverterThrowRuntimeExceptionCfCodeProvider( + appView, + factory.createString( + "Unsupported conversion for " + + context.type + + ". See compilation time warnings for more details."), + wrapperField.holder) + .generateCfCode(); } + assert context.isProgramClass(); + return new APIConverterWrapperConversionCfCodeProvider( + appView, reverseWrapperField, wrapperField) + .generateCfCode(); + } + + private void buildConversionMethod( + SyntheticMethodBuilder methodBuilder, DexProto proto, CfCode cfCode) { methodBuilder + .setName(factory.convertMethodName) + .setProto(proto) .setAccessFlags( MethodAccessFlags.fromCfAccessFlags( Constants.ACC_SYNTHETIC | Constants.ACC_STATIC | Constants.ACC_PUBLIC, false)) .setCode(methodSignature -> cfCode); } - private void buildWrapper( + private DexEncodedField buildWrapper( DexType wrappingType, DexType wrappedType, DexClass clazz, @@ -435,6 +411,7 @@ .setSuperType(superType) .setInstanceFields(Collections.singletonList(wrapperField)) .addMethod(methodBuilder -> buildWrapperConstructor(wrapperField, methodBuilder)); + return wrapperField; } private void buildWrapperConstructor( @@ -451,10 +428,8 @@ .generateCfCode()); } - private DexEncodedMethod[] synthesizeVirtualMethodsForVivifiedTypeWrapper( - DexClass dexClass, - DexEncodedField wrapperField, - DesugaredLibraryAPIConverterEventConsumer eventConsumer) { + private Collection<DexEncodedMethod> synthesizeVirtualMethodsForVivifiedTypeWrapper( + DexClass dexClass, DexEncodedField wrapperField) { List<DexEncodedMethod> dexMethods = allImplementedMethods(dexClass); List<DexEncodedMethod> generatedMethods = new ArrayList<>(); // Each method should use only types in their signature, but each method the wrapper forwards @@ -489,16 +464,13 @@ if (dexEncodedMethod.isFinal()) { finalMethods.add(dexEncodedMethod.getReference()); continue; - } else { + } else if (dexClass.isProgramClass()) { cfCode = new APIConverterVivifiedWrapperCfCodeProvider( - appView, - methodToInstall, - wrapperField.getReference(), - this, - isInterface, - eventConsumer) + appView, methodToInstall, wrapperField.getReference(), this, isInterface) .generateCfCode(); + } else { + cfCode = null; } DexEncodedMethod newDexEncodedMethod = newSynthesizedMethod(methodToInstall, dexEncodedMethod, cfCode); @@ -507,10 +479,8 @@ return finalizeWrapperMethods(generatedMethods, finalMethods); } - private DexEncodedMethod[] synthesizeVirtualMethodsForTypeWrapper( - DexClass dexClass, - DexEncodedField wrapperField, - DesugaredLibraryAPIConverterEventConsumer eventConsumer) { + private Collection<DexEncodedMethod> synthesizeVirtualMethodsForTypeWrapper( + DexClass dexClass, DexEncodedField wrapperField) { List<DexEncodedMethod> dexMethods = allImplementedMethods(dexClass); List<DexEncodedMethod> generatedMethods = new ArrayList<>(); // Each method should use only vivified types in their signature, but each method the wrapper @@ -535,16 +505,17 @@ if (dexEncodedMethod.isFinal()) { finalMethods.add(dexEncodedMethod.getReference()); continue; - } else { + } else if (dexClass.isProgramClass()) { cfCode = new APIConverterWrapperCfCodeProvider( appView, dexEncodedMethod.getReference(), wrapperField.getReference(), this, - isInterface, - eventConsumer) + isInterface) .generateCfCode(); + } else { + cfCode = null; } DexEncodedMethod newDexEncodedMethod = newSynthesizedMethod(methodToInstall, dexEncodedMethod, cfCode); @@ -553,14 +524,14 @@ return finalizeWrapperMethods(generatedMethods, finalMethods); } - private DexEncodedMethod[] finalizeWrapperMethods( + private Collection<DexEncodedMethod> finalizeWrapperMethods( List<DexEncodedMethod> generatedMethods, Set<DexMethod> finalMethods) { if (finalMethods.isEmpty()) { - return generatedMethods.toArray(DexEncodedMethod.EMPTY_ARRAY); + return generatedMethods; } // Wrapper is invalid, no need to add the virtual methods. reportFinalMethodsInWrapper(finalMethods); - return DexEncodedMethod.EMPTY_ARRAY; + return Collections.emptyList(); } private void reportFinalMethodsInWrapper(Set<DexMethod> methods) { @@ -582,9 +553,9 @@ DexMethod methodToInstall, DexEncodedMethod template, Code code) { MethodAccessFlags newFlags = template.accessFlags.copy(); assert newFlags.isPublic(); - if (code == null) { - newFlags.setAbstract(); - } else { + // It can happen that we wrap an abstract method, in which case the wrapping method is no + // longer abstract. + if (code != null) { newFlags.unsetAbstract(); } // TODO(b/146114533): Fix inlining in synthetic methods and remove unsetBridge. @@ -657,16 +628,63 @@ field, fieldAccessFlags, FieldTypeSignature.noSignature(), DexAnnotationSet.empty(), null); } - void ensureWrappersForL8(DesugaredLibraryAPIConverterEventConsumer eventConsumer) { + // Program wrappers are harder to deal with than classpath wrapper because generating a method's + // code may require other wrappers. To keep it simple (This is L8 specific), we generate first + // the wrappers with the conversion methods only, then the virtual methods assuming the + // conversion methods are present. + @Override + public void synthesizeClasses(CfL8ClassSynthesizerEventConsumer eventConsumer) { DesugaredLibraryConfiguration conf = appView.options().desugaredLibraryConfiguration; + List<DexProgramClass> validClassesToWrap = new ArrayList<>(); for (DexType type : conf.getWrapperConversions()) { assert !conf.getCustomConversions().containsKey(type); DexClass validClassToWrap = getValidClassToWrap(type); // In broken set-ups we can end up having a json files containing wrappers of non desugared // classes. Such wrappers are not required since the class won't be rewritten. if (validClassToWrap.isProgramClass()) { - ensureWrappers(validClassToWrap, ignored -> {}, eventConsumer); + validClassesToWrap.add(validClassToWrap.asProgramClass()); + ensureProgramWrappersWithoutVirtualMethods(validClassToWrap, eventConsumer); } } + for (DexProgramClass validClassToWrap : validClassesToWrap) { + ensureProgramWrappersVirtualMethods(validClassToWrap); + } + } + + // We generate first the two wrappers with the constructor method and the fields, then we + // the two conversion methods which requires the wrappers to know both fields. + private void ensureProgramWrappersWithoutVirtualMethods( + DexClass context, DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer eventConsumer) { + assert eventConsumer != null; + assert context.isProgramClass(); + DexType type = context.type; + assert appView.options().isDesugaredLibraryCompilation(); + DexProgramClass programContext = context.asProgramClass(); + DexClass wrapper = + ensureProgramWrapper( + SyntheticKind.WRAPPER, vivifiedTypeFor(type), type, programContext, eventConsumer); + DexClass vivifiedWrapper = + ensureProgramWrapper( + SyntheticKind.VIVIFIED_WRAPPER, + type, + vivifiedTypeFor(type), + programContext, + eventConsumer); + getExistingProgramConversionMethod( + SyntheticKind.WRAPPER, programContext, wrapper, vivifiedWrapper); + getExistingProgramConversionMethod( + SyntheticKind.VIVIFIED_WRAPPER, programContext, vivifiedWrapper, wrapper); + } + + private void ensureProgramWrappersVirtualMethods(DexClass context) { + assert context.isProgramClass(); + DexProgramClass wrapper = getExistingProgramWrapper(context, SyntheticKind.WRAPPER); + wrapper.addVirtualMethods( + synthesizeVirtualMethodsForTypeWrapper(context, getWrapperUniqueEncodedField(wrapper))); + DexProgramClass vivifiedWrapper = + getExistingProgramWrapper(context, SyntheticKind.VIVIFIED_WRAPPER); + vivifiedWrapper.addVirtualMethods( + synthesizeVirtualMethodsForVivifiedTypeWrapper( + context, getWrapperUniqueEncodedField(vivifiedWrapper))); } }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryWrapperSynthesizerEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryWrapperSynthesizerEventConsumer.java new file mode 100644 index 0000000..212ad66 --- /dev/null +++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryWrapperSynthesizerEventConsumer.java
@@ -0,0 +1,34 @@ +// 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.ir.desugar.desugaredlibrary; + +import com.android.tools.r8.graph.DexClasspathClass; +import com.android.tools.r8.graph.DexProgramClass; +import com.android.tools.r8.graph.ProgramMethod; + +public interface DesugaredLibraryWrapperSynthesizerEventConsumer { + + interface DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer { + + void acceptWrapperProgramClass(DexProgramClass clazz); + } + + interface DesugaredLibraryClasspathWrapperSynthesizeEventConsumer { + + void acceptWrapperClasspathClass(DexClasspathClass clazz); + } + + interface DesugaredLibraryAPIConverterEventConsumer + extends DesugaredLibraryClasspathWrapperSynthesizeEventConsumer { + + void acceptAPIConversion(ProgramMethod method); + } + + interface DesugaredLibraryAPICallbackSynthesizorEventConsumer + extends DesugaredLibraryClasspathWrapperSynthesizeEventConsumer { + + void acceptAPIConversionCallback(ProgramMethod method); + } +}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceSynthesizer.java similarity index 86% rename from src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceProcessor.java rename to src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceSynthesizer.java index c3fded8..5af4f7e 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceProcessor.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceSynthesizer.java
@@ -12,6 +12,8 @@ import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.MethodAccessFlags; import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.ir.desugar.CfL8ClassSynthesizer; +import com.android.tools.r8.ir.desugar.CfL8ClassSynthesizerEventConsumer; import com.android.tools.r8.ir.synthetic.EmulateInterfaceSyntheticCfCodeProvider; import com.android.tools.r8.synthesis.SyntheticMethodBuilder; import com.android.tools.r8.synthesis.SyntheticNaming; @@ -28,13 +30,21 @@ import java.util.Map; import java.util.Set; -public final class EmulatedInterfaceProcessor implements InterfaceDesugaringProcessor { +public final class EmulatedInterfaceSynthesizer implements CfL8ClassSynthesizer { private final AppView<?> appView; private final InterfaceDesugaringSyntheticHelper helper; private final Map<DexType, List<DexType>> emulatedInterfacesHierarchy; - EmulatedInterfaceProcessor(AppView<?> appView) { + public static EmulatedInterfaceSynthesizer create(AppView<?> appView) { + if (!appView.options().isDesugaredLibraryCompilation() + || appView.options().desugaredLibraryConfiguration.getEmulateLibraryInterface().isEmpty()) { + return null; + } + return new EmulatedInterfaceSynthesizer(appView); + } + + EmulatedInterfaceSynthesizer(AppView<?> appView) { this.appView = appView; helper = new InterfaceDesugaringSyntheticHelper(appView); // Avoid the computation outside L8 since it is not needed. @@ -83,7 +93,7 @@ } DexProgramClass ensureEmulateInterfaceLibrary( - DexProgramClass emulatedInterface, InterfaceProcessingDesugaringEventConsumer eventConsumer) { + DexProgramClass emulatedInterface, EmulatedInterfaceSynthesizerEventConsumer eventConsumer) { assert helper.isEmulatedInterface(emulatedInterface.type); DexProgramClass emulateInterfaceClass = appView @@ -101,7 +111,7 @@ synthesizeEmulatedInterfaceMethod( method, emulatedInterface, methodBuilder))), ignored -> {}); - emulateInterfaceClass.forEachProgramMethod(eventConsumer::acceptEmulatedInterfaceMethod); + eventConsumer.acceptEmulatedInterface(emulateInterfaceClass); assert emulateInterfaceClass.getType() == InterfaceDesugaringSyntheticHelper.getEmulateLibraryInterfaceClassType( emulatedInterface.type, appView.dexItemFactory()); @@ -209,15 +219,20 @@ } @Override - public void process( - DexProgramClass emulatedInterface, InterfaceProcessingDesugaringEventConsumer eventConsumer) { - if (!appView.options().isDesugaredLibraryCompilation() - || !helper.isEmulatedInterface(emulatedInterface.type) - || appView.isAlreadyLibraryDesugared(emulatedInterface)) { - return; - } - if (needsEmulateInterfaceLibrary(emulatedInterface)) { - ensureEmulateInterfaceLibrary(emulatedInterface, eventConsumer); + public void synthesizeClasses(CfL8ClassSynthesizerEventConsumer eventConsumer) { + assert appView.options().isDesugaredLibraryCompilation(); + for (DexType emulatedInterfaceType : helper.getEmulatedInterfaces()) { + DexClass emulatedInterfaceClazz = appView.definitionFor(emulatedInterfaceType); + if (emulatedInterfaceClazz == null || !emulatedInterfaceClazz.isProgramClass()) { + warnMissingEmulatedInterface(emulatedInterfaceType); + continue; + } + DexProgramClass emulatedInterface = emulatedInterfaceClazz.asProgramClass(); + assert emulatedInterface != null; + if (!appView.isAlreadyLibraryDesugared(emulatedInterface) + && needsEmulateInterfaceLibrary(emulatedInterface)) { + ensureEmulateInterfaceLibrary(emulatedInterface, eventConsumer); + } } } @@ -225,20 +240,6 @@ return Iterables.any(emulatedInterface.methods(), DexEncodedMethod::isDefaultMethod); } - @Override - public void finalizeProcessing(InterfaceProcessingDesugaringEventConsumer eventConsumer) { - warnMissingEmulatedInterfaces(); - } - - private void warnMissingEmulatedInterfaces() { - for (DexType interfaceType : helper.getEmulatedInterfaces()) { - DexClass theInterface = appView.definitionFor(interfaceType); - if (theInterface == null) { - warnMissingEmulatedInterface(interfaceType); - } - } - } - private void warnMissingEmulatedInterface(DexType interfaceType) { StringDiagnostic warning = new StringDiagnostic(
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceSynthesizerEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceSynthesizerEventConsumer.java new file mode 100644 index 0000000..cb73851 --- /dev/null +++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceSynthesizerEventConsumer.java
@@ -0,0 +1,12 @@ +// 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.ir.desugar.itf; + +import com.android.tools.r8.graph.DexProgramClass; + +public interface EmulatedInterfaceSynthesizerEventConsumer { + + void acceptEmulatedInterface(DexProgramClass clazz); +}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java index ad5aa5e..65816d4 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java
@@ -4,29 +4,56 @@ package com.android.tools.r8.ir.desugar.itf; +import com.android.tools.r8.cf.CfVersion; +import com.android.tools.r8.cf.code.CfFieldInstruction; +import com.android.tools.r8.cf.code.CfInitClass; +import com.android.tools.r8.cf.code.CfReturnVoid; +import com.android.tools.r8.cf.code.CfStackInstruction; +import com.android.tools.r8.cf.code.CfStackInstruction.Opcode; import com.android.tools.r8.errors.Unimplemented; import com.android.tools.r8.graph.AppView; +import com.android.tools.r8.graph.CfCode; import com.android.tools.r8.graph.ClasspathOrLibraryClass; +import com.android.tools.r8.graph.DexAnnotationSet; import com.android.tools.r8.graph.DexClass; import com.android.tools.r8.graph.DexClassAndMethod; +import com.android.tools.r8.graph.DexEncodedField; 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.DexMethod; +import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexString; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.DexValue.DexValueInt; +import com.android.tools.r8.graph.FieldAccessFlags; +import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature; import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature; import com.android.tools.r8.graph.InvalidCode; import com.android.tools.r8.graph.MethodAccessFlags; import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.synthesis.SyntheticMethodBuilder; import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind; import com.android.tools.r8.utils.InternalOptions; import com.android.tools.r8.utils.Pair; +import com.android.tools.r8.utils.structural.Ordered; +import com.google.common.collect.ImmutableList; import java.util.Map; import java.util.Set; +import java.util.function.Consumer; import java.util.function.Predicate; +import org.objectweb.asm.Opcodes; public class InterfaceDesugaringSyntheticHelper { + // Any interface method desugared code can be version 1.7 at the most. + // Note: we always desugar both default/static (v1.8) and private (v9) when targeting api < N. + public static final CfVersion MAX_INTERFACE_DESUGARED_CF_VERSION = CfVersion.V1_7; + + public static CfVersion getInterfaceDesugaredCfVersion(CfVersion existing) { + return Ordered.min(existing, MAX_INTERFACE_DESUGARED_CF_VERSION); + } + // Use InterfaceDesugaringForTesting for public accesses in tests. static final String EMULATE_LIBRARY_CLASS_NAME_SUFFIX = "$-EL"; static final String COMPANION_CLASS_NAME_SUFFIX = "$-CC"; @@ -167,9 +194,11 @@ return ensureMethodOfClasspathCompanionClassStub(companionMethodReference, context, appView); } - DexClassAndMethod ensureStaticAsMethodOfCompanionClassStub(DexClassAndMethod method) { + DexClassAndMethod ensureStaticAsMethodOfCompanionClassStub( + DexClassAndMethod method, Consumer<ProgramMethod> companionClinitConsumer) { if (method.isProgramMethod()) { - return ensureStaticAsMethodOfProgramCompanionClassStub(method.asProgramMethod()); + return ensureStaticAsMethodOfProgramCompanionClassStub( + method.asProgramMethod(), companionClinitConsumer); } else { ClasspathOrLibraryClass context = method.getHolder().asClasspathOrLibraryClass(); DexMethod companionMethodReference = staticAsMethodOfCompanionClass(method); @@ -207,7 +236,8 @@ .getCode() .getCodeAsInlining(syntheticMethod, method.getReference()) : InvalidCode.getInstance()); - }); + }, + ignored -> {}); } ProgramMethod ensurePrivateAsMethodOfProgramCompanionClassStub(ProgramMethod method) { @@ -239,11 +269,12 @@ .getCode() .getCodeAsInlining(syntheticMethod, method.getReference()) : InvalidCode.getInstance()); - }); + }, + ignored -> {}); } // Represent a static interface method as a method of companion class. - final DexMethod staticAsMethodOfCompanionClass(DexClassAndMethod method) { + private DexMethod staticAsMethodOfCompanionClass(DexClassAndMethod method) { DexItemFactory dexItemFactory = appView.dexItemFactory(); DexType companionClassType = getCompanionClassType(method.getHolderType(), dexItemFactory); DexMethod rewritten = method.getReference().withHolder(companionClassType, dexItemFactory); @@ -298,7 +329,11 @@ .setCode(DexEncodedMethod::buildEmptyThrowingCfCode)); } - ProgramMethod ensureStaticAsMethodOfProgramCompanionClassStub(ProgramMethod method) { + ProgramMethod ensureStaticAsMethodOfProgramCompanionClassStub( + ProgramMethod method, Consumer<ProgramMethod> companionClinitConsumer) { + if (!method.getDefinition().isClassInitializer() && method.getHolder().hasClassInitializer()) { + ensureCompanionClassInitializesInterface(method.getHolder(), companionClinitConsumer); + } DexMethod companionMethodReference = staticAsMethodOfCompanionClass(method); DexEncodedMethod definition = method.getDefinition(); return InterfaceProcessor.ensureCompanionMethod( @@ -323,7 +358,107 @@ .getCode() .getCodeAsInlining(syntheticMethod, method.getReference()) : InvalidCode.getInstance()); - }); + }, + ignored -> {}); + } + + private void ensureCompanionClassInitializesInterface( + DexProgramClass iface, Consumer<ProgramMethod> companionClinitConsumer) { + assert hasStaticMethodThatTriggersNonTrivialClassInitializer(iface); + InterfaceProcessor.ensureCompanionMethod( + iface, + appView.dexItemFactory().classConstructorMethodName, + appView.dexItemFactory().createProto(appView.dexItemFactory().voidType), + appView, + methodBuilder -> createCompanionClassInitializer(iface, methodBuilder), + companionClinitConsumer); + } + + private DexEncodedField ensureStaticClinitFieldToTriggerInterfaceInitialization( + DexProgramClass iface) { + DexEncodedField clinitField = + findExistingStaticClinitFieldToTriggerInterfaceInitialization(iface); + if (clinitField == null) { + clinitField = createStaticClinitFieldToTriggerInterfaceInitialization(iface); + iface.appendStaticField(clinitField); + } + return clinitField; + } + + private boolean hasStaticMethodThatTriggersNonTrivialClassInitializer(DexProgramClass iface) { + return iface.hasClassInitializer() + && iface + .getMethodCollection() + .hasDirectMethods(method -> method.isStatic() && !method.isClassInitializer()); + } + + private DexEncodedField findExistingStaticClinitFieldToTriggerInterfaceInitialization( + DexProgramClass iface) { + // Don't select a field that has been marked dead, since we'll assert later that these fields + // have been dead code eliminated. + for (DexEncodedField field : + iface.staticFields(field -> !field.isPrivate() && !field.getOptimizationInfo().isDead())) { + return field; + } + return null; + } + + private DexEncodedField createStaticClinitFieldToTriggerInterfaceInitialization( + DexProgramClass iface) { + DexItemFactory dexItemFactory = appView.dexItemFactory(); + DexField clinitFieldReference = + dexItemFactory.createFreshFieldNameWithoutHolder( + iface.getType(), + dexItemFactory.intType, + "$desugar$clinit", + candidate -> iface.lookupField(candidate) == null); + return new DexEncodedField( + clinitFieldReference, + FieldAccessFlags.builder().setPackagePrivate().setStatic().setSynthetic().build(), + FieldTypeSignature.noSignature(), + DexAnnotationSet.empty(), + DexValueInt.DEFAULT); + } + + private void createCompanionClassInitializer( + DexProgramClass iface, SyntheticMethodBuilder methodBuilder) { + methodBuilder + .setAccessFlags( + MethodAccessFlags.builder().setConstructor().setPackagePrivate().setStatic().build()) + .setClassFileVersion(getInterfaceDesugaredCfVersion(iface.getInitialClassFileVersion())) + .setCode( + method -> { + if (appView.canUseInitClass()) { + return new CfCode( + method.holder, + 1, + 0, + ImmutableList.of( + new CfInitClass(iface.getType()), + new CfStackInstruction(Opcode.Pop), + new CfReturnVoid()), + ImmutableList.of(), + ImmutableList.of()); + } + DexEncodedField clinitField = + ensureStaticClinitFieldToTriggerInterfaceInitialization(iface); + boolean isWide = clinitField.getType().isWideType(); + return new CfCode( + method.holder, + isWide ? 2 : 1, + 0, + ImmutableList.of( + new CfFieldInstruction( + Opcodes.GETSTATIC, + clinitField.getReference(), + clinitField.getReference()), + isWide + ? new CfStackInstruction(Opcode.Pop2) + : new CfStackInstruction(Opcode.Pop), + new CfReturnVoid()), + ImmutableList.of(), + ImmutableList.of()); + }); } private Predicate<DexType> getShouldIgnoreFromReportsPredicate(AppView<?> appView) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodDesugaringEventConsumer.java index 031e142..bdc8816 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodDesugaringEventConsumer.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodDesugaringEventConsumer.java
@@ -12,5 +12,7 @@ void acceptInvokeStaticInterfaceOutliningMethod(ProgramMethod method, ProgramMethod context); + void acceptCompanionClassClinit(ProgramMethod method); + // TODO(b/183998768): Add acceptCompanionClass and acceptEmulatedInterface. }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodProcessorFacade.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodProcessorFacade.java index fafc920..f989858 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodProcessorFacade.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodProcessorFacade.java
@@ -35,10 +35,6 @@ private List<InterfaceDesugaringProcessor> instantiateInterfaceDesugaringProcessors( AppView<?> appView) { - // During L8 compilation, emulated interfaces are processed to be renamed, to have - // their interfaces fixed-up and to generate the emulated dispatch code. - EmulatedInterfaceProcessor emulatedInterfaceProcessor = new EmulatedInterfaceProcessor(appView); - // Process all classes first. Add missing forwarding methods to // replace desugared default interface methods. ClassProcessor classProcessor = new ClassProcessor(appView); @@ -50,7 +46,7 @@ InterfaceProcessor interfaceProcessor = new InterfaceProcessor(appView); // The processors can be listed in any order. - return ImmutableList.of(classProcessor, interfaceProcessor, emulatedInterfaceProcessor); + return ImmutableList.of(classProcessor, interfaceProcessor); } /** Runs the interfaceProcessor, the class processor and the emulated interface processor. */ @@ -81,12 +77,6 @@ sortedSynthesizedMethods.add(method); } - @Override - public void acceptEmulatedInterfaceMethod(ProgramMethod method) { - - sortedSynthesizedMethods.add(method); - } - public SortedProgramMethodSet getSortedSynthesizedMethods() { return sortedSynthesizedMethods; }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java index 38ad3e4..dfdfb45 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
@@ -464,7 +464,8 @@ context, staticOutliningMethodConsumer, rewriteInvoke, - rewriteToThrow); + rewriteToThrow, + eventConsumer::acceptCompanionClassClinit); } assert invoke.isInvokeSpecial(); if (invoke.isInvokeSuper(context.getHolderType())) { @@ -665,7 +666,8 @@ context, synthesizedMethods::add, rewriteInvoke, - rewriteToThrow); + rewriteToThrow, + synthesizedMethods::add); } else { assert instruction.isInvokeSuper(); rewriteInvokeSuper(invoke.getInvokedMethod(), context, rewriteInvoke, rewriteToThrow); @@ -761,7 +763,8 @@ ProgramMethod context, Consumer<ProgramMethod> staticOutliningMethodConsumer, Function<DexMethod, Collection<CfInstruction>> rewriteInvoke, - Function<SingleResolutionResult, Collection<CfInstruction>> rewriteToThrow) { + Function<SingleResolutionResult, Collection<CfInstruction>> rewriteToThrow, + Consumer<ProgramMethod> companionClinitConsumer) { if (appView.getSyntheticItems().isPendingSynthetic(invokedMethod.holder)) { // We did not create this code yet, but it will not require rewriting. return null; @@ -856,7 +859,8 @@ assert resolutionResult.getResolvedMethod().isStatic(); assert invokeNeedsRewriting(invokedMethod, STATIC); DexClassAndMethod companionMethod = - helper.ensureStaticAsMethodOfCompanionClassStub(resolutionResult.getResolutionPair()); + helper.ensureStaticAsMethodOfCompanionClassStub( + resolutionResult.getResolutionPair(), companionClinitConsumer); return rewriteInvoke.apply(companionMethod.getReference()); }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessingDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessingDesugaringEventConsumer.java index 2581364..8fc50d1 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessingDesugaringEventConsumer.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessingDesugaringEventConsumer.java
@@ -10,7 +10,6 @@ void acceptForwardingMethod(ProgramMethod method); + // TODO(b/183998768): Remove this once interface desugaring is moved to the R8 enqueuer. void acceptCompanionClassClinit(ProgramMethod method); - - void acceptEmulatedInterfaceMethod(ProgramMethod method); }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java index c917520..1437d48 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
@@ -5,37 +5,25 @@ package com.android.tools.r8.ir.desugar.itf; -import com.android.tools.r8.cf.code.CfFieldInstruction; import com.android.tools.r8.cf.code.CfInstruction; import com.android.tools.r8.cf.code.CfInvoke; -import com.android.tools.r8.cf.code.CfReturnVoid; -import com.android.tools.r8.cf.code.CfStackInstruction; -import com.android.tools.r8.cf.code.CfStackInstruction.Opcode; import com.android.tools.r8.code.Instruction; import com.android.tools.r8.code.InvokeSuper; import com.android.tools.r8.errors.CompilationError; import com.android.tools.r8.errors.Unimplemented; import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.CfCode; import com.android.tools.r8.graph.Code; -import com.android.tools.r8.graph.DexAnnotationSet; import com.android.tools.r8.graph.DexClass; -import com.android.tools.r8.graph.DexEncodedField; 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.DexMethod; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexProto; import com.android.tools.r8.graph.DexString; import com.android.tools.r8.graph.DexType; -import com.android.tools.r8.graph.DexValue.DexValueInt; -import com.android.tools.r8.graph.FieldAccessFlags; import com.android.tools.r8.graph.GenericSignature.ClassTypeSignature; -import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature; import com.android.tools.r8.graph.GraphLens; import com.android.tools.r8.graph.InvalidCode; -import com.android.tools.r8.graph.MethodAccessFlags; import com.android.tools.r8.graph.MethodCollection; import com.android.tools.r8.graph.NestedGraphLens; import com.android.tools.r8.graph.ProgramMethod; @@ -48,7 +36,6 @@ import com.android.tools.r8.utils.collections.BidirectionalOneToOneMap; import com.android.tools.r8.utils.collections.EmptyBidirectionalOneToOneMap; import com.android.tools.r8.utils.collections.MutableBidirectionalOneToOneMap; -import com.google.common.collect.ImmutableList; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; @@ -59,7 +46,6 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; -import org.objectweb.asm.Opcodes; // Default and static method interface desugaring processor for interfaces. // @@ -101,12 +87,11 @@ private void ensureCompanionClassMethods( DexProgramClass iface, InterfaceProcessingDesugaringEventConsumer eventConsumer) { - ensureCompanionClassInitializesInterface(iface, eventConsumer); // TODO(b/183998768): Once fixed, the methods should be added for processing. // D8 and R8 don't need to optimize the methods since they are just moved from interfaces and // don't need to be re-processed. processVirtualInterfaceMethods(iface); - processDirectInterfaceMethods(iface); + processDirectInterfaceMethods(iface, eventConsumer); } static ProgramMethod ensureCompanionMethod( @@ -114,7 +99,8 @@ DexString methodName, DexProto methodProto, AppView<?> appView, - Consumer<SyntheticMethodBuilder> fn) { + Consumer<SyntheticMethodBuilder> methodBuilderCallback, + Consumer<ProgramMethod> newMethodCallback) { return appView .getSyntheticItems() .ensureFixedClassMethod( @@ -131,93 +117,8 @@ .getClassSignature() .toObjectBoundWithSameFormals( new ClassTypeSignature(appView.dexItemFactory().objectType))), - fn); - } - - private void ensureCompanionClassInitializesInterface( - DexProgramClass iface, InterfaceProcessingDesugaringEventConsumer eventConsumer) { - if (!hasStaticMethodThatTriggersNonTrivialClassInitializer(iface)) { - return; - } - DexEncodedField clinitField = ensureStaticClinitFieldToTriggerInterfaceInitialization(iface); - ProgramMethod clinit = - ensureCompanionMethod( - iface, - appView.dexItemFactory().classConstructorMethodName, - appView.dexItemFactory().createProto(appView.dexItemFactory().voidType), - appView, - methodBuilder -> createCompanionClassInitializer(iface, clinitField, methodBuilder)); - eventConsumer.acceptCompanionClassClinit(clinit); - } - - private DexEncodedField ensureStaticClinitFieldToTriggerInterfaceInitialization( - DexProgramClass iface) { - DexEncodedField clinitField = - findExistingStaticClinitFieldToTriggerInterfaceInitialization(iface); - if (clinitField == null) { - clinitField = createStaticClinitFieldToTriggerInterfaceInitialization(iface); - iface.appendStaticField(clinitField); - } - return clinitField; - } - - private boolean hasStaticMethodThatTriggersNonTrivialClassInitializer(DexProgramClass iface) { - return iface.hasClassInitializer() - && iface - .getMethodCollection() - .hasDirectMethods(method -> method.isStatic() && !method.isClassInitializer()); - } - - private DexEncodedField findExistingStaticClinitFieldToTriggerInterfaceInitialization( - DexProgramClass iface) { - // Don't select a field that has been marked dead, since we'll assert later that these fields - // have been dead code eliminated. - for (DexEncodedField field : - iface.staticFields(field -> !field.isPrivate() && !field.getOptimizationInfo().isDead())) { - return field; - } - return null; - } - - private DexEncodedField createStaticClinitFieldToTriggerInterfaceInitialization( - DexProgramClass iface) { - DexItemFactory dexItemFactory = appView.dexItemFactory(); - DexField clinitFieldReference = - dexItemFactory.createFreshFieldNameWithoutHolder( - iface.getType(), - dexItemFactory.intType, - "$desugar$clinit", - candidate -> iface.lookupField(candidate) == null); - return new DexEncodedField( - clinitFieldReference, - FieldAccessFlags.builder().setPackagePrivate().setStatic().setSynthetic().build(), - FieldTypeSignature.noSignature(), - DexAnnotationSet.empty(), - DexValueInt.DEFAULT); - } - - private void createCompanionClassInitializer( - DexProgramClass iface, DexEncodedField clinitField, SyntheticMethodBuilder methodBuilder) { - SyntheticMethodBuilder.SyntheticCodeGenerator codeGenerator = - method -> - new CfCode( - method.holder, - clinitField.getType().isWideType() ? 2 : 1, - 0, - ImmutableList.of( - new CfFieldInstruction( - Opcodes.GETSTATIC, clinitField.getReference(), clinitField.getReference()), - clinitField.getType().isWideType() - ? new CfStackInstruction(Opcode.Pop2) - : new CfStackInstruction(Opcode.Pop), - new CfReturnVoid()), - ImmutableList.of(), - ImmutableList.of()); - methodBuilder - .setAccessFlags( - MethodAccessFlags.builder().setConstructor().setPackagePrivate().setStatic().build()) - .setCode(codeGenerator) - .setClassFileVersion(iface.getInitialClassFileVersion()); + methodBuilderCallback, + newMethodCallback); } private void processVirtualInterfaceMethods(DexProgramClass iface) { @@ -248,7 +149,8 @@ } } - private void processDirectInterfaceMethods(DexProgramClass iface) { + private void processDirectInterfaceMethods( + DexProgramClass iface, InterfaceProcessingDesugaringEventConsumer eventConsumer) { for (ProgramMethod method : iface.directProgramMethods()) { DexEncodedMethod definition = method.getDefinition(); if (definition.isClassInitializer()) { @@ -271,7 +173,9 @@ + " is expected to " + "either be public or private in " + iface.origin; - companion = helper.ensureStaticAsMethodOfProgramCompanionClassStub(method); + companion = + helper.ensureStaticAsMethodOfProgramCompanionClassStub( + method, eventConsumer::acceptCompanionClassClinit); } else { assert definition.isPrivate(); Code code = definition.getCode();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/nest/AccessBridgeFactory.java b/src/main/java/com/android/tools/r8/ir/desugar/nest/AccessBridgeFactory.java index 9266ad9..8814c2e 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/nest/AccessBridgeFactory.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/nest/AccessBridgeFactory.java
@@ -38,6 +38,8 @@ .build()) .setMethod(bridgeMethodReference) .setD8R8Synthesized() + .setApiLevelForDefinition(field.getDefinition().getApiLevel()) + .setApiLevelForCode(field.getDefinition().getApiLevel()) .build()); } @@ -59,6 +61,8 @@ .build()) .setMethod(bridgeMethodReference) .setD8R8Synthesized() + .setApiLevelForDefinition(method.getDefinition().getApiLevelForDefinition()) + .setApiLevelForCode(method.getDefinition().getApiLevelForCode()) .build()); } @@ -87,6 +91,8 @@ builder -> builder.setDirectTarget(method.getReference(), isInterface)) .build()) .setMethod(bridgeMethodReference) + .setApiLevelForDefinition(method.getDefinition().getApiLevelForDefinition()) + .setApiLevelForCode(method.getDefinition().getApiLevelForDefinition()) .setD8R8Synthesized() .build()); }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java index a5ed9fb..2e74bb2 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
@@ -33,7 +33,9 @@ import com.android.tools.r8.graph.DexField; import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.DexMethod; +import com.android.tools.r8.graph.DexMethodHandle; import com.android.tools.r8.graph.DexProgramClass; +import com.android.tools.r8.graph.DexProto; import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.FieldResolutionResult; import com.android.tools.r8.graph.GraphLens; @@ -61,6 +63,7 @@ import com.android.tools.r8.ir.code.If; import com.android.tools.r8.ir.code.InstanceGet; import com.android.tools.r8.ir.code.Instruction; +import com.android.tools.r8.ir.code.InvokeCustom; import com.android.tools.r8.ir.code.InvokeMethod; import com.android.tools.r8.ir.code.InvokeStatic; import com.android.tools.r8.ir.code.InvokeVirtual; @@ -122,6 +125,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; @@ -217,6 +221,13 @@ } private DexProgramClass getEnumUnboxingCandidateOrNull(DexType type) { + if (type.isArrayType()) { + return getEnumUnboxingCandidateOrNull(type.toBaseType(appView.dexItemFactory())); + } + if (type.isPrimitiveType() || type.isVoidType()) { + return null; + } + assert type.isClassType(); return enumUnboxingCandidatesInfo.getCandidateClassOrNull(type); } @@ -253,6 +264,9 @@ case Opcodes.CHECK_CAST: analyzeCheckCast(instruction.asCheckCast(), eligibleEnums); break; + case Opcodes.INVOKE_CUSTOM: + analyzeInvokeCustom(instruction.asInvokeCustom(), eligibleEnums); + break; case INVOKE_STATIC: analyzeInvokeStatic(instruction.asInvokeStatic(), eligibleEnums, code.context()); break; @@ -289,6 +303,49 @@ } } + private void analyzeInvokeCustom(InvokeCustom invoke, Set<DexType> eligibleEnums) { + Consumer<DexType> typeReferenceConsumer = + type -> { + DexProgramClass enumClass = getEnumUnboxingCandidateOrNull(type); + if (enumClass != null) { + eligibleEnums.add(enumClass.getType()); + } + }; + invoke.getCallSite().getMethodProto().forEachType(typeReferenceConsumer); + invoke + .getCallSite() + .getBootstrapArgs() + .forEach( + bootstrapArgument -> { + if (bootstrapArgument.isDexValueMethodHandle()) { + DexMethodHandle methodHandle = + bootstrapArgument.asDexValueMethodHandle().getValue(); + if (methodHandle.isMethodHandle()) { + DexMethod method = methodHandle.asMethod(); + DexProgramClass enumClass = + getEnumUnboxingCandidateOrNull(method.getHolderType()); + if (enumClass != null) { + markEnumAsUnboxable(Reason.INVALID_INVOKE_CUSTOM, enumClass); + } else { + method.getProto().forEachType(typeReferenceConsumer); + } + } else { + assert methodHandle.isFieldHandle(); + DexField field = methodHandle.asField(); + DexProgramClass enumClass = getEnumUnboxingCandidateOrNull(field.getHolderType()); + if (enumClass != null) { + markEnumAsUnboxable(Reason.INVALID_INVOKE_CUSTOM, enumClass); + } else { + typeReferenceConsumer.accept(field.getType()); + } + } + } else if (bootstrapArgument.isDexValueMethodType()) { + DexProto proto = bootstrapArgument.asDexValueMethodType().getValue(); + proto.forEachType(typeReferenceConsumer); + } + }); + } + private void analyzeFieldInstruction( FieldInstruction fieldInstruction, Set<DexType> eligibleEnums, ProgramMethod context) { DexField field = fieldInstruction.getField();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java index 7a95765..9614ede 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java
@@ -4,7 +4,7 @@ package com.android.tools.r8.ir.optimize.enums; -import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabledForNewMember; +import static com.android.tools.r8.utils.AndroidApiLevel.minApiLevelIfEnabledOrUnknown; import com.android.tools.r8.cf.CfVersion; import com.android.tools.r8.cf.code.CfArrayStore; @@ -48,7 +48,6 @@ import java.util.Collections; import java.util.List; import java.util.Set; -import java.util.function.Function; import org.objectweb.asm.Opcodes; public class SharedEnumUnboxingUtilityClass extends EnumUnboxingUtilityClass { @@ -238,7 +237,7 @@ DexEncodedField.NO_STATIC_VALUE, DexEncodedField.NOT_DEPRECATED, DexEncodedField.D8_R8_SYNTHESIZED, - getApiLevelIfEnabledForNewMember(appView, Function.identity())); + minApiLevelIfEnabledOrUnknown(appView)); fieldAccessInfoCollectionModifierBuilder .recordFieldReadInUnknownContext(valuesField.getReference()) .recordFieldWriteInUnknownContext(valuesField.getReference()); @@ -258,8 +257,8 @@ createClassInitializerCode(sharedUtilityClassType, valuesField), DexEncodedMethod.D8_R8_SYNTHESIZED, CfVersion.V1_6, - getApiLevelIfEnabledForNewMember(appView, Function.identity()), - getApiLevelIfEnabledForNewMember(appView, Function.identity())); + minApiLevelIfEnabledOrUnknown(appView), + minApiLevelIfEnabledOrUnknown(appView)); } private CfCode createClassInitializerCode( @@ -305,8 +304,8 @@ createValuesMethodCode(sharedUtilityClassType, valuesField), DexEncodedMethod.D8_R8_SYNTHESIZED, CfVersion.V1_6, - getApiLevelIfEnabledForNewMember(appView, Function.identity()), - getApiLevelIfEnabledForNewMember(appView, Function.identity())); + minApiLevelIfEnabledOrUnknown(appView), + minApiLevelIfEnabledOrUnknown(appView)); this.valuesMethod = valuesMethod; return valuesMethod; }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/eligibility/Reason.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/eligibility/Reason.java index 429bdae..bac0275 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/enums/eligibility/Reason.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/eligibility/Reason.java
@@ -26,6 +26,7 @@ public static final Reason INVALID_INVOKE = new StringReason("INVALID_INVOKE"); public static final Reason INVALID_INVOKE_CLASSPATH = new StringReason("INVALID_INVOKE_CLASSPATH"); + public static final Reason INVALID_INVOKE_CUSTOM = new StringReason("INVALID_INVOKE_CUSTOM"); public static final Reason INVALID_INVOKE_ON_ARRAY = new StringReason("INVALID_INVOKE_ON_ARRAY"); public static final Reason IMPLICIT_UP_CAST_IN_RETURN = new StringReason("IMPLICIT_UP_CAST_IN_RETURN");
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationInfo.java index 4fd2fcd..c790a02 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationInfo.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationInfo.java
@@ -8,7 +8,6 @@ import com.android.tools.r8.ir.analysis.type.TypeElement; import com.android.tools.r8.ir.analysis.value.AbstractValue; import com.android.tools.r8.ir.analysis.value.UnknownValue; -import com.android.tools.r8.utils.AndroidApiLevel; public class DefaultFieldOptimizationInfo extends FieldOptimizationInfo { @@ -56,11 +55,6 @@ } @Override - public AndroidApiLevel getApiReferenceLevelForDefinition(AndroidApiLevel minApi) { - throw new RuntimeException("Should never be called"); - } - - @Override public MutableFieldOptimizationInfo toMutableOptimizationInfo() { return new MutableFieldOptimizationInfo(); }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationWithMinApiInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationWithMinApiInfo.java deleted file mode 100644 index a9c7462..0000000 --- a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationWithMinApiInfo.java +++ /dev/null
@@ -1,35 +0,0 @@ -// Copyright (c) 2019, 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.info; - -import com.android.tools.r8.utils.AndroidApiLevel; - -public class DefaultFieldOptimizationWithMinApiInfo extends DefaultFieldOptimizationInfo { - - private static final DefaultFieldOptimizationWithMinApiInfo INSTANCE = - new DefaultFieldOptimizationWithMinApiInfo(); - - public static DefaultFieldOptimizationWithMinApiInfo getInstance() { - return INSTANCE; - } - - @Override - public boolean hasApiReferenceLevelForDefinition() { - return true; - } - - @Override - public AndroidApiLevel getApiReferenceLevelForDefinition(AndroidApiLevel minApi) { - return minApi; - } - - @Override - public MutableFieldOptimizationInfo toMutableOptimizationInfo() { - MutableFieldOptimizationInfo updatableFieldOptimizationInfo = super.toMutableOptimizationInfo(); - // Use null to specify that the min api is set to minApi. - updatableFieldOptimizationInfo.setMinApiReferenceLevel(); - return updatableFieldOptimizationInfo; - } -}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java index 31ecb9b..24aeb3d 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
@@ -18,7 +18,6 @@ import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo; import com.android.tools.r8.ir.optimize.info.initializer.DefaultInstanceInitializerInfo; import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfo; -import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.InternalOptions; import com.google.common.collect.ImmutableSet; import java.util.BitSet; @@ -196,26 +195,6 @@ } @Override - public boolean hasApiReferenceLevelForCode() { - return false; - } - - @Override - public AndroidApiLevel getApiReferenceLevelForCode(AndroidApiLevel minApi) { - throw new RuntimeException("Should never be called"); - } - - @Override - public AndroidApiLevel getApiReferenceLevelForDefinition(AndroidApiLevel minApi) { - throw new RuntimeException("Should never be called"); - } - - @Override - public boolean hasApiReferenceLevelForDefinition() { - return false; - } - - @Override public MutableMethodOptimizationInfo toMutableOptimizationInfo() { return new MutableMethodOptimizationInfo(); }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationWithMinApiInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationWithMinApiInfo.java deleted file mode 100644 index cd06dee..0000000 --- a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationWithMinApiInfo.java +++ /dev/null
@@ -1,46 +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.ir.optimize.info; - -import com.android.tools.r8.utils.AndroidApiLevel; - -public class DefaultMethodOptimizationWithMinApiInfo extends DefaultMethodOptimizationInfo { - - private static final DefaultMethodOptimizationWithMinApiInfo DEFAULT_MIN_API_INSTANCE = - new DefaultMethodOptimizationWithMinApiInfo(); - - public static DefaultMethodOptimizationWithMinApiInfo getInstance() { - return DEFAULT_MIN_API_INSTANCE; - } - - @Override - public boolean hasApiReferenceLevelForDefinition() { - return true; - } - - @Override - public AndroidApiLevel getApiReferenceLevelForDefinition(AndroidApiLevel minApi) { - return minApi; - } - - @Override - public boolean hasApiReferenceLevelForCode() { - return true; - } - - @Override - public AndroidApiLevel getApiReferenceLevelForCode(AndroidApiLevel minApi) { - return minApi; - } - - @Override - public MutableMethodOptimizationInfo toMutableOptimizationInfo() { - MutableMethodOptimizationInfo updatableMethodOptimizationInfo = - super.toMutableOptimizationInfo(); - // Use null to specify that the min api is set to minApi. - updatableMethodOptimizationInfo.setMinApiReferenceLevel(); - return updatableMethodOptimizationInfo; - } -}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MemberOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MemberOptimizationInfo.java index 9cb8a2a..f5242e9 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/info/MemberOptimizationInfo.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MemberOptimizationInfo.java
@@ -4,8 +4,6 @@ package com.android.tools.r8.ir.optimize.info; -import com.android.tools.r8.utils.AndroidApiLevel; - public interface MemberOptimizationInfo< T extends MemberOptimizationInfo<T> & MutableOptimizationInfo> { @@ -21,12 +19,6 @@ return null; } - default boolean hasApiReferenceLevelForDefinition() { - return false; - } - - AndroidApiLevel getApiReferenceLevelForDefinition(AndroidApiLevel minApi); - T toMutableOptimizationInfo(); default boolean isFieldOptimizationInfo() {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java index bb45fbc..aab9aa6 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java
@@ -15,7 +15,6 @@ import com.android.tools.r8.ir.optimize.enums.classification.EnumUnboxerMethodClassification; import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo; import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfo; -import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.InternalOptions; import java.util.BitSet; import java.util.Set; @@ -101,10 +100,6 @@ public abstract boolean returnValueHasBeenPropagated(); - public abstract boolean hasApiReferenceLevelForCode(); - - public abstract AndroidApiLevel getApiReferenceLevelForCode(AndroidApiLevel minApi); - @Override public boolean isMethodOptimizationInfo() { return true;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java index bdab6e8..9150ea0 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java
@@ -15,8 +15,6 @@ import com.android.tools.r8.ir.analysis.value.AbstractValue; import com.android.tools.r8.ir.analysis.value.UnknownValue; import com.android.tools.r8.shaking.AppInfoWithLiveness; -import com.android.tools.r8.utils.AndroidApiLevel; -import java.util.Optional; import java.util.Set; /** @@ -38,7 +36,6 @@ private int readBits = 0; private ClassTypeElement dynamicLowerBoundType = null; private TypeElement dynamicUpperBoundType = null; - private Optional<AndroidApiLevel> apiReferenceLevel = null; public MutableFieldOptimizationInfo fixupClassTypeReferences( AppView<? extends AppInfoWithClassHierarchy> appView, GraphLens lens) { @@ -69,7 +66,6 @@ public MutableFieldOptimizationInfo mutableCopy() { MutableFieldOptimizationInfo copy = new MutableFieldOptimizationInfo(); copy.flags = flags; - copy.apiReferenceLevel = apiReferenceLevel; return copy; } @@ -154,29 +150,4 @@ public MutableFieldOptimizationInfo asMutableFieldOptimizationInfo() { return this; } - - @SuppressWarnings("OptionalAssignedToNull") - @Override - public boolean hasApiReferenceLevelForDefinition() { - return apiReferenceLevel != null; - } - - @Override - public AndroidApiLevel getApiReferenceLevelForDefinition(AndroidApiLevel minApi) { - assert hasApiReferenceLevelForDefinition(); - return apiReferenceLevel.orElse(minApi); - } - - @Override - @SuppressWarnings("OptionalAssignedToNull") - public void setMinApiReferenceLevel() { - assert apiReferenceLevel == null; - this.apiReferenceLevel = Optional.empty(); - } - - @Override - public void setApiReferenceLevelForDefinition(AndroidApiLevel apiReferenceLevel) { - assert apiReferenceLevel != null; - this.apiReferenceLevel = Optional.of(apiReferenceLevel); - } }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java index 54184d78..3efe7f6 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
@@ -25,11 +25,9 @@ import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfo; import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfoCollection; import com.android.tools.r8.shaking.AppInfoWithLiveness; -import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.BooleanUtils; import com.android.tools.r8.utils.InternalOptions; import java.util.BitSet; -import java.util.Optional; import java.util.Set; public class MutableMethodOptimizationInfo extends MethodOptimizationInfo @@ -75,9 +73,6 @@ private SimpleInliningConstraint simpleInliningConstraint = NeverSimpleInliningConstraint.getInstance(); - private Optional<AndroidApiLevel> codeApiReferenceLevel = null; - private Optional<AndroidApiLevel> definitionApiReferenceLevel = null; - // To reduce the memory footprint of UpdatableMethodOptimizationInfo, all the boolean fields are // merged into a flag int field. The various static final FLAG fields indicate which bit is // used by each boolean. DEFAULT_FLAGS encodes the default value for efficient instantiation and @@ -159,8 +154,6 @@ nonNullParamOnNormalExits = template.nonNullParamOnNormalExits; classInlinerConstraint = template.classInlinerConstraint; enumUnboxerMethodClassification = template.enumUnboxerMethodClassification; - definitionApiReferenceLevel = template.definitionApiReferenceLevel; - codeApiReferenceLevel = template.codeApiReferenceLevel; } public MutableMethodOptimizationInfo fixupClassTypeReferences( @@ -536,50 +529,6 @@ } @Override - public AndroidApiLevel getApiReferenceLevelForDefinition(AndroidApiLevel minApi) { - assert hasApiReferenceLevelForDefinition(); - return definitionApiReferenceLevel.orElse(minApi); - } - - @SuppressWarnings("OptionalAssignedToNull") - @Override - public boolean hasApiReferenceLevelForDefinition() { - return definitionApiReferenceLevel != null; - } - - @Override - @SuppressWarnings("OptionalAssignedToNull") - public boolean hasApiReferenceLevelForCode() { - return codeApiReferenceLevel != null; - } - - @Override - public AndroidApiLevel getApiReferenceLevelForCode(AndroidApiLevel minApi) { - assert hasApiReferenceLevelForCode(); - return codeApiReferenceLevel.orElse(minApi); - } - - @Override - @SuppressWarnings("OptionalAssignedToNull") - public void setMinApiReferenceLevel() { - assert codeApiReferenceLevel == null; - assert definitionApiReferenceLevel == null; - this.codeApiReferenceLevel = Optional.empty(); - this.definitionApiReferenceLevel = Optional.empty(); - } - - public void setApiReferenceLevelForCode(AndroidApiLevel apiLevel) { - assert apiLevel != null; - this.codeApiReferenceLevel = Optional.of(apiLevel); - } - - @Override - public void setApiReferenceLevelForDefinition(AndroidApiLevel apiLevel) { - assert apiLevel != null; - this.definitionApiReferenceLevel = Optional.of(apiLevel); - } - - @Override public boolean isMutableOptimizationInfo() { return true; }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableOptimizationInfo.java index 421f689..58f5470 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableOptimizationInfo.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableOptimizationInfo.java
@@ -4,11 +4,6 @@ package com.android.tools.r8.ir.optimize.info; -import com.android.tools.r8.utils.AndroidApiLevel; - public interface MutableOptimizationInfo { - void setMinApiReferenceLevel(); - - void setApiReferenceLevelForDefinition(AndroidApiLevel apiLevel); }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectsMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectsMethodOptimizer.java index 4b7cffb..1e518d6 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectsMethodOptimizer.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectsMethodOptimizer.java
@@ -177,11 +177,14 @@ instructionIterator.removeOrReplaceByDebugLocalRead(); } else if (inValue.isAlwaysNull(appView)) { if (singleTarget.getReference() == objectsMethods.requireNonNullElse) { - // Optimize Objects.requireNonNullElse(null, defaultObj) into defaultObj. - if (invoke.hasOutValue()) { - invoke.outValue().replaceUsers(invoke.getLastArgument(), affectedValues); + // Optimize Objects.requireNonNullElse(null, defaultObj) into defaultObj if defaultObj + // is never null. + if (invoke.getLastArgument().isNeverNull()) { + if (invoke.hasOutValue()) { + invoke.outValue().replaceUsers(invoke.getLastArgument(), affectedValues); + } + instructionIterator.removeOrReplaceByDebugLocalRead(); } - instructionIterator.removeOrReplaceByDebugLocalRead(); } else if (singleTarget.getReference() == objectsMethods.requireNonNullElseGet) { // Don't optimize Objects.requireNonNullElseGet. The result of calling supplier.get() still // needs a null-check, so two invokes will be needed.
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java index 4ce1fb6..7395cbf 100644 --- a/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java +++ b/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java
@@ -32,8 +32,8 @@ import com.android.tools.r8.ir.code.If; import com.android.tools.r8.ir.code.ValueType; import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter; -import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverterEventConsumer; import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizer; +import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryClasspathWrapperSynthesizeEventConsumer; import com.android.tools.r8.utils.BooleanUtils; import com.android.tools.r8.utils.collections.ImmutableDeque; import com.android.tools.r8.utils.collections.ImmutableInt2ReferenceSortedMap; @@ -58,21 +58,18 @@ private final DexMethod forwardMethod; private final DesugaredLibraryWrapperSynthesizer wrapperSynthesizer; private final boolean itfCall; - private final DesugaredLibraryAPIConverterEventConsumer eventConsumer; public APIConverterVivifiedWrapperCfCodeProvider( AppView<?> appView, DexMethod forwardMethod, DexField wrapperField, DesugaredLibraryWrapperSynthesizer wrapperSynthesizer, - boolean itfCall, - DesugaredLibraryAPIConverterEventConsumer eventConsumer) { + boolean itfCall) { super(appView, wrapperField.holder); this.forwardMethod = forwardMethod; this.wrapperField = wrapperField; this.wrapperSynthesizer = wrapperSynthesizer; this.itfCall = itfCall; - this.eventConsumer = eventConsumer; } @Override @@ -93,8 +90,8 @@ instructions.add( new CfInvoke( Opcodes.INVOKESTATIC, - wrapperSynthesizer.ensureConversionMethod( - param, param, vivifiedTypeFor(param), eventConsumer), + wrapperSynthesizer.getExistingProgramConversionMethod( + param, param, vivifiedTypeFor(param)), false)); newParameters[index - 1] = vivifiedTypeFor(param); } @@ -125,8 +122,8 @@ instructions.add( new CfInvoke( Opcodes.INVOKESTATIC, - wrapperSynthesizer.ensureConversionMethod( - returnType, vivifiedTypeFor(returnType), returnType, eventConsumer), + wrapperSynthesizer.getExistingProgramConversionMethod( + returnType, vivifiedTypeFor(returnType), returnType), false)); } if (returnType == factory.voidType) { @@ -138,31 +135,29 @@ } } - public static class APIConverterWrapperCfCodeProvider + public abstract static class AbstractAPIConverterWrapperCfCodeProvider extends DesugaredLibraryAPIConversionCfCodeProvider { - DexField wrapperField; DexMethod forwardMethod; DesugaredLibraryWrapperSynthesizer wrapperSynthesizor; boolean itfCall; - private final DesugaredLibraryAPIConverterEventConsumer eventConsumer; - public APIConverterWrapperCfCodeProvider( + public AbstractAPIConverterWrapperCfCodeProvider( AppView<?> appView, + DexType holder, DexMethod forwardMethod, - DexField wrapperField, DesugaredLibraryWrapperSynthesizer wrapperSynthesizor, - boolean itfCall, - DesugaredLibraryAPIConverterEventConsumer eventConsumer) { - // Var wrapperField is null if should forward to receiver. - super(appView, wrapperField == null ? forwardMethod.holder : wrapperField.holder); + boolean itfCall) { + super(appView, holder); this.forwardMethod = forwardMethod; - this.wrapperField = wrapperField; this.wrapperSynthesizor = wrapperSynthesizor; this.itfCall = itfCall; - this.eventConsumer = eventConsumer; } + abstract void generatePushReceiver(List<CfInstruction> instructions); + + abstract DexMethod ensureConversionMethod(DexType type, DexType srcType, DexType destType); + @Override public CfCode generateCfCode() { DexItemFactory factory = appView.dexItemFactory(); @@ -170,13 +165,7 @@ // Wrapped value is a type. Method uses vivifiedTypes as external. Forward method should // use types. - // Var wrapperField is null if should forward to receiver. - if (wrapperField == null) { - instructions.add(new CfLoad(ValueType.fromDexType(forwardMethod.holder), 0)); - } else { - instructions.add(new CfLoad(ValueType.fromDexType(wrapperField.holder), 0)); - instructions.add(new CfFieldInstruction(Opcodes.GETFIELD, wrapperField, wrapperField)); - } + generatePushReceiver(instructions); int stackIndex = 1; for (DexType param : forwardMethod.proto.parameters.values) { instructions.add(new CfLoad(ValueType.fromDexType(param), stackIndex)); @@ -184,8 +173,7 @@ instructions.add( new CfInvoke( Opcodes.INVOKESTATIC, - wrapperSynthesizor.ensureConversionMethod( - param, vivifiedTypeFor(param), param, eventConsumer), + ensureConversionMethod(param, vivifiedTypeFor(param), param), false)); } if (param == factory.longType || param == factory.doubleType) { @@ -205,8 +193,7 @@ instructions.add( new CfInvoke( Opcodes.INVOKESTATIC, - wrapperSynthesizor.ensureConversionMethod( - returnType, returnType, vivifiedTypeFor(returnType), eventConsumer), + ensureConversionMethod(returnType, returnType, vivifiedTypeFor(returnType)), false)); returnType = vivifiedTypeFor(returnType); } @@ -219,6 +206,59 @@ } } + public static class APICallbackWrapperCfCodeProvider + extends AbstractAPIConverterWrapperCfCodeProvider { + + private final DesugaredLibraryClasspathWrapperSynthesizeEventConsumer eventConsumer; + + public APICallbackWrapperCfCodeProvider( + AppView<?> appView, + DexMethod forwardMethod, + DesugaredLibraryWrapperSynthesizer wrapperSynthesizor, + boolean itfCall, + DesugaredLibraryClasspathWrapperSynthesizeEventConsumer eventConsumer) { + super(appView, forwardMethod.holder, forwardMethod, wrapperSynthesizor, itfCall); + this.eventConsumer = eventConsumer; + } + + @Override + void generatePushReceiver(List<CfInstruction> instructions) { + instructions.add(new CfLoad(ValueType.fromDexType(forwardMethod.holder), 0)); + } + + @Override + DexMethod ensureConversionMethod(DexType type, DexType srcType, DexType destType) { + return wrapperSynthesizor.ensureConversionMethod(type, srcType, destType, eventConsumer); + } + } + + public static class APIConverterWrapperCfCodeProvider + extends AbstractAPIConverterWrapperCfCodeProvider { + + private final DexField wrapperField; + + public APIConverterWrapperCfCodeProvider( + AppView<?> appView, + DexMethod forwardMethod, + DexField wrapperField, + DesugaredLibraryWrapperSynthesizer wrapperSynthesizor, + boolean itfCall) { + super(appView, wrapperField.holder, forwardMethod, wrapperSynthesizor, itfCall); + this.wrapperField = wrapperField; + } + + @Override + void generatePushReceiver(List<CfInstruction> instructions) { + instructions.add(new CfLoad(ValueType.fromDexType(wrapperField.holder), 0)); + instructions.add(new CfFieldInstruction(Opcodes.GETFIELD, wrapperField, wrapperField)); + } + + @Override + DexMethod ensureConversionMethod(DexType type, DexType srcType, DexType destType) { + return wrapperSynthesizor.getExistingProgramConversionMethod(type, srcType, destType); + } + } + public static class APIConverterWrapperConversionCfCodeProvider extends SyntheticCfCodeProvider { DexField reverseWrapperField;
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationArgumentInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationArgumentInfo.java index 373a5d2..6f34ad1 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationArgumentInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationArgumentInfo.java
@@ -68,7 +68,7 @@ private static KotlinAnnotationClassValueInfo create(KClassValue arg, DexItemFactory factory) { return new KotlinAnnotationClassValueInfo( - KotlinTypeReference.fromBinaryName(arg.getClassName(), factory), + KotlinTypeReference.fromBinaryName(arg.getClassName(), factory, arg.getClassName()), arg.getArrayDimensionCount()); } @@ -100,7 +100,8 @@ private static KotlinAnnotationEnumValueInfo create(EnumValue arg, DexItemFactory factory) { return new KotlinAnnotationEnumValueInfo( - KotlinTypeReference.fromBinaryName(arg.getEnumClassName(), factory), + KotlinTypeReference.fromBinaryName( + arg.getEnumClassName(), factory, arg.getEnumClassName()), arg.getEnumEntryName()); }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationInfo.java index cbdd76e..d21cfb1 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationInfo.java
@@ -34,7 +34,8 @@ static KotlinAnnotationInfo create(KmAnnotation annotation, DexItemFactory factory) { return new KotlinAnnotationInfo( - KotlinTypeReference.fromBinaryName(annotation.getClassName(), factory), + KotlinTypeReference.fromBinaryName( + annotation.getClassName(), factory, annotation.getClassName()), KotlinAnnotationArgumentInfo.create(annotation.getArguments(), factory)); }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java index aa3731f..9e7d703 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java
@@ -187,7 +187,8 @@ KmClass kmClass, DexItemFactory factory) { String anonymousObjectOriginName = JvmExtensionsKt.getAnonymousObjectOriginName(kmClass); if (anonymousObjectOriginName != null) { - return KotlinTypeReference.fromBinaryName(anonymousObjectOriginName, factory); + return KotlinTypeReference.fromBinaryName( + anonymousObjectOriginName, factory, anonymousObjectOriginName); } return null; } @@ -198,7 +199,7 @@ for (String nestedClass : nestedClasses) { String binaryName = clazz.type.toBinaryName() + DescriptorUtils.INNER_CLASS_SEPARATOR + nestedClass; - nestedTypes.add(KotlinTypeReference.fromBinaryName(binaryName, factory)); + nestedTypes.add(KotlinTypeReference.fromBinaryName(binaryName, factory, nestedClass)); } return nestedTypes.build(); } @@ -210,7 +211,7 @@ String binaryName = sealedSubClass.replace( DescriptorUtils.JAVA_PACKAGE_SEPARATOR, DescriptorUtils.INNER_CLASS_SEPARATOR); - sealedTypes.add(KotlinTypeReference.fromBinaryName(binaryName, factory)); + sealedTypes.add(KotlinTypeReference.fromBinaryName(binaryName, factory, sealedSubClass)); } return sealedTypes.build(); } @@ -326,30 +327,31 @@ } // Rewrite nested classes. for (KotlinTypeReference nestedClass : nestedClasses) { - rewritten |= + Box<String> nestedDescriptorBox = new Box<>(); + boolean nestedClassRewritten = nestedClass.toRenamedBinaryNameOrDefault( - nestedDescriptor -> { - if (nestedDescriptor != null) { - // If the class is a nested class, it should be on the form Foo.Bar$Baz, where Baz - // is the - // name we should record. - int innerClassIndex = - nestedDescriptor.lastIndexOf(DescriptorUtils.INNER_CLASS_SEPARATOR); - kmClass.visitNestedClass(nestedDescriptor.substring(innerClassIndex + 1)); - } - }, - appView, - namingLens, - null); + nestedDescriptorBox::set, appView, namingLens, null); + if (nestedDescriptorBox.isSet()) { + if (nestedClassRewritten) { + // If the class is a nested class, it should be on the form Foo.Bar$Baz, where Baz + // is the name we should record. + String nestedDescriptor = nestedDescriptorBox.get(); + int innerClassIndex = nestedDescriptor.lastIndexOf(DescriptorUtils.INNER_CLASS_SEPARATOR); + kmClass.visitNestedClass(nestedDescriptor.substring(innerClassIndex + 1)); + } else { + kmClass.visitNestedClass(nestedClass.getOriginalName()); + } + } + rewritten |= nestedClassRewritten; } // Rewrite sealed sub classes. for (KotlinTypeReference sealedSubClass : sealedSubClasses) { rewritten |= sealedSubClass.toRenamedBinaryNameOrDefault( - sealedDescriptor -> { - if (sealedDescriptor != null) { + sealedName -> { + if (sealedName != null) { kmClass.visitSealedSubclass( - sealedDescriptor.replace( + sealedName.replace( DescriptorUtils.INNER_CLASS_SEPARATOR, DescriptorUtils.JAVA_PACKAGE_SEPARATOR)); } @@ -409,7 +411,7 @@ declarationContainerInfo.trace(definitionSupplier); forEachApply(typeParameters, param -> param::trace, definitionSupplier); forEachApply(superTypes, type -> type::trace, definitionSupplier); - forEachApply(sealedSubClasses, sealed -> sealed::trace, definitionSupplier); + forEachApply(sealedSubClasses, sealedClass -> sealedClass::trace, definitionSupplier); forEachApply(nestedClasses, nested -> nested::trace, definitionSupplier); localDelegatedProperties.trace(definitionSupplier); // TODO(b/154347404): trace enum entries.
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinFunctionInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinFunctionInfo.java index e6a249c..5001c40 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinFunctionInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinFunctionInfo.java
@@ -106,7 +106,8 @@ KmFunction kmFunction, DexItemFactory factory) { String lambdaClassOriginName = JvmExtensionsKt.getLambdaClassOriginName(kmFunction); if (lambdaClassOriginName != null) { - return KotlinTypeReference.fromBinaryName(lambdaClassOriginName, factory); + return KotlinTypeReference.fromBinaryName( + lambdaClassOriginName, factory, lambdaClassOriginName); } return null; }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java index 0ff0070..fb6575c 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
@@ -182,6 +182,13 @@ writeMetadataFieldInfo); clazz.setAnnotations(clazz.annotations().rewrite(anno -> anno == oldMeta ? newMeta : anno)); } catch (Throwable t) { + assert appView.checkForTesting( + () -> { + throw appView + .options() + .reporter + .fatalError(KotlinMetadataDiagnostic.unexpectedErrorWhenRewriting(clazz.type, t)); + }); appView .options() .reporter
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassFacadeInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassFacadeInfo.java index 7088c7f..0545b20 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassFacadeInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassFacadeInfo.java
@@ -40,7 +40,7 @@ DexItemFactory factory) { ImmutableList.Builder<KotlinTypeReference> builder = ImmutableList.builder(); for (String partClassName : kmMultiFileClassFacade.getPartClassNames()) { - builder.add(KotlinTypeReference.fromBinaryName(partClassName, factory)); + builder.add(KotlinTypeReference.fromBinaryName(partClassName, factory, partClassName)); } return new KotlinMultiFileClassFacadeInfo(builder.build(), packageName, metadataVersion); }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java index c166103..8cea528 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java
@@ -24,28 +24,33 @@ class KotlinTypeReference implements EnqueuerMetadataTraceable { private final DexType known; - private final String unknown; + private final String originalName; - private KotlinTypeReference(DexType known) { + private KotlinTypeReference(String originalName, DexType known) { + this.originalName = originalName; this.known = known; - this.unknown = null; assert known != null; } - private KotlinTypeReference(String unknown) { + private KotlinTypeReference(String originalName) { this.known = null; - this.unknown = unknown; - assert unknown != null; + this.originalName = originalName; + assert originalName != null; } public DexType getKnown() { return known; } - static KotlinTypeReference fromBinaryName(String binaryName, DexItemFactory factory) { + public String getOriginalName() { + return originalName; + } + + static KotlinTypeReference fromBinaryName( + String binaryName, DexItemFactory factory, String originalName) { if (DescriptorUtils.isValidBinaryName(binaryName)) { return fromDescriptor( - DescriptorUtils.getDescriptorFromClassBinaryName(binaryName), factory, binaryName); + DescriptorUtils.getDescriptorFromClassBinaryName(binaryName), factory, originalName); } return new KotlinTypeReference(binaryName); } @@ -55,12 +60,12 @@ } static KotlinTypeReference fromDescriptor( - String descriptor, DexItemFactory factory, String unknownValue) { + String descriptor, DexItemFactory factory, String originalName) { if (DescriptorUtils.isDescriptor(descriptor)) { DexType type = factory.createType(descriptor); - return new KotlinTypeReference(type); + return new KotlinTypeReference(originalName, type); } - return new KotlinTypeReference(unknownValue); + return new KotlinTypeReference(originalName); } boolean toRenamedDescriptorOrDefault( @@ -68,11 +73,10 @@ AppView<?> appView, NamingLens namingLens, String defaultValue) { - if (unknown != null) { - rewrittenConsumer.accept(unknown); + if (known == null) { + rewrittenConsumer.accept(originalName); return false; } - assert known != null; DexType rewrittenType = toRewrittenTypeOrNull(appView, known); if (rewrittenType == null) { rewrittenConsumer.accept(defaultValue); @@ -85,7 +89,7 @@ String toKotlinClassifier(boolean isLocalOrAnonymous) { if (known == null) { - return unknown; + return originalName; } return getKotlinLocalOrAnonymousNameFromDescriptor( known.toDescriptorString(), isLocalOrAnonymous); @@ -96,9 +100,9 @@ AppView<?> appView, NamingLens namingLens, String defaultValue) { - if (unknown != null) { + if (known == null) { // Unknown values are always on the input form, so we can just return it. - rewrittenConsumer.accept(unknown); + rewrittenConsumer.accept(originalName); return false; } return toRenamedDescriptorOrDefault( @@ -136,7 +140,7 @@ @Override public String toString() { - return known != null ? known.descriptor.toString() : unknown; + return known != null ? known.descriptor.toString() : originalName; } @Override
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java index e53f285..ca54e1b 100644 --- a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java +++ b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
@@ -93,6 +93,10 @@ registerClassAsUsed(clazz.type, descriptor); } } + appView + .appInfo() + .getMissingClasses() + .forEach(missingClass -> registerClassAsUsed(missingClass, missingClass.getDescriptor())); timing.end(); timing.begin("rename-classes");
diff --git a/src/main/java/com/android/tools/r8/naming/MapVersion.java b/src/main/java/com/android/tools/r8/naming/MapVersion.java index 7069351..9c9c8d3 100644 --- a/src/main/java/com/android/tools/r8/naming/MapVersion.java +++ b/src/main/java/com/android/tools/r8/naming/MapVersion.java
@@ -6,10 +6,11 @@ import com.android.tools.r8.utils.structural.Ordered; public enum MapVersion implements Ordered<MapVersion> { - MapVersionNone("none"), - MapVersionExperimental("experimental"); + MAP_VERSION_NONE("none"), + MAP_VERSION_1_0("1.0"), + MAP_VERSION_EXPERIMENTAL("experimental"); - public static final MapVersion STABLE = MapVersionNone; + public static final MapVersion STABLE = MAP_VERSION_1_0; private final String name;
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java b/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java index f1e483f..52b63e0 100644 --- a/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java +++ b/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java
@@ -90,7 +90,7 @@ private int lineNo = 0; private int lineOffset = 0; private String line; - private MapVersion version = MapVersion.MapVersionNone; + private MapVersion version = MapVersion.MAP_VERSION_NONE; private int peekCodePoint() { return lineOffset < line.length() ? line.codePointAt(lineOffset) : '\n'; @@ -271,13 +271,13 @@ info -> { MapVersionMappingInformation generatorInfo = info.asMetaInfMappingInformation(); if (generatorInfo != null) { - if (generatorInfo.getMapVersion().equals(MapVersion.MapVersionExperimental)) { + if (generatorInfo.getMapVersion().equals(MapVersion.MAP_VERSION_EXPERIMENTAL)) { // A mapping file that is marked "experimental" will be treated as an unversioned // file if the compiler/tool is not explicitly running with experimental support. version = allowExperimentalMapping - ? MapVersion.MapVersionExperimental - : MapVersion.MapVersionNone; + ? MapVersion.MAP_VERSION_EXPERIMENTAL + : MapVersion.MAP_VERSION_NONE; } else { version = generatorInfo.getMapVersion(); }
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java b/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java index 8ac5e71..2d36290 100644 --- a/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java +++ b/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java
@@ -104,7 +104,7 @@ builder.append("# common_typos_disable" + "\n"); // Emit the R8 specific map-file version. MapVersion mapVersion = options.getMapFileVersion(); - if (mapVersion.isGreaterThan(MapVersion.MapVersionNone)) { + if (mapVersion.isGreaterThan(MapVersion.MAP_VERSION_NONE)) { builder .append("# ") .append(new MapVersionMappingInformation(mapVersion).serialize())
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/CompilerSynthesizedMappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/CompilerSynthesizedMappingInformation.java index 0c49e28..d26d9a8 100644 --- a/src/main/java/com/android/tools/r8/naming/mappinginformation/CompilerSynthesizedMappingInformation.java +++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/CompilerSynthesizedMappingInformation.java
@@ -12,7 +12,7 @@ public class CompilerSynthesizedMappingInformation extends MappingInformation { - public static final MapVersion SUPPORTED_VERSION = MapVersion.MapVersionExperimental; + public static final MapVersion SUPPORTED_VERSION = MapVersion.MAP_VERSION_1_0; public static final String ID = "com.android.tools.r8.synthesized"; public static class Builder {
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java index 13455ba..dbec312 100644 --- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java +++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java
@@ -80,10 +80,7 @@ WorkList<DexProgramClass> worklist = WorkList.newIdentityWorkList(clazz); while (worklist.hasNext()) { DexProgramClass current = worklist.next(); - immediateSubtypingInfo.forEachImmediateSuperClassMatching( - current, - (supertype, superclass) -> superclass != null && superclass.isProgramClass(), - (supertype, superclass) -> worklist.addIfNotSeen(superclass.asProgramClass())); + immediateSubtypingInfo.forEachImmediateProgramSuperClass(current, worklist::addIfNotSeen); worklist.addIfNotSeen(immediateSubtypingInfo.getSubclasses(current)); } return worklist.getSeenSet();
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorUnoptimizableMethods.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorUnoptimizableMethods.java index 9a478bd..36dae85 100644 --- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorUnoptimizableMethods.java +++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorUnoptimizableMethods.java
@@ -137,12 +137,11 @@ unoptimizableInterfaceMethods.computeIfAbsent(clazz, ignoreKey(Sets::newIdentityHashSet)); // Add the unoptimizable interface methods from the parent interfaces. - immediateSubtypingInfo.forEachImmediateSuperClassMatching( + immediateSubtypingInfo.forEachImmediateProgramSuperClass( clazz, - (supertype, superclass) -> superclass != null && superclass.isProgramClass(), - (supertype, superclass) -> + superclass -> unoptimizableInterfaceMethodsForClass.addAll( - unoptimizableInterfaceMethods.get(superclass.asProgramClass()))); + unoptimizableInterfaceMethods.get(superclass))); // Propagate the unoptimizable interface methods of this interface to all immediate // (non-interface) subclasses. @@ -221,12 +220,9 @@ unoptimizableMethods.computeIfAbsent(clazz, ignoreKey(DexMethodSignatureSet::create)); // Add the unoptimizable methods from the parent classes. - immediateSubtypingInfo.forEachImmediateSuperClassMatching( + immediateSubtypingInfo.forEachImmediateProgramSuperClass( clazz, - (supertype, superclass) -> superclass != null && superclass.isProgramClass(), - (supertype, superclass) -> - unoptimizableMethodsForClass.addAll( - unoptimizableMethods.get(superclass.asProgramClass()))); + superclass -> unoptimizableMethodsForClass.addAll(unoptimizableMethods.get(superclass))); // Disable argument propagation for the unoptimizable methods of this class. clazz.forEachProgramVirtualMethod(
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InterfaceMethodArgumentPropagator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InterfaceMethodArgumentPropagator.java index 99a0bac..69cbb7b 100644 --- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InterfaceMethodArgumentPropagator.java +++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InterfaceMethodArgumentPropagator.java
@@ -82,12 +82,11 @@ DexProgramClass interfaceDefinition) { // Join the state for all parent interfaces into a fresh state created for this interface. MethodStateCollectionBySignature interfaceState = MethodStateCollectionBySignature.create(); - immediateSubtypingInfo.forEachImmediateSuperClassMatching( + immediateSubtypingInfo.forEachImmediateProgramSuperClass( interfaceDefinition, - (supertype, superclass) -> superclass != null && superclass.isProgramClass(), - (supertype, superclass) -> { + superclass -> { MethodStateCollectionBySignature implementedInterfaceState = - methodStatesToPropagate.get(superclass.asProgramClass()); + methodStatesToPropagate.get(superclass); assert implementedInterfaceState != null; interfaceState.addMethodStates(appView, implementedInterfaceState); });
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/VirtualDispatchMethodArgumentPropagator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/VirtualDispatchMethodArgumentPropagator.java index 14c58f8..771a718 100644 --- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/VirtualDispatchMethodArgumentPropagator.java +++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/VirtualDispatchMethodArgumentPropagator.java
@@ -46,10 +46,8 @@ PropagationState(DexProgramClass clazz) { // Join the argument information from each of the super types. - immediateSubtypingInfo.forEachImmediateSuperClassMatching( - clazz, - (supertype, superclass) -> superclass != null && superclass.isProgramClass(), - (supertype, superclass) -> addParentState(clazz, superclass.asProgramClass())); + immediateSubtypingInfo.forEachImmediateProgramSuperClass( + clazz, superclass -> addParentState(clazz, superclass)); } // TODO(b/190154391): This currently copies the state of the superclass into its immediate
diff --git a/src/main/java/com/android/tools/r8/repackaging/Repackaging.java b/src/main/java/com/android/tools/r8/repackaging/Repackaging.java index 6621857..8e34c3f 100644 --- a/src/main/java/com/android/tools/r8/repackaging/Repackaging.java +++ b/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
@@ -274,16 +274,25 @@ } // Always repackage outer classes first, if any. - InnerClassAttribute innerClassAttribute = classToRepackage.getInnerClassAttributeForThisClass(); DexProgramClass outerClass = null; - if (innerClassAttribute != null && innerClassAttribute.getOuter() != null) { - outerClass = asProgramClassOrNull(appView.definitionFor(innerClassAttribute.getOuter())); - if (outerClass != null) { - if (pkg.contains(outerClass)) { - processClass(outerClass, pkg, newPackageDescriptor, mappings); - } else { - outerClass = null; - } + if (classToRepackage.hasEnclosingMethodAttribute()) { + DexType enclosingClass = classToRepackage.getEnclosingMethodAttribute().getEnclosingClass(); + if (enclosingClass != null) { + outerClass = asProgramClassOrNull(appView.definitionFor(enclosingClass)); + } + } + if (outerClass == null) { + InnerClassAttribute innerClassAttribute = + classToRepackage.getInnerClassAttributeForThisClass(); + if (innerClassAttribute != null && innerClassAttribute.getOuter() != null) { + outerClass = asProgramClassOrNull(appView.definitionFor(innerClassAttribute.getOuter())); + } + } + if (outerClass != null) { + if (pkg.contains(outerClass)) { + processClass(outerClass, pkg, newPackageDescriptor, mappings); + } else { + outerClass = null; } } mappings.put( @@ -318,13 +327,13 @@ public static class DefaultRepackagingConfiguration implements RepackagingConfiguration { - private final AppView<?> appView; + private final AppView<AppInfoWithLiveness> appView; private final DexItemFactory dexItemFactory; private final InternalOptions options; private final ProguardConfiguration proguardConfiguration; private final MinificationPackageNamingStrategy packageMinificationStrategy; - public DefaultRepackagingConfiguration(AppView<?> appView) { + public DefaultRepackagingConfiguration(AppView<AppInfoWithLiveness> appView) { this.appView = appView; this.dexItemFactory = appView.dexItemFactory(); this.options = appView.options(); @@ -342,7 +351,7 @@ return newPackageDescriptor; } else if (packageObfuscationMode.isMinification()) { assert !proguardConfiguration.hasApplyMappingFile(); - // Always keep top-level classes since there packages can never be minified. + // Always keep top-level classes since their packages can never be minified. if (pkg.getPackageDescriptor().equals("") || proguardConfiguration.getKeepPackageNamesPatterns().matches(pkg) || mayHavePinnedPackagePrivateOrProtectedItem(pkg)) { @@ -383,15 +392,21 @@ private boolean mayHavePinnedPackagePrivateOrProtectedItem(ProgramPackage pkg) { // Go through all package classes and members to see if there is a pinned package-private - // item, in which case we cannot move it because there may be a reflective access to it. + // item, in which case we cannot move it because there could be an access to it from outside + // the program, which would be rewritten with -applymapping. for (DexProgramClass clazz : pkg.classesInPackage()) { if (clazz.getAccessFlags().isPackagePrivateOrProtected() - && appView.getKeepInfo().getClassInfo(clazz).isPinned(options)) { + && !appView.getKeepInfo().getClassInfo(clazz).isShrinkingAllowed(options)) { return true; } for (DexEncodedMember<?, ?> member : clazz.members()) { + // Skip the class initializer. Even if it is kept, it cannot be invoked, and thus we don't + // need any special handling to make sure it is always accessible to callers from tests. + if (member.isDexEncodedMethod() && member.asDexEncodedMethod().isClassInitializer()) { + continue; + } if (member.getAccessFlags().isPackagePrivateOrProtected() - && appView.getKeepInfo().getMemberInfo(member, clazz).isPinned(options)) { + && !appView.getKeepInfo().getMemberInfo(member, clazz).isShrinkingAllowed(options)) { return true; } } @@ -427,17 +442,19 @@ } // Ensure that the generated name is unique. DexType finalRepackagedDexType = repackagedDexType; - for (int i = 1; isRepackageTypeUsed(finalRepackagedDexType, mappings, appView); i++) { + for (int i = 1; isRepackageTypeUsed(finalRepackagedDexType, mappings); i++) { finalRepackagedDexType = repackagedDexType.addSuffix(i + "", dexItemFactory); } return finalRepackagedDexType; } - } - private static boolean isRepackageTypeUsed( - DexType type, BiMap<DexType, DexType> mappings, AppView<?> appView) { - return mappings.inverse().containsKey(type) - || (appView.hasLiveness() && appView.withLiveness().appInfo().wasPruned(type)); + private boolean isRepackageTypeUsed(DexType type, BiMap<DexType, DexType> mappings) { + if (mappings.inverse().containsKey(type)) { + return true; + } + return appView.appInfo().wasPruned(type) + || appView.appInfo().getMissingClasses().contains(type); + } } /** Testing only. */
diff --git a/src/main/java/com/android/tools/r8/repackaging/RepackagingUseRegistry.java b/src/main/java/com/android/tools/r8/repackaging/RepackagingUseRegistry.java index 27247d4..2e7b6b5 100644 --- a/src/main/java/com/android/tools/r8/repackaging/RepackagingUseRegistry.java +++ b/src/main/java/com/android/tools/r8/repackaging/RepackagingUseRegistry.java
@@ -116,13 +116,22 @@ MemberResolutionResult<?, ?> resolutionResult, boolean isInvoke) { if (!resolutionResult.isSuccessfulMemberResolutionResult()) { // To preserve errors in the original program, we need to look at the failure dependencies. - // For example, if this method accesses in a package-private method in another package, and we - // move the two methods to the same package, then the invoke would no longer fail with an + // For example, if this member accesses a package-private method in another package, and we + // move the two members to the same package, then the invoke would no longer fail with an // IllegalAccessError. - if (isInvoke) { - // TODO(b/150589374): Only add this if we are in the minification mode of repackaging. - node.addNeighbor(missingTypeNode); + + // For fields and methods that cannot be found the chance of recovering by repackaging is + // pretty slim thus we allow for repackaging the callers. + if (resolutionResult.isFieldResolutionResult()) { + assert resolutionResult.asFieldResolutionResult().isFailedResolution(); + return; } + MethodResolutionResult methodResult = resolutionResult.asMethodResolutionResult(); + if (methodResult.isClassNotFoundResult() + || methodResult.isNoSuchMethodErrorResult(context.getContextClass(), appInfo)) { + return; + } + node.addNeighbor(missingTypeNode); return; } @@ -161,9 +170,6 @@ DexClass clazz = appInfo.definitionFor(type); if (clazz != null) { consumer.accept(clazz); - } else { - // The missing type reference can be package private and we cannot repackage. - node.addNeighbor(missingTypeNode); } }
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java index aef58b7..be31b16 100644 --- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java +++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -986,11 +986,6 @@ if (!keepInfo.getInfo(clazz).isRepackagingAllowed(clazz, options())) { return false; } - for (DexType superType : clazz.allImmediateSupertypes()) { - if (definitionFor(superType) == null) { - return false; - } - } return clazz .traverseProgramMembers( member -> {
diff --git a/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java b/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java index 3d76d73..bfc3ae7 100644 --- a/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java +++ b/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java
@@ -5,7 +5,7 @@ package com.android.tools.r8.shaking; import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull; -import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabledForNewMember; +import static com.android.tools.r8.utils.AndroidApiLevel.minApiLevelIfEnabledOrUnknown; import com.android.tools.r8.dex.Constants; import com.android.tools.r8.errors.Unreachable; @@ -22,7 +22,6 @@ import com.android.tools.r8.utils.Visibility; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; -import java.util.function.Function; public class ClassInitFieldSynthesizer { @@ -93,7 +92,7 @@ null, deprecated, DexEncodedField.D8_R8_SYNTHESIZED, - getApiLevelIfEnabledForNewMember(appView, Function.identity())); + minApiLevelIfEnabledOrUnknown(appView)); clazz.appendStaticField(encodedClinitField); } lensBuilder.map(type, encodedClinitField.getReference());
diff --git a/src/main/java/com/android/tools/r8/shaking/MissingClasses.java b/src/main/java/com/android/tools/r8/shaking/MissingClasses.java index 5ffc72b..1dd5360 100644 --- a/src/main/java/com/android/tools/r8/shaking/MissingClasses.java +++ b/src/main/java/com/android/tools/r8/shaking/MissingClasses.java
@@ -31,6 +31,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.function.Consumer; import java.util.function.Predicate; public class MissingClasses { @@ -56,6 +57,10 @@ .build(); } + public void forEach(Consumer<DexType> missingClassConsumer) { + missingClasses.forEach(missingClassConsumer); + } + public boolean contains(DexType type) { return missingClasses.contains(type); }
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java index 0a49379..27d25bb 100644 --- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java +++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -7,7 +7,6 @@ import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull; import static com.android.tools.r8.ir.code.Invoke.Type.DIRECT; import static com.android.tools.r8.ir.code.Invoke.Type.STATIC; -import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabledForNewMember; import com.android.tools.r8.androidapi.AndroidApiReferenceLevelCache; import com.android.tools.r8.errors.Unreachable; @@ -1451,8 +1450,8 @@ code, true, method.hasClassFileVersion() ? method.getClassFileVersion() : null, - getApiLevelIfEnabledForNewMember(appView, method::getApiReferenceLevelForDefinition), - getApiLevelIfEnabledForNewMember(appView, Function.identity())); + method.getApiLevelForDefinition(), + method.getApiLevelForDefinition()); bridge.setLibraryMethodOverride(method.isLibraryMethodOverride()); if (method.accessFlags.isPromotedToPublic()) { // The bridge is now the public method serving the role of the original method, and should
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java index eb97f48..a86e143 100644 --- a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java +++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
@@ -508,16 +508,31 @@ DexProgramClass context, AppView<?> appView, Consumer<SyntheticProgramClassBuilder> fn) { - // Obtain the outer synthesizing context in the case the context itself is synthetic. - // This is to ensure a flat input-type -> synthetic-item mapping. - SynthesizingContext outerContext = - context.isProgramClass() - ? getSynthesizingContext(context.asProgramClass(), appView) - : SynthesizingContext.fromNonSyntheticInputContext(context.asClasspathOrLibraryClass()); + SynthesizingContext outerContext = internalGetOuterContext(context, appView); DexType type = SyntheticNaming.createFixedType(kind, outerContext, appView.dexItemFactory()); return internalCreateClass(kind, fn, outerContext, type, appView.dexItemFactory()); } + public DexProgramClass getExistingFixedClass( + SyntheticKind kind, DexClass context, AppView<?> appView) { + assert kind.isFixedSuffixSynthetic; + SynthesizingContext outerContext = internalGetOuterContext(context, appView); + DexType type = SyntheticNaming.createFixedType(kind, outerContext, appView.dexItemFactory()); + DexClass clazz = appView.definitionFor(type); + assert clazz != null; + assert isSyntheticClass(type); + assert clazz.isProgramClass(); + return clazz.asProgramClass(); + } + + // Obtain the outer synthesizing context in the case the context itself is synthetic. + // This is to ensure a flat input-type -> synthetic-item mapping. + private SynthesizingContext internalGetOuterContext(DexClass context, AppView<?> appView) { + return context.isProgramClass() + ? getSynthesizingContext(context.asProgramClass(), appView) + : SynthesizingContext.fromNonSyntheticInputContext(context.asClasspathOrLibraryClass()); + } + /** * Ensure that a fixed synthetic class exists. * @@ -530,12 +545,7 @@ Consumer<SyntheticProgramClassBuilder> fn, Consumer<DexProgramClass> onCreationConsumer) { assert kind.isFixedSuffixSynthetic; - // Obtain the outer synthesizing context in the case the context itself is synthetic. - // This is to ensure a flat input-type -> synthetic-item mapping. - SynthesizingContext outerContext = - context.isProgramClass() - ? getSynthesizingContext(context.asProgramClass(), appView) - : SynthesizingContext.fromNonSyntheticInputContext(context.asClasspathOrLibraryClass()); + SynthesizingContext outerContext = internalGetOuterContext(context, appView); DexType type = SyntheticNaming.createFixedType(kind, outerContext, appView.dexItemFactory()); // Fast path is that the synthetic is already present. If so it must be a program class. DexClass clazz = appView.definitionFor(type); @@ -678,12 +688,8 @@ Consumer<SyntheticMethodBuilder> buildMethodCallback, Consumer<T> newMethodCallback) { MethodCollection methodCollection = clazz.getMethodCollection(); - DexEncodedMethod methodDefinition = methodCollection.getMethod(methodReference); - if (methodDefinition != null) { - return methodDefinition; - } synchronized (methodCollection) { - methodDefinition = methodCollection.getMethod(methodReference); + DexEncodedMethod methodDefinition = methodCollection.getMethod(methodReference); if (methodDefinition != null) { return methodDefinition; }
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java index adc3f40..196af3b 100644 --- a/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java +++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java
@@ -56,7 +56,7 @@ public SyntheticMethodBuilder setName(DexString name) { assert name != null; - assert this.name == null; + assert this.name == null || this.name == name; this.name = name; return this; }
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 1e4082b..e127d6c 100644 --- a/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java +++ b/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
@@ -4,6 +4,7 @@ package com.android.tools.r8.utils; import com.android.tools.r8.errors.Unreachable; +import com.android.tools.r8.graph.AppView; import com.android.tools.r8.utils.structural.Ordered; import java.util.Arrays; import java.util.List; @@ -75,6 +76,12 @@ return DexVersion.getDexVersion(this); } + public static AndroidApiLevel minApiLevelIfEnabledOrUnknown(AppView<?> appView) { + return appView.options().apiModelingOptions().enableApiCallerIdentification + ? appView.options().minApiLevel + : UNKNOWN; + } + public static List<AndroidApiLevel> getAndroidApiLevelsSorted() { return Arrays.asList(AndroidApiLevel.values()); }
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java b/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java index 9272066..96c4a2b 100644 --- a/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java +++ b/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java
@@ -4,32 +4,10 @@ package com.android.tools.r8.utils; -import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.ProgramMethod; -import java.util.function.Function; public class AndroidApiLevelUtils { - // Static api-level indicating that the api level is min-api. - public static final AndroidApiLevel MIN_API_LEVEL = null; - - public static AndroidApiLevel getApiLevelIfEnabledForNewMember( - AppView<?> appView, Function<AndroidApiLevel, AndroidApiLevel> getter) { - AndroidApiLevel apiLevelIfEnabled = getApiLevelIfEnabled(appView, getter); - if (apiLevelIfEnabled == appView.options().minApiLevel) { - return MIN_API_LEVEL; - } - return apiLevelIfEnabled; - } - - public static AndroidApiLevel getApiLevelIfEnabled( - AppView<?> appView, Function<AndroidApiLevel, AndroidApiLevel> getter) { - if (!appView.options().apiModelingOptions().enableApiCallerIdentification) { - return AndroidApiLevel.UNKNOWN; - } - return getter.apply(appView.options().minApiLevel); - } - public static OptionalBool isApiSafeForInlining( ProgramMethod caller, ProgramMethod inlinee, InternalOptions options) { if (!options.apiModelingOptions().enableApiCallerIdentification) { @@ -41,8 +19,7 @@ return OptionalBool.of( caller .getDefinition() - .getApiReferenceLevel(options.minApiLevel) - .isGreaterThanOrEqualTo( - inlinee.getDefinition().getApiReferenceLevelForCode(options.minApiLevel))); + .getApiLevel() + .isGreaterThanOrEqualTo(inlinee.getDefinition().getApiLevelForCode())); } }
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApp.java b/src/main/java/com/android/tools/r8/utils/AndroidApp.java index d58387f..b1a2757 100644 --- a/src/main/java/com/android/tools/r8/utils/AndroidApp.java +++ b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
@@ -75,7 +75,11 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; +import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.util.CheckClassAdapter; /** * Collection of program files needed for processing. @@ -762,6 +766,30 @@ return extractor.getDescriptor(); } + public void validateInputs() { + for (ProgramResourceProvider programResourceProvider : getProgramResourceProviders()) { + try { + for (ProgramResource programResource : programResourceProvider.getProgramResources()) { + try { + Kind kind = programResource.getKind(); + if (kind == Kind.DEX) { + continue; + } + byte[] bytes = programResource.getBytes(); + ClassReader classReader = new ClassReader(bytes); + classReader.accept( + new CheckClassAdapter(Opcodes.ASM9, new ClassNode(), true) {}, + ClassReader.EXPAND_FRAMES); + } catch (Throwable e) { + throw new CompilationError("Failed validating " + programResource.getOrigin(), e); + } + } + } catch (ResourceException e) { + throw new CompilationError("Resource exception in validation", e); + } + } + } + /** * Builder interface for constructing an AndroidApp. */
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 c0c5504..5ee21c1 100644 --- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java +++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -1210,7 +1210,7 @@ System.getProperty("com.android.tools.r8.noCfMarkerForDesugaredCode") != null; } - public static class CallSiteOptimizationOptions { + public class CallSiteOptimizationOptions { // Each time we see an invoke with more dispatch targets than the threshold, we stop call site // propagation for all these dispatch targets. The motivation for this is that it is expensive @@ -1223,7 +1223,7 @@ private boolean enableExperimentalArgumentPropagation = false; private boolean enableTypePropagation = true; - private void disableOptimization() { + public void disableOptimization() { enableConstantPropagation = false; enableTypePropagation = false; } @@ -1232,18 +1232,14 @@ enableTypePropagation = false; } - // TODO(b/69963623): Remove this once enabled. - @VisibleForTesting - public static void enableConstantPropagationForTesting(InternalOptions options) { - assert !options.callSiteOptimizationOptions().isConstantPropagationEnabled(); - options.callSiteOptimizationOptions().enableConstantPropagation = true; - } - public int getMaxNumberOfDispatchTargetsBeforeAbandoning() { return maxNumberOfDispatchTargetsBeforeAbandoning; } public boolean isEnabled() { + if (!isOptimizing()) { + return false; + } return enableConstantPropagation || enableTypePropagation; } @@ -1264,12 +1260,19 @@ enableConstantPropagation = true; } - public void setEnableExperimentalArgumentPropagation() { - assert !isExperimentalArgumentPropagationEnabled(); - enableExperimentalArgumentPropagation = true; + public void setEnableExperimentalArgumentPropagation( + boolean enableExperimentalArgumentPropagation) { + this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation; } } + // TODO(b/69963623): Remove this once enabled. + @VisibleForTesting + public static void enableConstantArgumentPropagationForTesting(InternalOptions options) { + assert !options.callSiteOptimizationOptions().isConstantPropagationEnabled(); + options.callSiteOptimizationOptions().enableConstantPropagation = true; + } + public class HorizontalClassMergerOptions { // TODO(b/138781768): Set enable to true when this bug is resolved. @@ -1571,6 +1574,7 @@ public boolean disableMappingToOriginalProgramVerification = false; public boolean allowInvalidCfAccessFlags = System.getProperty("com.android.tools.r8.allowInvalidCfAccessFlags") != null; + public boolean verifyInputs = System.getProperty("com.android.tools.r8.verifyInputs") != null; // TODO(b/177333791): Set to true public boolean checkForNotExpandingMainDexTracingResult = false; public Set<String> allowedUnusedDontWarnPatterns = new HashSet<>(); @@ -1640,7 +1644,7 @@ public MapVersion getMapFileVersion() { return testing.enableExperimentalMapFileVersion - ? MapVersion.MapVersionExperimental + ? MapVersion.MAP_VERSION_EXPERIMENTAL : MapVersion.STABLE; }
diff --git a/src/test/java/com/android/tools/r8/CompileWithJdkClassFileProviderTest.java b/src/test/java/com/android/tools/r8/CompileWithJdkClassFileProviderTest.java index d8e0196..848c566 100644 --- a/src/test/java/com/android/tools/r8/CompileWithJdkClassFileProviderTest.java +++ b/src/test/java/com/android/tools/r8/CompileWithJdkClassFileProviderTest.java
@@ -116,8 +116,12 @@ containsString( "java.lang.NoClassDefFoundError: " + "Failed resolution of: Ljava/util/concurrent/Flow$Subscriber;"), - // Art 10+. - containsString("java.lang.ClassNotFoundException: MySubscriber"))); + // Art 10. + containsString("java.lang.ClassNotFoundException: MySubscriber"), + // Art 11+. + containsString( + "java.lang.ClassNotFoundException: " + + "java.util.concurrent.SubmissionPublisher"))); } else { if (parameters.getRuntime().asCf().getVm() == CfVm.JDK8) { // java.util.concurrent.Flow$Subscriber not present in JDK8.
diff --git a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java index bcd4fea..f58f1fd 100644 --- a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java +++ b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
@@ -95,15 +95,17 @@ private static final String ART_TESTS_NATIVE_LIBRARY_DIR = "tests/2017-10-04/art/lib64"; private static final String ART_LEGACY_TESTS_NATIVE_LIBRARY_DIR = "tests/2016-12-19/art/lib64"; - private static final RuntimeSet LEGACY_RUNTIME = TestCondition.runtimes( - DexVm.Version.V4_0_4, - DexVm.Version.V4_4_4, - DexVm.Version.V5_1_1, - DexVm.Version.V6_0_1, - DexVm.Version.V7_0_0, - DexVm.Version.V8_1_0, - DexVm.Version.V9_0_0, - DexVm.Version.V10_0_0); + private static final RuntimeSet LEGACY_RUNTIME = + TestCondition.runtimes( + DexVm.Version.V4_0_4, + DexVm.Version.V4_4_4, + DexVm.Version.V5_1_1, + DexVm.Version.V6_0_1, + DexVm.Version.V7_0_0, + DexVm.Version.V8_1_0, + DexVm.Version.V9_0_0, + DexVm.Version.V10_0_0, + DexVm.Version.V12_0_0); // Input jar for jctf tests. private static final String JCTF_COMMON_JAR = "build/libs/jctfCommon.jar"; @@ -185,6 +187,18 @@ .put( "134-reg-promotion", TestCondition.match(TestCondition.runtimes(DexVm.Version.V10_0_0))) + // TODO(b/197078742): Triage - test OOMs. + .put( + "134-reg-promotion", + TestCondition.match(TestCondition.runtimes(DexVm.Version.V12_0_0))) + // TODO(b/197078746): Triage - fails with "java.lang.NoSuchMethodException: + // org.apache.harmony.dalvik.ddmc.DdmVmInternal.enableRecentAllocations [boolean]" + .put("098-ddmc", TestCondition.match(TestCondition.runtimes(DexVm.Version.V12_0_0))) + // TODO(b/197079442): Triage - fails with "java.lang.NoSuchMethodException: + // org.apache.harmony.dalvik.ddmc.DdmVmInternal.enableRecentAllocations [boolean]" + .put( + "145-alloc-tracking-stress", + TestCondition.match(TestCondition.runtimes(DexVm.Version.V12_0_0))) .build(); // Tests that are flaky with the Art version we currently use. @@ -488,115 +502,134 @@ static { ImmutableMap.Builder<DexVm.Version, List<String>> builder = ImmutableMap.builder(); builder - .put(DexVm.Version.V10_0_0, ImmutableList.of( - // TODO(b/144975341): Triage, Verif error. - "518-null-array-get", - // TODO(b/144975341): Triage, Linking error. - "457-regs", - "543-env-long-ref", - "454-get-vreg" - )) - .put(DexVm.Version.V9_0_0, ImmutableList.of( - // TODO(120400625): Triage. - "454-get-vreg", - // TODO(120402198): Triage. - "457-regs", - // TODO(120401674): Triage. - "543-env-long-ref", - // TODO(120261858) Triage. - "518-null-array-get" - )) - .put(DexVm.Version.V8_1_0, ImmutableList.of( - // TODO(119938529): Triage. - "709-checker-varhandles", - "454-get-vreg", - "457-regs" - )) - .put(DexVm.Version.V7_0_0, ImmutableList.of( - // Addition of checks for super-class-initialization cause this to abort on non-ToT art. - "008-exceptions", + .put( + DexVm.Version.V12_0_0, + ImmutableList.of("454-get-vreg", "457-regs", "543-env-long-ref", "518-null-array-get")) + .put( + DexVm.Version.V10_0_0, + ImmutableList.of( + // TODO(b/144975341): Triage, Verif error. + "518-null-array-get", + // TODO(b/144975341): Triage, Linking error. + "457-regs", + "543-env-long-ref", + "454-get-vreg")) + .put( + DexVm.Version.V9_0_0, + ImmutableList.of( + // TODO(120400625): Triage. + "454-get-vreg", + // TODO(120402198): Triage. + "457-regs", + // TODO(120401674): Triage. + "543-env-long-ref", + // TODO(120261858) Triage. + "518-null-array-get")) + .put( + DexVm.Version.V8_1_0, + ImmutableList.of( + // TODO(119938529): Triage. + "709-checker-varhandles", "454-get-vreg", "457-regs")) + .put( + DexVm.Version.V7_0_0, + ImmutableList.of( + // Addition of checks for super-class-initialization cause this to abort on non-ToT + // art. + "008-exceptions", - // Generally fails on non-R8/D8 running. - "156-register-dex-file-multi-loader", - "412-new-array", - "610-arraycopy", - "625-checker-licm-regressions")) - .put(DexVm.Version.V6_0_1, ImmutableList.of( - // Addition of checks for super-class-initialization cause this to abort on non-ToT art. - "008-exceptions", + // Generally fails on non-R8/D8 running. + "156-register-dex-file-multi-loader", + "412-new-array", + "610-arraycopy", + "625-checker-licm-regressions")) + .put( + DexVm.Version.V6_0_1, + ImmutableList.of( + // Addition of checks for super-class-initialization cause this to abort on non-ToT + // art. + "008-exceptions", - // Generally fails on non-R8/D8 running. - "004-checker-UnsafeTest18", - "005-annotations", - "008-exceptions", - "082-inline-execute", - "099-vmdebug", - "156-register-dex-file-multi-loader", - "412-new-array", - "580-checker-round", - "594-invoke-super", - "625-checker-licm-regressions", - "626-const-class-linking")) - .put(DexVm.Version.V5_1_1, ImmutableList.of( - // Addition of checks for super-class-initialization cause this to abort on non-ToT art. - "008-exceptions", + // Generally fails on non-R8/D8 running. + "004-checker-UnsafeTest18", + "005-annotations", + "008-exceptions", + "082-inline-execute", + "099-vmdebug", + "156-register-dex-file-multi-loader", + "412-new-array", + "580-checker-round", + "594-invoke-super", + "625-checker-licm-regressions", + "626-const-class-linking")) + .put( + DexVm.Version.V5_1_1, + ImmutableList.of( + // Addition of checks for super-class-initialization cause this to abort on non-ToT + // art. + "008-exceptions", - // Generally fails on non R8/D8 running. - "004-checker-UnsafeTest18", - "004-NativeAllocations", - "005-annotations", - "008-exceptions", - "082-inline-execute", - "099-vmdebug", - "143-string-value", - "156-register-dex-file-multi-loader", - "536-checker-intrinsic-optimization", - "552-invoke-non-existent-super", - "580-checker-round", - "580-checker-string-fact-intrinsics", - "594-invoke-super", - "605-new-string-from-bytes", - "626-const-class-linking")) - .put(DexVm.Version.V4_4_4, ImmutableList.of( - // Addition of checks for super-class-initialization cause this to abort on non-ToT art. - "008-exceptions", + // Generally fails on non R8/D8 running. + "004-checker-UnsafeTest18", + "004-NativeAllocations", + "005-annotations", + "008-exceptions", + "082-inline-execute", + "099-vmdebug", + "143-string-value", + "156-register-dex-file-multi-loader", + "536-checker-intrinsic-optimization", + "552-invoke-non-existent-super", + "580-checker-round", + "580-checker-string-fact-intrinsics", + "594-invoke-super", + "605-new-string-from-bytes", + "626-const-class-linking")) + .put( + DexVm.Version.V4_4_4, + ImmutableList.of( + // Addition of checks for super-class-initialization cause this to abort on non-ToT + // art. + "008-exceptions", - // Generally fails on non R8/D8 running. - "004-checker-UnsafeTest18", - "004-NativeAllocations", - "005-annotations", - "008-exceptions", - "082-inline-execute", - "099-vmdebug", - "143-string-value", - "156-register-dex-file-multi-loader", - "536-checker-intrinsic-optimization", - "552-invoke-non-existent-super", - "580-checker-round", - "580-checker-string-fact-intrinsics", - "594-invoke-super", - "605-new-string-from-bytes", - "626-const-class-linking")) - .put(DexVm.Version.V4_0_4, ImmutableList.of( - // Addition of checks for super-class-initialization cause this to abort on non-ToT art. - "008-exceptions", + // Generally fails on non R8/D8 running. + "004-checker-UnsafeTest18", + "004-NativeAllocations", + "005-annotations", + "008-exceptions", + "082-inline-execute", + "099-vmdebug", + "143-string-value", + "156-register-dex-file-multi-loader", + "536-checker-intrinsic-optimization", + "552-invoke-non-existent-super", + "580-checker-round", + "580-checker-string-fact-intrinsics", + "594-invoke-super", + "605-new-string-from-bytes", + "626-const-class-linking")) + .put( + DexVm.Version.V4_0_4, + ImmutableList.of( + // Addition of checks for super-class-initialization cause this to abort on non-ToT + // art. + "008-exceptions", - // Generally fails on non R8/D8 running. - "004-checker-UnsafeTest18", - "004-NativeAllocations", - "005-annotations", - "008-exceptions", - "082-inline-execute", - "099-vmdebug", - "143-string-value", - "156-register-dex-file-multi-loader", - "536-checker-intrinsic-optimization", - "552-invoke-non-existent-super", - "580-checker-round", - "580-checker-string-fact-intrinsics", - "594-invoke-super", - "605-new-string-from-bytes", - "626-const-class-linking")); + // Generally fails on non R8/D8 running. + "004-checker-UnsafeTest18", + "004-NativeAllocations", + "005-annotations", + "008-exceptions", + "082-inline-execute", + "099-vmdebug", + "143-string-value", + "156-register-dex-file-multi-loader", + "536-checker-intrinsic-optimization", + "552-invoke-non-existent-super", + "580-checker-round", + "580-checker-string-fact-intrinsics", + "594-invoke-super", + "605-new-string-from-bytes", + "626-const-class-linking")); expectedToFailRunWithArtVersion = builder.build(); } @@ -2050,6 +2083,10 @@ System.out.println("Running on 10.0.0 is disabled, see b/144966342"); continue; } + if (vm.getVersion() == DexVm.Version.V12_0_0) { + System.out.println("Running on 12.0.0 is disabled, see b/197078995"); + continue; + } vms.add(new DexRuntime(vm)); } }
diff --git a/src/test/java/com/android/tools/r8/TestCondition.java b/src/test/java/com/android/tools/r8/TestCondition.java index d72ba77..07fff0e 100644 --- a/src/test/java/com/android/tools/r8/TestCondition.java +++ b/src/test/java/com/android/tools/r8/TestCondition.java
@@ -25,6 +25,7 @@ ART_V8_1_0, ART_V9_0_0, ART_V10_0_0, + ART_V12_0_0, ART_DEFAULT, JAVA; @@ -49,6 +50,8 @@ return ART_V9_0_0; case V10_0_0: return ART_V10_0_0; + case V12_0_0: + return ART_V12_0_0; case DEFAULT: return ART_DEFAULT; default:
diff --git a/src/test/java/com/android/tools/r8/TestRunResult.java b/src/test/java/com/android/tools/r8/TestRunResult.java index 23e2e5c..90d4f75 100644 --- a/src/test/java/com/android/tools/r8/TestRunResult.java +++ b/src/test/java/com/android/tools/r8/TestRunResult.java
@@ -145,6 +145,14 @@ return assertFailure(); } + public RR assertFailureWithErrorThatMatchesIf(boolean condition, Matcher<String> matcher) { + if (condition) { + assertStderrMatches(matcher); + return assertFailure(); + } + return self(); + } + public RR assertFailureWithOutput(String expected) { assertStdoutMatches(is(expected)); return assertFailure();
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java index a1bdeb8..a38852e 100644 --- a/src/test/java/com/android/tools/r8/ToolHelper.java +++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -256,7 +256,9 @@ ART_9_0_0_TARGET(Version.V9_0_0, Kind.TARGET), ART_9_0_0_HOST(Version.V9_0_0, Kind.HOST), ART_10_0_0_TARGET(Version.V10_0_0, Kind.TARGET), - ART_10_0_0_HOST(Version.V10_0_0, Kind.HOST); + ART_10_0_0_HOST(Version.V10_0_0, Kind.HOST), + ART_12_0_0_TARGET(Version.V12_0_0, Kind.TARGET), + ART_12_0_0_HOST(Version.V12_0_0, Kind.HOST); private static final ImmutableMap<String, DexVm> SHORT_NAME_MAP = Arrays.stream(DexVm.values()).collect(ImmutableMap.toImmutableMap( @@ -271,7 +273,8 @@ V8_1_0("8.1.0"), DEFAULT("default"), V9_0_0("9.0.0"), - V10_0_0("10.0.0"); + V10_0_0("10.0.0"), + V12_0_0("12.0.0"); Version(String shortName) { this.shortName = shortName; @@ -289,6 +292,10 @@ return this == last(); } + public boolean isEqualTo(Version other) { + return compareTo(other) == 0; + } + public boolean isNewerThan(Version other) { return compareTo(other) > 0; } @@ -321,7 +328,7 @@ } public static Version last() { - return V10_0_0; + return V12_0_0; } static { @@ -358,10 +365,22 @@ return SHORT_NAME_MAP.get(version.shortName + "_" + Kind.HOST.toString()); } + public boolean isEqualTo(DexVm other) { + return version.isNewerThanOrEqual(other.version); + } + public boolean isNewerThan(DexVm other) { return version.isNewerThan(other.version); } + public boolean isNewerThanOrEqual(DexVm other) { + return version.isNewerThanOrEqual(other.version); + } + + public boolean isOlderThan(DexVm other) { + return version.isOlderThan(other.version); + } + public boolean isOlderThanOrEqual(DexVm other) { return version.isOlderThanOrEqual(other.version); } @@ -580,6 +599,7 @@ private static final Map<DexVm, String> ART_DIRS = ImmutableMap.<DexVm, String>builder() .put(DexVm.ART_DEFAULT, "art") + .put(DexVm.ART_12_0_0_HOST, "host/art-12.0.0-beta4") .put(DexVm.ART_10_0_0_HOST, "art-10.0.0") .put(DexVm.ART_9_0_0_HOST, "art-9.0.0") .put(DexVm.ART_8_1_0_HOST, "art-8.1.0") @@ -587,10 +607,12 @@ .put(DexVm.ART_6_0_1_HOST, "art-6.0.1") .put(DexVm.ART_5_1_1_HOST, "art-5.1.1") .put(DexVm.ART_4_4_4_HOST, "dalvik") - .put(DexVm.ART_4_0_4_HOST, "dalvik-4.0.4").build(); + .put(DexVm.ART_4_0_4_HOST, "dalvik-4.0.4") + .build(); private static final Map<DexVm, String> ART_BINARY_VERSIONS = ImmutableMap.<DexVm, String>builder() .put(DexVm.ART_DEFAULT, "bin/art") + .put(DexVm.ART_12_0_0_HOST, "bin/art") .put(DexVm.ART_10_0_0_HOST, "bin/art") .put(DexVm.ART_9_0_0_HOST, "bin/art") .put(DexVm.ART_8_1_0_HOST, "bin/art") @@ -598,16 +620,19 @@ .put(DexVm.ART_6_0_1_HOST, "bin/art") .put(DexVm.ART_5_1_1_HOST, "bin/art") .put(DexVm.ART_4_4_4_HOST, "bin/dalvik") - .put(DexVm.ART_4_0_4_HOST, "bin/dalvik").build(); + .put(DexVm.ART_4_0_4_HOST, "bin/dalvik") + .build(); private static final Map<DexVm, String> ART_BINARY_VERSIONS_X64 = ImmutableMap.<DexVm, String>builder() .put(DexVm.ART_DEFAULT, "bin/art") + .put(DexVm.ART_12_0_0_HOST, "bin/art") .put(DexVm.ART_10_0_0_HOST, "bin/art") .put(DexVm.ART_9_0_0_HOST, "bin/art") .put(DexVm.ART_8_1_0_HOST, "bin/art") .put(DexVm.ART_7_0_0_HOST, "bin/art") - .put(DexVm.ART_6_0_1_HOST, "bin/art").build(); + .put(DexVm.ART_6_0_1_HOST, "bin/art") + .build(); private static final List<String> DALVIK_BOOT_LIBS = ImmutableList.of( @@ -627,6 +652,7 @@ ImmutableMap.Builder<DexVm, List<String>> builder = ImmutableMap.builder(); builder .put(DexVm.ART_DEFAULT, ART_BOOT_LIBS) + .put(DexVm.ART_12_0_0_HOST, ART_BOOT_LIBS) .put(DexVm.ART_10_0_0_HOST, ART_BOOT_LIBS) .put(DexVm.ART_9_0_0_HOST, ART_BOOT_LIBS) .put(DexVm.ART_8_1_0_HOST, ART_BOOT_LIBS) @@ -644,6 +670,7 @@ ImmutableMap.Builder<DexVm, String> builder = ImmutableMap.builder(); builder .put(DexVm.ART_DEFAULT, "angler") + .put(DexVm.ART_12_0_0_HOST, "redfin") .put(DexVm.ART_10_0_0_HOST, "coral") .put(DexVm.ART_9_0_0_HOST, "marlin") .put(DexVm.ART_8_1_0_HOST, "marlin") @@ -1002,6 +1029,8 @@ switch (dexVm.version) { case DEFAULT: return AndroidApiLevel.O; + case V12_0_0: + return AndroidApiLevel.S; case V10_0_0: return AndroidApiLevel.Q; case V9_0_0: @@ -1898,7 +1927,8 @@ public static ProcessResult runDex2OatRaw(Path file, Path outFile, DexVm vm) throws IOException { // TODO(jmhenaff): find a way to run this on windows (push dex and run on device/emulator?) Assume.assumeTrue(ToolHelper.isDex2OatSupported()); - Assume.assumeFalse("b/144975341", vm.version == DexVm.Version.V10_0_0); + Assume.assumeFalse( + "b/144975341", vm.version == DexVm.Version.V10_0_0 || vm.version == DexVm.Version.V12_0_0); if (vm.isOlderThanOrEqual(DexVm.ART_4_4_4_HOST)) { // Run default dex2oat for tests on dalvik runtimes. vm = DexVm.ART_DEFAULT;
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchLinkInterfaceTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchLinkInterfaceTest.java index 04337ec..c87f2cc 100644 --- a/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchLinkInterfaceTest.java +++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchLinkInterfaceTest.java
@@ -7,7 +7,7 @@ import static com.android.tools.r8.apimodel.ApiModelingTestHelper.addTracedApiReferenceLevelCallBack; import static com.android.tools.r8.utils.AndroidApiLevel.LATEST; import static com.android.tools.r8.utils.AndroidApiLevel.R; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import com.android.tools.r8.TestBase; import com.android.tools.r8.TestParameters; @@ -56,7 +56,7 @@ addTracedApiReferenceLevelCallBack( (method, apiLevel) -> { if (Reference.methodFromMethod(main).equals(method)) { - assertEquals(R, apiLevel); + assertTrue(apiLevel.isGreaterThanOrEqualTo(R)); } })) .compile();
diff --git a/src/test/java/com/android/tools/r8/cf/stackmap/InvalidStackHeightTest.java b/src/test/java/com/android/tools/r8/cf/stackmap/InvalidStackHeightTest.java index 71b6637..9fffa07 100644 --- a/src/test/java/com/android/tools/r8/cf/stackmap/InvalidStackHeightTest.java +++ b/src/test/java/com/android/tools/r8/cf/stackmap/InvalidStackHeightTest.java
@@ -6,6 +6,8 @@ import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage; import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static org.junit.Assume.assumeTrue; import com.android.tools.r8.CompilationFailedException; @@ -88,6 +90,23 @@ .assertSuccessWithOutputLines(EXPECTED); } + @Test() + public void testR8InputVerification() throws Exception { + try { + testForR8(parameters.getBackend()) + .addProgramClassFileData(getMainWithChangedMaxStackHeight()) + .enableInliningAnnotations() + .addKeepMainRule(Main.class) + .setMinApi(parameters.getApiLevel()) + .addOptionsModification(options -> options.testing.verifyInputs = true) + .compile(); + } catch (CompilationFailedException e) { + assertTrue(e.getCause().getMessage().contains("Insufficient maximum stack size")); + return; + } + fail("Should always throw"); + } + public byte[] getMainWithChangedMaxStackHeight() throws Exception { return transformer(Main.class).setMaxStackHeight(MethodPredicate.onName("main"), 1).transform(); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorStackTraceTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorStackTraceTest.java index c39b7b5..d1cedfc 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorStackTraceTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorStackTraceTest.java
@@ -14,7 +14,6 @@ import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestRuntime.CfRuntime; import com.android.tools.r8.naming.retrace.StackTrace; -import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine; import org.junit.Before; import org.junit.Test; @@ -55,21 +54,7 @@ .inspectStackTrace( (stackTrace, codeInspector) -> { assertThat(codeInspector.clazz(A.class), isPresent()); - StackTrace expectedStackTraceWithMergedConstructor = - StackTrace.builder() - .add(expectedStackTrace) - .add( - 2, - StackTraceLine.builder() - .setClassName(A.class.getTypeName()) - // TODO(b/124483578): The synthetic method should not be part of the - // retraced stack trace. - .setMethodName("$r8$init$synthetic") - .setFileName(getClass().getSimpleName() + ".java") - .setLineNumber(0) - .build()) - .build(); - assertThat(stackTrace, isSame(expectedStackTraceWithMergedConstructor)); + assertThat(stackTrace, isSame(expectedStackTrace)); assertThat(codeInspector.clazz(B.class), not(isPresent())); }); }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorWithEquivalenceStackTraceTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorWithEquivalenceStackTraceTest.java index 9b5b87d..cb0b232 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorWithEquivalenceStackTraceTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorWithEquivalenceStackTraceTest.java
@@ -13,9 +13,7 @@ import com.android.tools.r8.NoVerticalClassMerging; import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestRuntime.CfRuntime; -import com.android.tools.r8.classmerging.horizontal.MergedConstructorStackTraceTest.A; import com.android.tools.r8.naming.retrace.StackTrace; -import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine; import org.junit.Before; import org.junit.Test; @@ -63,16 +61,6 @@ // constructors should retrace to the set of lines from each of the // individual source constructors. .map(1, stackTraceLine -> stackTraceLine.builderOf().setLineNumber(0).build()) - // TODO(b/124483578): The synthetic method should not be part of the retraced - // stack trace. - .add( - 2, - StackTraceLine.builder() - .setClassName(A.class.getTypeName()) - .setMethodName("$r8$init$synthetic") - .setFileName(getClass().getSimpleName() + ".java") - .setLineNumber(0) - .build()) .build(); assertThat(stackTrace, isSame(expectedStackTraceWithMergedConstructor)); assertThat(codeInspector.clazz(B.class), not(isPresent()));
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedVirtualMethodStackTraceTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedVirtualMethodStackTraceTest.java index 0375885..12edd71 100644 --- a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedVirtualMethodStackTraceTest.java +++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedVirtualMethodStackTraceTest.java
@@ -14,7 +14,6 @@ import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestRuntime.CfRuntime; import com.android.tools.r8.naming.retrace.StackTrace; -import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine; import org.junit.Before; import org.junit.Test; @@ -54,20 +53,7 @@ (stackTrace, codeInspector) -> { assertThat(codeInspector.clazz(Program.A.class), isPresent()); assertThat(codeInspector.clazz(Program.B.class), isAbsent()); - StackTrace expectedStackTraceWithMergedMethod = - StackTrace.builder() - .add(expectedStackTrace) - .add( - 1, - StackTraceLine.builder() - .setClassName(Program.A.class.getTypeName()) - .setMethodName("foo$bridge") - .setFileName("Program.java") - .setFileName(getClass().getSimpleName() + ".java") - .setLineNumber(stackTrace.get(1).lineNumber) - .build()) - .build(); - assertThat(stackTrace, isSame(expectedStackTraceWithMergedMethod)); + assertThat(stackTrace, isSame(expectedStackTrace)); }); }
diff --git a/src/test/java/com/android/tools/r8/desugar/LambdaMissingInterfaceTest.java b/src/test/java/com/android/tools/r8/desugar/LambdaMissingInterfaceTest.java index bdcfd8a..59853ee 100644 --- a/src/test/java/com/android/tools/r8/desugar/LambdaMissingInterfaceTest.java +++ b/src/test/java/com/android/tools/r8/desugar/LambdaMissingInterfaceTest.java
@@ -4,6 +4,8 @@ package com.android.tools.r8.desugar; +import static org.hamcrest.CoreMatchers.containsString; + import com.android.tools.r8.NeverInline; import com.android.tools.r8.TestBase; import com.android.tools.r8.TestParameters; @@ -38,7 +40,12 @@ .compile() .addRunClasspathClasses(MissingInterface.class) .run(parameters.getRuntime(), Main.class) - .assertFailureWithErrorThatThrows(AbstractMethodError.class); + // We allow for renaming if the class is missing + .assertFailureWithErrorThatMatchesIf( + parameters.getDexRuntimeVersion().isDalvik(), + containsString(descriptor(MissingInterface.class) + "' is not accessible")) + .assertFailureWithErrorThatThrowsIf( + !parameters.getDexRuntimeVersion().isDalvik(), IllegalAccessError.class); } interface MissingInterface {
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ByteBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/ByteBackportJava9Test.java index 37aa606..81038d6 100644 --- a/src/test/java/com/android/tools/r8/desugar/backports/ByteBackportJava9Test.java +++ b/src/test/java/com/android/tools/r8/desugar/backports/ByteBackportJava9Test.java
@@ -4,17 +4,18 @@ package com.android.tools.r8.desugar.backports; +import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION; + import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestRuntime.CfVm; import com.android.tools.r8.ToolHelper; +import com.android.tools.r8.utils.AndroidApiLevel; import java.nio.file.Path; import java.nio.file.Paths; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; -import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION; - @RunWith(Parameterized.class) public final class ByteBackportJava9Test extends AbstractBackportTest { @Parameters(name = "{0}") @@ -31,7 +32,8 @@ public ByteBackportJava9Test(TestParameters parameters) { super(parameters, Byte.class, TEST_JAR, "backport.ByteBackportJava9Main"); - // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in - // an actual API level, migrate these tests to ByteBackportTest. + + // Byte.compareUnsigned added in API 31. + registerTarget(AndroidApiLevel.S, 16); } }
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava10Test.java b/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava10Test.java index 309b319..7b80e96 100644 --- a/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava10Test.java +++ b/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava10Test.java
@@ -4,9 +4,12 @@ package com.android.tools.r8.desugar.backports; +import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION; + import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestRuntime.CfVm; import com.android.tools.r8.ToolHelper; +import com.android.tools.r8.utils.AndroidApiLevel; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; @@ -14,8 +17,6 @@ import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; -import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION; - @RunWith(Parameterized.class) public class ListBackportJava10Test extends AbstractBackportTest { @Parameters(name = "{0}") @@ -40,5 +41,8 @@ ignoreInvokes("get"); ignoreInvokes("set"); ignoreInvokes("size"); + + // List.copyOf added in API 31. + registerTarget(AndroidApiLevel.S, 3); } }
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava9Test.java index 0d55065..ddf502b 100644 --- a/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava9Test.java +++ b/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava9Test.java
@@ -44,13 +44,16 @@ ignoreInvokes("get"); ignoreInvokes("set"); ignoreInvokes("size"); + + // List.of added in API 30. + registerTarget(AndroidApiLevel.R, 18); } @Test public void desugaringApiLevelR() throws Exception { - // TODO(154759404): This test should start to fail when testing on an Android R VM. - if (parameters.getRuntime().isDex() - && parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.Q)) { + // TODO(b/154759404): This test should start to fail when testing on an Android R VM. + // This has now been checked with S, when R testing is added check and remove this. + if (parameters.getRuntime().isDex() && parameters.getApiLevel().isEqualTo(AndroidApiLevel.Q)) { testForD8() .setMinApi(AndroidApiLevel.R) .addProgramClasses(MiniAssert.class, IgnoreInvokes.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava10Test.java b/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava10Test.java index e54d7d8..11008cc 100644 --- a/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava10Test.java +++ b/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava10Test.java
@@ -4,9 +4,12 @@ package com.android.tools.r8.desugar.backports; +import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION; + import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestRuntime.CfVm; import com.android.tools.r8.ToolHelper; +import com.android.tools.r8.utils.AndroidApiLevel; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Map; @@ -14,8 +17,6 @@ import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; -import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION; - @RunWith(Parameterized.class) public class MapBackportJava10Test extends AbstractBackportTest { @Parameters(name = "{0}") @@ -40,5 +41,8 @@ ignoreInvokes("get"); ignoreInvokes("put"); ignoreInvokes("size"); + + // Map.copyOf added in API 31. + registerTarget(AndroidApiLevel.S, 4); } }
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava9Test.java index 27cb824..73ffa29 100644 --- a/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava9Test.java +++ b/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava9Test.java
@@ -44,13 +44,16 @@ ignoreInvokes("get"); ignoreInvokes("put"); ignoreInvokes("size"); + + // Map.entry, Map.of and Map.ofEntries added in API 30. + registerTarget(AndroidApiLevel.R, 29); } @Test public void desugaringApiLevelR() throws Exception { - // TODO(154759404): This test should start to fail when testing on an Android R VM. - if (parameters.getRuntime().isDex() - && parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.Q)) { + // TODO(b/154759404): This test should start to fail when testing on an Android R VM. + // This has now been checked with S, when R testing is added check and remove this. + if (parameters.getRuntime().isDex() && parameters.getApiLevel().isEqualTo(AndroidApiLevel.R)) { testForD8() .setMinApi(AndroidApiLevel.R) .addProgramClasses(MiniAssert.class, IgnoreInvokes.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/MathBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/MathBackportJava9Test.java index 387697e..2f70fc2 100644 --- a/src/test/java/com/android/tools/r8/desugar/backports/MathBackportJava9Test.java +++ b/src/test/java/com/android/tools/r8/desugar/backports/MathBackportJava9Test.java
@@ -9,6 +9,7 @@ import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestRuntime.CfVm; import com.android.tools.r8.ToolHelper; +import com.android.tools.r8.utils.AndroidApiLevel; import java.nio.file.Path; import java.nio.file.Paths; import org.junit.runner.RunWith; @@ -31,7 +32,9 @@ public MathBackportJava9Test(TestParameters parameters) { super(parameters, Math.class, TEST_JAR, "backport.MathBackportJava9Main"); - // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in - // an actual API level, migrate these tests to MathBackportTest. + + // Math.floorDiv, Math.floorMod, Math.multiplyExact, Math.multiplyFull and Math.multiplyHigh + // added in API 31. + registerTarget(AndroidApiLevel.S, 27); } }
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ObjectsBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/ObjectsBackportJava9Test.java index 09aef1e..527d2c0 100644 --- a/src/test/java/com/android/tools/r8/desugar/backports/ObjectsBackportJava9Test.java +++ b/src/test/java/com/android/tools/r8/desugar/backports/ObjectsBackportJava9Test.java
@@ -13,6 +13,7 @@ import com.android.tools.r8.utils.AndroidApiLevel; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Objects; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -34,16 +35,20 @@ private static final String TEST_CLASS = "backport.ObjectsBackportJava9Main"; public ObjectsBackportJava9Test(TestParameters parameters) { - super(parameters, Short.class, TEST_JAR, TEST_CLASS); + super(parameters, Objects.class, TEST_JAR, TEST_CLASS); // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in // an actual API level, migrate these tests to ObjectsBackportTest. + + // Objects.checkFromIndexSize, Objects.checkFromToIndex, Objects.checkIndex, + // Objects.requireNonNullElse and Objects.requireNonNullElseGet added in API 30. + registerTarget(AndroidApiLevel.R, 28); } @Test public void desugaringApiLevelR() throws Exception { - // TODO(154759404): This test should start to fail when testing on an Android R VM. - if (parameters.getRuntime().isDex() - && parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.Q)) { + // TODO(b/154759404): This test should start to fail when testing on an Android R VM. + // This has now been checked with S, when R testing is added chck and remove this. + if (parameters.getRuntime().isDex() && parameters.getApiLevel().isEqualTo(AndroidApiLevel.R)) { testForD8() .setMinApi(AndroidApiLevel.R) .addProgramClasses(MiniAssert.class, IgnoreInvokes.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava10Test.java b/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava10Test.java index 5c08b8f..2a17cb2 100644 --- a/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava10Test.java +++ b/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava10Test.java
@@ -4,9 +4,12 @@ package com.android.tools.r8.desugar.backports; +import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION; + import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestRuntime.CfVm; import com.android.tools.r8.ToolHelper; +import com.android.tools.r8.utils.AndroidApiLevel; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Set; @@ -14,8 +17,6 @@ import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; -import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION; - @RunWith(Parameterized.class) public class SetBackportJava10Test extends AbstractBackportTest { @Parameters(name = "{0}") @@ -39,5 +40,10 @@ ignoreInvokes("add"); ignoreInvokes("contains"); ignoreInvokes("size"); + + // Set.of added in API 30 + registerTarget(AndroidApiLevel.R, 1); + // Set.copyOf added in API 31 + registerTarget(AndroidApiLevel.S, 5); } }
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava9Test.java index 408b203..652cde0 100644 --- a/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava9Test.java +++ b/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava9Test.java
@@ -43,13 +43,16 @@ ignoreInvokes("add"); ignoreInvokes("contains"); ignoreInvokes("size"); + + // Set.of added in API 30. + registerTarget(AndroidApiLevel.R, 21); } @Test public void desugaringApiLevelR() throws Exception { - // TODO(154759404): This test should start to fail when testing on an Android R VM. - if (parameters.getRuntime().isDex() - && parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.Q)) { + // TODO(b/154759404): This test should start to fail when testing on an Android R VM. + // This has now been checked with S, when R testing is added check and remove this. + if (parameters.getRuntime().isDex() && parameters.getApiLevel().isEqualTo(AndroidApiLevel.R)) { testForD8() .setMinApi(AndroidApiLevel.R) .addProgramClasses(MiniAssert.class, IgnoreInvokes.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ShortBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/ShortBackportJava9Test.java index beffd8a..d1d3c95 100644 --- a/src/test/java/com/android/tools/r8/desugar/backports/ShortBackportJava9Test.java +++ b/src/test/java/com/android/tools/r8/desugar/backports/ShortBackportJava9Test.java
@@ -4,17 +4,18 @@ package com.android.tools.r8.desugar.backports; +import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION; + import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestRuntime.CfVm; import com.android.tools.r8.ToolHelper; +import com.android.tools.r8.utils.AndroidApiLevel; import java.nio.file.Path; import java.nio.file.Paths; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; -import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION; - @RunWith(Parameterized.class) public final class ShortBackportJava9Test extends AbstractBackportTest { @Parameters(name = "{0}") @@ -31,7 +32,8 @@ public ShortBackportJava9Test(TestParameters parameters) { super(parameters, Short.class, TEST_JAR, "backport.ShortBackportJava9Main"); - // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in - // an actual API level, migrate these tests to ShortBackportTest. + + // Short.compareUnsigned added in API 31. + registerTarget(AndroidApiLevel.S, 16); } }
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/SparseArrayBackportTest.java b/src/test/java/com/android/tools/r8/desugar/backports/SparseArrayBackportTest.java index 61cf95d..1ebfe97 100644 --- a/src/test/java/com/android/tools/r8/desugar/backports/SparseArrayBackportTest.java +++ b/src/test/java/com/android/tools/r8/desugar/backports/SparseArrayBackportTest.java
@@ -5,6 +5,8 @@ package com.android.tools.r8.desugar.backports; import com.android.tools.r8.TestParameters; +import com.android.tools.r8.ToolHelper.DexVm; +import com.android.tools.r8.utils.AndroidApiLevel; import com.google.common.collect.ImmutableList; import java.io.IOException; import org.junit.runner.RunWith; @@ -24,18 +26,29 @@ public SparseArrayBackportTest(TestParameters parameters) throws IOException { super( parameters, - SparseArrayBackportTest.getSparseArray(), + SparseArrayBackportTest.getSparseArray(parameters), ImmutableList.of( - SparseArrayBackportTest.getTestRunner(), SparseArrayBackportTest.getSparseArray())); + SparseArrayBackportTest.getTestRunner(), + SparseArrayBackportTest.getSparseArray(parameters))); // The constructor is used by the test and put has been available since API 1 and is the // method set is rewritten to. ignoreInvokes("<init>"); ignoreInvokes("put"); + + // android.util.SparseArray.set added in API 31. + registerTarget(AndroidApiLevel.S, 1); } - private static byte[] getSparseArray() throws IOException { - return transformer(SparseArray.class).setClassDescriptor(SPARSE_ARRAY_DESCRIPTOR).transform(); + private static byte[] getSparseArray(TestParameters parameters) throws IOException { + if (parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.S)) { + assert parameters.getRuntime().asDex().getVm().isNewerThanOrEqual(DexVm.ART_12_0_0_HOST); + return transformer(SparseArrayAndroid12.class) + .setClassDescriptor(SPARSE_ARRAY_DESCRIPTOR) + .transform(); + } else { + return transformer(SparseArray.class).setClassDescriptor(SPARSE_ARRAY_DESCRIPTOR).transform(); + } } private static byte[] getTestRunner() throws IOException { @@ -56,6 +69,17 @@ } } + public static class SparseArrayAndroid12 { + public void set(int index, Object value) { + TestRunner.doAssertEquals(42, index); + TestRunner.doAssertEquals("Forty two", value); + } + + public void put(int index, Object value) { + TestRunner.doFail("put should not be called"); + } + } + public static class TestRunner extends MiniAssert { public static void main(String[] args) {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeTests.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeTests.java index c8ddd5d..2d6b833 100644 --- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeTests.java +++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeTests.java
@@ -11,6 +11,7 @@ import com.android.tools.r8.D8TestRunResult; import com.android.tools.r8.TestParameters; import com.android.tools.r8.ToolHelper; +import com.android.tools.r8.ToolHelper.DexVm; import com.android.tools.r8.ToolHelper.DexVm.Version; import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.BooleanUtils; @@ -134,6 +135,10 @@ @Test public void testTime() throws Exception { + if (parameters.getRuntime().asDex().getVm().isEqualTo(DexVm.ART_12_0_0_HOST)) { + // TODO(b/197078988): Many additional tests fails with Android 12. + return; + } KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters); String verbosity = "2"; D8TestCompileResult compileResult =
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPrivateStaticResolutionInvokeVirtualTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPrivateStaticResolutionInvokeVirtualTest.java index cd2b968..363e539 100644 --- a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPrivateStaticResolutionInvokeVirtualTest.java +++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPrivateStaticResolutionInvokeVirtualTest.java
@@ -111,13 +111,6 @@ result.assertSuccessWithOutput(EXPECTED); return; } - if (!unexpectedArtFailure() && !parameters.canUseDefaultAndStaticInterfaceMethods()) { - assert false : "Dead code until future ART behavior change. See b/152199517"; - // Desugaring will insert a forwarding bridge which will hide the "invalid invoke" case. - // Thus, a future ART runtime that does not have the invalid IAE for the private override - // will end up calling the forward method to I.m. - result.assertSuccessWithOutput(EXPECTED); - } // The expected behavior is IAE since the resolved method is private. result.assertFailureWithErrorThatThrows(IllegalAccessError.class); return; @@ -142,7 +135,8 @@ private boolean unexpectedArtFailure() { return parameters.isDexRuntime() - && parameters.getRuntime().asDex().getVm().isNewerThan(DexVm.ART_6_0_1_HOST); + && parameters.getRuntime().asDex().getVm().isNewerThan(DexVm.ART_6_0_1_HOST) + && parameters.getRuntime().asDex().getVm().isOlderThan(DexVm.ART_12_0_0_HOST); } static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionInvokeVirtualTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionInvokeVirtualTest.java index 92f5365..12869e2 100644 --- a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionInvokeVirtualTest.java +++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionInvokeVirtualTest.java
@@ -116,7 +116,8 @@ if (isR8 && parameters.isDexRuntime() - && parameters.getDexRuntimeVersion().isNewerThan(Version.V6_0_1)) { + && parameters.getDexRuntimeVersion().isNewerThan(Version.V6_0_1) + && parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0)) { // TODO(b/182255398): This should be EXPECTED. result.assertSuccessWithOutput(EXPECTED_R8); return;
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InterfaceWithClinitAndNoStaticMethodReferencesTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InterfaceWithClinitAndNoStaticMethodReferencesTest.java new file mode 100644 index 0000000..7589f8a --- /dev/null +++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InterfaceWithClinitAndNoStaticMethodReferencesTest.java
@@ -0,0 +1,74 @@ +// 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.desugaring.interfacemethods; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.utils.StringUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class InterfaceWithClinitAndNoStaticMethodReferencesTest extends TestBase { + + static final String EXPECTED = StringUtils.lines("allocated A", "called A.m"); + + private final TestParameters parameters; + + @Parameterized.Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().withAllApiLevelsAlsoForCf().build(); + } + + public InterfaceWithClinitAndNoStaticMethodReferencesTest(TestParameters parameters) { + this.parameters = parameters; + } + + @Test + public void testReference() throws Exception { + testForDesugaring(parameters) + .addInnerClasses(getClass()) + .run(parameters.getRuntime(), TestClass.class) + .assertSuccessWithOutput(EXPECTED); + } + + @Test + public void testR8() throws Exception { + testForR8(parameters.getBackend()) + .addInnerClasses(InterfaceWithClinitAndNoStaticMethodReferencesTest.class) + .addKeepMainRule(TestClass.class) + .setMinApi(parameters.getApiLevel()) + .run(parameters.getRuntime(), TestClass.class) + .assertSuccessWithOutput(EXPECTED); + } + + static class A { + + A() { + System.out.println("allocated A"); + } + + void m() { + System.out.println("called A.m"); + } + } + + interface I { + + A a = new A(); + + static void f() { + System.out.println("unused"); + } + } + + static class TestClass { + + public static void main(String[] args) { + I.a.m(); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InterfaceWithClinitAndNoStaticMethodsTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InterfaceWithClinitAndNoStaticMethodsTest.java new file mode 100644 index 0000000..414520f --- /dev/null +++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InterfaceWithClinitAndNoStaticMethodsTest.java
@@ -0,0 +1,70 @@ +// 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.desugaring.interfacemethods; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.utils.StringUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class InterfaceWithClinitAndNoStaticMethodsTest extends TestBase { + + static final String EXPECTED = StringUtils.lines("allocated A", "called A.m"); + + private final TestParameters parameters; + + @Parameterized.Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().withAllApiLevelsAlsoForCf().build(); + } + + public InterfaceWithClinitAndNoStaticMethodsTest(TestParameters parameters) { + this.parameters = parameters; + } + + @Test + public void testReference() throws Exception { + testForDesugaring(parameters) + .addInnerClasses(getClass()) + .run(parameters.getRuntime(), TestClass.class) + .assertSuccessWithOutput(EXPECTED); + } + + @Test + public void testR8() throws Exception { + testForR8(parameters.getBackend()) + .addInnerClasses(InterfaceWithClinitAndNoStaticMethodsTest.class) + .addKeepMainRule(TestClass.class) + .setMinApi(parameters.getApiLevel()) + .run(parameters.getRuntime(), TestClass.class) + .assertSuccessWithOutput(EXPECTED); + } + + static class A { + + A() { + System.out.println("allocated A"); + } + + void m() { + System.out.println("called A.m"); + } + } + + interface I { + + A a = new A(); + } + + static class TestClass { + + public static void main(String[] args) { + I.a.m(); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationLibraryLambdaPropagationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationLibraryLambdaPropagationTest.java index d53a470..9b42105 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationLibraryLambdaPropagationTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationLibraryLambdaPropagationTest.java
@@ -45,14 +45,12 @@ testForR8(parameters.getBackend()) .addInnerClasses(CallSiteOptimizationLibraryLambdaPropagationTest.class) .addKeepMainRule(TestClass.class) - .applyIf( - enableExperimentalArgumentPropagation, - builder -> - builder.addOptionsModification( - options -> - options - .callSiteOptimizationOptions() - .setEnableExperimentalArgumentPropagation())) + .addOptionsModification( + options -> + options + .callSiteOptimizationOptions() + .setEnableExperimentalArgumentPropagation( + enableExperimentalArgumentPropagation)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationPinnedMethodOverridePropagationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationPinnedMethodOverridePropagationTest.java index 2bf8f8d..ea88ead 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationPinnedMethodOverridePropagationTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationPinnedMethodOverridePropagationTest.java
@@ -63,14 +63,12 @@ + "Arg getArg2(); \npublic static " + CLASS_PREFIX + "Call getCaller(); \n}")) - .applyIf( - enableExperimentalArgumentPropagation, - builder -> - builder.addOptionsModification( - options -> - options - .callSiteOptimizationOptions() - .setEnableExperimentalArgumentPropagation())) + .addOptionsModification( + options -> + options + .callSiteOptimizationOptions() + .setEnableExperimentalArgumentPropagation( + enableExperimentalArgumentPropagation)) .enableNoVerticalClassMergingAnnotations() .enableNoHorizontalClassMergingAnnotations() .enableInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationProgramLambdaPropagationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationProgramLambdaPropagationTest.java index 6d8e9d4..2771975 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationProgramLambdaPropagationTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationProgramLambdaPropagationTest.java
@@ -38,14 +38,12 @@ testForR8(parameters.getBackend()) .addInnerClasses(CallSiteOptimizationProgramLambdaPropagationTest.class) .addKeepMainRule(TestClass.class) - .applyIf( - enableExperimentalArgumentPropagation, - builder -> - builder.addOptionsModification( - options -> - options - .callSiteOptimizationOptions() - .setEnableExperimentalArgumentPropagation())) + .addOptionsModification( + options -> + options + .callSiteOptimizationOptions() + .setEnableExperimentalArgumentPropagation( + enableExperimentalArgumentPropagation)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationWithInvokeCustomTargetTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationWithInvokeCustomTargetTest.java index d0d2d22..5edca84 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationWithInvokeCustomTargetTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationWithInvokeCustomTargetTest.java
@@ -67,14 +67,12 @@ .addProgramClassFileData(getProgramClassFileData()) .addKeepMainRule(TestClass.class) .addKeepMethodRules(methodFromMethod(TestClass.class.getDeclaredMethod("bar", int.class))) - .applyIf( - enableExperimentalArgumentPropagation, - builder -> - builder.addOptionsModification( - options -> - options - .callSiteOptimizationOptions() - .setEnableExperimentalArgumentPropagation())) + .addOptionsModification( + options -> + options + .callSiteOptimizationOptions() + .setEnableExperimentalArgumentPropagation( + enableExperimentalArgumentPropagation)) .enableInliningAnnotations() .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationWithLambdaTargetTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationWithLambdaTargetTest.java index 4db8c2f..20827d8 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationWithLambdaTargetTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationWithLambdaTargetTest.java
@@ -38,14 +38,12 @@ testForR8(parameters.getBackend()) .addInnerClasses(CallSiteOptimizationWithLambdaTargetTest.class) .addKeepMainRule(TestClass.class) - .applyIf( - enableExperimentalArgumentPropagation, - builder -> - builder.addOptionsModification( - options -> - options - .callSiteOptimizationOptions() - .setEnableExperimentalArgumentPropagation())) + .addOptionsModification( + options -> + options + .callSiteOptimizationOptions() + .setEnableExperimentalArgumentPropagation( + enableExperimentalArgumentPropagation)) .enableInliningAnnotations() .enableNeverClassInliningAnnotations() .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/KeptMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/KeptMethodTest.java index b579686..452e472 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/KeptMethodTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/KeptMethodTest.java
@@ -48,14 +48,12 @@ .addInnerClasses(KeptMethodTest.class) .addKeepMainRule(MAIN) .addKeepClassAndMembersRules(A.class) - .applyIf( - enableExperimentalArgumentPropagation, - builder -> - builder.addOptionsModification( - options -> - options - .callSiteOptimizationOptions() - .setEnableExperimentalArgumentPropagation())) + .addOptionsModification( + options -> + options + .callSiteOptimizationOptions() + .setEnableExperimentalArgumentPropagation( + enableExperimentalArgumentPropagation)) .enableNeverClassInliningAnnotations() .enableInliningAnnotations() .addOptionsModification(
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/LibraryMethodOverridesTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/LibraryMethodOverridesTest.java index ea7641f..2d6bec7 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/LibraryMethodOverridesTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/LibraryMethodOverridesTest.java
@@ -63,14 +63,12 @@ .addOptionsModification( o -> o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect) - .applyIf( - enableExperimentalArgumentPropagation, - builder -> - builder.addOptionsModification( - options -> - options - .callSiteOptimizationOptions() - .setEnableExperimentalArgumentPropagation())) + .addOptionsModification( + options -> + options + .callSiteOptimizationOptions() + .setEnableExperimentalArgumentPropagation( + enableExperimentalArgumentPropagation)) .enableInliningAnnotations() .setMinApi(parameters.getRuntime()) .compile()
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 55daa59..e3fa7d7 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
@@ -15,7 +15,7 @@ import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.value.AbstractValue; import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo; -import com.android.tools.r8.utils.InternalOptions.CallSiteOptimizationOptions; +import com.android.tools.r8.utils.InternalOptions; import com.android.tools.r8.utils.codeinspector.ClassSubject; import com.android.tools.r8.utils.codeinspector.CodeInspector; import com.android.tools.r8.utils.codeinspector.InstructionSubject; @@ -52,7 +52,7 @@ o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect; }) .setMinApi(parameters.getApiLevel()) - .addOptionsModification(CallSiteOptimizationOptions::enableConstantPropagationForTesting) + .addOptionsModification(InternalOptions::enableConstantArgumentPropagationForTesting) .run(parameters.getRuntime(), MAIN) .assertSuccessWithOutputLines("non-null") .inspect(this::inspect);
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 9f25fdb..93594ff 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
@@ -16,7 +16,7 @@ import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.value.AbstractValue; import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo; -import com.android.tools.r8.utils.InternalOptions.CallSiteOptimizationOptions; +import com.android.tools.r8.utils.InternalOptions; import com.android.tools.r8.utils.codeinspector.ClassSubject; import com.android.tools.r8.utils.codeinspector.CodeInspector; import com.android.tools.r8.utils.codeinspector.InstructionSubject; @@ -49,7 +49,7 @@ .enableNeverClassInliningAnnotations() .enableInliningAnnotations() .enableNoHorizontalClassMergingAnnotations() - .addOptionsModification(CallSiteOptimizationOptions::enableConstantPropagationForTesting) + .addOptionsModification(InternalOptions::enableConstantArgumentPropagationForTesting) .addOptionsModification( o -> { // To prevent invoke-interface from being rewritten to invoke-virtual w/ a single
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 3a00d96..096362a 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
@@ -14,7 +14,7 @@ import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.value.AbstractValue; import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo; -import com.android.tools.r8.utils.InternalOptions.CallSiteOptimizationOptions; +import com.android.tools.r8.utils.InternalOptions; import com.android.tools.r8.utils.codeinspector.ClassSubject; import com.android.tools.r8.utils.codeinspector.CodeInspector; import com.android.tools.r8.utils.codeinspector.InstructionSubject; @@ -50,7 +50,7 @@ o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect; }) .setMinApi(parameters.getApiLevel()) - .addOptionsModification(CallSiteOptimizationOptions::enableConstantPropagationForTesting) + .addOptionsModification(InternalOptions::enableConstantArgumentPropagationForTesting) .run(parameters.getRuntime(), MAIN) .assertSuccessWithOutputLines("non-null") .inspect(this::inspect);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualPositiveTest.java index 5b3b309..e254dc6 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualPositiveTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualPositiveTest.java
@@ -16,7 +16,7 @@ import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.analysis.value.AbstractValue; import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo; -import com.android.tools.r8.utils.InternalOptions.CallSiteOptimizationOptions; +import com.android.tools.r8.utils.InternalOptions; import com.android.tools.r8.utils.codeinspector.ClassSubject; import com.android.tools.r8.utils.codeinspector.CodeInspector; import com.android.tools.r8.utils.codeinspector.InstructionSubject; @@ -53,7 +53,7 @@ o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect; }) .setMinApi(parameters.getApiLevel()) - .addOptionsModification(CallSiteOptimizationOptions::enableConstantPropagationForTesting) + .addOptionsModification(InternalOptions::enableConstantArgumentPropagationForTesting) .run(parameters.getRuntime(), MAIN) .assertSuccessWithOutputLines("non-null", "null") .inspect(this::inspect);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/library/ObjectsRequireNonNullElseTest.java b/src/test/java/com/android/tools/r8/ir/optimize/library/ObjectsRequireNonNullElseTest.java index 39acb1e..bde8237 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/library/ObjectsRequireNonNullElseTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/library/ObjectsRequireNonNullElseTest.java
@@ -36,6 +36,16 @@ } @Test + public void testD8() throws Exception { + testForD8(parameters.getBackend()) + .addProgramClassFileData(getProgramClassFileData()) + .setMinApi(parameters.getApiLevel()) + .compile() + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines("Foo", "Bar", "Expected NPE"); + } + + @Test public void test() throws Exception { testForR8(parameters.getBackend()) .addProgramClassFileData(getProgramClassFileData()) @@ -62,7 +72,7 @@ testNullArgumentMethodSubject, not(invokesMethodWithName("requireNonNullElse"))); }) .run(parameters.getRuntime(), Main.class) - .assertSuccessWithOutputLines("Foo", "Bar"); + .assertSuccessWithOutputLines("Foo", "Bar", "Expected NPE"); } private byte[] getProgramClassFileData() throws IOException { @@ -77,6 +87,12 @@ public static void main(String[] args) { testNonNullArgument(); testNullArgument(); + try { + testNullArgumentAndNullDefaultValue(); + System.out.println("Unexpected"); + } catch (NullPointerException e) { + System.out.println("Expected NPE"); + } } @NeverInline @@ -88,6 +104,11 @@ static void testNullArgument() { System.out.println(Mock.requireNonNullElse(null, "Bar")); } + + @NeverInline + static void testNullArgumentAndNullDefaultValue() { + System.out.println(Mock.requireNonNullElse(null, null)); + } } // References to this class are rewritten to java.util.Objects by transformation.
diff --git a/src/test/java/com/android/tools/r8/naming/MissingReferenceNamingClashTest.java b/src/test/java/com/android/tools/r8/naming/MissingReferenceNamingClashTest.java new file mode 100644 index 0000000..1082d2e --- /dev/null +++ b/src/test/java/com/android/tools/r8/naming/MissingReferenceNamingClashTest.java
@@ -0,0 +1,92 @@ +// 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.naming; + +import static com.android.tools.r8.utils.DescriptorUtils.descriptorToJavaType; +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.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.utils.codeinspector.ClassSubject; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +/** This is a reproduction of b/196406764 */ +@RunWith(Parameterized.class) +public class MissingReferenceNamingClashTest extends TestBase { + + private final TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); + } + + public MissingReferenceNamingClashTest(TestParameters parameters) { + this.parameters = parameters; + } + + @Test + public void testR8() throws Exception { + // The references to Missing will be rewritten to a.a but the definition will not be present. + String newDescriptor = "La/a;"; + testForR8(parameters.getBackend()) + .addProgramClasses(A.class, Main.class) + .addProgramClassFileData( + transformer(Anno.class) + .replaceClassDescriptorInMembers(descriptor(Missing.class), newDescriptor) + .transform()) + .setMinApi(parameters.getApiLevel()) + .addKeepMainRule(Main.class) + .addKeepClassAndMembersRules(Anno.class) + .addKeepClassRulesWithAllowObfuscation(A.class) + .addKeepRuntimeVisibleAnnotations() + .addDontWarn(descriptorToJavaType(newDescriptor)) + .compile() + .inspect( + inspector -> { + ClassSubject aSubject = inspector.clazz(A.class); + assertThat(aSubject, isPresent()); + assertEquals("La/b;", aSubject.getFinalDescriptor()); + }) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines("A::foo"); + } + + /* Will be missing on input */ + public enum Missing { + FOO; + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + public @interface Anno { + + /* Rewritten to a.a */ Missing missing(); + } + + public static class A { + + public void foo() { + System.out.println("A::foo"); + } + } + + public static class Main { + + public static void main(String[] args) { + new A().foo(); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/naming/PackageMinificationWithDontOptimizeTest.java b/src/test/java/com/android/tools/r8/naming/PackageMinificationWithDontOptimizeTest.java new file mode 100644 index 0000000..45c9f14 --- /dev/null +++ b/src/test/java/com/android/tools/r8/naming/PackageMinificationWithDontOptimizeTest.java
@@ -0,0 +1,65 @@ +// 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.naming; + +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.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.utils.codeinspector.ClassSubject; +import java.util.Properties; +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 PackageMinificationWithDontOptimizeTest extends TestBase { + + @Parameter(0) + public TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection parameters() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); + } + + @Test + public void test() throws Exception { + testForR8(parameters.getBackend()) + .addInnerClasses(getClass()) + .addKeepMainRule(Main.class) + .addDontOptimize() + .setMinApi(parameters.getApiLevel()) + .compile() + .inspect( + inspector -> { + ClassSubject classSubject = inspector.clazz(TestClass.class); + assertThat(classSubject, isPresent()); + assertEquals("a.a", classSubject.getFinalName()); + }); + } + + public static class Main { + + public static void main(String[] args) { + TestClass.getProperty("abc"); + TestClass.getProperty("def"); + } + } + + public static class TestClass { + + private static final Properties properties = new Properties(); + + public static String getProperty(String key) { + return properties.getProperty(key); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/naming/retrace/DesugarLambdaRetraceTest.java b/src/test/java/com/android/tools/r8/naming/retrace/DesugarLambdaRetraceTest.java index 1fbc7cf..7a4914a 100644 --- a/src/test/java/com/android/tools/r8/naming/retrace/DesugarLambdaRetraceTest.java +++ b/src/test/java/com/android/tools/r8/naming/retrace/DesugarLambdaRetraceTest.java
@@ -12,7 +12,6 @@ import static org.junit.Assume.assumeTrue; import com.android.tools.r8.CompilationMode; -import com.android.tools.r8.R8TestBuilder; import com.android.tools.r8.TestParameters; import com.android.tools.r8.utils.BooleanUtils; import com.google.common.collect.ImmutableList; @@ -76,12 +75,6 @@ assertEquals(expectedActualStackTraceHeight(), actualStackTrace.size()); } - @Override - public void configure(R8TestBuilder<?> builder) { - // Enable pruning of lambda synthetics in retrace. - builder.enableExperimentalMapFileVersion(); - } - @Test public void testSourceFileAndLineNumberTable() throws Exception { runTest(ImmutableList.of("-keepattributes SourceFile,LineNumberTable"), this::checkIsSame);
diff --git a/src/test/java/com/android/tools/r8/naming/retrace/DesugarStaticInterfaceMethodDirectRetraceTest.java b/src/test/java/com/android/tools/r8/naming/retrace/DesugarStaticInterfaceMethodDirectRetraceTest.java index b0a87ee..2cbb911 100644 --- a/src/test/java/com/android/tools/r8/naming/retrace/DesugarStaticInterfaceMethodDirectRetraceTest.java +++ b/src/test/java/com/android/tools/r8/naming/retrace/DesugarStaticInterfaceMethodDirectRetraceTest.java
@@ -48,7 +48,6 @@ @Override public void configure(R8TestBuilder<?> builder) { builder.enableInliningAnnotations(); - builder.enableExperimentalMapFileVersion(); } @Test
diff --git a/src/test/java/com/android/tools/r8/naming/retrace/DesugarStaticInterfaceMethodsInlineIntoStaticRetraceTest.java b/src/test/java/com/android/tools/r8/naming/retrace/DesugarStaticInterfaceMethodsInlineIntoStaticRetraceTest.java index 38ef3038..56f306c 100644 --- a/src/test/java/com/android/tools/r8/naming/retrace/DesugarStaticInterfaceMethodsInlineIntoStaticRetraceTest.java +++ b/src/test/java/com/android/tools/r8/naming/retrace/DesugarStaticInterfaceMethodsInlineIntoStaticRetraceTest.java
@@ -38,7 +38,6 @@ @Override public void configure(R8TestBuilder<?> builder) { builder.enableInliningAnnotations(); - builder.enableExperimentalMapFileVersion(); } @Override
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 4e44d1f..9b246e1 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
@@ -44,7 +44,7 @@ options -> { CallSiteOptimizationOptions callSiteOptimizationOptions = options.callSiteOptimizationOptions(); - callSiteOptimizationOptions.setEnableExperimentalArgumentPropagation(); + callSiteOptimizationOptions.setEnableExperimentalArgumentPropagation(true); callSiteOptimizationOptions.setEnableConstantPropagation(); }) .enableInliningAnnotations()
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 b0387b2..45cd552 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
@@ -44,7 +44,7 @@ options -> { CallSiteOptimizationOptions callSiteOptimizationOptions = options.callSiteOptimizationOptions(); - callSiteOptimizationOptions.setEnableExperimentalArgumentPropagation(); + callSiteOptimizationOptions.setEnableExperimentalArgumentPropagation(true); callSiteOptimizationOptions.setEnableConstantPropagation(); }) .enableInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageLambdaMissingInterfaceTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageLambdaMissingInterfaceTest.java index df0bfa6..2265ba0 100644 --- a/src/test/java/com/android/tools/r8/repackage/RepackageLambdaMissingInterfaceTest.java +++ b/src/test/java/com/android/tools/r8/repackage/RepackageLambdaMissingInterfaceTest.java
@@ -5,7 +5,7 @@ package com.android.tools.r8.repackage; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed; -import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.startsWith; import static org.hamcrest.MatcherAssert.assertThat; import com.android.tools.r8.NeverInline; @@ -52,10 +52,6 @@ .inspect( inspector -> { // Find the generated lambda class - if (!parameters.isDexRuntime()) { - assertThat(ClassWithLambda.class, isNotRepackaged(inspector)); - return; - } if (repackage) { assertThat(ClassWithLambda.class, isRepackaged(inspector)); } else { @@ -66,7 +62,8 @@ clazz -> { if (clazz.isSynthesizedJavaLambdaClass()) { assertThat( - clazz.getFinalName(), containsString(Main.class.getPackage().getName())); + clazz.getFinalName(), + startsWith(repackage ? getRepackagePackage() : "a.")); } }); }) @@ -74,7 +71,7 @@ .run(parameters.getRuntime(), Main.class); } - interface MissingInterface { + public interface MissingInterface { void bar(int x); }
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageMissingMemberReferenceTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageMissingMemberReferenceTest.java index 9dc8746..8a40226 100644 --- a/src/test/java/com/android/tools/r8/repackage/RepackageMissingMemberReferenceTest.java +++ b/src/test/java/com/android/tools/r8/repackage/RepackageMissingMemberReferenceTest.java
@@ -4,10 +4,10 @@ package com.android.tools.r8.repackage; +import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed; import static org.hamcrest.MatcherAssert.assertThat; import com.android.tools.r8.NeverInline; -import com.android.tools.r8.R8TestRunResult; import com.android.tools.r8.TestParameters; import org.junit.Test; import org.junit.runner.RunWith; @@ -25,16 +25,16 @@ @Test public void testR8WithoutRepackaging() throws Exception { - runTest(false).assertSuccessWithOutputLines(EXPECTED); + runTest(false); } @Test public void testR8() throws Exception { - runTest(true).assertSuccessWithOutputLines(EXPECTED); + runTest(true); } - private R8TestRunResult runTest(boolean repackage) throws Exception { - return testForR8(parameters.getBackend()) + private void runTest(boolean repackage) throws Exception { + testForR8(parameters.getBackend()) .addProgramClasses(ClassWithMissingReferenceInCode.class, Main.class) .addKeepMainRule(Main.class) .applyIf(repackage, this::configureRepackaging) @@ -43,13 +43,20 @@ .enableInliningAnnotations() .compile() .inspect( - inspector -> - assertThat(ClassWithMissingReferenceInCode.class, isNotRepackaged(inspector))) + inspector -> { + if (repackage) { + assertThat(ClassWithMissingReferenceInCode.class, isRepackaged(inspector)); + } else { + assertThat( + inspector.clazz(ClassWithMissingReferenceInCode.class), isPresentAndRenamed()); + } + }) .addRunClasspathClasses(MissingReference.class) - .run(parameters.getRuntime(), Main.class); + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines(EXPECTED); } - static class MissingReference { + public static class MissingReference { public static void doSomething() { System.out.println("MissingReference::doSomething"); }
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageMissingSuperInterfaceTestTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageMissingSuperInterfaceTestTest.java index c853a99..e5ffadc 100644 --- a/src/test/java/com/android/tools/r8/repackage/RepackageMissingSuperInterfaceTestTest.java +++ b/src/test/java/com/android/tools/r8/repackage/RepackageMissingSuperInterfaceTestTest.java
@@ -4,12 +4,13 @@ package com.android.tools.r8.repackage; +import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed; import static org.hamcrest.MatcherAssert.assertThat; import com.android.tools.r8.NeverClassInline; import com.android.tools.r8.NeverInline; -import com.android.tools.r8.R8TestRunResult; import com.android.tools.r8.TestParameters; +import com.android.tools.r8.utils.codeinspector.ClassSubject; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -26,16 +27,16 @@ @Test public void testR8WithoutRepackaging() throws Exception { - runTest(false).assertSuccessWithOutputLines(EXPECTED); + runTest(false); } @Test public void testR8() throws Exception { - runTest(true).assertSuccessWithOutputLines(EXPECTED); + runTest(true); } - private R8TestRunResult runTest(boolean repackage) throws Exception { - return testForR8(parameters.getBackend()) + private void runTest(boolean repackage) throws Exception { + testForR8(parameters.getBackend()) .addProgramClasses(ClassImplementingMissingInterface.class, Main.class) .addKeepMainRule(Main.class) .applyIf(repackage, this::configureRepackaging) @@ -46,13 +47,20 @@ .compile() .inspect( inspector -> { - assertThat(ClassImplementingMissingInterface.class, isNotRepackaged(inspector)); + if (repackage) { + assertThat(ClassImplementingMissingInterface.class, isRepackaged(inspector)); + } else { + // The class is minified. + ClassSubject clazz = inspector.clazz(ClassImplementingMissingInterface.class); + assertThat(clazz, isPresentAndRenamed()); + } }) .addRunClasspathClasses(MissingInterface.class) - .run(parameters.getRuntime(), Main.class); + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines(EXPECTED); } - private interface MissingInterface { + public interface MissingInterface { void bar(); }
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageMissingSuperTypeTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageMissingSuperTypeTest.java index 5880f86..af4995f 100644 --- a/src/test/java/com/android/tools/r8/repackage/RepackageMissingSuperTypeTest.java +++ b/src/test/java/com/android/tools/r8/repackage/RepackageMissingSuperTypeTest.java
@@ -4,11 +4,11 @@ package com.android.tools.r8.repackage; +import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed; import static org.hamcrest.MatcherAssert.assertThat; import com.android.tools.r8.NeverClassInline; import com.android.tools.r8.NeverInline; -import com.android.tools.r8.R8TestRunResult; import com.android.tools.r8.TestParameters; import org.junit.Test; import org.junit.runner.RunWith; @@ -32,16 +32,16 @@ @Test public void testR8WithoutRepackaging() throws Exception { - runTest(false).assertSuccessWithOutputLines(EXPECTED); + runTest(false); } @Test public void testR8() throws Exception { - runTest(true).assertSuccessWithOutputLines(EXPECTED); + runTest(true); } - private R8TestRunResult runTest(boolean repackage) throws Exception { - return testForR8(parameters.getBackend()) + private void runTest(boolean repackage) throws Exception { + testForR8(parameters.getBackend()) .addProgramClasses( ClassWithSuperCall.class, ClassWithoutSuperCall.class, @@ -56,14 +56,20 @@ .compile() .inspect( inspector -> { - assertThat(ClassWithSuperCall.class, isNotRepackaged(inspector)); - assertThat(ClassWithoutSuperCall.class, isNotRepackaged(inspector)); + if (repackage) { + assertThat(ClassWithSuperCall.class, isRepackaged(inspector)); + assertThat(ClassWithoutSuperCall.class, isRepackaged(inspector)); + } else { + assertThat(inspector.clazz(ClassWithSuperCall.class), isPresentAndRenamed()); + assertThat(inspector.clazz(ClassWithoutSuperCall.class), isPresentAndRenamed()); + } }) .addRunClasspathClasses(MissingSuperType.class) - .run(parameters.getRuntime(), Main.class); + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines(EXPECTED); } - static class MissingSuperType { + public static class MissingSuperType { public void foo() { System.out.println("MissingSuperType::foo");
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageMissingTypeCollisionTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageMissingTypeCollisionTest.java new file mode 100644 index 0000000..2fc2cb0 --- /dev/null +++ b/src/test/java/com/android/tools/r8/repackage/RepackageMissingTypeCollisionTest.java
@@ -0,0 +1,143 @@ +// 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.repackage; + +import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assume.assumeTrue; + +import com.android.tools.r8.R8CompatTestBuilder; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.utils.DescriptorUtils; +import com.android.tools.r8.utils.codeinspector.ClassSubject; +import com.android.tools.r8.utils.codeinspector.HorizontallyMergedClassesInspector; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +/* This is a reproduction of b/196406764 where a collision will appear when repackaging */ +@RunWith(Parameterized.class) +public class RepackageMissingTypeCollisionTest extends RepackageTestBase { + + public RepackageMissingTypeCollisionTest( + String flattenPackageHierarchyOrRepackageClasses, TestParameters parameters) { + super(flattenPackageHierarchyOrRepackageClasses, parameters); + } + + @Test + public void testJvm() throws Exception { + assumeTrue(parameters.isCfRuntime()); + String newMissingTypeName = + getRepackagePackage() + (isFlattenPackageHierarchy() ? ".a.a" : ".a"); + String newMissingDescriptor = DescriptorUtils.javaTypeToDescriptor(newMissingTypeName); + String newATypeName = A.class.getPackage().getName() + ".a"; + String newADescriptor = DescriptorUtils.javaTypeToDescriptor(newATypeName); + testForJvm() + .addProgramClassFileData( + transformer(A.class).setClassDescriptor(newADescriptor).transform(), + transformer(Anno.class) + .replaceClassDescriptorInMembers(descriptor(Missing.class), newMissingDescriptor) + .replaceClassDescriptorInAnnotationDefault( + descriptor(Missing.class), newMissingDescriptor) + .transform(), + transformer(Main.class) + .replaceClassDescriptorInMethodInstructions(descriptor(A.class), newADescriptor) + .replaceClassDescriptorInMethodInstructions( + descriptor(Missing.class), newMissingDescriptor) + .transform()) + .run(parameters.getRuntime(), Main.class) + .assertFailureWithErrorThatThrows(NoClassDefFoundError.class); + } + + @Test + public void testRepackageMissingCollision() throws Exception { + testMissingReference(true) + .compile() + .inspect( + inspector -> { + ClassSubject clazz = inspector.clazz(getNewATypeName()); + assertThat(clazz, isPresentAndRenamed()); + assertEquals( + getRepackagePackage() + (isFlattenPackageHierarchy() ? ".a.b" : ".b"), + clazz.getFinalName()); + }) + .run(parameters.getRuntime(), Main.class) + .assertFailureWithErrorThatThrows(NoClassDefFoundError.class); + } + + @Test + public void testNoRepackage() throws Exception { + testMissingReference(false) + .run(parameters.getRuntime(), Main.class) + .assertFailureWithErrorThatThrows(NoClassDefFoundError.class); + } + + private String getNewMissingTypeName() { + return getRepackagePackage() + (isFlattenPackageHierarchy() ? ".a.a" : ".a"); + } + + private String getNewATypeName() { + return A.class.getPackage().getName() + ".a"; + } + + private R8CompatTestBuilder testMissingReference(boolean repackage) throws Exception { + // The references to Missing will be rewritten to <repackage>.a but the definition will not be + // present. + String newMissingDescriptor = DescriptorUtils.javaTypeToDescriptor(getNewMissingTypeName()); + String newADescriptor = DescriptorUtils.javaTypeToDescriptor(getNewATypeName()); + return testForR8Compat(parameters.getBackend()) + .addProgramClassFileData( + transformer(A.class).setClassDescriptor(newADescriptor).transform(), + transformer(Anno.class) + .replaceClassDescriptorInMembers(descriptor(Missing.class), newMissingDescriptor) + .replaceClassDescriptorInAnnotationDefault( + descriptor(Missing.class), newMissingDescriptor) + .transform(), + transformer(Main.class) + .replaceClassDescriptorInMethodInstructions(descriptor(A.class), newADescriptor) + .replaceClassDescriptorInMethodInstructions( + descriptor(Missing.class), newMissingDescriptor) + .transform()) + .addKeepMainRule(Main.class) + .addKeepClassAndMembersRules(Anno.class) + .addKeepRuntimeVisibleAnnotations() + .applyIf(repackage, this::configureRepackaging) + .setMinApi(parameters.getApiLevel()) + .addDontWarn(getNewMissingTypeName()) + .addOptionsModification(internalOptions -> internalOptions.enableEnumUnboxing = false) + .addHorizontallyMergedClassesInspector( + HorizontallyMergedClassesInspector::assertNoClassesMerged); + } + + /* Will be missing on input */ + public enum Missing { + foo; + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + public @interface Anno { + + /* Renamed to <repackage>.a */ Missing missing() default Missing.foo; + } + + @Anno + public enum /* renamed to a */ A { + foo; + } + + public static class Main { + + public static void main(String[] args) { + Anno annotation = A.class.getAnnotation(Anno.class); + System.out.println(annotation.missing()); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java b/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java index f7aae45..252dcc5 100644 --- a/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java +++ b/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java
@@ -66,7 +66,6 @@ public void testD8() throws Exception { testForD8(parameters.getBackend()) .internalEnableMappingOutput() - .enableExperimentalMapFileVersion() .addInnerClasses(getClass()) .setMinApi(parameters.getApiLevel()) .run(parameters.getRuntime(), Main.class) @@ -102,7 +101,6 @@ "Skip R8/CF for min-api > 1 (R8/CF does not desugar)", parameters.isDexRuntime() || parameters.getApiLevel().isEqualTo(AndroidApiLevel.B)); testForR8(parameters.getBackend()) - .enableExperimentalMapFileVersion() .addInnerClasses(getClass()) .addKeepMainRule(Main.class) .addKeepPackageNamesRule(getClass().getPackage())
diff --git a/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java b/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java index efa7b4e..e110f57 100644 --- a/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java +++ b/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java
@@ -74,6 +74,7 @@ case V4_0_4: case V4_4_4: case V10_0_0: + case V12_0_0: return StringUtils.joinLines("Hello!", "Goodbye!", ""); case V7_0_0:
diff --git a/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java b/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java index fb2db95..ea7b6cc 100644 --- a/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java +++ b/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
@@ -7,6 +7,7 @@ import static com.android.tools.r8.utils.DescriptorUtils.getBinaryNameFromDescriptor; import static com.android.tools.r8.utils.StringUtils.replaceAll; import static org.objectweb.asm.Opcodes.ASM7; +import static org.objectweb.asm.Opcodes.ASM9; import com.android.tools.r8.TestRuntime.CfVm; import com.android.tools.r8.ToolHelper; @@ -740,6 +741,57 @@ }); } + public ClassFileTransformer replaceClassDescriptorInMembers( + String oldDescriptor, String newDescriptor) { + return addClassTransformer( + new ClassTransformer() { + @Override + public FieldVisitor visitField( + int access, String name, String descriptor, String signature, Object value) { + return super.visitField( + access, + name, + replaceAll(descriptor, oldDescriptor, newDescriptor), + signature, + value); + } + + @Override + public MethodVisitor visitMethod( + int access, String name, String descriptor, String signature, String[] exceptions) { + return super.visitMethod( + access, + name, + replaceAll(descriptor, oldDescriptor, newDescriptor), + signature, + exceptions); + } + }); + } + + public ClassFileTransformer replaceClassDescriptorInAnnotationDefault( + String oldDescriptor, String newDescriptor) { + return addMethodTransformer( + new MethodTransformer() { + + @Override + public AnnotationVisitor visitAnnotationDefault() { + return new AnnotationVisitor(ASM9, super.visitAnnotationDefault()) { + @Override + public void visit(String name, Object value) { + super.visit(name, value); + } + + @Override + public void visitEnum(String name, String descriptor, String value) { + super.visitEnum( + name, descriptor.equals(oldDescriptor) ? newDescriptor : descriptor, value); + } + }; + } + }); + } + public ClassFileTransformer replaceClassDescriptorInMethodInstructions( String oldDescriptor, String newDescriptor) { return addMethodTransformer(
diff --git a/tools/compiledump.py b/tools/compiledump.py index 83bc2aa..e8070da 100755 --- a/tools/compiledump.py +++ b/tools/compiledump.py
@@ -252,6 +252,19 @@ utils.download_file_from_cloud_storage(source, dest) return dest + +def clean_config(file): + with open(file) as f: + lines = f.readlines() + with open(file, 'w') as f: + for line in lines: + if ('-injars' not in line and '-libraryjars' not in line and + '-print' not in line): + f.write(line) + else: + print('Removing from config line: \n%s' % line) + + def prepare_wrapper(dist, temp, jdkhome): wrapper_file = os.path.join( utils.REPO_ROOT, @@ -329,6 +342,10 @@ if compiler != 'd8' and dump.config_file(): if hasattr(args, 'config_file_consumer') and args.config_file_consumer: args.config_file_consumer(dump.config_file()) + else: + # If we get a dump from the wild we can't use -injars, -libraryjars or + # -print{mapping,usage} + clean_config(dump.config_file()) cmd.extend(['--pg-conf', dump.config_file()]) if dump.main_dex_rules_resource(): cmd.extend(['--main-dex-rules', dump.main_dex_rules_resource()])
diff --git a/tools/linux/README.art-versions b/tools/linux/README.art-versions index 9cf0717..ff57695 100644 --- a/tools/linux/README.art-versions +++ b/tools/linux/README.art-versions
@@ -41,6 +41,33 @@ repo init -u https://android.googlesource.com/platform/manifest -m aosp_master_manifest.xml <continue with repo sync as above> + +art-12.0.0 (Android S) +--------------------- +Build from branch sc-beta4-release. + +export BRANCH=sc-beta4-release +mkdir ${BRANCH} +cd ${BRANCH} +repo init -u https://android.googlesource.com/platform/manifest -b ${BRANCH} +repo sync -cq -j24 +source build/envsetup.sh +lunch aosp_redfin-userdebug +m -j48 +m -j48 build-art +m -j48 test-art-host + +Collected into tools/linux/host/art-12.0.0-beta4. The "host" path element is checked +by the script for running Art. + + cd <r8 checkout> + scripts/update-host-art.sh \ + --android-checkout /usr/local/ssd/android/${BRANCH} \ + --art-dir host/art-12.0.0-beta4 \ + --android-product redfin + +(cd tools/linux/host; upload_to_google_storage.py -a --bucket r8-deps art-12.0.0-beta4) + art-10.0.0 (Android Q) --------------------- Build from branch android-10.0.0_r14.
diff --git a/tools/linux/host/art-12.0.0-beta4.tar.gz.sha1 b/tools/linux/host/art-12.0.0-beta4.tar.gz.sha1 new file mode 100644 index 0000000..b95d909 --- /dev/null +++ b/tools/linux/host/art-12.0.0-beta4.tar.gz.sha1
@@ -0,0 +1 @@ +9b6d0b061669e0fb1b09ba92c3650d5c7bdc9e85 \ No newline at end of file
diff --git a/tools/test.py b/tools/test.py index 9c35352..6553358 100755 --- a/tools/test.py +++ b/tools/test.py
@@ -23,6 +23,7 @@ ALL_ART_VMS = [ "default", + "12.0.0", "10.0.0", "9.0.0", "8.1.0",