Merge commit '4c45ccb630775825fc4bff2009944dd8994752ba' into dev-release
diff --git a/build.gradle b/build.gradle index 01d41fc..17206b1 100644 --- a/build.gradle +++ b/build.gradle
@@ -46,7 +46,7 @@ // The kotlin version is only here to specify the kotlin language level, // all kotlin compilations are done in tests. kotlinVersion = '1.5.0' - kotlinExtMetadataJVMVersion = '0.2.0' + kotlinExtMetadataJVMVersion = '0.3.0' smaliVersion = '2.2b4' errorproneVersion = '2.3.2' testngVersion = '6.10' @@ -273,7 +273,8 @@ apiUsageSampleCompile "com.google.guava:guava:$guavaVersion" kotlinR8TestResourcesCompileOnly "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" errorprone("com.google.errorprone:error_prone_core:$errorproneVersion") - testImplementation "org.jetbrains.kotlin:kotlin-reflect:1.3.31" + testImplementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" + testImplementation "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion" } def r8LibPath = "$buildDir/libs/r8lib.jar"
diff --git a/infra/config/global/generated/cr-buildbucket.cfg b/infra/config/global/generated/cr-buildbucket.cfg index b8a3edb..8caf056 100644 --- a/infra/config/global/generated/cr-buildbucket.cfg +++ b/infra/config/global/generated/cr-buildbucket.cfg
@@ -11,7 +11,7 @@ } acls { role: SCHEDULER - group: "luci-scheduler@appspot.gserviceaccount.com" + identity: "user:luci-scheduler@appspot.gserviceaccount.com" } acls { role: SCHEDULER @@ -21,6 +21,7 @@ builders { name: "archive" swarming_host: "chrome-swarming.appspot.com" + swarming_tags: "vpython:native-python-wrapper" dimensions: "cores:8" dimensions: "cpu:x86-64" dimensions: "os:Ubuntu-16.04" @@ -29,28 +30,18 @@ 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: "archive:true" + properties_j: "archive:\"true\"" + properties_j: "builder_group:\"internal.client.r8\"" } + priority: 25 execution_timeout_secs: 1800 + expiration_secs: 126000 + build_numbers: YES + service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com" } builders { name: "archive_release" swarming_host: "chrome-swarming.appspot.com" - dimensions: "cores:8" - dimensions: "cpu:x86-64" - 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: "archive:true" - } - execution_timeout_secs: 1800 - } - builders { - name: "linux-android-4.0.4" - swarming_host: "chrome-swarming.appspot.com" swarming_tags: "vpython:native-python-wrapper" dimensions: "cores:8" dimensions: "cpu:x86-64" @@ -60,10 +51,35 @@ 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: "archive:\"true\"" + properties_j: "builder_group:\"internal.client.r8\"" + } + priority: 25 + execution_timeout_secs: 1800 + expiration_secs: 126000 + build_numbers: YES + service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com" + } + builders { + name: "linux-android-4.0.4" + 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=4.0.4\",\"--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 { @@ -72,16 +88,20 @@ 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=4.0.4\",\"--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 { @@ -90,16 +110,20 @@ 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=4.4.4\",\"--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 { @@ -108,16 +132,20 @@ 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=4.4.4\",\"--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 { @@ -126,16 +154,20 @@ 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=5.1.1\",\"--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 { @@ -144,16 +176,20 @@ 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=5.1.1\",\"--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 { @@ -162,16 +198,20 @@ 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=6.0.1\",\"--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 { @@ -180,16 +220,20 @@ 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=6.0.1\",\"--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 { @@ -198,16 +242,20 @@ 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=7.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 { @@ -216,16 +264,20 @@ 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=7.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 { @@ -234,16 +286,20 @@ 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=10.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 { @@ -252,16 +308,20 @@ 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=10.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 { @@ -270,16 +330,20 @@ 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=8.1.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 { @@ -288,16 +352,20 @@ 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=8.1.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 { @@ -306,16 +374,20 @@ 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=9.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 { @@ -324,16 +396,20 @@ 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=9.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 { @@ -342,16 +418,20 @@ 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:[\"--runtimes=dex-default\",\"--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 { @@ -360,52 +440,64 @@ 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:[\"--runtimes=dex-default\",\"--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-internal" swarming_host: "chrome-swarming.appspot.com" swarming_tags: "vpython:native-python-wrapper" - dimensions: "cores:8" + dimensions: "cores:2" dimensions: "cpu:x86-64" + dimensions: "internal: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: "test_options:[\"--runtimes=jdk11\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]" + properties_j: "builder_group:\"internal.client.r8\"" + properties_j: "internal:\"true\"" } - execution_timeout_secs: 21600 + priority: 25 + execution_timeout_secs: 43200 expiration_secs: 126000 + build_numbers: YES service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com" } builders { name: "linux-internal_release" swarming_host: "chrome-swarming.appspot.com" swarming_tags: "vpython:native-python-wrapper" - dimensions: "cores:8" + dimensions: "cores:2" dimensions: "cpu:x86-64" + dimensions: "internal: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: "test_options:[\"--runtimes=jdk11\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]" + properties_j: "builder_group:\"internal.client.r8\"" + properties_j: "internal:\"true\"" } - execution_timeout_secs: 21600 + priority: 25 + execution_timeout_secs: 43200 expiration_secs: 126000 + build_numbers: YES service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com" } builders { @@ -414,16 +506,20 @@ 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:[\"--runtimes=jdk11\",\"--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 { @@ -432,16 +528,20 @@ 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:[\"--runtimes=jdk11\",\"--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 { @@ -450,16 +550,20 @@ 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:[\"--runtimes=jdk8\",\"--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 { @@ -468,16 +572,20 @@ 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:[\"--runtimes=jdk8\",\"--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 { @@ -486,16 +594,20 @@ 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:[\"--runtimes=jdk9\",\"--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 { @@ -504,16 +616,20 @@ 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:[\"--runtimes=jdk9\",\"--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 { @@ -522,16 +638,20 @@ 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:[\"--runtimes=none\",\"--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 { @@ -540,16 +660,20 @@ 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:[\"--runtimes=none\",\"--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 { @@ -564,10 +688,13 @@ 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:[\"--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 { @@ -582,10 +709,13 @@ 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:[\"--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" } }
diff --git a/infra/config/global/generated/luci-milo.cfg b/infra/config/global/generated/luci-milo.cfg index 3202e40..112e9a1 100644 --- a/infra/config/global/generated/luci-milo.cfg +++ b/infra/config/global/generated/luci-milo.cfg
@@ -17,60 +17,10 @@ } builders { name: "buildbucket/luci.r8.ci/archive_release" - category: "R8" + category: "R8 release" short_name: "archive_release" } builders { - name: "buildbucket/luci.r8.ci/linux-dex_default" - category: "R8" - short_name: "dex_default" - } - builders { - name: "buildbucket/luci.r8.ci/linux-dex_default_release" - category: "R8 release" - short_name: "dex_default" - } - builders { - name: "buildbucket/luci.r8.ci/linux-none" - category: "R8" - short_name: "none" - } - builders { - name: "buildbucket/luci.r8.ci/linux-none_release" - category: "R8 release" - short_name: "none" - } - builders { - name: "buildbucket/luci.r8.ci/linux-jdk8" - category: "R8" - short_name: "jdk8" - } - builders { - name: "buildbucket/luci.r8.ci/linux-jdk8_release" - category: "R8 release" - short_name: "jdk8" - } - builders { - name: "buildbucket/luci.r8.ci/linux-jdk9" - category: "R8" - short_name: "jdk9" - } - builders { - name: "buildbucket/luci.r8.ci/linux-jdk9_release" - category: "R8 release" - short_name: "jdk9" - } - builders { - name: "buildbucket/luci.r8.ci/linux-jdk11" - category: "R8" - short_name: "jdk11" - } - builders { - name: "buildbucket/luci.r8.ci/linux-jdk11_release" - category: "R8 release" - short_name: "jdk11" - } - builders { name: "buildbucket/luci.r8.ci/linux-internal" category: "R8" short_name: "internal" @@ -78,7 +28,57 @@ builders { name: "buildbucket/luci.r8.ci/linux-internal_release" category: "R8 release" - short_name: "internal" + short_name: "internal_release" + } + builders { + name: "buildbucket/luci.r8.ci/linux-dex_default" + category: "R8" + short_name: "dex_default" + } + builders { + name: "buildbucket/luci.r8.ci/linux-dex_default_release" + category: "R8 release" + short_name: "dex_default_release" + } + builders { + name: "buildbucket/luci.r8.ci/linux-none" + category: "R8" + short_name: "none" + } + builders { + name: "buildbucket/luci.r8.ci/linux-none_release" + category: "R8 release" + short_name: "none_release" + } + builders { + name: "buildbucket/luci.r8.ci/linux-jdk8" + category: "R8" + short_name: "jdk8" + } + builders { + name: "buildbucket/luci.r8.ci/linux-jdk8_release" + category: "R8 release" + short_name: "jdk8_release" + } + builders { + name: "buildbucket/luci.r8.ci/linux-jdk9" + category: "R8" + short_name: "jdk9" + } + builders { + name: "buildbucket/luci.r8.ci/linux-jdk9_release" + category: "R8 release" + short_name: "jdk9_release" + } + builders { + name: "buildbucket/luci.r8.ci/linux-jdk11" + category: "R8" + short_name: "jdk11" + } + builders { + name: "buildbucket/luci.r8.ci/linux-jdk11_release" + category: "R8 release" + short_name: "jdk11_release" } builders { name: "buildbucket/luci.r8.ci/linux-android-4.0.4" @@ -88,7 +88,7 @@ builders { name: "buildbucket/luci.r8.ci/linux-android-4.0.4_release" category: "R8 release" - short_name: "4.0.4" + short_name: "4.0.4_release" } builders { name: "buildbucket/luci.r8.ci/linux-android-4.4.4" @@ -98,7 +98,7 @@ builders { name: "buildbucket/luci.r8.ci/linux-android-4.4.4_release" category: "R8 release" - short_name: "4.4.4" + short_name: "4.4.4_release" } builders { name: "buildbucket/luci.r8.ci/linux-android-5.1.1" @@ -108,7 +108,7 @@ builders { name: "buildbucket/luci.r8.ci/linux-android-5.1.1_release" category: "R8 release" - short_name: "5.1.1" + short_name: "5.1.1_release" } builders { name: "buildbucket/luci.r8.ci/linux-android-6.0.1" @@ -118,7 +118,7 @@ builders { name: "buildbucket/luci.r8.ci/linux-android-6.0.1_release" category: "R8 release" - short_name: "6.0.1" + short_name: "6.0.1_release" } builders { name: "buildbucket/luci.r8.ci/linux-android-7.0.0" @@ -128,7 +128,7 @@ builders { name: "buildbucket/luci.r8.ci/linux-android-7.0.0_release" category: "R8 release" - short_name: "7.0.0" + short_name: "7.0.0_release" } builders { name: "buildbucket/luci.r8.ci/linux-android=8.1.0" @@ -138,7 +138,7 @@ builders { name: "buildbucket/luci.r8.ci/linux-android=8.1.0_release" category: "R8 release" - short_name: "android=8.1.0" + short_name: "android=8.1.0_release" } builders { name: "buildbucket/luci.r8.ci/linux-android=9.0.0" @@ -148,7 +148,7 @@ builders { name: "buildbucket/luci.r8.ci/linux-android=9.0.0_release" category: "R8 release" - short_name: "android=9.0.0" + short_name: "android=9.0.0_release" } builders { name: "buildbucket/luci.r8.ci/linux-android=10.0.0" @@ -158,7 +158,7 @@ builders { name: "buildbucket/luci.r8.ci/linux-android=10.0.0_release" category: "R8 release" - short_name: "android=10.0.0" + short_name: "android=10.0.0_release" } builders { name: "buildbucket/luci.r8.ci/windows" @@ -168,6 +168,6 @@ builders { name: "buildbucket/luci.r8.ci/windows_release" category: "R8 release" - short_name: "windows" + short_name: "windows_release" } }
diff --git a/infra/config/global/generated/luci-notify.cfg b/infra/config/global/generated/luci-notify.cfg index 24a7816..5267938 100644 --- a/infra/config/global/generated/luci-notify.cfg +++ b/infra/config/global/generated/luci-notify.cfg
@@ -12,6 +12,30 @@ } builders { bucket: "ci" + name: "archive" + repository: "https://r8.googlesource.com/r8" + } +} +notifiers { + notifications { + on_failure: true + on_new_failure: true + notify_blamelist {} + } + builders { + bucket: "ci" + name: "archive_release" + repository: "https://r8.googlesource.com/r8" + } +} +notifiers { + notifications { + on_failure: true + on_new_failure: true + notify_blamelist {} + } + builders { + bucket: "ci" name: "linux-android-4.0.4" 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 72809c3..4aa3c0f 100644 --- a/infra/config/global/generated/luci-scheduler.cfg +++ b/infra/config/global/generated/luci-scheduler.cfg
@@ -197,6 +197,11 @@ job { id: "linux-internal" acl_sets: "ci" + triggering_policy { + kind: GREEDY_BATCHING + max_concurrent_invocations: 1 + max_batch_size: 1 + } buildbucket { server: "cr-buildbucket.appspot.com" bucket: "luci.r8.ci" @@ -206,6 +211,11 @@ job { id: "linux-internal_release" acl_sets: "ci" + triggering_policy { + kind: GREEDY_BATCHING + max_concurrent_invocations: 1 + max_batch_size: 1 + } buildbucket { server: "cr-buildbucket.appspot.com" bucket: "luci.r8.ci"
diff --git a/infra/config/global/main.star b/infra/config/global/main.star index cdadb61..77d9887 100755 --- a/infra/config/global/main.star +++ b/infra/config/global/main.star
@@ -23,9 +23,11 @@ acl.BUILDBUCKET_TRIGGERER, ], groups = [ - "luci-scheduler@appspot.gserviceaccount.com", "project-r8-committers" - ], + ], + users = [ + "luci-scheduler@appspot.gserviceaccount.com" + ] ), ] @@ -87,7 +89,7 @@ "--archive_failures" ] -def get_dimensions(windows=False, jctf=False, internal=False): +def get_dimensions(windows=False, jctf=False, internal=False, normal=False): dimensions = { "cores" : "2" if internal else "8", "cpu" : "x86-64", @@ -101,84 +103,91 @@ dimensions["jctf"] = "true" if internal: dimensions["internal"] = "true" + if normal: + dimensions["normal"] = "true" return dimensions +def r8_builder(name, priority=26, **kwargs): + release = name.endswith("release") + triggered = ["branch-gitiles-trigger"] if release \ + else ["main-gitiles-trigger"] + + luci.builder( + name = name, + bucket = "ci", + service_account = "r8-ci-builder@chops-service-accounts." + + "iam.gserviceaccount.com", + build_numbers = True, + swarming_tags = ["vpython:native-python-wrapper"], + notifies = ["r8-failures"], + priority = priority, + triggered_by = triggered, + executable = "rex", + **kwargs + ) + category = "R8 release" if release else "R8" + builder_view(name, category, name.split("-")[-1]) + def r8_tester(name, test_options, - dimensions=None, - execution_timeout=time.hour * 6, - expiration_timeout=time.hour * 35): - dimensions = dimensions if dimensions else get_dimensions() - luci.builder( - name = name, - bucket = "ci", - service_account = "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com", - swarming_tags = ["vpython:native-python-wrapper"], - execution_timeout=execution_timeout, - expiration_timeout=expiration_timeout, - executable = "rex", - dimensions = dimensions, - triggered_by = ["main-gitiles-trigger"], - properties = { - "test_options" : test_options - }, - notifies = ["r8-failures"] - ) - builder_view(name, "R8", name.split("-")[-1]) - - # Branch version - release_name = name + "_release" - luci.builder( - name = release_name, - bucket = "ci", - service_account = "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com", - swarming_tags = ["vpython:native-python-wrapper"], - execution_timeout=execution_timeout, - expiration_timeout=expiration_timeout, - executable = "rex", - dimensions = dimensions, - triggered_by = ["branch-gitiles-trigger"], - properties = { - "test_options" : test_options - }, - notifies = ["r8-failures"] - ) - builder_view(release_name, "R8 release", name.split("-")[-1]) + dimensions = None, + execution_timeout = time.hour * 6, + expiration_timeout = time.hour * 35): + dimensions = dimensions if dimensions else get_dimensions(normal=True) + for name in [name, name + "_release"]: + r8_builder( + name = name, + execution_timeout=execution_timeout, + expiration_timeout=expiration_timeout, + dimensions = dimensions, + properties = { + "test_options" : test_options, + "builder_group" : "internal.client.r8" + } + ) def r8_tester_with_default(name, test_options, dimensions=None): r8_tester(name, test_options + common_test_options, dimensions) -luci.builder( - name = "archive", - bucket = "ci", - dimensions = get_dimensions(), - triggered_by = ["main-gitiles-trigger"], - executable = "rex", - execution_timeout = time.minute * 30, - triggering_policy = scheduler.policy( - kind = scheduler.GREEDY_BATCHING_KIND, - max_batch_size = 1, - max_concurrent_invocations = 3 - ), - properties = {"archive": True} -) -builder_view("archive", "R8", "archive") +def archivers(): + for name in ["archive", "archive_release"]: + r8_builder( + name, + dimensions = get_dimensions(), + triggering_policy = scheduler.policy( + kind = scheduler.GREEDY_BATCHING_KIND, + max_batch_size = 1, + max_concurrent_invocations = 3 + ), + priority = 25, + properties = { + "archive": "true", + "builder_group" : "internal.client.r8" + }, + execution_timeout = time.minute * 30, + expiration_timeout = time.hour * 35, + ) +archivers() -luci.builder( - name = "archive_release", - bucket = "ci", - dimensions = get_dimensions(), - triggered_by = ["branch-gitiles-trigger"], - execution_timeout = time.minute * 30, - executable = "rex", - triggering_policy = scheduler.policy( - kind = scheduler.GREEDY_BATCHING_KIND, - max_batch_size = 1, - max_concurrent_invocations = 3 - ), - properties = {"archive": True} -) -builder_view("archive_release", "R8", "archive_release") +def internal(): + for name in ["linux-internal", "linux-internal_release"]: + r8_builder( + name, + dimensions = get_dimensions(internal=True), + triggering_policy = scheduler.policy( + kind = scheduler.GREEDY_BATCHING_KIND, + max_batch_size = 1, + max_concurrent_invocations = 1 + ), + priority = 25, + properties = { + "internal": "true", + "builder_group" : "internal.client.r8" + }, + execution_timeout = time.hour * 12, + expiration_timeout = time.hour * 35, + ) +internal() r8_tester_with_default("linux-dex_default", ["--runtimes=dex-default"]) r8_tester_with_default("linux-none", ["--runtimes=none"]) @@ -186,8 +195,6 @@ r8_tester_with_default("linux-jdk9", ["--runtimes=jdk9"]) r8_tester_with_default("linux-jdk11", ["--runtimes=jdk11"]) -r8_tester_with_default("linux-internal", ["--runtimes=jdk11"]) - r8_tester_with_default("linux-android-4.0.4", ["--dex_vm=4.0.4", "--all_tests"]) r8_tester_with_default("linux-android-4.4.4",
diff --git a/src/main/java/com/android/tools/r8/GenerateLintFiles.java b/src/main/java/com/android/tools/r8/GenerateLintFiles.java index 19d4a98..2906011 100644 --- a/src/main/java/com/android/tools/r8/GenerateLintFiles.java +++ b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
@@ -162,6 +162,8 @@ code, false, CfVersion.V1_6, + AndroidApiLevel.UNKNOWN, + AndroidApiLevel.UNKNOWN, false); if (method.isStatic() || method.isDirectMethod()) { directMethods.add(throwingMethod);
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java index c2ee174..6f2675f 100644 --- a/src/main/java/com/android/tools/r8/R8.java +++ b/src/main/java/com/android/tools/r8/R8.java
@@ -106,6 +106,7 @@ import com.android.tools.r8.shaking.WhyAreYouKeepingConsumer; import com.android.tools.r8.synthesis.SyntheticFinalization; import com.android.tools.r8.synthesis.SyntheticItems; +import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.AndroidApp; import com.android.tools.r8.utils.CfgPrinter; import com.android.tools.r8.utils.CollectionUtils; @@ -370,7 +371,6 @@ assert appView.rootSet().verifyKeptMethodsAreTargetedAndLive(appViewWithLiveness.appInfo()); assert appView.rootSet().verifyKeptTypesAreLive(appViewWithLiveness.appInfo()); assert appView.rootSet().verifyKeptItemsAreKept(appView); - appView.rootSet().checkAllRulesAreUsed(options); if (options.proguardSeedsConsumer != null) { @@ -392,7 +392,7 @@ // Build enclosing information and type-parameter information before pruning. // TODO(b/187922482): Only consider referenced classes. GenericSignatureContextBuilder genericContextBuilder = - GenericSignatureContextBuilder.create(appView.appInfo().classes()); + GenericSignatureContextBuilder.create(appView); // Compute if all signatures are valid before modifying them. GenericSignatureCorrectnessHelper.createForInitialCheck(appView, genericContextBuilder) @@ -432,6 +432,7 @@ AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness(); assert verifyNoJarApplicationReaders(appView.appInfo().classes()); + assert appView.checkForTesting(() -> allReferencesAssignedApiLevel(appViewWithLiveness)); // Build conservative main dex content after first round of tree shaking. This is used // by certain optimizations to avoid introducing additional class references into main dex // classes, as that can cause the final number of main dex methods to grow. @@ -530,6 +531,7 @@ // None of the optimizations above should lead to the creation of type lattice elements. assert appView.dexItemFactory().verifyNoCachedTypeElements(); + assert appView.checkForTesting(() -> allReferencesAssignedApiLevel(appViewWithLiveness)); // Collect switch maps and ordinals maps. if (options.enableEnumSwitchMapRemoval) { @@ -615,7 +617,7 @@ DefaultTreePrunerConfiguration.getInstance()); GenericSignatureContextBuilder genericContextBuilder = - GenericSignatureContextBuilder.create(appView.appInfo().classes()); + GenericSignatureContextBuilder.create(appView); TreePruner pruner = new TreePruner(appViewWithLiveness, treePrunerConfiguration); DirectMappedDexApplication application = pruner.run(executorService); @@ -663,8 +665,7 @@ assert appView.checkForTesting( () -> GenericSignatureCorrectnessHelper.createForVerification( - appView, - GenericSignatureContextBuilder.create(appView.appInfo().classes())) + appView, GenericSignatureContextBuilder.create(appView)) .run(appView.appInfo().classes()) .isValid()) : "Could not validate generic signatures"; @@ -748,7 +749,7 @@ appView.dexItemFactory().clearTypeElementsCache(); GenericSignatureContextBuilder genericContextBuilderBeforeFinalMerging = - GenericSignatureContextBuilder.create(appView.appInfo().classes()); + GenericSignatureContextBuilder.create(appView); // Run horizontal class merging. This runs even if shrinking is disabled to ensure synthetics // are always merged. @@ -839,8 +840,7 @@ () -> !options.isShrinking() || GenericSignatureCorrectnessHelper.createForVerification( - appView, - GenericSignatureContextBuilder.create(appView.appInfo().classes())) + appView, GenericSignatureContextBuilder.create(appView)) .run(appView.appInfo().classes()) .isValid()) : "Could not validate generic signatures"; @@ -872,6 +872,27 @@ } } + private static boolean allReferencesAssignedApiLevel(AppView<?> appView) { + if (!appView.options().apiModelingOptions().checkAllApiReferencesAreSet) { + return true; + } + // This will return false if we find anything in the library which is not modeled. + appView + .appInfo() + .classes() + .forEach( + clazz -> { + if (appView.options().apiModelingOptions().enableApiCallerIdentification) { + assert clazz.getMembersApiReferenceLevel(appView) != AndroidApiLevel.UNKNOWN + : "Every member should have been analyzed"; + } else { + assert clazz.getMembersApiReferenceLevel(appView) == AndroidApiLevel.UNKNOWN + : "Every member should have level UNKNOWN"; + } + }); + return true; + } + private void performInitialMainDexTracing( AppView<AppInfoWithClassHierarchy> appView, ExecutorService executorService) throws ExecutionException {
diff --git a/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java b/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java index f2502e2..e3fa030 100644 --- a/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java +++ b/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java
@@ -69,7 +69,9 @@ public AndroidApiLevel lookup(DexReference reference) { DexType contextType = reference.getContextType(); - assert !contextType.isArrayType(); + if (contextType.isArrayType()) { + return lookup(contextType.toBaseType(appView.dexItemFactory())); + } if (contextType.isPrimitiveType() || contextType.isVoidType()) { return AndroidApiLevel.B; }
diff --git a/src/main/java/com/android/tools/r8/graph/ClassDefinition.java b/src/main/java/com/android/tools/r8/graph/ClassDefinition.java index da0f128..589dd76 100644 --- a/src/main/java/com/android/tools/r8/graph/ClassDefinition.java +++ b/src/main/java/com/android/tools/r8/graph/ClassDefinition.java
@@ -28,11 +28,6 @@ return true; } - @Override - default ClassDefinition asClass() { - return this; - } - boolean isClasspathClass(); DexClasspathClass asClasspathClass(); @@ -40,8 +35,4 @@ boolean isLibraryClass(); DexLibraryClass asLibraryClass(); - - boolean isProgramClass(); - - DexProgramClass asProgramClass(); }
diff --git a/src/main/java/com/android/tools/r8/graph/ClasspathMember.java b/src/main/java/com/android/tools/r8/graph/ClasspathMember.java index 8fad10f..1919491 100644 --- a/src/main/java/com/android/tools/r8/graph/ClasspathMember.java +++ b/src/main/java/com/android/tools/r8/graph/ClasspathMember.java
@@ -7,6 +7,7 @@ public interface ClasspathMember<D extends DexEncodedMember<D, R>, R extends DexMember<D, R>> extends ClasspathDefinition { + @Override D getDefinition(); DexClasspathClass getHolder();
diff --git a/src/main/java/com/android/tools/r8/graph/Definition.java b/src/main/java/com/android/tools/r8/graph/Definition.java index 7e42398..b3dcc3a 100644 --- a/src/main/java/com/android/tools/r8/graph/Definition.java +++ b/src/main/java/com/android/tools/r8/graph/Definition.java
@@ -24,8 +24,12 @@ ProgramDerivedContext asProgramDerivedContext(ProgramDerivedContext witness); + AccessFlags<?> getAccessFlags(); + DexType getContextType(); + DexDefinition getDefinition(); + Origin getOrigin(); DexReference getReference(); @@ -34,7 +38,7 @@ return false; } - default ClassDefinition asClass() { + default DexClass asClass() { return null; } @@ -46,6 +50,14 @@ return null; } + default boolean isMember() { + return !isClass(); + } + + default DexClassAndMember<?, ?> asMember() { + return null; + } + default boolean isMethod() { return false; } @@ -54,6 +66,54 @@ return null; } + default boolean isClasspathField() { + return false; + } + + default ClasspathField asClasspathField() { + return null; + } + + default boolean isClasspathMember() { + return false; + } + + default boolean isClasspathMethod() { + return false; + } + + default ClasspathMethod asClasspathMethod() { + return null; + } + + default boolean isLibraryField() { + return false; + } + + default LibraryField asLibraryField() { + return null; + } + + default boolean isLibraryMember() { + return false; + } + + default boolean isLibraryMethod() { + return false; + } + + default LibraryMethod asLibraryMethod() { + return null; + } + + default boolean isProgramClass() { + return false; + } + + default DexProgramClass asProgramClass() { + return null; + } + default boolean isProgramDefinition() { return false; } @@ -61,4 +121,28 @@ default ProgramDefinition asProgramDefinition() { return null; } + + default boolean isProgramField() { + return false; + } + + default ProgramField asProgramField() { + return null; + } + + default boolean isProgramMember() { + return false; + } + + default ProgramMember<?, ?> asProgramMember() { + return null; + } + + default boolean isProgramMethod() { + return false; + } + + default ProgramMethod asProgramMethod() { + return null; + } }
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 50362b0..f3937c2 100644 --- a/src/main/java/com/android/tools/r8/graph/DexClass.java +++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -676,6 +676,11 @@ } @Override + public DexClass asClass() { + return this; + } + + @Override public boolean isDexClass() { return true; } @@ -737,6 +742,11 @@ } @Override + public DexClass getDefinition() { + return this; + } + + @Override public Origin getOrigin() { return this.origin; }
diff --git a/src/main/java/com/android/tools/r8/graph/DexClassAndField.java b/src/main/java/com/android/tools/r8/graph/DexClassAndField.java index 2c78b93..30179b3 100644 --- a/src/main/java/com/android/tools/r8/graph/DexClassAndField.java +++ b/src/main/java/com/android/tools/r8/graph/DexClassAndField.java
@@ -55,27 +55,8 @@ return this; } - public boolean isClasspathField() { - return false; - } - - public ClasspathField asClasspathField() { - return null; - } - - public boolean isLibraryField() { - return false; - } - - public LibraryField asLibraryField() { - return null; - } - - public boolean isProgramField() { - return false; - } - - public ProgramField asProgramField() { - return null; + @Override + public DexClassAndField asMember() { + return this; } }
diff --git a/src/main/java/com/android/tools/r8/graph/DexClassAndMember.java b/src/main/java/com/android/tools/r8/graph/DexClassAndMember.java index 52cb7a9..f82bcbc 100644 --- a/src/main/java/com/android/tools/r8/graph/DexClassAndMember.java +++ b/src/main/java/com/android/tools/r8/graph/DexClassAndMember.java
@@ -22,8 +22,6 @@ this.definition = definition; } - public abstract AccessFlags<?> getAccessFlags(); - public final DexAnnotationSet getAnnotations() { return definition.annotations(); } @@ -41,6 +39,7 @@ return holder.type; } + @Override public D getDefinition() { return definition; } @@ -63,18 +62,6 @@ return holder.origin; } - public boolean isClasspathMember() { - return false; - } - - public boolean isLibraryMember() { - return false; - } - - public boolean isProgramMember() { - return false; - } - public String toSourceString() { return getReference().toSourceString(); }
diff --git a/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java b/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java index 2f18405..b39a1a7 100644 --- a/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java +++ b/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java
@@ -6,6 +6,7 @@ import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo; import com.android.tools.r8.references.MethodReference; +import java.util.function.Consumer; public abstract class DexClassAndMethod extends DexClassAndMember<DexEncodedMethod, DexMethod> implements LookupTarget { @@ -98,31 +99,18 @@ } @Override + public DexClassAndMethod asMember() { + return this; + } + + @Override public DexClassAndMethod asMethod() { return this; } - public boolean isClasspathMethod() { - return false; - } - - public ClasspathMethod asClasspathMethod() { - return null; - } - - public boolean isLibraryMethod() { - return false; - } - - public LibraryMethod asLibraryMethod() { - return null; - } - - public boolean isProgramMethod() { - return false; - } - - public ProgramMethod asProgramMethod() { - return null; + @Override + public void accept( + Consumer<DexClassAndMethod> methodConsumer, Consumer<LookupLambdaTarget> lambdaConsumer) { + methodConsumer.accept(this); } }
diff --git a/src/main/java/com/android/tools/r8/graph/DexDefinition.java b/src/main/java/com/android/tools/r8/graph/DexDefinition.java index 25c339e..9b69a2f 100644 --- a/src/main/java/com/android/tools/r8/graph/DexDefinition.java +++ b/src/main/java/com/android/tools/r8/graph/DexDefinition.java
@@ -58,6 +58,10 @@ annotations().rewrite(annotation -> rewriter.apply(annotation, AnnotatedKind.from(this)))); } + public DexClass asClass() { + return null; + } + public boolean isDexClass() { return false; }
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 5049ee4..6daff01 100644 --- a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java +++ b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
@@ -6,6 +6,7 @@ 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; @@ -44,7 +45,7 @@ /** Generic signature information if the attribute is present in the input */ private FieldTypeSignature genericSignature; - private FieldOptimizationInfo optimizationInfo = DefaultFieldOptimizationInfo.getInstance(); + private FieldOptimizationInfo optimizationInfo; private KotlinFieldLevelInfo kotlinMemberInfo = getNoKotlinInfo(); private static void specify(StructuralSpecification<DexEncodedField, ?> spec) { @@ -77,7 +78,15 @@ DexAnnotationSet annotations, DexValue staticValue, boolean deprecated) { - this(field, accessFlags, genericSignature, annotations, staticValue, deprecated, false); + this( + field, + accessFlags, + genericSignature, + annotations, + staticValue, + deprecated, + false, + AndroidApiLevel.UNKNOWN); } public DexEncodedField( @@ -87,12 +96,22 @@ DexAnnotationSet annotations, DexValue staticValue, boolean deprecated, - boolean d8R8Synthesized) { + boolean d8R8Synthesized, + AndroidApiLevel apiLevel) { super(field, annotations, d8R8Synthesized); 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); } @@ -448,7 +467,8 @@ annotations, staticValue, deprecated, - d8R8Synthesized); + d8R8Synthesized, + AndroidApiLevel.UNKNOWN); dexEncodedField.optimizationInfo = optimizationInfo; buildConsumer.accept(dexEncodedField); return dexEncodedField;
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 d3af4ee..c6913f8 100644 --- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java +++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -11,6 +11,7 @@ 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; @@ -258,7 +259,9 @@ parameterAnnotationsList, code, false, - null); + null, + AndroidApiLevel.UNKNOWN, + AndroidApiLevel.UNKNOWN); } public DexEncodedMethod( @@ -277,7 +280,9 @@ parameterAnnotationsList, code, d8R8Synthesized, - null); + null, + AndroidApiLevel.UNKNOWN, + AndroidApiLevel.UNKNOWN); } public DexEncodedMethod( @@ -288,7 +293,9 @@ ParameterAnnotationsList parameterAnnotationsList, Code code, boolean d8R8Synthesized, - CfVersion classFileVersion) { + CfVersion classFileVersion, + AndroidApiLevel apiLevelForDefinition, + AndroidApiLevel apiLevelForCode) { this( method, accessFlags, @@ -298,6 +305,8 @@ code, d8R8Synthesized, classFileVersion, + apiLevelForDefinition, + apiLevelForCode, false); } @@ -310,6 +319,8 @@ Code code, boolean d8R8Synthesized, CfVersion classFileVersion, + AndroidApiLevel apiLevelForDefinition, + AndroidApiLevel apiLevelForCode, boolean deprecated) { super(method, annotations, d8R8Synthesized); this.accessFlags = accessFlags; @@ -318,6 +329,18 @@ 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; + } assert accessFlags != null; assert code == null || !shouldNotHaveCode(); assert parameterAnnotationsList != null; @@ -1714,7 +1737,9 @@ parameterAnnotations, code, d8R8Synthesized, - classFileVersion); + classFileVersion, + AndroidApiLevel.UNKNOWN, + AndroidApiLevel.UNKNOWN); result.setKotlinMemberInfo(kotlinInfo); result.compilationState = compilationState; result.optimizationInfo = optimizationInfo;
diff --git a/src/main/java/com/android/tools/r8/graph/DexMember.java b/src/main/java/com/android/tools/r8/graph/DexMember.java index bffc842..2fa9753 100644 --- a/src/main/java/com/android/tools/r8/graph/DexMember.java +++ b/src/main/java/com/android/tools/r8/graph/DexMember.java
@@ -65,7 +65,10 @@ public AndroidApiLevel computeApiLevelForReferencedTypes( AppView<?> appView, BiFunction<DexReference, AndroidApiLevel, AndroidApiLevel> computeMax) { - AndroidApiLevel computedLevel = appView.options().minApiLevel; + AndroidApiLevel computedLevel = + appView.options().apiModelingOptions().enableApiCallerIdentification + ? appView.options().minApiLevel + : AndroidApiLevel.UNKNOWN; for (DexType type : getReferencedBaseTypes(appView.dexItemFactory())) { computedLevel = computeMax.apply(type, computedLevel); }
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 90841e1..8a3f39a 100644 --- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java +++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -4,6 +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.google.common.base.Predicates.alwaysTrue; import com.android.tools.r8.ProgramResource; @@ -823,22 +824,27 @@ } public AndroidApiLevel getApiReferenceLevel( - AndroidApiLevel minApiLevel, + 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 = minApiLevel; + AndroidApiLevel computedApiLevel = getApiLevelIfEnabled(appView, Function.identity()); for (DexType superType : allImmediateSupertypes()) { computedApiLevel = apiLevelLookup.apply(superType, computedApiLevel); if (computedApiLevel == AndroidApiLevel.UNKNOWN) { return AndroidApiLevel.UNKNOWN; } } + return computedApiLevel.max(getMembersApiReferenceLevel(appView)); + } + + public AndroidApiLevel getMembersApiReferenceLevel(AppView<?> appView) { + AndroidApiLevel memberLevel = getApiLevelIfEnabled(appView, Function.identity()); for (DexEncodedMember<?, ?> member : members()) { - computedApiLevel = member.getApiReferenceLevel(computedApiLevel); - if (computedApiLevel == AndroidApiLevel.UNKNOWN) { + memberLevel = memberLevel.max(getApiLevelIfEnabled(appView, member::getApiReferenceLevel)); + if (memberLevel == AndroidApiLevel.UNKNOWN) { return AndroidApiLevel.UNKNOWN; } } - return computedApiLevel; + return memberLevel; } }
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignatureContextBuilder.java b/src/main/java/com/android/tools/r8/graph/GenericSignatureContextBuilder.java index 1b1eabf..3492c06 100644 --- a/src/main/java/com/android/tools/r8/graph/GenericSignatureContextBuilder.java +++ b/src/main/java/com/android/tools/r8/graph/GenericSignatureContextBuilder.java
@@ -131,7 +131,15 @@ this.enclosingInfo = enclosingInfo; } - public static GenericSignatureContextBuilder create(Collection<DexProgramClass> programClasses) { + public static GenericSignatureContextBuilder create(AppView<?> appView) { + return create(appView, appView.appInfo().classes()); + } + + public static GenericSignatureContextBuilder create( + AppView<?> appView, Collection<DexProgramClass> programClasses) { + if (!appView.options().parseSignatureAttribute()) { + return null; + } Map<DexReference, TypeParameterSubstitutions> formalsInfo = new IdentityHashMap<>(); Map<DexReference, DexReference> enclosingInfo = new IdentityHashMap<>(); programClasses.forEach( @@ -187,7 +195,7 @@ workList.addIfNotSeen(outer.asProgramClass()); } } - return create(workList.getSeenSet()); + return create(appView, workList.getSeenSet()); } public TypeParameterContext computeTypeParameterContext(
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignatureCorrectnessHelper.java b/src/main/java/com/android/tools/r8/graph/GenericSignatureCorrectnessHelper.java index 1946512..d8c3142 100644 --- a/src/main/java/com/android/tools/r8/graph/GenericSignatureCorrectnessHelper.java +++ b/src/main/java/com/android/tools/r8/graph/GenericSignatureCorrectnessHelper.java
@@ -21,6 +21,9 @@ import com.android.tools.r8.graph.GenericSignature.ReturnType; import com.android.tools.r8.graph.GenericSignature.TypeSignature; import com.android.tools.r8.graph.GenericSignatureContextBuilder.TypeParameterContext; +import com.android.tools.r8.shaking.KeepClassInfo; +import com.android.tools.r8.shaking.KeepFieldInfo; +import com.android.tools.r8.shaking.KeepMethodInfo; import com.android.tools.r8.utils.ListUtils; import java.util.List; import java.util.function.Consumer; @@ -101,7 +104,8 @@ } public SignatureEvaluationResult run(List<DexProgramClass> programClasses) { - if (appView.options().disableGenericSignatureValidation) { + if (appView.options().disableGenericSignatureValidation + || !appView.options().parseSignatureAttribute()) { return VALID; } SignatureEvaluationResult evaluationResult = VALID; @@ -112,7 +116,8 @@ } public SignatureEvaluationResult evaluateSignaturesForClass(DexProgramClass clazz) { - if (appView.options().disableGenericSignatureValidation) { + if (appView.options().disableGenericSignatureValidation + || !appView.options().parseSignatureAttribute()) { return VALID; } @@ -125,7 +130,12 @@ SignatureEvaluationResult result = genericSignatureContextEvaluator.evaluateClassSignatureForContext(typeParameterContext); if (result.isInvalid() && mode.clearIfInvalid()) { - if (appView.hasLiveness() && appView.getKeepInfo().getClassInfo(clazz).isPinned()) { + // Only report info messages for classes that are kept explicitly. This is to ensure we do not + // spam the developer with messages they can do nothing about. + KeepClassInfo classInfo = appView.getKeepInfo().getClassInfo(clazz); + if (appView.hasLiveness() && !classInfo.isShrinkingAllowed(appView.options())) { + // If/when this no longer holds it should be moved into the condition. + assert !classInfo.isSignatureAttributeRemovalAllowed(appView.options()); appView .options() .reporter @@ -147,8 +157,13 @@ genericSignatureContextEvaluator.visitMethodSignature( methodSignature, typeParameterContext), invalidResult -> { + // Only report info messages for methods that are kept explicitly. This is to + // ensure we do not spam the developer with messages they can do nothing about. + KeepMethodInfo methodInfo = appView.getKeepInfo().getMethodInfo(method, clazz); if (appView.hasLiveness() - && appView.getKeepInfo().getMethodInfo(method, clazz).isPinned()) { + && !methodInfo.isShrinkingAllowed(appView.options())) { + // If/when this no longer holds it should be moved into the condition. + assert !methodInfo.isSignatureAttributeRemovalAllowed(appView.options()); appView .options() .reporter @@ -171,8 +186,12 @@ genericSignatureContextEvaluator.visitFieldTypeSignature( fieldSignature, typeParameterContext), invalidResult -> { - if (appView.hasLiveness() - && appView.getKeepInfo().getFieldInfo(field, clazz).isPinned()) { + KeepFieldInfo fieldInfo = appView.getKeepInfo().getFieldInfo(field, clazz); + // Only report info messages for fields that are kept explicitly. This is to + // ensure we do not spam the developer with messages they can do nothing about. + if (appView.hasLiveness() && !fieldInfo.isShrinkingAllowed(appView.options())) { + // If/when this no longer holds it should be moved into the condition. + assert !fieldInfo.isSignatureAttributeRemovalAllowed(appView.options()); appView .options() .reporter
diff --git a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java index 0b179ac..55482fc 100644 --- a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java +++ b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
@@ -38,6 +38,7 @@ import com.android.tools.r8.origin.Origin; import com.android.tools.r8.shaking.ProguardKeepAttributes; import com.android.tools.r8.synthesis.SyntheticMarker; +import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.AsmUtils; import com.android.tools.r8.utils.DescriptorUtils; import com.android.tools.r8.utils.ExceptionUtils; @@ -381,9 +382,11 @@ assert superName != null || name.equals(Constants.JAVA_LANG_OBJECT_NAME); superType = superName == null ? null : application.getTypeFromName(superName); this.interfaces = application.getTypeListFromNames(interfaces); - classSignature = - GenericSignature.parseClassSignature( - name, signature, origin, application.getFactory(), application.options.reporter); + if (application.options.parseSignatureAttribute()) { + classSignature = + GenericSignature.parseClassSignature( + name, signature, origin, application.getFactory(), application.options.reporter); + } } @Override @@ -620,7 +623,7 @@ private final String name; private final String desc; private final Object value; - private FieldTypeSignature fieldSignature; + private final FieldTypeSignature fieldSignature; private List<DexAnnotation> annotations = null; public CreateFieldVisitor( @@ -637,12 +640,14 @@ this.desc = desc; this.value = value; this.fieldSignature = - GenericSignature.parseFieldTypeSignature( - name, - signature, - parent.origin, - parent.application.getFactory(), - parent.application.options.reporter); + parent.application.options.parseSignatureAttribute() + ? GenericSignature.parseFieldTypeSignature( + name, + signature, + parent.origin, + parent.application.getFactory(), + parent.application.options.reporter) + : FieldTypeSignature.noSignature(); } @Override @@ -771,12 +776,14 @@ values, parent.application.getFactory())); } genericSignature = - GenericSignature.parseMethodSignature( - name, - signature, - parent.origin, - parent.application.getFactory(), - parent.application.options.reporter); + parent.application.options.parseSignatureAttribute() + ? GenericSignature.parseMethodSignature( + name, + signature, + parent.origin, + parent.application.getFactory(), + parent.application.options.reporter) + : MethodTypeSignature.noSignature(); } @Override @@ -908,6 +915,8 @@ code, false, parent.version, + AndroidApiLevel.UNKNOWN, + AndroidApiLevel.UNKNOWN, deprecated); Wrapper<DexMethod> signature = MethodSignatureEquivalence.get().wrap(method); if (parent.methodSignatures.add(signature)) {
diff --git a/src/main/java/com/android/tools/r8/graph/LibraryMember.java b/src/main/java/com/android/tools/r8/graph/LibraryMember.java index bf6bb03..b887324 100644 --- a/src/main/java/com/android/tools/r8/graph/LibraryMember.java +++ b/src/main/java/com/android/tools/r8/graph/LibraryMember.java
@@ -7,6 +7,7 @@ public interface LibraryMember<D extends DexEncodedMember<D, R>, R extends DexMember<D, R>> extends LibraryDefinition { + @Override D getDefinition(); DexLibraryClass getHolder();
diff --git a/src/main/java/com/android/tools/r8/graph/LookupLambdaTarget.java b/src/main/java/com/android/tools/r8/graph/LookupLambdaTarget.java index b41ef8f..12eeddc 100644 --- a/src/main/java/com/android/tools/r8/graph/LookupLambdaTarget.java +++ b/src/main/java/com/android/tools/r8/graph/LookupLambdaTarget.java
@@ -4,8 +4,10 @@ package com.android.tools.r8.graph; import com.android.tools.r8.ir.desugar.LambdaDescriptor; +import java.util.function.Consumer; public class LookupLambdaTarget implements LookupTarget { + private final LambdaDescriptor lambda; private final DexClassAndMethod method; @@ -26,6 +28,12 @@ return this; } + @Override + public void accept( + Consumer<DexClassAndMethod> methodConsumer, Consumer<LookupLambdaTarget> lambdaConsumer) { + lambdaConsumer.accept(this); + } + public DexClassAndMethod getImplementationMethod() { return method; }
diff --git a/src/main/java/com/android/tools/r8/graph/LookupTarget.java b/src/main/java/com/android/tools/r8/graph/LookupTarget.java index 6966a44..cc0d574 100644 --- a/src/main/java/com/android/tools/r8/graph/LookupTarget.java +++ b/src/main/java/com/android/tools/r8/graph/LookupTarget.java
@@ -3,6 +3,8 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.graph; +import java.util.function.Consumer; + public interface LookupTarget { default boolean isMethodTarget() { return false; @@ -19,4 +21,7 @@ default LookupLambdaTarget asLambdaTarget() { return null; } + + void accept( + Consumer<DexClassAndMethod> methodConsumer, Consumer<LookupLambdaTarget> lambdaConsumer); }
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramDefinition.java b/src/main/java/com/android/tools/r8/graph/ProgramDefinition.java index c1dedd5..b36e87c 100644 --- a/src/main/java/com/android/tools/r8/graph/ProgramDefinition.java +++ b/src/main/java/com/android/tools/r8/graph/ProgramDefinition.java
@@ -19,6 +19,16 @@ } @Override + default ProgramField asField() { + return null; + } + + @Override + default ProgramMethod asMethod() { + return null; + } + + @Override default ProgramDerivedContext asProgramDerivedContext(ProgramDerivedContext witness) { return this; } @@ -34,18 +44,6 @@ DexProgramClass getContextClass(); - AccessFlags<?> getAccessFlags(); - - DexDefinition getDefinition(); - - default boolean isProgramClass() { - return false; - } - - default DexProgramClass asProgramClass() { - return null; - } - @Override default boolean isProgramDefinition() { return true; @@ -55,28 +53,4 @@ default ProgramDefinition asProgramDefinition() { return this; } - - default boolean isProgramField() { - return false; - } - - default ProgramField asProgramField() { - return null; - } - - default boolean isProgramMember() { - return false; - } - - default ProgramMember<?, ?> asProgramMember() { - return null; - } - - default boolean isProgramMethod() { - return false; - } - - default ProgramMethod asProgramMethod() { - return null; - } }
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramField.java b/src/main/java/com/android/tools/r8/graph/ProgramField.java index aec6be0..d53cb1c 100644 --- a/src/main/java/com/android/tools/r8/graph/ProgramField.java +++ b/src/main/java/com/android/tools/r8/graph/ProgramField.java
@@ -38,6 +38,11 @@ } @Override + public ProgramField asField() { + return this; + } + + @Override public ProgramField asProgramField() { return this; }
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java index 5faf268..a34b49d 100644 --- a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java +++ b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
@@ -83,6 +83,11 @@ } @Override + public ProgramMethod asMethod() { + return this; + } + + @Override public ProgramMethod asProgramMethod() { return this; }
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 32c9420..b4615df 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
@@ -9,6 +9,7 @@ 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.LookupTarget; import com.android.tools.r8.graph.ProgramDefinition; import com.android.tools.r8.graph.ProgramField; import com.android.tools.r8.graph.ProgramMethod; @@ -59,6 +60,27 @@ setApiLevelForCode(method.getDefinition(), registry.getMaxApiReferenceLevel()); } + @Override + public void notifyMarkMethodAsTargeted(ProgramMethod method) { + setApiLevelForMemberDefinition(method.getDefinition(), minApiLevel); + } + + @Override + public void notifyMarkFieldAsReachable(ProgramField field) { + setApiLevelForMemberDefinition(field.getDefinition(), minApiLevel); + } + + @Override + public void notifyMarkVirtualDispatchTargetAsLive(LookupTarget target) { + target.accept( + dexClassAndMethod -> { + setApiLevelForMemberDefinition(dexClassAndMethod.getDefinition(), minApiLevel); + }, + 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
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java index dc87519..0610c55 100644 --- a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java +++ b/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java
@@ -5,6 +5,7 @@ package com.android.tools.r8.graph.analysis; import com.android.tools.r8.graph.DexProgramClass; +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; @@ -30,6 +31,12 @@ /** Called when a method's code has been processed by the registry. */ public void processTracedCode(ProgramMethod method, DefaultEnqueuerUseRegistry registry) {} + public void notifyMarkMethodAsTargeted(ProgramMethod method) {} + + public void notifyMarkFieldAsReachable(ProgramField field) {} + + public void notifyMarkVirtualDispatchTargetAsLive(LookupTarget target) {} + /** * Called when the Enqueuer reaches a fixpoint. This may happen multiple times, since each * analysis may enqueue items into the worklist upon the fixpoint using {@param worklist}.
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 7483522..a772278 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
@@ -4,6 +4,7 @@ package com.android.tools.r8.horizontalclassmerging; +import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabledForNewMember; import static com.google.common.base.Predicates.not; import com.android.tools.r8.graph.AppInfoWithClassHierarchy; @@ -32,6 +33,7 @@ import com.android.tools.r8.ir.analysis.value.NumberFromIntervalValue; import com.android.tools.r8.ir.optimize.info.OptimizationFeedback; import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple; +import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.SetUtils; import com.google.common.collect.Iterables; import com.google.common.collect.Sets; @@ -43,6 +45,7 @@ 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} @@ -127,6 +130,7 @@ newMethodReference.withName("$r8$clinit$synthetic", dexItemFactory); lensBuilder.recordNewMethodSignature(syntheticMethodReference, newMethodReference, true); + AndroidApiLevel apiReferenceLevel = classInitializerMerger.getApiReferenceLevel(appView); DexEncodedMethod definition = new DexEncodedMethod( newMethodReference, @@ -136,7 +140,9 @@ ParameterAnnotationsList.empty(), classInitializerMerger.getCode(syntheticMethodReference), DexEncodedMethod.D8_R8_SYNTHESIZED, - classInitializerMerger.getCfVersion()); + classInitializerMerger.getCfVersion(), + getApiLevelIfEnabledForNewMember(appView, ignored -> apiReferenceLevel), + getApiLevelIfEnabledForNewMember(appView, ignored -> apiReferenceLevel)); classMethodsBuilder.addDirectMethod(definition); // In case we didn't synthesize CF code, we register the class initializer for conversion to dex @@ -223,7 +229,8 @@ DexAnnotationSet.empty(), null, deprecated, - d8R8Synthesized); + d8R8Synthesized, + getApiLevelIfEnabledForNewMember(appView, Function.identity())); // 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 e17c574..adc89fc 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java
@@ -5,6 +5,7 @@ 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; @@ -360,6 +361,7 @@ instanceInitializer.getReference(), newMethodReference, extraParameters); } + DexEncodedMethod representativeMethod = representative.getDefinition(); DexEncodedMethod newInstanceInitializer = new DexEncodedMethod( newMethodReference, @@ -369,7 +371,11 @@ ParameterAnnotationsList.empty(), getNewCode(newMethodReference, syntheticMethodReference, needsClassId, extraNulls), true, - getNewClassFileVersion()); + getNewClassFileVersion(), + getApiLevelIfEnabledForNewMember( + appView, representativeMethod::getApiReferenceLevelForDefinition), + getApiLevelIfEnabledForNewMember( + appView, representativeMethod::getApiReferenceLevelForCode)); 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 394c884..d5f2b8b 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
@@ -4,6 +4,8 @@ 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; @@ -267,7 +269,7 @@ originalMethodReference.proto, originalMethodReference.getHolderType(), classMethodsBuilder::isFresh); - + DexEncodedMethod representativeMethod = representative.getDefinition(); DexMethod newMethodReference = getNewMethodReference(); AbstractSynthesizedCode synthesizedCode = new VirtualMethodEntryPointSynthesizedCode( @@ -286,7 +288,11 @@ ParameterAnnotationsList.empty(), synthesizedCode, true, - classFileVersion); + classFileVersion, + getApiLevelIfEnabledForNewMember( + appView, representativeMethod::getApiReferenceLevelForDefinition), + getApiLevelIfEnabledForNewMember( + appView, representativeMethod::getApiReferenceLevelForCode)); 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 ade97ad..cff4480 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,6 +4,7 @@ package com.android.tools.r8.horizontalclassmerging.code; +import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabled; import static java.lang.Integer.max; import com.android.tools.r8.cf.CfVersion; @@ -34,6 +35,7 @@ import com.android.tools.r8.ir.code.Return; import com.android.tools.r8.naming.ClassNameMapper; import com.android.tools.r8.origin.Origin; +import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.CfVersionUtils; import com.android.tools.r8.utils.IterableUtils; import com.android.tools.r8.utils.ListUtils; @@ -98,6 +100,18 @@ return null; } + public AndroidApiLevel getApiReferenceLevel(AppView<?> appView) { + 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))); + } + public static class Builder { private final ImmutableList.Builder<ProgramMethod> classInitializers = ImmutableList.builder();
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoDifferentApiReferenceLevel.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoDifferentApiReferenceLevel.java index 97d8d21..3b7e1e0 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoDifferentApiReferenceLevel.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoDifferentApiReferenceLevel.java
@@ -13,13 +13,13 @@ public class NoDifferentApiReferenceLevel extends MultiClassSameReferencePolicy<AndroidApiLevel> { private final AndroidApiReferenceLevelCache apiReferenceLevelCache; - private final AndroidApiLevel minApi; + private final AppView<?> appView; // TODO(b/188388130): Remove when stabilized. private final boolean enableApiCallerIdentification; public NoDifferentApiReferenceLevel(AppView<?> appView) { apiReferenceLevelCache = AndroidApiReferenceLevelCache.create(appView); - minApi = appView.options().minApiLevel; + this.appView = appView; enableApiCallerIdentification = appView.options().apiModelingOptions().enableApiCallerIdentification; } @@ -37,6 +37,6 @@ @Override public AndroidApiLevel getMergeKey(DexProgramClass clazz) { assert enableApiCallerIdentification; - return clazz.getApiReferenceLevel(minApi, apiReferenceLevelCache::lookupMax); + return clazz.getApiReferenceLevel(appView, apiReferenceLevelCache::lookupMax); } }
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 9508da1..136d452 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,8 +13,6 @@ 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.CfPostProcessingDesugaringEventConsumer; -import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer.D8CfPostProcessingDesugaringEventConsumer; import com.android.tools.r8.utils.ThreadUtils; import com.google.common.collect.Sets; import java.util.ArrayList; @@ -112,13 +110,6 @@ classes = deferred; } - - D8CfPostProcessingDesugaringEventConsumer eventConsumer = - CfPostProcessingDesugaringEventConsumer.createForD8(methodProcessor, appView); - methodProcessor.newWave(); - converter.postProcessDesugaring(eventConsumer); - methodProcessor.awaitMethodProcessing(); - eventConsumer.finalizeDesugaring(); } abstract void convertClass(
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 0b3c524..3144113 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
@@ -51,11 +51,13 @@ import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer.D8CfInstructionDesugaringEventConsumer; 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; import com.android.tools.r8.ir.desugar.CovariantReturnTypeAnnotationTransformer; import com.android.tools.r8.ir.desugar.ProgramAdditions; import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter; import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter.Mode; import com.android.tools.r8.ir.desugar.itf.EmulatedInterfaceApplicationRewriter; +import com.android.tools.r8.ir.desugar.itf.InterfaceMethodProcessorFacade; import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter; import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.Flavor; import com.android.tools.r8.ir.desugar.lambda.LambdaDeserializationMethodRemover; @@ -105,7 +107,6 @@ import com.android.tools.r8.utils.DescriptorUtils; import com.android.tools.r8.utils.ExceptionUtils; import com.android.tools.r8.utils.InternalOptions; -import com.android.tools.r8.utils.InternalOptions.DesugarState; import com.android.tools.r8.utils.ListUtils; import com.android.tools.r8.utils.StringDiagnostic; import com.android.tools.r8.utils.ThreadUtils; @@ -226,10 +227,7 @@ assert options.desugarState.isOn(); this.instructionDesugaring = CfInstructionDesugaringCollection.create(appView); this.classDesugaring = instructionDesugaring.createClassDesugaringCollection(); - this.interfaceMethodRewriter = - options.desugaredLibraryConfiguration.getEmulateLibraryInterface().isEmpty() - ? null - : new InterfaceMethodRewriter(appView, this); + this.interfaceMethodRewriter = null; this.desugaredLibraryAPIConverter = new DesugaredLibraryAPIConverter(appView, Mode.GENERATE_CALLBACKS_AND_WRAPPERS); this.covariantReturnTypeAnnotationTransformer = null; @@ -259,7 +257,7 @@ : CfInstructionDesugaringCollection.create(appView); this.classDesugaring = instructionDesugaring.createClassDesugaringCollection(); this.interfaceMethodRewriter = - options.isInterfaceMethodDesugaringEnabled() + options.isInterfaceMethodDesugaringEnabled() && appView.enableWholeProgramOptimizations() ? new InterfaceMethodRewriter(appView, this) : null; this.covariantReturnTypeAnnotationTransformer = @@ -367,11 +365,6 @@ D8NestBasedAccessDesugaring::clearNestAttributes); } - void postProcessDesugaring(CfPostProcessingDesugaringEventConsumer eventConsumer) { - CfPostProcessingDesugaringCollection.create(appView, instructionDesugaring.getRetargetingInfo()) - .postProcessingDesugaring(eventConsumer); - } - private void staticizeClasses( OptimizationFeedback feedback, ExecutorService executorService, GraphLens applied) throws ExecutionException { @@ -394,11 +387,11 @@ } } - private void runInterfaceDesugaringProcessors( + private void runInterfaceDesugaringProcessorsForR8( Flavor includeAllResources, ExecutorService executorService) throws ExecutionException { assert !appView.getSyntheticItems().hasPendingSyntheticClasses(); if (interfaceMethodRewriter != null) { - interfaceMethodRewriter.runInterfaceDesugaringProcessors( + interfaceMethodRewriter.runInterfaceDesugaringProcessorsForR8( this, includeAllResources, executorService); } } @@ -415,25 +408,24 @@ workaroundAbstractMethodOnNonAbstractClassVerificationBug( executor, OptimizationFeedbackIgnore.getInstance()); DexApplication application = appView.appInfo().app(); + D8MethodProcessor methodProcessor = new D8MethodProcessor(this, executor); + timing.begin("IR conversion"); - convertClasses(executor); + convertClasses(methodProcessor, executor); reportNestDesugarDependencies(); clearNestAttributes(); - if (appView.getSyntheticItems().hasPendingSyntheticClasses()) { - appView.setAppInfo( - new AppInfo( - appView.appInfo().getSyntheticItems().commit(application), - appView.appInfo().getMainDexInfo())); - application = appView.appInfo().app(); - } + application = commitPendingSyntheticItems(appView, application); + + postProcessingDesugaringForD8(methodProcessor, executor); + + application = commitPendingSyntheticItems(appView, application); // Build a new application with jumbo string info, Builder<?> builder = application.builder().setHighestSortingString(highestSortingString); - runInterfaceDesugaringProcessors(ExcludeDexResources, executor); if (appView.options().isDesugaredLibraryCompilation()) { new EmulatedInterfaceApplicationRewriter(appView).rewriteApplication(builder); } @@ -449,8 +441,34 @@ appView.appInfo().getMainDexInfo())); } - private void convertClasses(ExecutorService executorService) throws ExecutionException { - D8MethodProcessor methodProcessor = new D8MethodProcessor(this, executorService); + private DexApplication commitPendingSyntheticItems( + AppView<AppInfo> appView, DexApplication application) { + if (appView.getSyntheticItems().hasPendingSyntheticClasses()) { + appView.setAppInfo( + new AppInfo( + appView.appInfo().getSyntheticItems().commit(application), + appView.appInfo().getMainDexInfo())); + application = appView.appInfo().app(); + } + return application; + } + + private void postProcessingDesugaringForD8( + D8MethodProcessor methodProcessor, ExecutorService executorService) + throws ExecutionException { + D8CfPostProcessingDesugaringEventConsumer eventConsumer = + CfPostProcessingDesugaringEventConsumer.createForD8(methodProcessor, appView); + methodProcessor.newWave(); + InterfaceMethodProcessorFacade interfaceDesugaring = + instructionDesugaring.getInterfaceMethodPostProcessingDesugaring(ExcludeDexResources); + CfPostProcessingDesugaringCollection.create( + appView, interfaceDesugaring, instructionDesugaring.getRetargetingInfo()) + .postProcessingDesugaring(eventConsumer, executorService); + eventConsumer.finalizeDesugaring(); + } + + private void convertClasses(D8MethodProcessor methodProcessor, ExecutorService executorService) + throws ExecutionException { ClassConverterResult classConverterResult = ClassConverter.create(appView, this, methodProcessor).convertClasses(executorService); @@ -797,7 +815,7 @@ printPhase("Interface method desugaring"); finalizeInterfaceMethodRewritingThroughIR(executorService); - runInterfaceDesugaringProcessors(IncludeAllResources, executorService); + runInterfaceDesugaringProcessorsForR8(IncludeAllResources, executorService); feedback.updateVisibleOptimizationInfo(); printPhase("Desugared library API Conversion finalization"); @@ -1445,12 +1463,6 @@ deadCodeRemover.run(code, timing); assert code.isConsistentSSA(); - if (options.desugarState == DesugarState.ON && options.enableTryWithResourcesDesugaring()) { - timing.begin("Rewrite Throwable suppresed methods"); - codeRewriter.rewriteThrowableAddAndGetSuppressed(code); - timing.end(); - } - previous = printMethod(code, "IR after lambda desugaring (SSA)", previous); assert code.verifyTypes(appView);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringCollection.java index 6efa25b..8512734 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringCollection.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringCollection.java
@@ -8,6 +8,8 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.desugar.desugaredlibrary.RetargetingInfo; +import com.android.tools.r8.ir.desugar.itf.InterfaceMethodProcessorFacade; +import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.Flavor; import com.android.tools.r8.ir.desugar.nest.D8NestBasedAccessDesugaring; import com.android.tools.r8.utils.ThrowingConsumer; @@ -58,5 +60,8 @@ public abstract <T extends Throwable> void withD8NestBasedAccessDesugaring( ThrowingConsumer<D8NestBasedAccessDesugaring, T> consumer) throws T; + public abstract InterfaceMethodProcessorFacade getInterfaceMethodPostProcessingDesugaring( + Flavor flavor); + public abstract RetargetingInfo getRetargetingInfo(); }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaring.java index 2a2de5f..38a0413 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaring.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaring.java
@@ -3,7 +3,12 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.ir.desugar; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; + public interface CfPostProcessingDesugaring { - void postProcessingDesugaring(CfPostProcessingDesugaringEventConsumer eventConsumer); + void postProcessingDesugaring( + CfPostProcessingDesugaringEventConsumer eventConsumer, ExecutorService executorService) + throws ExecutionException; }
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 f659ad8..986c6ea 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
@@ -6,15 +6,21 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterPostProcessor; import com.android.tools.r8.ir.desugar.desugaredlibrary.RetargetingInfo; -import java.util.Collections; +import com.android.tools.r8.ir.desugar.itf.InterfaceMethodProcessorFacade; +import java.util.ArrayList; import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; public abstract class CfPostProcessingDesugaringCollection { public static CfPostProcessingDesugaringCollection create( - AppView<?> appView, RetargetingInfo retargetingInfo) { + AppView<?> appView, + InterfaceMethodProcessorFacade interfaceMethodProcessorFacade, + RetargetingInfo retargetingInfo) { if (appView.options().desugarState.isOn()) { - return NonEmptyCfPostProcessingDesugaringCollection.create(appView, retargetingInfo); + return NonEmptyCfPostProcessingDesugaringCollection.create( + appView, interfaceMethodProcessorFacade, retargetingInfo); } return empty(); } @@ -24,7 +30,8 @@ } public abstract void postProcessingDesugaring( - CfPostProcessingDesugaringEventConsumer eventConsumer); + CfPostProcessingDesugaringEventConsumer eventConsumer, ExecutorService executorService) + throws ExecutionException; public static class NonEmptyCfPostProcessingDesugaringCollection extends CfPostProcessingDesugaringCollection { @@ -37,19 +44,29 @@ } public static CfPostProcessingDesugaringCollection create( - AppView<?> appView, RetargetingInfo retargetingInfo) { - if (appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember().isEmpty()) { + AppView<?> appView, + InterfaceMethodProcessorFacade interfaceMethodProcessorFacade, + RetargetingInfo retargetingInfo) { + if (appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember().isEmpty() + && interfaceMethodProcessorFacade == null) { return empty(); } - return new NonEmptyCfPostProcessingDesugaringCollection( - Collections.singletonList( - new DesugaredLibraryRetargeterPostProcessor(appView, retargetingInfo))); + ArrayList<CfPostProcessingDesugaring> desugarings = new ArrayList<>(); + if (!appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember().isEmpty()) { + desugarings.add(new DesugaredLibraryRetargeterPostProcessor(appView, retargetingInfo)); + } + if (interfaceMethodProcessorFacade != null) { + desugarings.add(interfaceMethodProcessorFacade); + } + return new NonEmptyCfPostProcessingDesugaringCollection(desugarings); } @Override - public void postProcessingDesugaring(CfPostProcessingDesugaringEventConsumer eventConsumer) { + public void postProcessingDesugaring( + CfPostProcessingDesugaringEventConsumer eventConsumer, ExecutorService executorService) + throws ExecutionException { for (CfPostProcessingDesugaring desugaring : desugarings) { - desugaring.postProcessingDesugaring(eventConsumer); + desugaring.postProcessingDesugaring(eventConsumer, executorService); } } } @@ -67,7 +84,9 @@ } @Override - public void postProcessingDesugaring(CfPostProcessingDesugaringEventConsumer eventConsumer) { + public void postProcessingDesugaring( + CfPostProcessingDesugaringEventConsumer eventConsumer, ExecutorService executorService) + throws ExecutionException { // Intentionally empty. } }
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 dc67ee9..5734cab 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
@@ -11,7 +11,10 @@ import com.android.tools.r8.ir.conversion.D8MethodProcessor; import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter; import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterInstructionEventConsumer.DesugaredLibraryRetargeterPostProcessingEventConsumer; +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; +import java.util.concurrent.ExecutionException; /** * Specialized Event consumer for desugaring finalization. During finalization, it is not possible @@ -19,7 +22,8 @@ * explicit calls must be done here. */ public abstract class CfPostProcessingDesugaringEventConsumer - implements DesugaredLibraryRetargeterPostProcessingEventConsumer { + implements DesugaredLibraryRetargeterPostProcessingEventConsumer, + InterfaceProcessingDesugaringEventConsumer { protected DesugaredLibraryAPIConverter desugaredLibraryAPIConverter; protected CfPostProcessingDesugaringEventConsumer(AppView<?> appView) { @@ -36,13 +40,14 @@ return new R8PostProcessingDesugaringEventConsumer(appView, additions); } - public void finalizeDesugaring() { - desugaredLibraryAPIConverter.generateTrackingWarnings(); - } + public abstract void finalizeDesugaring() throws ExecutionException; 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. + private final ProgramMethodSet methodsToReprocess = ProgramMethodSet.createConcurrent(); private D8CfPostProcessingDesugaringEventConsumer( D8MethodProcessor methodProcessor, AppView<?> appView) { @@ -52,7 +57,7 @@ @Override public void acceptDesugaredLibraryRetargeterDispatchProgramClass(DexProgramClass clazz) { - methodProcessor.scheduleDesugaredMethodsForProcessing(clazz.programMethods()); + methodsToReprocess.addAll(clazz.programMethods()); } @Override @@ -67,9 +72,25 @@ @Override public void acceptForwardingMethod(ProgramMethod method) { - methodProcessor.scheduleDesugaredMethodForProcessing(method); - // TODO(b/189912077): Uncomment when API conversion is performed cf to cf in D8. - // desugaredLibraryAPIConverter.generateCallbackIfRequired(method); + methodsToReprocess.add(method); + } + + @Override + public void acceptCompanionClassClinit(ProgramMethod method) { + methodsToReprocess.add(method); + } + + @Override + public void acceptEmulatedInterfaceMethod(ProgramMethod method) { + methodsToReprocess.add(method); + } + + @Override + public void finalizeDesugaring() throws ExecutionException { + assert methodProcessor.verifyNoPendingMethodProcessing(); + methodProcessor.newWave(); + methodProcessor.scheduleDesugaredMethodsForProcessing(methodsToReprocess); + methodProcessor.awaitMethodProcessing(); } } @@ -84,6 +105,11 @@ } @Override + public void finalizeDesugaring() throws ExecutionException { + desugaredLibraryAPIConverter.generateTrackingWarnings(); + } + + @Override public void acceptDesugaredLibraryRetargeterDispatchProgramClass(DexProgramClass clazz) { additions.addLiveMethods(clazz.programMethods()); } @@ -106,5 +132,15 @@ additions.addLiveMethod(callback); } } + + @Override + public void acceptCompanionClassClinit(ProgramMethod method) { + assert false : "TODO(b/183998768): Support Interface processing in R8"; + } + + @Override + public void acceptEmulatedInterfaceMethod(ProgramMethod method) { + assert false : "TODO(b/183998768): Support Interface processing in R8"; + } } }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/EmptyCfInstructionDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/EmptyCfInstructionDesugaringCollection.java index 61c9617..7991ac3 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/EmptyCfInstructionDesugaringCollection.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/EmptyCfInstructionDesugaringCollection.java
@@ -8,6 +8,8 @@ import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.desugar.CfClassDesugaringCollection.EmptyCfClassDesugaringCollection; import com.android.tools.r8.ir.desugar.desugaredlibrary.RetargetingInfo; +import com.android.tools.r8.ir.desugar.itf.InterfaceMethodProcessorFacade; +import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.Flavor; import com.android.tools.r8.ir.desugar.nest.D8NestBasedAccessDesugaring; import com.android.tools.r8.utils.ThrowingConsumer; @@ -63,6 +65,11 @@ } @Override + public InterfaceMethodProcessorFacade getInterfaceMethodPostProcessingDesugaring(Flavor flavor) { + return null; + } + + @Override public RetargetingInfo getRetargetingInfo() { return null; }
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 3b5a40b..2d53448 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,6 +5,7 @@ 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; @@ -43,6 +44,7 @@ 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 @@ -241,7 +243,8 @@ DexAnnotationSet.empty(), null, deprecated, - d8R8Synthesized)); + d8R8Synthesized, + getApiLevelIfEnabledForNewMember(appView, Function.identity()))); } builder.setInstanceFields(fields); } @@ -266,7 +269,8 @@ DexAnnotationSet.empty(), DexValueNull.NULL, deprecated, - d8R8Synthesized))); + d8R8Synthesized, + getApiLevelIfEnabledForNewMember(appView, Function.identity())))); } }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java index 8ddd45c..a7f1a33 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
@@ -17,13 +17,15 @@ import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeter; import com.android.tools.r8.ir.desugar.desugaredlibrary.RetargetingInfo; import com.android.tools.r8.ir.desugar.invokespecial.InvokeSpecialToSelfDesugaring; +import com.android.tools.r8.ir.desugar.itf.InterfaceMethodProcessorFacade; import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter; +import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.Flavor; import com.android.tools.r8.ir.desugar.lambda.LambdaInstructionDesugaring; import com.android.tools.r8.ir.desugar.nest.D8NestBasedAccessDesugaring; import com.android.tools.r8.ir.desugar.nest.NestBasedAccessDesugaring; import com.android.tools.r8.ir.desugar.records.RecordRewriter; import com.android.tools.r8.ir.desugar.stringconcat.StringConcatInstructionDesugaring; -import com.android.tools.r8.ir.desugar.twr.TwrCloseResourceInstructionDesugaring; +import com.android.tools.r8.ir.desugar.twr.TwrInstructionDesugaring; import com.android.tools.r8.utils.IntBox; import com.android.tools.r8.utils.ListUtils; import com.android.tools.r8.utils.StringDiagnostic; @@ -42,6 +44,7 @@ private final NestBasedAccessDesugaring nestBasedAccessDesugaring; private final RecordRewriter recordRewriter; private final DesugaredLibraryRetargeter desugaredLibraryRetargeter; + private final InterfaceMethodRewriter interfaceMethodRewriter; NonEmptyCfInstructionDesugaringCollection(AppView<?> appView) { this.appView = appView; @@ -49,6 +52,7 @@ this.nestBasedAccessDesugaring = null; this.recordRewriter = null; this.desugaredLibraryRetargeter = null; + this.interfaceMethodRewriter = null; return; } this.nestBasedAccessDesugaring = NestBasedAccessDesugaring.create(appView); @@ -65,14 +69,17 @@ } // Place TWR before Interface desugaring to eliminate potential $closeResource interface calls. if (appView.options().enableTryWithResourcesDesugaring()) { - desugarings.add(new TwrCloseResourceInstructionDesugaring(appView)); + desugarings.add(new TwrInstructionDesugaring(appView)); } // TODO(b/183998768): Enable interface method rewriter cf to cf also in R8. - if (appView.options().isInterfaceMethodDesugaringEnabled() - && !appView.enableWholeProgramOptimizations()) { - desugarings.add( - new InterfaceMethodRewriter( - appView, backportedMethodRewriter, desugaredLibraryRetargeter)); + interfaceMethodRewriter = + appView.options().isInterfaceMethodDesugaringEnabled() + && !appView.enableWholeProgramOptimizations() + ? new InterfaceMethodRewriter( + appView, backportedMethodRewriter, desugaredLibraryRetargeter) + : null; + if (interfaceMethodRewriter != null) { + desugarings.add(interfaceMethodRewriter); } desugarings.add(new LambdaInstructionDesugaring(appView)); desugarings.add(new InvokeSpecialToSelfDesugaring(appView)); @@ -288,7 +295,7 @@ || (appliedDesugaring instanceof InterfaceMethodRewriter && (desugaring instanceof InvokeToPrivateRewriter || desugaring instanceof D8NestBasedAccessDesugaring)) - || (appliedDesugaring instanceof TwrCloseResourceInstructionDesugaring + || (appliedDesugaring instanceof TwrInstructionDesugaring && desugaring instanceof InterfaceMethodRewriter) : "Desugaring of " + instruction @@ -312,6 +319,13 @@ } @Override + public InterfaceMethodProcessorFacade getInterfaceMethodPostProcessingDesugaring(Flavor flavor) { + return interfaceMethodRewriter != null + ? interfaceMethodRewriter.getPostProcessingDesugaring(flavor) + : null; + } + + @Override public RetargetingInfo getRetargetingInfo() { if (desugaredLibraryRetargeter != null) { return desugaredLibraryRetargeter.getRetargetingInfo();
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 0b0039e..dac3079 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
@@ -23,6 +23,8 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; // The rewrite of virtual calls requires to go through emulate dispatch. This class is responsible // for inserting interfaces on library boundaries and forwarding methods in the program, and to @@ -41,7 +43,9 @@ } @Override - public void postProcessingDesugaring(CfPostProcessingDesugaringEventConsumer eventConsumer) { + public void postProcessingDesugaring( + CfPostProcessingDesugaringEventConsumer eventConsumer, ExecutorService executorService) + throws ExecutionException { if (appView.options().isDesugaredLibraryCompilation()) { ensureEmulatedDispatchMethodsSynthesized(eventConsumer); } else {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java index d86d22c..14e5fea 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
@@ -380,7 +380,8 @@ } @Override - public void process(DexProgramClass clazz, ProgramMethodSet synthesizedMethods) { + public void process( + DexProgramClass clazz, InterfaceProcessingDesugaringEventConsumer eventConsumer) { if (!clazz.isInterface()) { visitClassInfo(clazz, new ReportingContext(clazz, clazz)); } @@ -389,11 +390,11 @@ // We introduce forwarding methods only once all desugaring has been performed to avoid // confusing the look-up with inserted forwarding methods. @Override - public final void finalizeProcessing(ProgramMethodSet synthesizedMethods) { + public final void finalizeProcessing(InterfaceProcessingDesugaringEventConsumer eventConsumer) { newSyntheticMethods.forEach( (clazz, newForwardingMethods) -> { clazz.addVirtualMethods(newForwardingMethods.toDefinitionSet()); - newForwardingMethods.forEach(synthesizedMethods::add); + newForwardingMethods.forEach(eventConsumer::acceptForwardingMethod); }); }
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/EmulatedInterfaceProcessor.java index 46bd871..1c29a09 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/EmulatedInterfaceProcessor.java
@@ -19,7 +19,6 @@ import com.android.tools.r8.synthesis.SyntheticNaming; import com.android.tools.r8.utils.Pair; import com.android.tools.r8.utils.StringDiagnostic; -import com.android.tools.r8.utils.collections.ProgramMethodSet; import com.google.common.collect.Iterables; import com.google.common.collect.Sets; import java.util.ArrayList; @@ -89,7 +88,7 @@ } DexProgramClass ensureEmulateInterfaceLibrary( - DexProgramClass emulatedInterface, ProgramMethodSet synthesizedMethods) { + DexProgramClass emulatedInterface, InterfaceProcessingDesugaringEventConsumer eventConsumer) { assert rewriter.isEmulatedInterface(emulatedInterface.type); DexProgramClass emulateInterfaceClass = appView @@ -107,7 +106,7 @@ synthesizeEmulatedInterfaceMethod( method, emulatedInterface, methodBuilder))), ignored -> {}); - emulateInterfaceClass.forEachProgramMethod(synthesizedMethods::add); + emulateInterfaceClass.forEachProgramMethod(eventConsumer::acceptEmulatedInterfaceMethod); assert emulateInterfaceClass.getType() == InterfaceMethodRewriter.getEmulateLibraryInterfaceClassType( emulatedInterface.type, appView.dexItemFactory()); @@ -212,14 +211,15 @@ } @Override - public void process(DexProgramClass emulatedInterface, ProgramMethodSet synthesizedMethods) { + public void process( + DexProgramClass emulatedInterface, InterfaceProcessingDesugaringEventConsumer eventConsumer) { if (!appView.options().isDesugaredLibraryCompilation() || !rewriter.isEmulatedInterface(emulatedInterface.type) || appView.isAlreadyLibraryDesugared(emulatedInterface)) { return; } if (needsEmulateInterfaceLibrary(emulatedInterface)) { - ensureEmulateInterfaceLibrary(emulatedInterface, synthesizedMethods); + ensureEmulateInterfaceLibrary(emulatedInterface, eventConsumer); } } @@ -228,7 +228,7 @@ } @Override - public void finalizeProcessing(ProgramMethodSet synthesizedMethods) { + public void finalizeProcessing(InterfaceProcessingDesugaringEventConsumer eventConsumer) { warnMissingEmulatedInterfaces(); }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringProcessor.java index 7f3d047..4f4ba32 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringProcessor.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringProcessor.java
@@ -5,7 +5,6 @@ package com.android.tools.r8.ir.desugar.itf; import com.android.tools.r8.graph.DexProgramClass; -import com.android.tools.r8.utils.collections.ProgramMethodSet; public interface InterfaceDesugaringProcessor { @@ -14,11 +13,11 @@ // so this phase cannot modify the classes themselves (for example insertion/removal of methods). // The phase can insert new classes with new methods, such as emulated interface dispatch classes // or companion classes with their methods. - void process(DexProgramClass clazz, ProgramMethodSet synthesizedMethods); + void process(DexProgramClass clazz, InterfaceProcessingDesugaringEventConsumer eventConsumer); // The finalization phase is done at a join point, after all code desugaring have been performed. // All finalization phases of all desugaring processors are performed sequentially. // Complex computations should be avoided if possible here and be moved to the concurrent phase. // Classes may be mutated here (new methods can be inserted, etc.). - void finalizeProcessing(ProgramMethodSet synthesizedMethods); + void finalizeProcessing(InterfaceProcessingDesugaringEventConsumer eventConsumer); }
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 731316f..71844b0 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
@@ -6,7 +6,10 @@ import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexProgramClass; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.conversion.IRConverter; +import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaring; +import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer; import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.Flavor; import com.android.tools.r8.utils.ThreadUtils; import com.android.tools.r8.utils.collections.SortedProgramMethodSet; @@ -16,21 +19,22 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; -class InterfaceMethodProcessorFacade { +public class InterfaceMethodProcessorFacade implements CfPostProcessingDesugaring { private final AppView<?> appView; + private final Flavor flavour; + private final List<InterfaceDesugaringProcessor> interfaceDesugaringProcessors; - InterfaceMethodProcessorFacade(AppView<?> appView) { + InterfaceMethodProcessorFacade( + AppView<?> appView, Flavor flavour, InterfaceMethodRewriter rewriter) { this.appView = appView; + this.flavour = flavour; + interfaceDesugaringProcessors = instantiateInterfaceDesugaringProcessors(appView, rewriter); } - /** Runs the interfaceProcessor, the class processor and the emulated interface processor. */ - void runInterfaceDesugaringProcessors( - InterfaceMethodRewriter rewriter, - IRConverter converter, - Flavor flavour, - ExecutorService executorService) - throws ExecutionException { + private List<InterfaceDesugaringProcessor> instantiateInterfaceDesugaringProcessors( + AppView<?> appView, InterfaceMethodRewriter rewriter) { + // 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 = @@ -46,17 +50,47 @@ // classes if needed. InterfaceProcessor interfaceProcessor = new InterfaceProcessor(appView, rewriter); - // The interface processors must be ordered so that finalization of the processing is performed - // in that order. The emulatedInterfaceProcessor has to be last at this point to avoid renaming - // emulated interfaces before the other processing. - ImmutableList<InterfaceDesugaringProcessor> orderedInterfaceDesugaringProcessors = - ImmutableList.of(classProcessor, interfaceProcessor, emulatedInterfaceProcessor); + // The processors can be listed in any order. + return ImmutableList.of(classProcessor, interfaceProcessor, emulatedInterfaceProcessor); + } + + /** Runs the interfaceProcessor, the class processor and the emulated interface processor. */ + void runInterfaceDesugaringProcessorsForR8(IRConverter converter, ExecutorService executorService) + throws ExecutionException { + + CollectingInterfaceDesugaringEventConsumer eventConsumer = + new CollectingInterfaceDesugaringEventConsumer(); + processClassesConcurrently(eventConsumer, executorService); + converter.processMethodsConcurrently( + eventConsumer.getSortedSynthesizedMethods(), executorService); + } + + // This temporary class avoids the duality between collecting with IR processing and + // having events with the Cf desugaring. + private static class CollectingInterfaceDesugaringEventConsumer + implements InterfaceProcessingDesugaringEventConsumer { SortedProgramMethodSet sortedSynthesizedMethods = SortedProgramMethodSet.createConcurrent(); - processClassesConcurrently( - orderedInterfaceDesugaringProcessors, sortedSynthesizedMethods, flavour, executorService); - assert converter != null; - converter.processMethodsConcurrently(sortedSynthesizedMethods, executorService); + + @Override + public void acceptForwardingMethod(ProgramMethod method) { + sortedSynthesizedMethods.add(method); + } + + @Override + public void acceptCompanionClassClinit(ProgramMethod method) { + sortedSynthesizedMethods.add(method); + } + + @Override + public void acceptEmulatedInterfaceMethod(ProgramMethod method) { + + sortedSynthesizedMethods.add(method); + } + + public SortedProgramMethodSet getSortedSynthesizedMethods() { + return sortedSynthesizedMethods; + } } private boolean shouldProcess(DexProgramClass clazz, Flavor flavour) { @@ -67,22 +101,28 @@ } private void processClassesConcurrently( - List<InterfaceDesugaringProcessor> processors, - SortedProgramMethodSet sortedSynthesizedMethods, - Flavor flavour, - ExecutorService executorService) + InterfaceProcessingDesugaringEventConsumer eventConsumer, ExecutorService executorService) throws ExecutionException { ThreadUtils.processItems( Iterables.filter( appView.appInfo().classes(), (DexProgramClass clazz) -> shouldProcess(clazz, flavour)), clazz -> { - for (InterfaceDesugaringProcessor processor : processors) { - processor.process(clazz, sortedSynthesizedMethods); + for (InterfaceDesugaringProcessor processor : interfaceDesugaringProcessors) { + processor.process(clazz, eventConsumer); } }, executorService); - for (InterfaceDesugaringProcessor processor : processors) { - processor.finalizeProcessing(sortedSynthesizedMethods); + for (InterfaceDesugaringProcessor processor : interfaceDesugaringProcessors) { + processor.finalizeProcessing(eventConsumer); } } + + @Override + public void postProcessingDesugaring( + CfPostProcessingDesugaringEventConsumer eventConsumer, ExecutorService executorService) + throws ExecutionException { + // TODO(b/183998768): Would be nice to use the ClassProcessing for the processing of classes, + // and do here only the finalization. + processClassesConcurrently(eventConsumer, executorService); + } }
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 6ab6f1f..3e93691 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
@@ -1376,11 +1376,15 @@ this.synthesizedMethods.clear(); } - public void runInterfaceDesugaringProcessors( + public void runInterfaceDesugaringProcessorsForR8( IRConverter converter, Flavor flavour, ExecutorService executorService) throws ExecutionException { - new InterfaceMethodProcessorFacade(appView) - .runInterfaceDesugaringProcessors(this, converter, flavour, executorService); + getPostProcessingDesugaring(flavour) + .runInterfaceDesugaringProcessorsForR8(converter, executorService); + } + + public InterfaceMethodProcessorFacade getPostProcessingDesugaring(Flavor flavour) { + return new InterfaceMethodProcessorFacade(appView, flavour, this); } final boolean isDefaultMethod(DexEncodedMethod method) {
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 new file mode 100644 index 0000000..2581364 --- /dev/null +++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessingDesugaringEventConsumer.java
@@ -0,0 +1,16 @@ +// 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.ProgramMethod; + +public interface InterfaceProcessingDesugaringEventConsumer { + + void acceptForwardingMethod(ProgramMethod method); + + 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 cb752ad..2dd65a9 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
@@ -47,7 +47,6 @@ import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap; import com.android.tools.r8.utils.collections.BidirectionalOneToOneMap; import com.android.tools.r8.utils.collections.MutableBidirectionalOneToOneMap; -import com.android.tools.r8.utils.collections.ProgramMethodSet; import com.google.common.collect.ImmutableList; import java.util.ArrayDeque; import java.util.ArrayList; @@ -80,12 +79,13 @@ } @Override - public void process(DexProgramClass iface, ProgramMethodSet synthesizedMethods) { + public void process( + DexProgramClass iface, InterfaceProcessingDesugaringEventConsumer eventConsumer) { if (!iface.isInterface()) { return; } analyzeBridges(iface); - ensureCompanionClassMethods(iface, synthesizedMethods); + ensureCompanionClassMethods(iface, eventConsumer); } private void analyzeBridges(DexProgramClass iface) { @@ -99,8 +99,8 @@ } private void ensureCompanionClassMethods( - DexProgramClass iface, ProgramMethodSet synthesizedMethods) { - ensureCompanionClassInitializesInterface(iface, synthesizedMethods); + 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. @@ -134,7 +134,7 @@ } private void ensureCompanionClassInitializesInterface( - DexProgramClass iface, ProgramMethodSet synthesizedMethods) { + DexProgramClass iface, InterfaceProcessingDesugaringEventConsumer eventConsumer) { if (!hasStaticMethodThatTriggersNonTrivialClassInitializer(iface)) { return; } @@ -146,7 +146,7 @@ appView.dexItemFactory().createProto(appView.dexItemFactory().voidType), appView, methodBuilder -> createCompanionClassInitializer(iface, clinitField, methodBuilder)); - synthesizedMethods.add(clinit); + eventConsumer.acceptCompanionClassClinit(clinit); } private DexEncodedField ensureStaticClinitFieldToTriggerInterfaceInitialization( @@ -441,7 +441,7 @@ } @Override - public void finalizeProcessing(ProgramMethodSet synthesizedMethods) { + public void finalizeProcessing(InterfaceProcessingDesugaringEventConsumer eventConsumer) { InterfaceProcessorNestedGraphLens graphLens = postProcessInterfaces(); if (appView.enableWholeProgramOptimizations() && graphLens != null) { appView.setGraphLens(graphLens);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/twr/TwrCloseResourceInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/twr/TwrCloseResourceInstructionDesugaring.java deleted file mode 100644 index 212259a..0000000 --- a/src/main/java/com/android/tools/r8/ir/desugar/twr/TwrCloseResourceInstructionDesugaring.java +++ /dev/null
@@ -1,95 +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.twr; - -import com.android.tools.r8.cf.code.CfInstruction; -import com.android.tools.r8.cf.code.CfInvoke; -import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext; -import com.android.tools.r8.graph.AppView; -import com.android.tools.r8.graph.DexItemFactory; -import com.android.tools.r8.graph.DexMethod; -import com.android.tools.r8.graph.DexProto; -import com.android.tools.r8.graph.MethodAccessFlags; -import com.android.tools.r8.graph.ProgramMethod; -import com.android.tools.r8.ir.desugar.CfInstructionDesugaring; -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.backports.BackportedMethods; -import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind; -import com.google.common.collect.ImmutableList; -import java.util.Collection; -import org.objectweb.asm.Opcodes; - -public class TwrCloseResourceInstructionDesugaring implements CfInstructionDesugaring { - - private final AppView<?> appView; - private final DexItemFactory dexItemFactory; - private final DexProto twrCloseResourceProto; - - public TwrCloseResourceInstructionDesugaring(AppView<?> appView) { - this.appView = appView; - this.dexItemFactory = appView.dexItemFactory(); - this.twrCloseResourceProto = - dexItemFactory.createProto( - dexItemFactory.voidType, dexItemFactory.throwableType, dexItemFactory.objectType); - } - - @Override - public Collection<CfInstruction> desugarInstruction( - CfInstruction instruction, - FreshLocalProvider freshLocalProvider, - LocalStackAllocator localStackAllocator, - CfInstructionDesugaringEventConsumer eventConsumer, - ProgramMethod context, - MethodProcessingContext methodProcessingContext, - DexItemFactory dexItemFactory) { - if (!instruction.isInvokeStatic()) { - return null; - } - - CfInvoke invoke = instruction.asInvoke(); - DexMethod invokedMethod = invoke.getMethod(); - if (!isTwrCloseResourceMethod(invokedMethod)) { - return null; - } - - // Synthesize a new method. - ProgramMethod closeMethod = createSyntheticCloseResourceMethod(methodProcessingContext); - eventConsumer.acceptTwrCloseResourceMethod(closeMethod, context); - - // Rewrite the invoke to the new synthetic. - return ImmutableList.of(new CfInvoke(Opcodes.INVOKESTATIC, closeMethod.getReference(), false)); - } - - private ProgramMethod createSyntheticCloseResourceMethod( - MethodProcessingContext methodProcessingContext) { - return appView - .getSyntheticItems() - .createMethod( - SyntheticKind.TWR_CLOSE_RESOURCE, - methodProcessingContext.createUniqueContext(), - appView, - methodBuilder -> - methodBuilder - .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic()) - .setProto(twrCloseResourceProto) - .setCode( - m -> - BackportedMethods.CloseResourceMethod_closeResourceImpl( - appView.options(), m))); - } - - @Override - public boolean needsDesugaring(CfInstruction instruction, ProgramMethod context) { - return instruction.isInvokeStatic() - && isTwrCloseResourceMethod(instruction.asInvoke().getMethod()); - } - - private boolean isTwrCloseResourceMethod(DexMethod method) { - return method.name == dexItemFactory.twrCloseResourceMethodName - && method.proto == dexItemFactory.twrCloseResourceMethodProto; - } -}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/twr/TwrInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/twr/TwrInstructionDesugaring.java new file mode 100644 index 0000000..b63846d --- /dev/null +++ b/src/main/java/com/android/tools/r8/ir/desugar/twr/TwrInstructionDesugaring.java
@@ -0,0 +1,166 @@ +// 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.twr; + +import com.android.tools.r8.cf.code.CfConstNumber; +import com.android.tools.r8.cf.code.CfInstruction; +import com.android.tools.r8.cf.code.CfInvoke; +import com.android.tools.r8.cf.code.CfNewArray; +import com.android.tools.r8.cf.code.CfStackInstruction; +import com.android.tools.r8.cf.code.CfStackInstruction.Opcode; +import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext; +import com.android.tools.r8.errors.CompilationError; +import com.android.tools.r8.graph.AppView; +import com.android.tools.r8.graph.DexClass; +import com.android.tools.r8.graph.DexItemFactory; +import com.android.tools.r8.graph.DexMethod; +import com.android.tools.r8.graph.DexProto; +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.code.ValueType; +import com.android.tools.r8.ir.desugar.CfInstructionDesugaring; +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.backports.BackportedMethods; +import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind; +import com.google.common.collect.ImmutableList; +import java.util.Collection; +import org.jetbrains.annotations.NotNull; +import org.objectweb.asm.Opcodes; + +public class TwrInstructionDesugaring implements CfInstructionDesugaring { + + private final AppView<?> appView; + private final DexItemFactory dexItemFactory; + private final DexProto twrCloseResourceProto; + private final DexMethod addSuppressed; + private final DexMethod getSuppressed; + + public TwrInstructionDesugaring(AppView<?> appView) { + this.appView = appView; + this.dexItemFactory = appView.dexItemFactory(); + this.twrCloseResourceProto = + dexItemFactory.createProto( + dexItemFactory.voidType, dexItemFactory.throwableType, dexItemFactory.objectType); + this.addSuppressed = dexItemFactory.throwableMethods.addSuppressed; + this.getSuppressed = dexItemFactory.throwableMethods.getSuppressed; + } + + @Override + public Collection<CfInstruction> desugarInstruction( + CfInstruction instruction, + FreshLocalProvider freshLocalProvider, + LocalStackAllocator localStackAllocator, + CfInstructionDesugaringEventConsumer eventConsumer, + ProgramMethod context, + MethodProcessingContext methodProcessingContext, + DexItemFactory dexItemFactory) { + if (!instruction.isInvoke()) { + return null; + } + if (isTwrCloseResourceInvoke(instruction)) { + return rewriteTwrCloseResourceInvoke(eventConsumer, context, methodProcessingContext); + } + if (isTwrSuppressedInvoke(instruction, addSuppressed)) { + return rewriteTwrAddSuppressedInvoke(); + } + if (isTwrSuppressedInvoke(instruction, getSuppressed)) { + return rewriteTwrGetSuppressedInvoke(); + } + return null; + } + + private Collection<CfInstruction> rewriteTwrAddSuppressedInvoke() { + // Remove Throwable::addSuppressed(Throwable) call. + return ImmutableList.of(new CfStackInstruction(Opcode.Pop), new CfStackInstruction(Opcode.Pop)); + } + + private Collection<CfInstruction> rewriteTwrGetSuppressedInvoke() { + // Replace call to Throwable::getSuppressed() with new Throwable[0]. + return ImmutableList.of( + new CfStackInstruction(Opcode.Pop), + new CfConstNumber(0, ValueType.INT), + new CfNewArray(dexItemFactory.createArrayType(1, dexItemFactory.throwableType))); + } + + @NotNull + private ImmutableList<CfInstruction> rewriteTwrCloseResourceInvoke( + CfInstructionDesugaringEventConsumer eventConsumer, + ProgramMethod context, + MethodProcessingContext methodProcessingContext) { + // Synthesize a new method. + ProgramMethod closeMethod = createSyntheticCloseResourceMethod(methodProcessingContext); + eventConsumer.acceptTwrCloseResourceMethod(closeMethod, context); + // Rewrite the invoke to the new synthetic. + return ImmutableList.of(new CfInvoke(Opcodes.INVOKESTATIC, closeMethod.getReference(), false)); + } + + private ProgramMethod createSyntheticCloseResourceMethod( + MethodProcessingContext methodProcessingContext) { + return appView + .getSyntheticItems() + .createMethod( + SyntheticKind.TWR_CLOSE_RESOURCE, + methodProcessingContext.createUniqueContext(), + appView, + methodBuilder -> + methodBuilder + .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic()) + .setProto(twrCloseResourceProto) + .setCode( + m -> + BackportedMethods.CloseResourceMethod_closeResourceImpl( + appView.options(), m))); + } + + @Override + public boolean needsDesugaring(CfInstruction instruction, ProgramMethod context) { + if (!instruction.isInvoke()) { + return false; + } + return isTwrCloseResourceInvoke(instruction) + || isTwrSuppressedInvoke(instruction, addSuppressed) + || isTwrSuppressedInvoke(instruction, getSuppressed); + } + + private boolean isTwrSuppressedInvoke(CfInstruction instruction, DexMethod suppressed) { + return instruction.isInvoke() + && matchesMethodOfThrowable(instruction.asInvoke().getMethod(), suppressed); + } + + private boolean matchesMethodOfThrowable(DexMethod invoked, DexMethod expected) { + return invoked.name == expected.name + && invoked.proto == expected.proto + && isSubtypeOfThrowable(invoked.holder); + } + + private boolean isSubtypeOfThrowable(DexType type) { + while (type != null && type != dexItemFactory.objectType) { + if (type == dexItemFactory.throwableType) { + return true; + } + DexClass dexClass = appView.definitionFor(type); + if (dexClass == null) { + throw new CompilationError( + "Class or interface " + + type.toSourceString() + + " required for desugaring of try-with-resources is not found."); + } + type = dexClass.superType; + } + return false; + } + + private boolean isTwrCloseResourceInvoke(CfInstruction instruction) { + return instruction.isInvokeStatic() + && isTwrCloseResourceMethod(instruction.asInvoke().getMethod()); + } + + private boolean isTwrCloseResourceMethod(DexMethod method) { + return method.name == dexItemFactory.twrCloseResourceMethodName + && method.proto == dexItemFactory.twrCloseResourceMethodProto; + } +}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java index 2a1ec57..86fb8e9 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -21,7 +21,6 @@ import com.android.tools.r8.graph.DexEncodedField; import com.android.tools.r8.graph.DexEncodedMethod; import com.android.tools.r8.graph.DexItemFactory; -import com.android.tools.r8.graph.DexItemFactory.ThrowableMethods; import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DexProgramClass; import com.android.tools.r8.graph.DexProto; @@ -3651,75 +3650,6 @@ } } - // Removes calls to Throwable.addSuppressed(Throwable) and rewrites - // Throwable.getSuppressed() into new Throwable[0]. - // - // Note that addSuppressed() and getSuppressed() methods are final in - // Throwable, so these changes don't have to worry about overrides. - public void rewriteThrowableAddAndGetSuppressed(IRCode code) { - ThrowableMethods throwableMethods = dexItemFactory.throwableMethods; - - for (BasicBlock block : code.blocks) { - InstructionListIterator iterator = block.listIterator(code); - while (iterator.hasNext()) { - Instruction current = iterator.next(); - if (current.isInvokeMethod()) { - DexMethod invokedMethod = current.asInvokeMethod().getInvokedMethod(); - if (matchesMethodOfThrowable(invokedMethod, throwableMethods.addSuppressed)) { - // Remove Throwable::addSuppressed(Throwable) call. - iterator.removeOrReplaceByDebugLocalRead(); - } else if (matchesMethodOfThrowable(invokedMethod, throwableMethods.getSuppressed)) { - Value destValue = current.outValue(); - if (destValue == null) { - // If the result of the call was not used we don't create - // an empty array and just remove the call. - iterator.removeOrReplaceByDebugLocalRead(); - continue; - } - - // Replace call to Throwable::getSuppressed() with new Throwable[0]. - - // First insert the constant value *before* the current instruction. - ConstNumber zero = code.createIntConstant(0); - zero.setPosition(current.getPosition()); - assert iterator.hasPrevious(); - iterator.previous(); - iterator.add(zero); - - // Then replace the invoke instruction with new-array instruction. - Instruction next = iterator.next(); - assert current == next; - NewArrayEmpty newArray = new NewArrayEmpty(destValue, zero.outValue(), - dexItemFactory.createType(dexItemFactory.throwableArrayDescriptor)); - iterator.replaceCurrentInstruction(newArray); - } - } - } - } - assert code.isConsistentSSA(); - } - - private boolean matchesMethodOfThrowable(DexMethod invoked, DexMethod expected) { - return invoked.name == expected.name - && invoked.proto == expected.proto - && isSubtypeOfThrowable(invoked.holder); - } - - private boolean isSubtypeOfThrowable(DexType type) { - while (type != null && type != dexItemFactory.objectType) { - if (type == dexItemFactory.throwableType) { - return true; - } - DexClass dexClass = appView.definitionFor(type); - if (dexClass == null) { - throw new CompilationError("Class or interface " + type.toSourceString() + - " required for desugaring of try-with-resources is not found."); - } - type = dexClass.superType; - } - return false; - } - private Value addConstString(IRCode code, InstructionListIterator iterator, String s) { TypeElement typeLattice = TypeElement.stringClassType(appView, definitelyNotNull()); Value value = code.createValue(typeLattice);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java index ececbe3..8c5f439 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
@@ -3,9 +3,9 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.ir.optimize; -import static com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo.isApiSafeForInlining; import static com.android.tools.r8.ir.optimize.inliner.InlinerUtils.addMonitorEnterValue; import static com.android.tools.r8.ir.optimize.inliner.InlinerUtils.collectAllMonitorEnterValues; +import static com.android.tools.r8.utils.AndroidApiLevelUtils.isApiSafeForInlining; import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.features.ClassToFeatureSplitMap; @@ -130,11 +130,9 @@ } // Do not inline if the inlinee is greater than the api caller level. - MethodOptimizationInfo callerOptimizationInfo = method.getDefinition().getOptimizationInfo(); // TODO(b/188498051): We should not force inline lower api method calls. if (reason != Reason.FORCE - && isApiSafeForInlining(callerOptimizationInfo, targetOptimizationInfo, appView.options()) - .isPossiblyFalse()) { + && isApiSafeForInlining(method, singleTarget, appView.options()).isPossiblyFalse()) { whyAreYouNotInliningReporter.reportInlineeHigherApiCall(); return false; }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java index e653838..01d23b6 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
@@ -5,6 +5,7 @@ package com.android.tools.r8.ir.optimize.classinliner; import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull; +import static com.android.tools.r8.utils.AndroidApiLevelUtils.isApiSafeForInlining; import com.android.tools.r8.errors.InternalCompilerError; import com.android.tools.r8.errors.Unreachable; @@ -879,7 +880,10 @@ if (instanceInitializerInfo.receiverMayEscapeOutsideConstructorChain()) { return null; } - + // Check the api level is allowed to be inlined. + if (isApiSafeForInlining(method, singleTarget, appView.options()).isPossiblyFalse()) { + return null; + } // Check that the entire constructor chain can be inlined into the current context. DexMethod parent = instanceInitializerInfo.getParent(); while (parent != dexItemFactory.objectMembers.constructor) { @@ -906,6 +910,10 @@ NopWhyAreYouNotInliningReporter.getInstance())) { return null; } + // Check the api level is allowed to be inlined. + if (isApiSafeForInlining(method, encodedParent, appView.options()).isPossiblyFalse()) { + return null; + } parent = encodedParentMethod .getOptimizationInfo()
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 5cbab1f..7a95765 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,6 +4,8 @@ package com.android.tools.r8.ir.optimize.enums; +import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabledForNewMember; + import com.android.tools.r8.cf.CfVersion; import com.android.tools.r8.cf.code.CfArrayStore; import com.android.tools.r8.cf.code.CfConstNumber; @@ -46,6 +48,7 @@ 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 { @@ -234,7 +237,8 @@ DexAnnotationSet.empty(), DexEncodedField.NO_STATIC_VALUE, DexEncodedField.NOT_DEPRECATED, - DexEncodedField.D8_R8_SYNTHESIZED); + DexEncodedField.D8_R8_SYNTHESIZED, + getApiLevelIfEnabledForNewMember(appView, Function.identity())); fieldAccessInfoCollectionModifierBuilder .recordFieldReadInUnknownContext(valuesField.getReference()) .recordFieldWriteInUnknownContext(valuesField.getReference()); @@ -253,7 +257,9 @@ ParameterAnnotationsList.empty(), createClassInitializerCode(sharedUtilityClassType, valuesField), DexEncodedMethod.D8_R8_SYNTHESIZED, - CfVersion.V1_6); + CfVersion.V1_6, + getApiLevelIfEnabledForNewMember(appView, Function.identity()), + getApiLevelIfEnabledForNewMember(appView, Function.identity())); } private CfCode createClassInitializerCode( @@ -298,7 +304,9 @@ ParameterAnnotationsList.empty(), createValuesMethodCode(sharedUtilityClassType, valuesField), DexEncodedMethod.D8_R8_SYNTHESIZED, - CfVersion.V1_6); + CfVersion.V1_6, + getApiLevelIfEnabledForNewMember(appView, Function.identity()), + getApiLevelIfEnabledForNewMember(appView, Function.identity())); this.valuesMethod = valuesMethod; return valuesMethod; }
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 aebd195..31ecb9b 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
@@ -42,7 +42,6 @@ static boolean UNKNOWN_RETURN_VALUE_ONLY_DEPENDS_ON_ARGUMENTS = false; static BitSet NO_NULL_PARAMETER_OR_THROW_FACTS = null; static BitSet NO_NULL_PARAMETER_ON_NORMAL_EXITS_FACTS = null; - static AndroidApiLevel UNKNOWN_API_REFERENCE_LEVEL = null; protected DefaultMethodOptimizationInfo() {}
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 30c8d7a..bb45fbc 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
@@ -4,8 +4,6 @@ package com.android.tools.r8.ir.optimize.info; -import static com.android.tools.r8.utils.OptionalBool.UNKNOWN; - import com.android.tools.r8.graph.DexType; import com.android.tools.r8.ir.analysis.inlining.SimpleInliningConstraint; import com.android.tools.r8.ir.analysis.type.ClassTypeElement; @@ -19,7 +17,6 @@ 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.android.tools.r8.utils.OptionalBool; import java.util.BitSet; import java.util.Set; @@ -108,20 +105,6 @@ public abstract AndroidApiLevel getApiReferenceLevelForCode(AndroidApiLevel minApi); - public static OptionalBool isApiSafeForInlining( - MethodOptimizationInfo caller, MethodOptimizationInfo inlinee, InternalOptions options) { - if (!options.apiModelingOptions().enableApiCallerIdentification) { - return OptionalBool.TRUE; - } - if (!caller.hasApiReferenceLevelForCode() || !inlinee.hasApiReferenceLevelForCode()) { - return UNKNOWN; - } - return OptionalBool.of( - caller - .getApiReferenceLevelForCode(options.minApiLevel) - .isGreaterThanOrEqualTo(inlinee.getApiReferenceLevelForCode(options.minApiLevel))); - } - @Override public boolean isMethodOptimizationInfo() { return true;
diff --git a/src/main/java/com/android/tools/r8/kotlin/Kotlin.java b/src/main/java/com/android/tools/r8/kotlin/Kotlin.java index ef44b4b..2bbd2b3 100644 --- a/src/main/java/com/android/tools/r8/kotlin/Kotlin.java +++ b/src/main/java/com/android/tools/r8/kotlin/Kotlin.java
@@ -28,6 +28,8 @@ public static final String NAME = "kotlin"; public static final String PACKAGE_PREFIX = "L" + NAME + "/"; + public final DexString kotlinJvmTypePrefix; + public static final class ClassClassifiers { public static final String arrayBinaryName = NAME + "/Array"; @@ -41,6 +43,7 @@ this.intrinsics = new Intrinsics(); this.metadata = new Metadata(); this.assertions = new _Assertions(); + kotlinJvmTypePrefix = factory.createString("Lkotlin/jvm/"); } public final class Functional { @@ -67,10 +70,6 @@ private Functional() { } - public final DexString kotlinStyleLambdaInstanceName = factory.createString("INSTANCE"); - - public final DexType functionBase = - factory.createType(PACKAGE_PREFIX + "jvm/internal/FunctionBase;"); public final DexType lambdaType = factory.createType(PACKAGE_PREFIX + "jvm/internal/Lambda;"); public final DexMethod lambdaInitializerMethod = factory.createMethod(
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 883be66..373a5d2 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationArgumentInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationArgumentInfo.java
@@ -29,10 +29,10 @@ ImmutableMap.of(); abstract boolean rewrite( - Consumer<KmAnnotationArgument<?>> consumer, AppView<?> appView, NamingLens namingLens); + Consumer<KmAnnotationArgument> consumer, AppView<?> appView, NamingLens namingLens); private static KotlinAnnotationArgumentInfo createArgument( - KmAnnotationArgument<?> arg, DexItemFactory factory) { + KmAnnotationArgument arg, DexItemFactory factory) { if (arg instanceof KClassValue) { return KotlinAnnotationClassValueInfo.create((KClassValue) arg, factory); } else if (arg instanceof EnumValue) { @@ -47,7 +47,7 @@ } static Map<String, KotlinAnnotationArgumentInfo> create( - Map<String, KmAnnotationArgument<?>> arguments, DexItemFactory factory) { + Map<String, KmAnnotationArgument> arguments, DexItemFactory factory) { if (arguments.isEmpty()) { return EMPTY_ARGUMENTS; } @@ -59,14 +59,17 @@ private static class KotlinAnnotationClassValueInfo extends KotlinAnnotationArgumentInfo { private final KotlinTypeReference value; + private final int arrayDimensionCount; - private KotlinAnnotationClassValueInfo(KotlinTypeReference value) { + private KotlinAnnotationClassValueInfo(KotlinTypeReference value, int arrayDimensionCount) { this.value = value; + this.arrayDimensionCount = arrayDimensionCount; } private static KotlinAnnotationClassValueInfo create(KClassValue arg, DexItemFactory factory) { return new KotlinAnnotationClassValueInfo( - KotlinTypeReference.fromBinaryName(arg.getValue(), factory)); + KotlinTypeReference.fromBinaryName(arg.getClassName(), factory), + arg.getArrayDimensionCount()); } @Override @@ -76,9 +79,9 @@ @Override boolean rewrite( - Consumer<KmAnnotationArgument<?>> consumer, AppView<?> appView, NamingLens namingLens) { + Consumer<KmAnnotationArgument> consumer, AppView<?> appView, NamingLens namingLens) { return value.toRenamedBinaryNameOrDefault( - rewrittenValue -> consumer.accept(new KClassValue(rewrittenValue)), + rewrittenValue -> consumer.accept(new KClassValue(rewrittenValue, arrayDimensionCount)), appView, namingLens, ClassClassifiers.anyName); @@ -108,7 +111,7 @@ @Override boolean rewrite( - Consumer<KmAnnotationArgument<?>> consumer, AppView<?> appView, NamingLens namingLens) { + Consumer<KmAnnotationArgument> consumer, AppView<?> appView, NamingLens namingLens) { return enumClassName.toRenamedBinaryNameOrDefault( rewrittenEnumClassName -> consumer.accept(new EnumValue(rewrittenEnumClassName, enumEntryName)), @@ -129,7 +132,7 @@ private static KotlinAnnotationAnnotationValueInfo create( AnnotationValue arg, DexItemFactory factory) { return new KotlinAnnotationAnnotationValueInfo( - KotlinAnnotationInfo.create(arg.getValue(), factory)); + KotlinAnnotationInfo.create(arg.getAnnotation(), factory)); } @Override @@ -139,7 +142,7 @@ @Override boolean rewrite( - Consumer<KmAnnotationArgument<?>> consumer, AppView<?> appView, NamingLens namingLens) { + Consumer<KmAnnotationArgument> consumer, AppView<?> appView, NamingLens namingLens) { return value.rewrite( rewrittenAnnotation -> { if (rewrittenAnnotation != null) { @@ -163,11 +166,11 @@ } private static KotlinAnnotationArrayValueInfo create(ArrayValue arg, DexItemFactory factory) { - if (arg.getValue().isEmpty()) { + if (arg.getElements().isEmpty()) { return EMPTY; } ImmutableList.Builder<KotlinAnnotationArgumentInfo> builder = ImmutableList.builder(); - for (KmAnnotationArgument<?> argument : arg.getValue()) { + for (KmAnnotationArgument argument : arg.getElements()) { builder.add(createArgument(argument, factory)); } return new KotlinAnnotationArrayValueInfo(builder.build()); @@ -182,8 +185,8 @@ @Override boolean rewrite( - Consumer<KmAnnotationArgument<?>> consumer, AppView<?> appView, NamingLens namingLens) { - List<KmAnnotationArgument<?>> rewrittenArguments = new ArrayList<>(); + Consumer<KmAnnotationArgument> consumer, AppView<?> appView, NamingLens namingLens) { + List<KmAnnotationArgument> rewrittenArguments = new ArrayList<>(); boolean rewritten = false; for (KotlinAnnotationArgumentInfo kotlinAnnotationArgumentInfo : value) { rewritten |= @@ -203,13 +206,13 @@ private static class KotlinAnnotationPrimitiveArgumentInfo extends KotlinAnnotationArgumentInfo { - private final KmAnnotationArgument<?> argument; + private final KmAnnotationArgument argument; - private KotlinAnnotationPrimitiveArgumentInfo(KmAnnotationArgument<?> argument) { + private KotlinAnnotationPrimitiveArgumentInfo(KmAnnotationArgument argument) { this.argument = argument; } - private static KotlinAnnotationPrimitiveArgumentInfo create(KmAnnotationArgument<?> argument) { + private static KotlinAnnotationPrimitiveArgumentInfo create(KmAnnotationArgument argument) { return new KotlinAnnotationPrimitiveArgumentInfo(argument); } @@ -220,7 +223,7 @@ @Override boolean rewrite( - Consumer<KmAnnotationArgument<?>> consumer, AppView<?> appView, NamingLens namingLens) { + Consumer<KmAnnotationArgument> consumer, AppView<?> appView, NamingLens namingLens) { consumer.accept(argument); return false; }
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 fd036d8..cbdd76e 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationInfo.java
@@ -63,7 +63,7 @@ return; } String classifier = DescriptorUtils.descriptorToKotlinClassifier(renamedDescriptor); - Map<String, KmAnnotationArgument<?>> rewrittenArguments = new LinkedHashMap<>(); + Map<String, KmAnnotationArgument> rewrittenArguments = new LinkedHashMap<>(); arguments.forEach( (key, arg) -> rewritten.or(
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 08236e2..aa3731f 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java
@@ -52,6 +52,11 @@ private final String packageName; private final KotlinLocalDelegatedPropertyInfo localDelegatedProperties; private final int[] metadataVersion; + private final String inlineClassUnderlyingPropertyName; + private final KotlinTypeInfo inlineClassUnderlyingType; + + // List of tracked assignments of kotlin metadata. + private final KotlinMetadataMembersTracker originalMembersWithKotlinInfo; private KotlinClassInfo( int flags, @@ -69,7 +74,10 @@ KotlinTypeReference anonymousObjectOrigin, String packageName, KotlinLocalDelegatedPropertyInfo localDelegatedProperties, - int[] metadataVersion) { + int[] metadataVersion, + String inlineClassUnderlyingPropertyName, + KotlinTypeInfo inlineClassUnderlyingType, + KotlinMetadataMembersTracker originalMembersWithKotlinInfo) { this.flags = flags; this.name = name; this.nameCanBeSynthesizedFromClassOrAnonymousObjectOrigin = @@ -87,6 +95,9 @@ this.packageName = packageName; this.localDelegatedProperties = localDelegatedProperties; this.metadataVersion = metadataVersion; + this.inlineClassUnderlyingPropertyName = inlineClassUnderlyingPropertyName; + this.inlineClassUnderlyingType = inlineClassUnderlyingType; + this.originalMembersWithKotlinInfo = originalMembersWithKotlinInfo; } public static KotlinClassInfo create( @@ -112,6 +123,8 @@ } ImmutableList.Builder<KotlinConstructorInfo> notBackedConstructors = ImmutableList.builder(); int constructorIndex = 0; + KotlinMetadataMembersTracker originalMembersWithKotlinInfo = + new KotlinMetadataMembersTracker(appView); for (KmConstructor kmConstructor : kmClass.getConstructors()) { boolean readConstructorSignature = extensionInformation.hasJvmMethodSignatureExtensionForConstructor(constructorIndex++); @@ -122,6 +135,7 @@ DexEncodedMethod method = methodMap.get(signature.asString()); if (method != null) { method.setKotlinMemberInfo(constructorInfo); + originalMembersWithKotlinInfo.add(method.getReference()); continue; } } @@ -130,7 +144,14 @@ } KotlinDeclarationContainerInfo container = KotlinDeclarationContainerInfo.create( - kmClass, methodMap, fieldMap, factory, reporter, keepByteCode, extensionInformation); + kmClass, + methodMap, + fieldMap, + factory, + reporter, + keepByteCode, + extensionInformation, + originalMembersWithKotlinInfo); setCompanionObject(kmClass, hostClass, reporter); KotlinTypeReference anonymousObjectOrigin = getAnonymousObjectOrigin(kmClass, factory); boolean nameCanBeDeducedFromClassOrOrigin = @@ -156,7 +177,10 @@ packageName, KotlinLocalDelegatedPropertyInfo.create( JvmExtensionsKt.getLocalDelegatedProperties(kmClass), factory, reporter), - metadataVersion); + metadataVersion, + kmClass.getInlineClassUnderlyingPropertyName(), + KotlinTypeInfo.create(kmClass.getInlineClassUnderlyingType(), factory, reporter), + originalMembersWithKotlinInfo); } private static KotlinTypeReference getAnonymousObjectOrigin( @@ -269,10 +293,12 @@ rewritten |= constructorInfo.rewrite(kmClass, null, appView, namingLens); } // Find all constructors. + KotlinMetadataMembersTracker rewrittenReferences = new KotlinMetadataMembersTracker(appView); for (DexEncodedMethod method : clazz.methods()) { if (method.getKotlinInfo().isConstructor()) { KotlinConstructorInfo constructorInfo = method.getKotlinInfo().asConstructor(); rewritten |= constructorInfo.rewrite(kmClass, method, appView, namingLens); + rewrittenReferences.add(method.getReference()); } } // Rewrite functions, type-aliases and type-parameters. @@ -283,7 +309,8 @@ kmClass::visitTypeAlias, clazz, appView, - namingLens); + namingLens, + rewrittenReferences); // Rewrite type parameters. for (KotlinTypeParameterInfo typeParameter : typeParameters) { rewritten |= typeParameter.rewrite(kmClass::visitTypeParameter, appView, namingLens); @@ -334,6 +361,12 @@ // TODO(b/154347404): Understand enum entries. kmClass.getEnumEntries().addAll(enumEntries); rewritten |= versionRequirements.rewrite(kmClass::visitVersionRequirement); + if (inlineClassUnderlyingPropertyName != null && inlineClassUnderlyingType != null) { + kmClass.setInlineClassUnderlyingPropertyName(inlineClassUnderlyingPropertyName); + rewritten |= + inlineClassUnderlyingType.rewrite( + kmClass::visitInlineClassUnderlyingType, appView, namingLens); + } JvmClassExtensionVisitor extensionVisitor = (JvmClassExtensionVisitor) kmClass.visitExtensions(JvmClassExtensionVisitor.TYPE); extensionVisitor.visitModuleName(moduleName); @@ -355,7 +388,9 @@ extensionVisitor.visitEnd(); KotlinClassMetadata.Class.Writer writer = new KotlinClassMetadata.Class.Writer(); kmClass.accept(writer); - return Pair.create(writer.write().getHeader(), rewritten); + return Pair.create( + writer.write().getHeader(), + rewritten || !originalMembersWithKotlinInfo.isEqual(rewrittenReferences, appView)); } @Override
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java index 1b928d9..d166380 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java
@@ -56,7 +56,8 @@ DexItemFactory factory, Reporter reporter, Consumer<DexEncodedMethod> keepByteCode, - KotlinJvmSignatureExtensionInformation extensionInformation) { + KotlinJvmSignatureExtensionInformation extensionInformation, + KotlinMetadataMembersTracker originalAssignmentTracker) { ImmutableList.Builder<KotlinFunctionInfo> notBackedFunctions = ImmutableList.builder(); int functionCounter = 0; for (KmFunction kmFunction : container.getFunctions()) { @@ -88,6 +89,7 @@ } keepIfInline(kmFunction.getFlags(), method, keepByteCode); method.setKotlinMemberInfo(kotlinFunctionInfo); + originalAssignmentTracker.add(method.getReference()); } ImmutableList.Builder<KotlinPropertyInfo> notBackedProperties = ImmutableList.builder(); @@ -102,6 +104,7 @@ if (field != null) { hasBacking = true; field.setKotlinMemberInfo(kotlinPropertyInfo); + originalAssignmentTracker.add(field.getReference()); } } if (propertyProcessor.getterSignature() != null) { @@ -111,6 +114,7 @@ hasBacking = true; keepIfAccessorInline(kmProperty.getGetterFlags(), method, keepByteCode); method.setKotlinMemberInfo(kotlinPropertyInfo); + originalAssignmentTracker.add(method.getReference()); } } if (propertyProcessor.setterSignature() != null) { @@ -120,6 +124,7 @@ hasBacking = true; keepIfAccessorInline(kmProperty.getGetterFlags(), method, keepByteCode); method.setKotlinMemberInfo(kotlinPropertyInfo); + originalAssignmentTracker.add(method.getReference()); } } if (!hasBacking) { @@ -161,7 +166,8 @@ KmVisitorProviders.KmTypeAliasVisitorProvider typeAliasProvider, DexClass clazz, AppView<?> appView, - NamingLens namingLens) { + NamingLens namingLens, + KotlinMetadataMembersTracker rewrittenMembersWithKotlinInfo) { // Type aliases only have a representation here, so we can generate them directly. boolean rewritten = false; for (KotlinTypeAliasInfo typeAlias : typeAliases) { @@ -175,6 +181,7 @@ .computeIfAbsent( field.getKotlinInfo().asProperty(), ignored -> new KotlinPropertyGroup()) .setBackingField(field); + rewrittenMembersWithKotlinInfo.add(field.getReference()); } } for (DexEncodedMethod method : clazz.methods()) { @@ -184,12 +191,14 @@ .getKotlinInfo() .asFunction() .rewrite(functionProvider, method, appView, namingLens); + rewrittenMembersWithKotlinInfo.add(method.getReference()); continue; } KotlinPropertyInfo kotlinPropertyInfo = method.getKotlinInfo().asProperty(); if (kotlinPropertyInfo == null) { continue; } + rewrittenMembersWithKotlinInfo.add(method.getReference()); KotlinPropertyGroup kotlinPropertyGroup = properties.computeIfAbsent(kotlinPropertyInfo, ignored -> new KotlinPropertyGroup()); if (method.getReference().proto.returnType == appView.dexItemFactory().voidType) {
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataMembersTracker.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataMembersTracker.java new file mode 100644 index 0000000..88691a9 --- /dev/null +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataMembersTracker.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.kotlin; + +import com.android.tools.r8.graph.AppView; +import com.android.tools.r8.graph.DexMember; +import com.android.tools.r8.graph.DexReference; +import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.utils.IterableUtils; +import com.google.common.collect.Sets; +import com.google.common.collect.Sets.SetView; +import java.util.Set; + +public class KotlinMetadataMembersTracker { + + private int count; + // Only used for asserting equality during local testing. + private final Set<DexMember<?, ?>> references; + + public KotlinMetadataMembersTracker(AppView<?> appView) { + references = appView.options().testing.enableTestAssertions ? Sets.newIdentityHashSet() : null; + } + + public void add(DexMember<?, ?> reference) { + count += 1; + if (references != null) { + references.add(reference); + } + } + + public boolean isEqual(KotlinMetadataMembersTracker tracker, AppView<?> appView) { + if (count != tracker.count) { + return false; + } + if (references != null) { + assert tracker.references != null; + assert references.size() == tracker.references.size(); + SetView<DexMember<?, ?>> diffComparedToRewritten = + Sets.difference(references, tracker.references); + if (!diffComparedToRewritten.isEmpty()) { + SetView<DexMember<?, ?>> diffComparedToOriginal = + Sets.difference(tracker.references, references); + // Known kotlin types may not exist directly in the way they are annotated in the metadata. + // As an example kotlin.Function2 exists in the metadata but the concrete type is + // kotlin.jvm.functions.Function2. As a result we may not rewrite metadata but the + // underlying types are changed. + diffComparedToRewritten.forEach( + diff -> { + DexReference rewrittenReference = appView.graphLens().lookupReference(diff); + assert diffComparedToOriginal.contains(rewrittenReference); + assert IterableUtils.findOrDefault( + diff.getReferencedTypes(), type -> isKotlinJvmType(appView, type), null) + != null; + }); + } + } + return true; + } + + private boolean isKotlinJvmType(AppView<?> appView, DexType type) { + return type.descriptor.startsWith(appView.dexItemFactory().kotlin.kotlinJvmTypePrefix); + } +}
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 a094a88..0ff0070 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
@@ -160,7 +160,8 @@ try { Pair<KotlinClassHeader, Boolean> kotlinClassHeader = kotlinInfo.rewrite(clazz, appView, lens); // TODO(b/185756596): Remove when special handling is no longer needed. - if (!kotlinClassHeader.getSecond() && !appView.enableWholeProgramOptimizations()) { + if (!kotlinClassHeader.getSecond() + && appView.options().testing.keepMetadataInR8IfNotRewritten) { // No rewrite occurred and the data is the same as before. assert appView.checkForTesting( () ->
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataWriter.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataWriter.java index fbfb3bb..ee9ea2c 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataWriter.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataWriter.java
@@ -325,6 +325,22 @@ appendKmType(nextIndent, sb, kmType); }); }); + if (kmClass.getInlineClassUnderlyingPropertyName() != null) { + appendKeyValue( + indent, + "inlineClassUnderlyingPropertyName", + sb, + kmClass.getInlineClassUnderlyingPropertyName()); + } + if (kmClass.getInlineClassUnderlyingType() != null) { + appendKeyValue( + indent, + "inlineClassUnderlyingType", + sb, + nextIndent -> { + appendKmType(nextIndent, sb, kmClass.getInlineClassUnderlyingType()); + }); + } String companionObject = kmClass.getCompanionObject(); appendKeyValue( indent, "enumEntries", sb, "[" + StringUtils.join(",", kmClass.getEnumEntries()) + "]"); @@ -769,7 +785,7 @@ "arguments", sb, nextIndent -> { - Map<String, KmAnnotationArgument<?>> arguments = kmAnnotation.getArguments(); + Map<String, KmAnnotationArgument> arguments = kmAnnotation.getArguments(); appendKmList( nextIndent, "{ key: String, value: KmAnnotationArgument<?> }", @@ -795,9 +811,9 @@ } private static void appendKmArgument( - String indent, StringBuilder sb, KmAnnotationArgument<?> annotationArgument) { + String indent, StringBuilder sb, KmAnnotationArgument annotationArgument) { if (annotationArgument instanceof KmAnnotationArgument.ArrayValue) { - List<KmAnnotationArgument<?>> value = ((ArrayValue) annotationArgument).getValue(); + List<KmAnnotationArgument> value = ((ArrayValue) annotationArgument).getElements(); appendKmList( indent, "ArrayValue",
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinPackageInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinPackageInfo.java index d28e7c3..fa483ae 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinPackageInfo.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinPackageInfo.java
@@ -27,14 +27,17 @@ private final String moduleName; private final KotlinDeclarationContainerInfo containerInfo; private final KotlinLocalDelegatedPropertyInfo localDelegatedProperties; + private final KotlinMetadataMembersTracker originalMembersWithKotlinInfo; private KotlinPackageInfo( String moduleName, KotlinDeclarationContainerInfo containerInfo, - KotlinLocalDelegatedPropertyInfo localDelegatedProperties) { + KotlinLocalDelegatedPropertyInfo localDelegatedProperties, + KotlinMetadataMembersTracker originalMembersWithKotlinInfo) { this.moduleName = moduleName; this.containerInfo = containerInfo; this.localDelegatedProperties = localDelegatedProperties; + this.originalMembersWithKotlinInfo = originalMembersWithKotlinInfo; } public static KotlinPackageInfo create( @@ -51,6 +54,8 @@ for (DexEncodedMethod method : clazz.methods()) { methodMap.put(toJvmMethodSignature(method.getReference()).asString(), method); } + KotlinMetadataMembersTracker originalMembersWithKotlinInfo = + new KotlinMetadataMembersTracker(appView); return new KotlinPackageInfo( JvmExtensionsKt.getModuleName(kmPackage), KotlinDeclarationContainerInfo.create( @@ -60,14 +65,17 @@ appView.dexItemFactory(), appView.reporter(), keepByteCode, - extensionInformation), + extensionInformation, + originalMembersWithKotlinInfo), KotlinLocalDelegatedPropertyInfo.create( JvmExtensionsKt.getLocalDelegatedProperties(kmPackage), appView.dexItemFactory(), - appView.reporter())); + appView.reporter()), + originalMembersWithKotlinInfo); } boolean rewrite(KmPackage kmPackage, DexClass clazz, AppView<?> appView, NamingLens namingLens) { + KotlinMetadataMembersTracker rewrittenReferences = new KotlinMetadataMembersTracker(appView); boolean rewritten = containerInfo.rewrite( kmPackage::visitFunction, @@ -75,7 +83,8 @@ kmPackage::visitTypeAlias, clazz, appView, - namingLens); + namingLens, + rewrittenReferences); JvmPackageExtensionVisitor extensionVisitor = (JvmPackageExtensionVisitor) kmPackage.visitExtensions(JvmPackageExtensionVisitor.TYPE); rewritten |= @@ -83,7 +92,7 @@ extensionVisitor::visitLocalDelegatedProperty, appView, namingLens); extensionVisitor.visitModuleName(moduleName); extensionVisitor.visitEnd(); - return rewritten; + return rewritten || !originalMembersWithKotlinInfo.isEqual(rewrittenReferences, appView); } @Override
diff --git a/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java b/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java index b719c89..bc285b7 100644 --- a/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java +++ b/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java
@@ -42,7 +42,9 @@ throws ExecutionException { // Rewrite signature annotations for applications that are minified or if we have liveness // information, since we could have pruned types. - if (namingLens.isIdentityLens() && !appView.appInfo().hasLiveness()) { + if (namingLens.isIdentityLens() + && !appView.appInfo().hasLiveness() + && !appView.options().parseSignatureAttribute()) { return; } // Classes may not be the same as appInfo().classes() if applymapping is used on classpath
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 e8d52aa..3d76d73 100644 --- a/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java +++ b/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java
@@ -5,6 +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 com.android.tools.r8.dex.Constants; import com.android.tools.r8.errors.Unreachable; @@ -21,6 +22,7 @@ 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 { @@ -82,7 +84,6 @@ | Constants.ACC_PUBLIC | Constants.ACC_STATIC); boolean deprecated = false; - boolean d8R8Synthesized = true; encodedClinitField = new DexEncodedField( appView.dexItemFactory().createField(clazz.type, clinitField.type, clinitField.name), @@ -91,7 +92,8 @@ DexAnnotationSet.empty(), null, deprecated, - d8R8Synthesized); + DexEncodedField.D8_R8_SYNTHESIZED, + getApiLevelIfEnabledForNewMember(appView, Function.identity())); clazz.appendStaticField(encodedClinitField); } lensBuilder.map(type, encodedClinitField.getReference());
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java index 822a7dc..645d5b9 100644 --- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java +++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -116,6 +116,7 @@ import com.android.tools.r8.shaking.EnqueuerEvent.ClassEnqueuerEvent; import com.android.tools.r8.shaking.EnqueuerEvent.InstantiatedClassEnqueuerEvent; import com.android.tools.r8.shaking.EnqueuerEvent.LiveClassEnqueuerEvent; +import com.android.tools.r8.shaking.EnqueuerEvent.UnconditionalKeepInfoEvent; import com.android.tools.r8.shaking.EnqueuerWorklist.EnqueuerAction; import com.android.tools.r8.shaking.GraphReporter.KeepReasonWitness; import com.android.tools.r8.shaking.KeepInfoCollection.MutableKeepInfoCollection; @@ -387,18 +388,6 @@ private final MutableKeepInfoCollection keepInfo = new MutableKeepInfoCollection(); /** - * The minimum keep info for classes, fields, and methods. The minimum keep info for a program - * item should be applied to the {@link KeepInfo} of that item when the item becomes live. - */ - private final Map<DexProgramClass, KeepClassInfo.Joiner> minimumKeepClassInfo = - new IdentityHashMap<>(); - - private final ProgramFieldMap<KeepFieldInfo.Joiner> minimumKeepFieldInfo = - ProgramFieldMap.create(); - private final ProgramMethodMap<KeepMethodInfo.Joiner> minimumKeepMethodInfo = - ProgramMethodMap.create(); - - /** * Conditional minimum keep info for classes, fields, and methods, which should only be applied if * the outermost {@link EnqueuerEvent} is triggered during tracing (e.g., class X becomes live). */ @@ -2290,9 +2279,9 @@ } } - private void shouldNotBeMinified(DexReference reference) { + private void shouldNotBeMinified(ProgramDefinition definition) { if (options.isMinificationEnabled()) { - rootSet.shouldNotBeMinified(reference); + rootSet.shouldNotBeMinified(definition); } } @@ -2300,17 +2289,17 @@ KeepReasonWitness keepReasonWitness = graphReporter.registerClass(clazz, keepReason); markClassAsInstantiatedWithCompatRule(clazz.asProgramClass(), () -> keepReasonWitness); keepInfo.keepClass(clazz); - shouldNotBeMinified(clazz.getReference()); + shouldNotBeMinified(clazz); clazz.forEachProgramField( field -> { keepInfo.keepField(field); - shouldNotBeMinified(field.getReference()); + shouldNotBeMinified(field); markFieldAsKept(field, keepReasonWitness); }); clazz.forEachProgramMethod( method -> { keepInfo.keepMethod(method); - shouldNotBeMinified(method.getReference()); + shouldNotBeMinified(method); markMethodAsKept(method, keepReasonWitness); }); } @@ -2763,6 +2752,8 @@ } traceFieldDefinition(field); + + analyses.forEach(analysis -> analysis.notifyMarkFieldAsReachable(field)); } private void traceFieldDefinition(ProgramField field) { @@ -2836,7 +2827,7 @@ } public boolean isPreconditionForMinimumKeepInfoSatisfied(EnqueuerEvent preconditionEvent) { - if (preconditionEvent == null) { + if (preconditionEvent == null || preconditionEvent.isUnconditionalKeepInfoEvent()) { return true; } if (preconditionEvent.isClassEvent()) { @@ -2979,12 +2970,10 @@ private void markVirtualDispatchTargetAsLive( LookupTarget target, Function<ProgramMethod, KeepReasonWitness> reason) { - if (target.isMethodTarget()) { - markVirtualDispatchTargetAsLive(target.asMethodTarget(), reason); - } else { - assert target.isLambdaTarget(); - markVirtualDispatchTargetAsLive(target.asLambdaTarget(), reason); - } + target.accept( + method -> markVirtualDispatchTargetAsLive(method, reason), + lambda -> markVirtualDispatchTargetAsLive(lambda, reason)); + analyses.forEach(analysis -> analysis.notifyMarkVirtualDispatchTargetAsLive(target)); } private void markVirtualDispatchTargetAsLive( @@ -3039,7 +3028,7 @@ // marking for not renaming it is in the root set. workList.enqueueMarkMethodKeptAction(valuesMethod, reason); keepInfo.joinMethod(valuesMethod, joiner -> joiner.pin().disallowMinification()); - shouldNotBeMinified(valuesMethod.getReference()); + shouldNotBeMinified(valuesMethod); } } @@ -3187,9 +3176,13 @@ } private void applyMinimumKeepInfo(DexProgramClass clazz) { - KeepClassInfo.Joiner minimumKeepInfoForClass = minimumKeepClassInfo.remove(clazz); - if (minimumKeepInfoForClass != null) { - keepInfo.joinClass(clazz, info -> info.merge(minimumKeepInfoForClass)); + Map<DexProgramClass, KeepClassInfo.Joiner> minimumKeepClassInfo = + dependentMinimumKeepClassInfo.get(UnconditionalKeepInfoEvent.get()); + if (minimumKeepClassInfo != null) { + KeepClassInfo.Joiner minimumKeepInfoForClass = minimumKeepClassInfo.remove(clazz); + if (minimumKeepInfoForClass != null) { + keepInfo.joinClass(clazz, info -> info.merge(minimumKeepInfoForClass)); + } } } @@ -3198,7 +3191,8 @@ if (liveTypes.contains(clazz)) { keepInfo.joinClass(clazz, info -> info.merge(minimumKeepInfo)); } else { - minimumKeepClassInfo + dependentMinimumKeepClassInfo + .computeIfAbsent(UnconditionalKeepInfoEvent.get(), ignoreKey(IdentityHashMap::new)) .computeIfAbsent(clazz, ignoreKey(KeepClassInfo::newEmptyJoiner)) .merge(minimumKeepInfo); } @@ -3219,9 +3213,13 @@ } private void applyMinimumKeepInfo(ProgramField field) { - KeepFieldInfo.Joiner minimumKeepInfoForField = minimumKeepFieldInfo.remove(field); - if (minimumKeepInfoForField != null) { - keepInfo.joinField(field, info -> info.merge(minimumKeepInfoForField)); + ProgramFieldMap<KeepFieldInfo.Joiner> minimumKeepFieldInfo = + dependentMinimumKeepFieldInfo.get(UnconditionalKeepInfoEvent.get()); + if (minimumKeepFieldInfo != null) { + KeepFieldInfo.Joiner minimumKeepInfoForField = minimumKeepFieldInfo.remove(field); + if (minimumKeepInfoForField != null) { + keepInfo.joinField(field, info -> info.merge(minimumKeepInfoForField)); + } } } @@ -3230,7 +3228,8 @@ if (liveFields.contains(field)) { keepInfo.joinField(field, info -> info.merge(minimumKeepInfo)); } else { - minimumKeepFieldInfo + dependentMinimumKeepFieldInfo + .computeIfAbsent(UnconditionalKeepInfoEvent.get(), ignoreKey(ProgramFieldMap::create)) .computeIfAbsent(field, ignoreKey(KeepFieldInfo::newEmptyJoiner)) .merge(minimumKeepInfo); } @@ -3249,9 +3248,13 @@ } private void applyMinimumKeepInfo(ProgramMethod method) { - KeepMethodInfo.Joiner minimumKeepInfoForMethod = minimumKeepMethodInfo.remove(method); - if (minimumKeepInfoForMethod != null) { - keepInfo.joinMethod(method, info -> info.merge(minimumKeepInfoForMethod)); + ProgramMethodMap<KeepMethodInfo.Joiner> minimumKeepMethodInfo = + dependentMinimumKeepMethodInfo.get(UnconditionalKeepInfoEvent.get()); + if (minimumKeepMethodInfo != null) { + KeepMethodInfo.Joiner minimumKeepInfoForMethod = minimumKeepMethodInfo.remove(method); + if (minimumKeepInfoForMethod != null) { + keepInfo.joinMethod(method, info -> info.merge(minimumKeepInfoForMethod)); + } } } @@ -3260,7 +3263,8 @@ if (liveMethods.contains(method) || targetedMethods.contains(method)) { keepInfo.joinMethod(method, info -> info.merge(minimumKeepInfo)); } else { - minimumKeepMethodInfo + dependentMinimumKeepMethodInfo + .computeIfAbsent(UnconditionalKeepInfoEvent.get(), ignoreKey(ProgramMethodMap::create)) .computeIfAbsent(method, ignoreKey(KeepMethodInfo::newEmptyJoiner)) .merge(minimumKeepInfo); } @@ -3886,14 +3890,14 @@ } } - private void postProcessingDesugaring() { + private void postProcessingDesugaring() throws ExecutionException { SyntheticAdditions syntheticAdditions = new SyntheticAdditions(appView.createProcessorContext()); R8PostProcessingDesugaringEventConsumer eventConsumer = CfPostProcessingDesugaringEventConsumer.createForR8(appView, syntheticAdditions); - CfPostProcessingDesugaringCollection.create(appView, desugaring.getRetargetingInfo()) - .postProcessingDesugaring(eventConsumer); + CfPostProcessingDesugaringCollection.create(appView, null, desugaring.getRetargetingInfo()) + .postProcessingDesugaring(eventConsumer, executorService); if (syntheticAdditions.isEmpty()) { return; @@ -4189,6 +4193,7 @@ markMethodAsLiveWithCompatRule(method); } } + analyses.forEach(analysis -> analysis.notifyMarkMethodAsTargeted(method)); } void traceMethodDefinitionExcludingCode(ProgramMethod method) {
diff --git a/src/main/java/com/android/tools/r8/shaking/EnqueuerEvent.java b/src/main/java/com/android/tools/r8/shaking/EnqueuerEvent.java index 6f68a59..ba7ee40 100644 --- a/src/main/java/com/android/tools/r8/shaking/EnqueuerEvent.java +++ b/src/main/java/com/android/tools/r8/shaking/EnqueuerEvent.java
@@ -33,6 +33,10 @@ return null; } + public boolean isUnconditionalKeepInfoEvent() { + return false; + } + public abstract static class ClassEnqueuerEvent extends EnqueuerEvent { private final DexType clazz; @@ -123,4 +127,20 @@ return (getType().hashCode() << 1) | 1; } } + + public static class UnconditionalKeepInfoEvent extends EnqueuerEvent { + + private static final UnconditionalKeepInfoEvent INSTANCE = new UnconditionalKeepInfoEvent(); + + private UnconditionalKeepInfoEvent() {} + + public static UnconditionalKeepInfoEvent get() { + return INSTANCE; + } + + @Override + public boolean isUnconditionalKeepInfoEvent() { + return true; + } + } }
diff --git a/src/main/java/com/android/tools/r8/shaking/L8TreePruner.java b/src/main/java/com/android/tools/r8/shaking/L8TreePruner.java index 8e5e7a3..57f27cf 100644 --- a/src/main/java/com/android/tools/r8/shaking/L8TreePruner.java +++ b/src/main/java/com/android/tools/r8/shaking/L8TreePruner.java
@@ -42,15 +42,22 @@ typeMap.put(aClass.type, aClass); } List<DexProgramClass> toKeep = new ArrayList<>(); + boolean pruneNestMember = false; for (DexProgramClass aClass : app.classes()) { if (rewritePrefix.hasRewrittenType(aClass.type, null) || emulatedInterfaces.contains(aClass.type) || interfaceImplementsEmulatedInterface(aClass, typeMap)) { toKeep.add(aClass); } else { + pruneNestMember |= aClass.isInANest(); pruned.add(aClass.type); } } + if (pruneNestMember) { + for (DexProgramClass keptClass : toKeep) { + TreePruner.rewriteNestAttributes(keptClass, type -> !pruned.contains(type), typeMap::get); + } + } typeMap.clear(); // TODO(b/134732760): Would be nice to add pruned type to the appView removedClasses instead // of just doing nothing with it.
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java index 28094a1..03e9de3 100644 --- a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java +++ b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
@@ -36,6 +36,7 @@ import com.android.tools.r8.graph.DexType; import com.android.tools.r8.graph.DirectMappedDexApplication; import com.android.tools.r8.graph.GraphLens; +import com.android.tools.r8.graph.ProgramDefinition; import com.android.tools.r8.graph.ProgramField; import com.android.tools.r8.graph.ProgramMember; import com.android.tools.r8.graph.ProgramMethod; @@ -51,6 +52,7 @@ import com.android.tools.r8.shaking.DelayedRootSetActionItem.InterfaceMethodSyntheticBridgeAction; import com.android.tools.r8.shaking.EnqueuerEvent.InstantiatedClassEnqueuerEvent; import com.android.tools.r8.shaking.EnqueuerEvent.LiveClassEnqueuerEvent; +import com.android.tools.r8.shaking.EnqueuerEvent.UnconditionalKeepInfoEvent; import com.android.tools.r8.shaking.KeepInfo.Joiner; import com.android.tools.r8.utils.ArrayUtils; import com.android.tools.r8.utils.Consumer3; @@ -96,37 +98,23 @@ public class RootSetUtils { - static void modifyMinimumKeepInfo( - Map<DexReference, KeepInfo.Joiner<?, ?, ?>> minimumKeepInfo, - DexDefinition definition, - Consumer<Joiner<?, ?, ?>> consumer) { - modifyMinimumKeepInfo(minimumKeepInfo, definition.getReference(), consumer); - } - - static void modifyMinimumKeepInfo( - Map<DexReference, KeepInfo.Joiner<?, ?, ?>> minimumKeepInfo, - DexReference reference, - Consumer<Joiner<?, ?, ?>> consumer) { - Joiner<?, ?, ?> joiner = - minimumKeepInfo.computeIfAbsent( - reference, - key -> - key.apply( - clazz -> KeepClassInfo.newEmptyJoiner(), - field -> KeepFieldInfo.newEmptyJoiner(), - method -> KeepMethodInfo.newEmptyJoiner())); - consumer.accept(joiner); - assert !joiner.isBottom(); - } - static void modifyDependentMinimumKeepInfo( Map<EnqueuerEvent, Map<DexReference, KeepInfo.Joiner<?, ?, ?>>> dependentMinimumKeepInfo, EnqueuerEvent event, - DexDefinition dependent, + ProgramDefinition dependent, Consumer<Joiner<?, ?, ?>> consumer) { - Map<DexReference, KeepInfo.Joiner<?, ?, ?>> minimumKeepInfoForDependants = - dependentMinimumKeepInfo.computeIfAbsent(event, ignoreKey(IdentityHashMap::new)); - modifyMinimumKeepInfo(minimumKeepInfoForDependants, dependent, consumer); + Joiner<?, ?, ?> joiner = + dependentMinimumKeepInfo + .computeIfAbsent(event, ignoreKey(IdentityHashMap::new)) + .computeIfAbsent( + dependent.getReference(), + key -> + key.apply( + clazz -> KeepClassInfo.newEmptyJoiner(), + field -> KeepFieldInfo.newEmptyJoiner(), + method -> KeepMethodInfo.newEmptyJoiner())); + consumer.accept(joiner); + assert !joiner.isBottom(); } public static class RootSetBuilder { @@ -136,8 +124,6 @@ private final DirectMappedDexApplication application; private final Iterable<? extends ProguardConfigurationRule> rules; private final MutableItemsWithRules noShrinking = new MutableItemsWithRules(); - private final Map<DexReference, KeepInfo.Joiner<?, ?, ?>> minimumKeepInfo = - new IdentityHashMap<>(); private final Map<EnqueuerEvent, Map<DexReference, KeepInfo.Joiner<?, ?, ?>>> dependentMinimumKeepInfo = new HashMap<>(); private final LinkedHashMap<DexReference, DexReference> reasonAsked = new LinkedHashMap<>(); @@ -401,7 +387,6 @@ : "A method cannot be marked as both -neverinline and -forceinline/-alwaysinline."; return new RootSet( noShrinking, - minimumKeepInfo, dependentMinimumKeepInfo, ImmutableList.copyOf(reasonAsked.values()), ImmutableList.copyOf(checkDiscarded.values()), @@ -497,7 +482,6 @@ neverInlineDueToSingleCaller, neverClassInline, noShrinking, - minimumKeepInfo, dependentMinimumKeepInfo, dependentNoShrinking, dependentKeepClassCompatRule, @@ -686,8 +670,7 @@ } DexProgramClass precondition = testAndGetPrecondition(methodToKeep.getDefinition(), preconditionSupplier); - rootSetBuilder.addItemToSets( - methodToKeep.getDefinition(), context, rule, precondition, ifRule); + rootSetBuilder.addItemToSets(methodToKeep, context, rule, precondition, ifRule); })); } } @@ -1094,7 +1077,7 @@ if (methodsMarked != null) { methodsMarked.add(MethodSignatureEquivalence.get().wrap(method.getReference())); } - addItemToSets(method.getDefinition(), context, rule, precondition, ifRule); + addItemToSets(method, context, rule, precondition, ifRule); } } } @@ -1110,7 +1093,7 @@ if (Log.ENABLED) { Log.verbose(getClass(), "Marking field `%s` due to `%s { %s }`.", field, context, rule); } - addItemToSets(field.getDefinition(), context, rule, precondition, ifRule); + addItemToSets(field, context, rule, precondition, ifRule); } } } @@ -1124,7 +1107,7 @@ // TODO(b/192636793): This needs to use the precondition. private void includeDescriptor( - DexDefinition item, + ProgramDefinition item, DexType type, ProguardKeepRuleBase context, DexProgramClass precondition) { @@ -1149,187 +1132,58 @@ // Disable minification for the type. if (appView.options().isMinificationEnabled()) { - modifyMinimumKeepInfo(minimumKeepInfo, clazz, Joiner::disallowMinification); + modifyDependentMinimumKeepInfo( + dependentMinimumKeepInfo, + UnconditionalKeepInfoEvent.get(), + clazz, + Joiner::disallowMinification); } } private void includeDescriptorClasses( - DexDefinition item, ProguardKeepRuleBase context, DexProgramClass precondition) { - if (item.isDexEncodedMethod()) { - DexEncodedMethod method = item.asDexEncodedMethod(); - includeDescriptor(item, method.getReturnType(), context, precondition); + ProgramDefinition item, ProguardKeepRuleBase context, DexProgramClass precondition) { + if (item.isMethod()) { + ProgramMethod method = item.asProgramMethod(); + includeDescriptor(method, method.getReturnType(), context, precondition); for (DexType value : method.getParameters()) { - includeDescriptor(item, value, context, precondition); + includeDescriptor(method, value, context, precondition); } - } else if (item.isDexEncodedField()) { - DexEncodedField field = item.asDexEncodedField(); - includeDescriptor(item, field.getType(), context, precondition); + } else if (item.isField()) { + ProgramField field = item.asProgramField(); + includeDescriptor(field, field.getType(), context, precondition); } else { - assert item.isDexClass(); + assert item.isClass(); } } private synchronized void addItemToSets( - DexDefinition item, + Definition item, ProguardConfigurationRule context, ProguardMemberRule rule, DexProgramClass precondition, ProguardIfRule ifRule) { if (context instanceof ProguardKeepRule) { - if (item.isDexEncodedField()) { - DexEncodedField encodedField = item.asDexEncodedField(); - if (encodedField.getOptimizationInfo().cannotBeKept()) { - // We should only ever get here with if rules. - assert ifRule != null; - return; - } - } else if (item.isDexEncodedMethod()) { - DexEncodedMethod encodedMethod = item.asDexEncodedMethod(); - if (encodedMethod.isClassInitializer() && !options.debug) { - // Don't keep class initializers. - return; - } - if (encodedMethod.getOptimizationInfo().cannotBeKept()) { - // We should only ever get here with if rules. - assert ifRule != null; - return; - } - if (options.isGeneratingDex() - && encodedMethod.getReference().isLambdaDeserializeMethod(appView.dexItemFactory())) { - // Don't keep lambda deserialization methods. - return; - } - // If desugaring is enabled, private and static interface methods will be moved to a - // companion class. So we don't need to add them to the root set in the beginning. - if (options.isInterfaceMethodDesugaringEnabled() - && encodedMethod.hasCode() - && (encodedMethod.isPrivateMethod() || encodedMethod.isStaticMember())) { - DexClass holder = appView.definitionFor(encodedMethod.getHolderType()); - if (holder != null && holder.isInterface()) { - if (rule.isSpecific()) { - options.reporter.warning( - new StringDiagnostic( - "The rule `" - + rule - + "` is ignored because the targeting interface method `" - + encodedMethod.getReference().toSourceString() - + "` will be desugared.")); - } - return; - } - } - } - - // The reason for keeping should link to the conditional rule as a whole, if present. - ProguardKeepRuleBase keepRule = ifRule != null ? ifRule : (ProguardKeepRuleBase) context; - - // The modifiers are specified on the actual keep rule (ie, the consequent/context). - ProguardKeepRuleModifiers modifiers = ((ProguardKeepRule) context).getModifiers(); - if (modifiers.isBottom()) { - // This rule is a no-op. + if (!item.isProgramDefinition()) { + // Keep rules do not apply to non-program items. return; } - - // In compatibility mode, for a match on instance members a referenced class becomes live. - if (options.forceProguardCompatibility - && !modifiers.allowsShrinking - && precondition != null - && precondition.isDexClass()) { - if (!item.isDexClass() && !item.isStaticMember()) { - dependentKeepClassCompatRule - .computeIfAbsent(precondition.asDexClass().getType(), i -> new HashSet<>()) - .add(keepRule); - context.markAsUsed(); - } - } - - // TODO(b/192636793): Remove the noShrinking and dependentNoShrinking collections. A - // prerequisite for this is that the ProguardKeepRule instances are added to the KeepInfo, - // since this is needed for the -whyareyoukeeping graph. - if (!modifiers.allowsShrinking) { - if (precondition != null) { - dependentNoShrinking - .computeIfAbsent(precondition.getReference(), x -> new MutableItemsWithRules()) - .addReferenceWithRule(item.getReference(), keepRule); - } else { - noShrinking.addReferenceWithRule(item.getReference(), keepRule); - } - context.markAsUsed(); - } - - EnqueuerEvent preconditionEvent; - if (precondition != null) { - preconditionEvent = - item.getAccessFlags().isStatic() - ? new LiveClassEnqueuerEvent(precondition) - : new InstantiatedClassEnqueuerEvent(precondition); - } else { - preconditionEvent = null; - } - - if (appView.options().isAnnotationRemovalEnabled() && !modifiers.allowsAnnotationRemoval) { - if (precondition != null) { - modifyDependentMinimumKeepInfo( - dependentMinimumKeepInfo, - preconditionEvent, - item, - Joiner::disallowAnnotationRemoval); - } else { - modifyMinimumKeepInfo(minimumKeepInfo, item, Joiner::disallowAnnotationRemoval); - } - context.markAsUsed(); - } - - if (appView.options().isMinificationEnabled() && !modifiers.allowsObfuscation) { - if (precondition != null) { - modifyDependentMinimumKeepInfo( - dependentMinimumKeepInfo, preconditionEvent, item, Joiner::disallowMinification); - } else { - modifyMinimumKeepInfo(minimumKeepInfo, item, Joiner::disallowMinification); - } - context.markAsUsed(); - } - - if (appView.options().isOptimizationEnabled() && !modifiers.allowsOptimization) { - if (precondition != null) { - modifyDependentMinimumKeepInfo( - dependentMinimumKeepInfo, preconditionEvent, item, Joiner::disallowOptimization); - } else { - modifyMinimumKeepInfo(minimumKeepInfo, item, Joiner::disallowOptimization); - } - context.markAsUsed(); - } - - if (appView.options().isShrinking() && !modifiers.allowsShrinking) { - if (precondition != null) { - modifyDependentMinimumKeepInfo( - dependentMinimumKeepInfo, preconditionEvent, item, Joiner::disallowShrinking); - } else { - modifyMinimumKeepInfo(minimumKeepInfo, item, Joiner::disallowShrinking); - } - context.markAsUsed(); - } - - if (modifiers.includeDescriptorClasses) { - includeDescriptorClasses(item, keepRule, precondition); - context.markAsUsed(); - } + evaluateKeepRule(item.asProgramDefinition(), context, rule, precondition, ifRule); } else if (context instanceof ProguardAssumeMayHaveSideEffectsRule) { mayHaveSideEffects.put(item.getReference(), rule); context.markAsUsed(); } else if (context instanceof ProguardAssumeNoSideEffectRule) { - if (item.isDexEncodedMember()) { - DexEncodedMember<?, ?> member = item.asDexEncodedMember(); + if (item.isMember()) { + DexClassAndMember<?, ?> member = item.asMember(); if (member.getHolderType() == appView.dexItemFactory().objectType) { - assert member.isDexEncodedMethod(); + assert member.isMethod(); reportAssumeNoSideEffectsWarningForJavaLangClassMethod( - member.asDexEncodedMethod(), (ProguardAssumeNoSideEffectRule) context); + member.asMethod(), (ProguardAssumeNoSideEffectRule) context); } else { noSideEffects.put(member.getReference(), rule); - if (member.isDexEncodedMethod()) { - DexEncodedMethod method = member.asDexEncodedMethod(); - if (method.isClassInitializer()) { - feedback.classInitializerMayBePostponed(method); + if (member.isMethod()) { + DexClassAndMethod method = member.asMethod(); + if (method.getDefinition().isClassInitializer()) { + feedback.classInitializerMayBePostponed(method.getDefinition()); } } } @@ -1339,16 +1193,16 @@ reasonAsked.computeIfAbsent(item.getReference(), i -> i); context.markAsUsed(); } else if (context instanceof ProguardAssumeValuesRule) { - if (item.isDexEncodedMember()) { - assumedValues.put(item.asDexEncodedMember().getReference(), rule); + if (item.isMember()) { + assumedValues.put(item.asMember().getReference(), rule); context.markAsUsed(); } } else if (context instanceof ProguardCheckDiscardRule) { checkDiscarded.computeIfAbsent(item.getReference(), i -> i); context.markAsUsed(); } else if (context instanceof InlineRule) { - if (item.isDexEncodedMethod()) { - DexMethod reference = item.asDexEncodedMethod().getReference(); + if (item.isMethod()) { + DexMethod reference = item.asMethod().getReference(); switch (((InlineRule) context).getType()) { case ALWAYS: alwaysInline.add(reference); @@ -1368,14 +1222,14 @@ context.markAsUsed(); } } else if (context instanceof WhyAreYouNotInliningRule) { - if (!item.isDexEncodedMethod()) { + if (!item.isMethod()) { throw new Unreachable(); } - whyAreYouNotInlining.add(item.asDexEncodedMethod().getReference()); + whyAreYouNotInlining.add(item.asMethod().getReference()); context.markAsUsed(); } else if (context.isClassInlineRule()) { ClassInlineRule classInlineRule = context.asClassInlineRule(); - DexClass clazz = item.asDexClass(); + DexClass clazz = item.asClass(); if (clazz == null) { throw new IllegalStateException( "Unexpected -" @@ -1386,39 +1240,39 @@ } switch (classInlineRule.getType()) { case ALWAYS: - alwaysClassInline.addElement(item.asDexClass().type); + alwaysClassInline.addElement(item.asClass().getType()); break; case NEVER: - neverClassInline.add(item.asDexClass().type); + neverClassInline.add(item.asClass().getType()); break; default: throw new Unreachable(); } context.markAsUsed(); } else if (context instanceof NoUnusedInterfaceRemovalRule) { - noUnusedInterfaceRemoval.add(item.asDexClass().type); + noUnusedInterfaceRemoval.add(item.asClass().type); context.markAsUsed(); } else if (context instanceof NoVerticalClassMergingRule) { - noVerticalClassMerging.add(item.asDexClass().type); + noVerticalClassMerging.add(item.asClass().type); context.markAsUsed(); } else if (context instanceof NoHorizontalClassMergingRule) { - noHorizontalClassMerging.add(item.asDexClass().type); + noHorizontalClassMerging.add(item.asClass().type); context.markAsUsed(); } else if (context instanceof MemberValuePropagationRule) { switch (((MemberValuePropagationRule) context).getType()) { case NEVER: // Only add members from propgram classes to `neverPropagateValue` since class member // values from library types are not propagated by default. - if (item.isDexEncodedField()) { - DexEncodedField field = item.asDexEncodedField(); - if (field.isProgramField(appView)) { - neverPropagateValue.add(item.asDexEncodedField().getReference()); + if (item.isField()) { + DexClassAndField field = item.asField(); + if (field.isProgramField()) { + neverPropagateValue.add(field.getReference()); context.markAsUsed(); } - } else if (item.isDexEncodedMethod()) { - DexEncodedMethod method = item.asDexEncodedMethod(); - if (method.isProgramMethod(appView)) { - neverPropagateValue.add(item.asDexEncodedMethod().getReference()); + } else if (item.isMethod()) { + DexClassAndMethod method = item.asMethod(); + if (method.isProgramMethod()) { + neverPropagateValue.add(method.getReference()); context.markAsUsed(); } } @@ -1427,16 +1281,16 @@ throw new Unreachable(); } } else if (context instanceof ProguardIdentifierNameStringRule) { - if (item.isDexEncodedField()) { - identifierNameStrings.add(item.asDexEncodedField().getReference()); + if (item.isField()) { + identifierNameStrings.add(item.asField().getReference()); context.markAsUsed(); - } else if (item.isDexEncodedMethod()) { - identifierNameStrings.add(item.asDexEncodedMethod().getReference()); + } else if (item.isMethod()) { + identifierNameStrings.add(item.asMethod().getReference()); context.markAsUsed(); } } else if (context instanceof ConstantArgumentRule) { - if (item.isDexEncodedMethod()) { - keepParametersWithConstantValue.add(item.asDexEncodedMethod().getReference()); + if (item.isMethod()) { + keepParametersWithConstantValue.add(item.asMethod().getReference()); context.markAsUsed(); } } else if (context instanceof ReprocessClassInitializerRule) { @@ -1455,8 +1309,8 @@ context.markAsUsed(); } } else if (context.isReprocessMethodRule()) { - if (item.isDexEncodedMethod()) { - DexEncodedMethod method = item.asDexEncodedMethod(); + if (item.isMethod()) { + DexClassAndMethod method = item.asMethod(); switch (context.asReprocessMethodRule().getType()) { case ALWAYS: reprocess.add(method.getReference()); @@ -1470,8 +1324,8 @@ context.markAsUsed(); } } else if (context instanceof UnusedArgumentRule) { - if (item.isDexEncodedMethod()) { - keepUnusedArguments.add(item.asDexEncodedMethod().getReference()); + if (item.isMethod()) { + keepUnusedArguments.add(item.asMethod().getReference()); context.markAsUsed(); } } else { @@ -1479,8 +1333,135 @@ } } + private synchronized void evaluateKeepRule( + ProgramDefinition item, + ProguardConfigurationRule context, + ProguardMemberRule rule, + DexProgramClass precondition, + ProguardIfRule ifRule) { + if (item.isField()) { + ProgramField field = item.asProgramField(); + if (field.getOptimizationInfo().cannotBeKept()) { + // We should only ever get here with if rules. + assert ifRule != null; + return; + } + } else if (item.isMethod()) { + ProgramMethod method = item.asProgramMethod(); + if (method.getDefinition().isClassInitializer() && !options.debug) { + // Don't keep class initializers. + return; + } + if (method.getOptimizationInfo().cannotBeKept()) { + // We should only ever get here with if rules. + assert ifRule != null; + return; + } + if (options.isGeneratingDex() + && method.getReference().isLambdaDeserializeMethod(appView.dexItemFactory())) { + // Don't keep lambda deserialization methods. + return; + } + // If desugaring is enabled, private and static interface methods will be moved to a + // companion class. So we don't need to add them to the root set in the beginning. + if (options.isInterfaceMethodDesugaringEnabled() + && method.getDefinition().hasCode() + && (method.getAccessFlags().isPrivate() || method.getAccessFlags().isStatic())) { + DexClass holder = appView.definitionFor(method.getHolderType()); + if (holder != null && holder.isInterface()) { + if (rule.isSpecific()) { + options.reporter.warning( + new StringDiagnostic( + "The rule `" + + rule + + "` is ignored because the targeting interface method `" + + method.getReference().toSourceString() + + "` will be desugared.")); + } + return; + } + } + } + + // The reason for keeping should link to the conditional rule as a whole, if present. + ProguardKeepRuleBase keepRule = ifRule != null ? ifRule : (ProguardKeepRuleBase) context; + + // The modifiers are specified on the actual keep rule (ie, the consequent/context). + ProguardKeepRuleModifiers modifiers = ((ProguardKeepRule) context).getModifiers(); + if (modifiers.isBottom()) { + // This rule is a no-op. + return; + } + + // In compatibility mode, for a match on instance members a referenced class becomes live. + if (options.forceProguardCompatibility + && !modifiers.allowsShrinking + && precondition != null + && precondition.isDexClass()) { + if (!item.isClass() && !item.getAccessFlags().isStatic()) { + dependentKeepClassCompatRule + .computeIfAbsent(precondition.asDexClass().getType(), i -> new HashSet<>()) + .add(keepRule); + context.markAsUsed(); + } + } + + // TODO(b/192636793): Remove the noShrinking and dependentNoShrinking collections. A + // prerequisite for this is that the ProguardKeepRule instances are added to the KeepInfo, + // since this is needed for the -whyareyoukeeping graph. + if (!modifiers.allowsShrinking) { + if (precondition != null) { + dependentNoShrinking + .computeIfAbsent(precondition.getReference(), x -> new MutableItemsWithRules()) + .addReferenceWithRule(item.getReference(), keepRule); + } else { + noShrinking.addReferenceWithRule(item.getReference(), keepRule); + } + context.markAsUsed(); + } + + EnqueuerEvent preconditionEvent; + if (precondition != null) { + preconditionEvent = + item.getAccessFlags().isStatic() + ? new LiveClassEnqueuerEvent(precondition) + : new InstantiatedClassEnqueuerEvent(precondition); + } else { + preconditionEvent = UnconditionalKeepInfoEvent.get(); + } + + if (appView.options().isAnnotationRemovalEnabled() && !modifiers.allowsAnnotationRemoval) { + modifyDependentMinimumKeepInfo( + dependentMinimumKeepInfo, preconditionEvent, item, Joiner::disallowAnnotationRemoval); + context.markAsUsed(); + } + + if (appView.options().isMinificationEnabled() && !modifiers.allowsObfuscation) { + modifyDependentMinimumKeepInfo( + dependentMinimumKeepInfo, preconditionEvent, item, Joiner::disallowMinification); + context.markAsUsed(); + } + + if (appView.options().isOptimizationEnabled() && !modifiers.allowsOptimization) { + modifyDependentMinimumKeepInfo( + dependentMinimumKeepInfo, preconditionEvent, item, Joiner::disallowOptimization); + context.markAsUsed(); + } + + if (appView.options().isShrinking() && !modifiers.allowsShrinking) { + modifyDependentMinimumKeepInfo( + dependentMinimumKeepInfo, preconditionEvent, item, Joiner::disallowShrinking); + context.markAsUsed(); + } + + if (modifiers.includeDescriptorClasses) { + includeDescriptorClasses(item, keepRule, precondition); + context.markAsUsed(); + } + } + private void reportAssumeNoSideEffectsWarningForJavaLangClassMethod( - DexEncodedMethod method, ProguardAssumeNoSideEffectRule context) { + DexClassAndMethod method, ProguardAssumeNoSideEffectRule context) { assert method.getHolderType() == options.dexItemFactory().objectType; OriginWithPosition key = new OriginWithPosition(context.getOrigin(), context.getPosition()); assumeNoSideEffectsWarnings @@ -1527,7 +1508,6 @@ final Set<DexMethod> neverInlineDueToSingleCaller; final Set<DexType> neverClassInline; final MutableItemsWithRules noShrinking; - final Map<DexReference, KeepInfo.Joiner<?, ?, ?>> minimumKeepInfo; final Map<EnqueuerEvent, Map<DexReference, KeepInfo.Joiner<?, ?, ?>>> dependentMinimumKeepInfo; final Map<DexReference, MutableItemsWithRules> dependentNoShrinking; final Map<DexType, Set<ProguardKeepRuleBase>> dependentKeepClassCompatRule; @@ -1538,7 +1518,6 @@ Set<DexMethod> neverInlineDueToSingleCaller, Set<DexType> neverClassInline, MutableItemsWithRules noShrinking, - Map<DexReference, KeepInfo.Joiner<?, ?, ?>> minimumKeepInfo, Map<EnqueuerEvent, Map<DexReference, KeepInfo.Joiner<?, ?, ?>>> dependentMinimumKeepInfo, Map<DexReference, MutableItemsWithRules> dependentNoShrinking, Map<DexType, Set<ProguardKeepRuleBase>> dependentKeepClassCompatRule, @@ -1547,7 +1526,6 @@ this.neverInlineDueToSingleCaller = neverInlineDueToSingleCaller; this.neverClassInline = neverClassInline; this.noShrinking = noShrinking; - this.minimumKeepInfo = minimumKeepInfo; this.dependentMinimumKeepInfo = dependentMinimumKeepInfo; this.dependentNoShrinking = dependentNoShrinking; this.dependentKeepClassCompatRule = dependentKeepClassCompatRule; @@ -1664,8 +1642,6 @@ TriConsumer<EnqueuerEvent, DexProgramClass, KeepClassInfo.Joiner> classConsumer, TriConsumer<EnqueuerEvent, ProgramField, KeepFieldInfo.Joiner> fieldConsumer, TriConsumer<EnqueuerEvent, ProgramMethod, KeepMethodInfo.Joiner> methodConsumer) { - internalForEachMinimumKeepInfo( - appView, minimumKeepInfo, null, classConsumer, fieldConsumer, methodConsumer); dependentMinimumKeepInfo.forEach( (precondition, minimumKeepInfoForDependents) -> internalForEachMinimumKeepInfo( @@ -1996,7 +1972,6 @@ private RootSet( MutableItemsWithRules noShrinking, - Map<DexReference, KeepInfo.Joiner<?, ?, ?>> minimumKeepInfo, Map<EnqueuerEvent, Map<DexReference, KeepInfo.Joiner<?, ?, ?>>> dependentMinimumKeepInfo, ImmutableList<DexReference> reasonAsked, ImmutableList<DexReference> checkDiscarded, @@ -2029,7 +2004,6 @@ neverInlineDueToSingleCaller, neverClassInline, noShrinking, - minimumKeepInfo, dependentMinimumKeepInfo, dependentNoShrinking, dependentKeepClassCompatRule, @@ -2139,8 +2113,12 @@ }); } - void shouldNotBeMinified(DexReference reference) { - modifyMinimumKeepInfo(minimumKeepInfo, reference, Joiner::disallowMinification); + void shouldNotBeMinified(ProgramDefinition definition) { + modifyDependentMinimumKeepInfo( + dependentMinimumKeepInfo, + UnconditionalKeepInfoEvent.get(), + definition, + Joiner::disallowMinification); } public boolean verifyKeptFieldsAreAccessedAndLive(AppInfoWithLiveness appInfo) { @@ -2335,7 +2313,6 @@ Set<DexMethod> neverInlineDueToSingleCaller, Set<DexType> neverClassInline, MutableItemsWithRules noShrinking, - Map<DexReference, KeepInfo.Joiner<?, ?, ?>> minimumKeepInfo, Map<EnqueuerEvent, Map<DexReference, KeepInfo.Joiner<?, ?, ?>>> dependentMinimumKeepInfo, Map<DexReference, MutableItemsWithRules> dependentNoShrinking, Map<DexType, Set<ProguardKeepRuleBase>> dependentKeepClassCompatRule, @@ -2345,7 +2322,6 @@ neverInlineDueToSingleCaller, neverClassInline, noShrinking, - minimumKeepInfo, dependentMinimumKeepInfo, dependentNoShrinking, dependentKeepClassCompatRule, @@ -2400,7 +2376,6 @@ super( noShrinking, emptyMap(), - emptyMap(), reasonAsked, checkDiscarded, Collections.emptySet(), @@ -2450,7 +2425,7 @@ } @Override - void shouldNotBeMinified(DexReference reference) { + void shouldNotBeMinified(ProgramDefinition definition) { // Do nothing. }
diff --git a/src/main/java/com/android/tools/r8/shaking/TreePruner.java b/src/main/java/com/android/tools/r8/shaking/TreePruner.java index df989fe..276d737 100644 --- a/src/main/java/com/android/tools/r8/shaking/TreePruner.java +++ b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
@@ -36,6 +36,7 @@ import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; +import java.util.function.Function; import java.util.function.Predicate; public class TreePruner { @@ -195,21 +196,22 @@ } clazz.removeInnerClasses(this::isAttributeReferencingMissingOrPrunedType); clazz.removeEnclosingMethodAttribute(this::isAttributeReferencingPrunedItem); - rewriteNestAttributes(clazz); + rewriteNestAttributes(clazz, this::isTypeLive, appView::definitionFor); unusedItemsPrinter.visited(); assert verifyNoDeadFields(clazz); } - private void rewriteNestAttributes(DexProgramClass clazz) { - if (!clazz.isInANest() || !isTypeLive(clazz.type)) { + public static void rewriteNestAttributes( + DexProgramClass clazz, Predicate<DexType> isLive, Function<DexType, DexClass> definition) { + if (!clazz.isInANest() || !isLive.test(clazz.type)) { return; } if (clazz.isNestHost()) { - clearDeadNestMembers(clazz); + clearDeadNestMembers(clazz, isLive, definition); } else { assert clazz.isNestMember(); - if (!isTypeLive(clazz.getNestHost())) { - claimNestOwnership(clazz); + if (!isLive.test(clazz.getNestHost())) { + claimNestOwnership(clazz, isLive, definition); } } } @@ -222,26 +224,28 @@ return appView.appInfo().isNonProgramTypeOrLiveProgramType(type); } - private void clearDeadNestMembers(DexClass nestHost) { + private static void clearDeadNestMembers( + DexClass nestHost, Predicate<DexType> isLive, Function<DexType, DexClass> definition) { // null definition should raise a warning which is raised later on in Nest specific passes. nestHost .getNestMembersClassAttributes() .removeIf( nestMemberAttr -> - appView.definitionFor(nestMemberAttr.getNestMember()) != null - && !isTypeLive(nestMemberAttr.getNestMember())); + definition.apply(nestMemberAttr.getNestMember()) != null + && !isLive.test(nestMemberAttr.getNestMember())); } - private void claimNestOwnership(DexClass newHost) { - DexClass previousHost = appView.definitionFor(newHost.getNestHost()); + private static void claimNestOwnership( + DexClass newHost, Predicate<DexType> isLive, Function<DexType, DexClass> definition) { + DexClass previousHost = definition.apply(newHost.getNestHost()); if (previousHost == null) { // Nest host will be cleared from all nest members in Nest specific passes. return; } newHost.clearNestHost(); for (NestMemberClassAttribute attr : previousHost.getNestMembersClassAttributes()) { - if (attr.getNestMember() != newHost.type && isTypeLive(attr.getNestMember())) { - DexClass nestMember = appView.definitionFor(attr.getNestMember()); + if (attr.getNestMember() != newHost.type && isLive.test(attr.getNestMember())) { + DexClass nestMember = definition.apply(attr.getNestMember()); if (nestMember != null) { nestMember.setNestHost(newHost.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 061eb02..8bd2f01 100644 --- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java +++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -7,6 +7,7 @@ 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; @@ -441,11 +442,9 @@ // Only merge if api reference level of source class is equal to target class. if (appView.options().apiModelingOptions().enableApiCallerIdentification) { AndroidApiLevel sourceApiLevel = - sourceClass.getApiReferenceLevel( - appView.options().minApiLevel, apiReferenceLevelCache::lookupMax); + sourceClass.getApiReferenceLevel(appView, apiReferenceLevelCache::lookupMax); AndroidApiLevel targetApiLevel = - targetClass.getApiReferenceLevel( - appView.options().minApiLevel, apiReferenceLevelCache::lookupMax); + targetClass.getApiReferenceLevel(appView, apiReferenceLevelCache::lookupMax); if (sourceApiLevel != targetApiLevel) { if (Log.ENABLED) { AbortReason.API_REFERENCE_LEVEL.printLogMessageForClass(sourceClass); @@ -1441,7 +1440,9 @@ ParameterAnnotationsList.empty(), code, true, - method.hasClassFileVersion() ? method.getClassFileVersion() : null); + method.hasClassFileVersion() ? method.getClassFileVersion() : null, + getApiLevelIfEnabledForNewMember(appView, method::getApiReferenceLevelForDefinition), + getApiLevelIfEnabledForNewMember(appView, Function.identity())); 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/SyntheticMethodBuilder.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java index e2cd6eb..adc3f40 100644 --- a/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java +++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java
@@ -16,6 +16,7 @@ import com.android.tools.r8.graph.MethodAccessFlags; import com.android.tools.r8.graph.ParameterAnnotationsList; import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind; +import com.android.tools.r8.utils.AndroidApiLevel; import java.util.function.Consumer; public class SyntheticMethodBuilder { @@ -115,7 +116,9 @@ parameterAnnotationsList, accessFlags.isAbstract() ? null : getCodeObject(methodSignature), isCompilerSynthesized, - classFileVersion); + classFileVersion, + AndroidApiLevel.UNKNOWN, + AndroidApiLevel.UNKNOWN); assert isValidSyntheticMethod(method, syntheticKind); if (onBuildConsumer != null) { onBuildConsumer.accept(method);
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java b/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java new file mode 100644 index 0000000..9272066 --- /dev/null +++ b/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java
@@ -0,0 +1,48 @@ +// 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.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) { + return OptionalBool.TRUE; + } + if (caller.getHolderType() == inlinee.getHolderType()) { + return OptionalBool.TRUE; + } + return OptionalBool.of( + caller + .getDefinition() + .getApiReferenceLevel(options.minApiLevel) + .isGreaterThanOrEqualTo( + inlinee.getDefinition().getApiReferenceLevelForCode(options.minApiLevel))); + } +}
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 c17a6ac..0a9c18a 100644 --- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java +++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -618,6 +618,10 @@ return forceProguardCompatibility; } + public boolean parseSignatureAttribute() { + return proguardConfiguration == null || isKeepAttributesSignatureEnabled(); + } + @Override public boolean isKeepAttributesSignatureEnabled() { return proguardConfiguration.getKeepAttributes().signature; @@ -1342,6 +1346,7 @@ public BiConsumer<MethodReference, AndroidApiLevel> tracedMethodApiLevelCallback = null; public boolean enableApiCallerIdentification = false; + public boolean checkAllApiReferencesAreSet = true; public void visitMockedApiReferences(BiConsumer<ClassReference, AndroidApiClass> consumer) { if (methodApiMapping.isEmpty() && fieldApiMapping.isEmpty() && classApiMapping.isEmpty()) { @@ -1543,6 +1548,7 @@ public boolean enableTestAssertions = System.getProperty("com.android.tools.r8.enableTestAssertions") != null; public boolean testEnableTestAssertions = false; + public boolean keepMetadataInR8IfNotRewritten = true; public boolean allowConflictingSyntheticTypes = false;
diff --git a/src/test/java/com/android/tools/r8/KotlinCompilerTool.java b/src/test/java/com/android/tools/r8/KotlinCompilerTool.java index 468c1e9..33152f1 100644 --- a/src/test/java/com/android/tools/r8/KotlinCompilerTool.java +++ b/src/test/java/com/android/tools/r8/KotlinCompilerTool.java
@@ -12,7 +12,9 @@ import com.android.tools.r8.TestRuntime.CfRuntime; import com.android.tools.r8.ToolHelper.KotlinTargetVersion; import com.android.tools.r8.ToolHelper.ProcessResult; +import com.android.tools.r8.utils.ArrayUtils; import com.android.tools.r8.utils.FileUtils; +import com.android.tools.r8.utils.structural.Ordered; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -28,16 +30,22 @@ public class KotlinCompilerTool { - public enum KotlinCompilerVersion { + public enum KotlinCompilerVersion implements Ordered<KotlinCompilerVersion> { KOTLINC_1_3_72("kotlin-compiler-1.3.72"), KOTLINC_1_4_20("kotlin-compiler-1.4.20"), KOTLINC_1_5_0("kotlin-compiler-1.5.0"); + public static final KotlinCompilerVersion MIN_SUPPORTED_VERSION = KOTLINC_1_4_20; + private final String folder; KotlinCompilerVersion(String folder) { this.folder = folder; } + + public static KotlinCompilerVersion latest() { + return ArrayUtils.last(values()); + } } public static final class KotlinCompiler {
diff --git a/src/test/java/com/android/tools/r8/KotlinTestParameters.java b/src/test/java/com/android/tools/r8/KotlinTestParameters.java index 7cfcc07..4306e53 100644 --- a/src/test/java/com/android/tools/r8/KotlinTestParameters.java +++ b/src/test/java/com/android/tools/r8/KotlinTestParameters.java
@@ -3,13 +3,12 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8; -import static org.junit.Assert.assertNotNull; - import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler; import com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion; import com.android.tools.r8.ToolHelper.KotlinTargetVersion; import java.util.ArrayList; import java.util.List; +import java.util.function.Predicate; public class KotlinTestParameters { @@ -55,13 +54,23 @@ public static class Builder { - private KotlinCompiler[] compilers; - private KotlinTargetVersion[] targetVersions; + private Predicate<KotlinCompilerVersion> compilerFilter = c -> false; + private Predicate<KotlinTargetVersion> targetVersionFilter = t -> false; private Builder() {} + private Builder withCompilerFilter(Predicate<KotlinCompilerVersion> predicate) { + compilerFilter = compilerFilter.or(predicate); + return this; + } + + private Builder withTargetVersionFilter(Predicate<KotlinTargetVersion> predicate) { + targetVersionFilter = targetVersionFilter.or(predicate); + return this; + } + public Builder withAllCompilers() { - compilers = ToolHelper.getKotlinCompilers(); + withCompilerFilter(compiler -> true); return this; } @@ -69,41 +78,46 @@ return withAllCompilers().withAllTargetVersions(); } - public Builder withCompiler(KotlinCompiler compiler) { - compilers = new KotlinCompiler[] {compiler}; + public Builder withCompiler(KotlinCompilerVersion compilerVersion) { + withCompilerFilter(c -> c.isEqualTo(compilerVersion)); return this; } public Builder withAllTargetVersions() { - targetVersions = KotlinTargetVersion.values(); + withTargetVersionFilter(t -> true); return this; } public Builder withTargetVersion(KotlinTargetVersion targetVersion) { - targetVersions = new KotlinTargetVersion[] {targetVersion}; + withTargetVersionFilter(t -> t.equals(targetVersion)); + return this; + } + + public Builder withCompilersStartingFromIncluding(KotlinCompilerVersion version) { + withCompilerFilter(c -> c.isGreaterThanOrEqualTo(version)); return this; } public KotlinTestParametersCollection build() { - validate(); List<KotlinTestParameters> testParameters = new ArrayList<>(); int index = 0; - for (KotlinCompiler kotlinc : compilers) { - for (KotlinTargetVersion targetVersion : targetVersions) { + for (KotlinCompilerVersion kotlinVersion : KotlinCompilerVersion.values()) { + for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) { // KotlinTargetVersion java 6 is deprecated from kotlinc 1.5 and forward, no need to run // tests on that target. - if (targetVersion != KotlinTargetVersion.JAVA_6 - || kotlinc.isNot(KotlinCompilerVersion.KOTLINC_1_5_0)) { - testParameters.add(new KotlinTestParameters(kotlinc, targetVersion, index++)); + if (targetVersion == KotlinTargetVersion.JAVA_6 + && kotlinVersion.equals(KotlinCompilerVersion.KOTLINC_1_5_0)) { + continue; + } + if (compilerFilter.test(kotlinVersion) && targetVersionFilter.test(targetVersion)) { + testParameters.add( + new KotlinTestParameters( + new KotlinCompiler(kotlinVersion), targetVersion, index++)); } } } + assert !testParameters.isEmpty(); return new KotlinTestParametersCollection(testParameters); } - - private void validate() { - assertNotNull(compilers); - assertNotNull(targetVersions); - } } }
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java index d41987d..e75ab6c 100644 --- a/src/test/java/com/android/tools/r8/TestBase.java +++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -56,6 +56,7 @@ import com.android.tools.r8.shaking.ProguardClassNameList; import com.android.tools.r8.shaking.ProguardConfiguration; import com.android.tools.r8.shaking.ProguardConfigurationRule; +import com.android.tools.r8.shaking.ProguardKeepAttributes; import com.android.tools.r8.shaking.ProguardKeepRule; import com.android.tools.r8.shaking.ProguardKeepRule.Builder; import com.android.tools.r8.shaking.ProguardKeepRuleType; @@ -735,17 +736,17 @@ MainDexInfo.none()); } - protected static AppView<AppInfoWithClassHierarchy> computeAppViewWithClassHierachy( + protected static AppView<AppInfoWithClassHierarchy> computeAppViewWithClassHierarchy( AndroidApp app) throws Exception { - return computeAppViewWithClassHierachy(app, null); + return computeAppViewWithClassHierarchy(app, null); } - private static AppView<AppInfoWithClassHierarchy> computeAppViewWithClassHierachy( + protected static AppView<AppInfoWithClassHierarchy> computeAppViewWithClassHierarchy( AndroidApp app, Function<DexItemFactory, ProguardConfiguration> keepConfig) throws Exception { - return computeAppViewWithClassHierachy(app, keepConfig, null); + return computeAppViewWithClassHierarchy(app, keepConfig, null); } - private static AppView<AppInfoWithClassHierarchy> computeAppViewWithClassHierachy( + private static AppView<AppInfoWithClassHierarchy> computeAppViewWithClassHierarchy( AndroidApp app, Function<DexItemFactory, ProguardConfiguration> keepConfig, Consumer<InternalOptions> optionsConsumer) @@ -753,9 +754,13 @@ DexItemFactory dexItemFactory = new DexItemFactory(); if (keepConfig == null) { keepConfig = - factory -> - buildConfigForRules( - factory, ImmutableList.of(ProguardKeepRule.defaultKeepAllRule(unused -> {}))); + factory -> { + ProguardConfiguration.Builder builder = + ProguardConfiguration.builder(factory, new Reporter()); + builder.addRule(ProguardKeepRule.defaultKeepAllRule(unused -> {})); + builder.addKeepAttributePatterns(ImmutableList.of(ProguardKeepAttributes.SIGNATURE)); + return builder.build(); + }; } InternalOptions options = new InternalOptions(keepConfig.apply(dexItemFactory), new Reporter()); if (optionsConsumer != null) { @@ -791,7 +796,7 @@ Consumer<InternalOptions> optionsConsumer) throws Exception { AppView<AppInfoWithClassHierarchy> appView = - computeAppViewWithClassHierachy(app, keepConfig, optionsConsumer); + computeAppViewWithClassHierarchy(app, keepConfig, optionsConsumer); // Run the tree shaker to compute an instance of AppInfoWithLiveness. ExecutorService executor = Executors.newSingleThreadExecutor(); SubtypingInfo subtypingInfo = new SubtypingInfo(appView);
diff --git a/src/test/java/com/android/tools/r8/apimodel/AndroidApiDatabaseBuilderGenerator.java b/src/test/java/com/android/tools/r8/apimodel/AndroidApiDatabaseBuilderGenerator.java index 9aa8f4d..dfaecd1 100644 --- a/src/test/java/com/android/tools/r8/apimodel/AndroidApiDatabaseBuilderGenerator.java +++ b/src/test/java/com/android/tools/r8/apimodel/AndroidApiDatabaseBuilderGenerator.java
@@ -36,6 +36,7 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.stream.Collectors; +import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; @@ -102,7 +103,8 @@ .removeMethods(MethodPredicate.onName("placeHolderForGetMemberCount")) .removeMethods(MethodPredicate.onName("placeHolderForVisitFields")) .removeMethods(MethodPredicate.onName("placeHolderForVisitMethods")) - .transform()); + .computeMaxs() + .transform(ClassWriter.COMPUTE_MAXS)); } for (String pkg : packages) { @@ -112,7 +114,8 @@ .setClassDescriptor(getPackageBuilderDescriptor(pkg)) .addMethodTransformer(getBuildClassTransformer(packageToClassesMap.get(pkg))) .removeMethods(MethodPredicate.onName("placeHolder")) - .transform()); + .computeMaxs() + .transform(ClassWriter.COMPUTE_MAXS)); } consumer.accept( @@ -123,7 +126,8 @@ .addMethodTransformer(getBuildPackageTransformer(packages)) .removeMethods(MethodPredicate.onName("placeHolderForVisitApiClasses")) .removeMethods(MethodPredicate.onName("placeHolderForBuildClass")) - .transform()); + .computeMaxs() + .transform(ClassWriter.COMPUTE_MAXS)); } private static String getPackageBuilderDescriptor(String pkg) { @@ -179,7 +183,7 @@ private static MethodTransformer getGetMemberCountTransformer(ParsedApiClass apiClass) { return replaceCode( "placeHolderForGetMemberCount", - transformer -> transformer.visitLdcInsn(apiClass.getMemberCount())); + transformer -> transformer.visitLdcInsn(apiClass.getTotalMemberCount())); } // The transformer below changes AndroidApiDatabaseClassTemplate.visitFields from:
diff --git a/src/test/java/com/android/tools/r8/apimodel/AndroidApiDatabaseBuilderGeneratorTest.java b/src/test/java/com/android/tools/r8/apimodel/AndroidApiDatabaseBuilderGeneratorTest.java index 6d46bfd..2ad1e72 100644 --- a/src/test/java/com/android/tools/r8/apimodel/AndroidApiDatabaseBuilderGeneratorTest.java +++ b/src/test/java/com/android/tools/r8/apimodel/AndroidApiDatabaseBuilderGeneratorTest.java
@@ -237,7 +237,7 @@ apiClass -> { expected.add(apiClass.getClassReference().getDescriptor()); expected.add(apiClass.getApiLevel().getName()); - expected.add(apiClass.getMemberCount() + ""); + expected.add(apiClass.getTotalMemberCount() + ""); BooleanBox added = new BooleanBox(false); apiClass.visitFieldReferences( (apiLevel, fieldReferences) -> {
diff --git a/src/test/java/com/android/tools/r8/apimodel/AndroidApiVersionsXmlParser.java b/src/test/java/com/android/tools/r8/apimodel/AndroidApiVersionsXmlParser.java index dbb71d3..4002bf9 100644 --- a/src/test/java/com/android/tools/r8/apimodel/AndroidApiVersionsXmlParser.java +++ b/src/test/java/com/android/tools/r8/apimodel/AndroidApiVersionsXmlParser.java
@@ -148,8 +148,19 @@ return apiLevel; } - public int getMemberCount() { - return fieldReferences.size() + methodReferences.size(); + /** + * getMemberCount() returns the total number of members present on the max api level, that is it + * is the disjoint union of all members for all api levels. + */ + public int getTotalMemberCount() { + int count = 0; + for (List<FieldReference> value : fieldReferences.values()) { + count += value.size(); + } + for (List<MethodReference> value : methodReferences.values()) { + count += value.size(); + } + return count; } private void register(FieldReference reference, AndroidApiLevel apiLevel) {
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelBackportTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelBackportTest.java new file mode 100644 index 0000000..e32a62e --- /dev/null +++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelBackportTest.java
@@ -0,0 +1,95 @@ +// 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.apimodel; + +import static com.android.tools.r8.apimodel.ApiModelingTestHelper.addTracedApiReferenceLevelCallBack; +import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; +import static org.hamcrest.CoreMatchers.not; +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.references.Reference; +import com.android.tools.r8.utils.AndroidApiLevel; +import java.lang.reflect.Method; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ApiModelBackportTest extends TestBase { + + private final TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); + } + + public ApiModelBackportTest(TestParameters parameters) { + this.parameters = parameters; + } + + @Test + public void testR8() throws Exception { + // For dex runtimes the `callBackport` is always min-api, because we either: + // - backport `Integer.toUnsignedString` thus the code is program code + // - call the implementation in the library where min-api >= 0. + // For CF we do not desugar the call and thus have to keep it at the api level O. + Method callBackport = ApiCaller.class.getDeclaredMethod("callBackport", int.class); + testForR8(parameters.getBackend()) + .addProgramClasses(ApiCaller.class, ApiCallerCaller.class, Main.class) + .setMinApi(parameters.getApiLevel()) + .addKeepMainRule(Main.class) + .apply(ApiModelingTestHelper::enableApiCallerIdentification) + .apply( + addTracedApiReferenceLevelCallBack( + (method, apiLevel) -> { + if (Reference.methodFromMethod(callBackport).equals(method)) { + assertEquals( + parameters.isCfRuntime() ? AndroidApiLevel.O : parameters.getApiLevel(), + apiLevel); + } + })) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines("0") + .inspect( + inspector -> { + if (parameters.isCfRuntime()) { + assertThat(inspector.clazz(ApiCaller.class), isPresent()); + assertThat(inspector.clazz(Main.class), isPresent()); + assertEquals(2, inspector.allClasses().size()); + } else { + assertThat(inspector.clazz(ApiCaller.class), not(isPresent())); + assertThat(inspector.clazz(Main.class), isPresent()); + assertEquals(1, inspector.allClasses().size()); + } + }); + } + + public static class ApiCaller { + + public static String callBackport(int length) { + return Integer.toUnsignedString(length); + } + } + + public static class ApiCallerCaller { + + public static String callCallBackport(int length) { + return ApiCaller.callBackport(length); + } + } + + public static class Main { + + public static void main(String[] args) { + System.out.println(ApiCallerCaller.callCallBackport(args.length)); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelClassMergingWithDifferentApiFieldsTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelClassMergingWithDifferentApiFieldsTest.java index cb837ac..18b35f5 100644 --- a/src/test/java/com/android/tools/r8/apimodel/ApiModelClassMergingWithDifferentApiFieldsTest.java +++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelClassMergingWithDifferentApiFieldsTest.java
@@ -51,6 +51,7 @@ } }) .apply(ApiModelingTestHelper::enableApiCallerIdentification) + .apply(ApiModelingTestHelper::disableCheckAllApiReferencesAreNotUnknown) .apply(setMockApiLevelForClass(Api.class, AndroidApiLevel.L_MR1)) .compile() .addRunClasspathClasses(Api.class)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelFieldSuperTypeTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelFieldSuperTypeTest.java new file mode 100644 index 0000000..32b111e --- /dev/null +++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelFieldSuperTypeTest.java
@@ -0,0 +1,85 @@ +// 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.apimodel; + +import static com.android.tools.r8.apimodel.ApiModelingTestHelper.addTracedApiReferenceLevelCallBack; +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertEquals; + +import com.android.tools.r8.CompilationFailedException; +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.ToolHelper; +import com.android.tools.r8.references.Reference; +import com.android.tools.r8.utils.AndroidApiLevel; +import java.lang.reflect.Method; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ApiModelFieldSuperTypeTest extends TestBase { + + private final TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); + } + + public ApiModelFieldSuperTypeTest(TestParameters parameters) { + this.parameters = parameters; + } + + @Test(expected = CompilationFailedException.class) + public void testR8() throws Exception { + Method main = Main.class.getDeclaredMethod("main", String[].class); + testForR8(parameters.getBackend()) + .addProgramClassFileData( + transformer(Main.class) + .replaceClassDescriptorInMethodInstructions( + descriptor(AccessibilityService.class), + "Landroid/accessibilityservice/AccessibilityService;") + .transform()) + .addLibraryFiles( + ToolHelper.getFirstSupportedAndroidJar( + parameters.isCfRuntime() ? AndroidApiLevel.B : parameters.getApiLevel())) + .setMinApi(parameters.getApiLevel()) + .addKeepMainRule(Main.class) + .apply(ApiModelingTestHelper::enableApiCallerIdentification) + .apply( + addTracedApiReferenceLevelCallBack( + (method, apiLevel) -> { + if (Reference.methodFromMethod(main).equals(method)) { + // TODO(b/193414761): Should not be UNKNOWN. + assertEquals(AndroidApiLevel.UNKNOWN, apiLevel); + } + })) + .compileWithExpectedDiagnostics( + diagnostics -> { + // TODO(b/193414761): We should analyze all members. + diagnostics.assertErrorMessageThatMatches( + containsString("Every member should have been analyzed")); + }); + } + + /* Only here to get the test to compile */ + public static class AccessibilityService { + + int START_CONTINUATION_MASK = 42; + } + + public static class Main { + + public static void main(String[] args) { + // START_CONTINUATION_MASK is inherited from android/app/Service which was introduced at + // AndroidApiLevel.B. + System.out.println( + new /* android.accessibilityservice */ AccessibilityService().START_CONTINUATION_MASK); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelFieldTypeReferenceTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelFieldTypeReferenceTest.java new file mode 100644 index 0000000..149c93e --- /dev/null +++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelFieldTypeReferenceTest.java
@@ -0,0 +1,97 @@ +// 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.apimodel; + +import static com.android.tools.r8.apimodel.ApiModelingTestHelper.addTracedApiReferenceLevelCallBack; +import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass; +import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer; +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.references.Reference; +import com.android.tools.r8.utils.AndroidApiLevel; +import java.lang.reflect.Method; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ApiModelFieldTypeReferenceTest extends TestBase { + + private final TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); + } + + public ApiModelFieldTypeReferenceTest(TestParameters parameters) { + this.parameters = parameters; + } + + @Test + public void testR8() throws Exception { + Method readApiField = B.class.getDeclaredMethod("readApiField"); + Method setApiField = B.class.getDeclaredMethod("setApiField", Object.class); + testForR8(parameters.getBackend()) + .addProgramClasses(A.class, B.class, Main.class) + .addLibraryClasses(Api.class) + .addDefaultRuntimeLibrary(parameters) + .setMinApi(parameters.getApiLevel()) + .addKeepMainRule(Main.class) + .apply(setMockApiLevelForClass(Api.class, AndroidApiLevel.L_MR1)) + .apply(setMockApiLevelForDefaultInstanceInitializer(Api.class, AndroidApiLevel.L_MR1)) + .apply(ApiModelingTestHelper::enableApiCallerIdentification) + .apply( + addTracedApiReferenceLevelCallBack( + (method, apiLevel) -> { + if (Reference.methodFromMethod(readApiField).equals(method) + || Reference.methodFromMethod(setApiField).equals(method)) { + if (parameters.isCfRuntime()) { + assertEquals(AndroidApiLevel.L_MR1, apiLevel); + } else { + assertEquals(AndroidApiLevel.L_MR1.max(parameters.getApiLevel()), apiLevel); + } + } + })) + .compile() + .addRunClasspathClasses(Api.class) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines("Api"); + } + + public static class Api {} + + public static class A { + + public static Api api; + } + + public static class B { + + public static void readApiField() { + System.out.println(A.api == null ? "null" : "Api"); + } + + public static void setApiField(Object obj) { + A.api = (Api) obj; + } + } + + public static class Main { + + public static void main(String[] args) { + if (args.length > 0) { + B.setApiField(args[0]); + } else { + B.setApiField(new Api()); + } + B.readApiField(); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelInlineInSameClassDifferentApiLevelTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelInlineInSameClassDifferentApiLevelTest.java new file mode 100644 index 0000000..8002d8c --- /dev/null +++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelInlineInSameClassDifferentApiLevelTest.java
@@ -0,0 +1,81 @@ +// 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.apimodel; + +import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod; +import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat; + +import com.android.tools.r8.NeverInline; +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.utils.AndroidApiLevel; +import java.lang.reflect.Method; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ApiModelInlineInSameClassDifferentApiLevelTest extends TestBase { + + private final TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); + } + + public ApiModelInlineInSameClassDifferentApiLevelTest(TestParameters parameters) { + this.parameters = parameters; + } + + @Test + public void testR8() throws Exception { + Method apiLevel22 = Api.class.getDeclaredMethod("apiLevel22"); + Method callApi = ApiCaller.class.getDeclaredMethod("callApi"); + Method callCallApi = ApiCaller.class.getDeclaredMethod("callCallApi"); + testForR8(parameters.getBackend()) + .addProgramClasses(ApiCaller.class, Main.class) + .addLibraryClasses(Api.class) + .addDefaultRuntimeLibrary(parameters) + .setMinApi(parameters.getApiLevel()) + .addKeepMainRule(Main.class) + .apply(setMockApiLevelForMethod(apiLevel22, AndroidApiLevel.L_MR1)) + .apply(ApiModelingTestHelper::enableApiCallerIdentification) + .enableInliningAnnotations() + .compile() + .inspect(verifyThat(parameters, callApi).inlinedInto(callCallApi)) + .addRunClasspathClasses(Api.class) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines("Api::apiLevel22"); + } + + public static class Api { + + public static void apiLevel22() { + System.out.println("Api::apiLevel22"); + } + } + + public static class ApiCaller { + + public static void callApi() { + Api.apiLevel22(); + } + + @NeverInline + public static void callCallApi() { + callApi(); + } + } + + public static class Main { + + public static void main(String[] args) { + ApiCaller.callCallApi(); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMethodTypeReferenceTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMethodTypeReferenceTest.java new file mode 100644 index 0000000..d3d9572 --- /dev/null +++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMethodTypeReferenceTest.java
@@ -0,0 +1,105 @@ +// 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.apimodel; + +import static com.android.tools.r8.apimodel.ApiModelingTestHelper.addTracedApiReferenceLevelCallBack; +import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass; +import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer; +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.references.Reference; +import com.android.tools.r8.utils.AndroidApiLevel; +import java.lang.reflect.Method; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ApiModelMethodTypeReferenceTest extends TestBase { + + private final TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); + } + + public ApiModelMethodTypeReferenceTest(TestParameters parameters) { + this.parameters = parameters; + } + + @Test + public void testR8() throws Exception { + Method readApi = B.class.getDeclaredMethod("readApi"); + Method setApi = B.class.getDeclaredMethod("setApi", Object.class); + testForR8(parameters.getBackend()) + .addProgramClasses(A.class, B.class, Main.class) + .addLibraryClasses(Api.class) + .addDefaultRuntimeLibrary(parameters) + .setMinApi(parameters.getApiLevel()) + .addKeepMainRule(Main.class) + .apply(setMockApiLevelForClass(Api.class, AndroidApiLevel.L_MR1)) + .apply(setMockApiLevelForDefaultInstanceInitializer(Api.class, AndroidApiLevel.L_MR1)) + .apply(ApiModelingTestHelper::enableApiCallerIdentification) + .apply( + addTracedApiReferenceLevelCallBack( + (method, apiLevel) -> { + if (Reference.methodFromMethod(readApi).equals(method) + || Reference.methodFromMethod(setApi).equals(method)) { + if (parameters.isCfRuntime()) { + assertEquals(AndroidApiLevel.L_MR1, apiLevel); + } else { + assertEquals(AndroidApiLevel.L_MR1.max(parameters.getApiLevel()), apiLevel); + } + } + })) + .compile() + .addRunClasspathClasses(Api.class) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines("Api"); + } + + public static class Api {} + + public static class A { + + private static Api api; + + public static void setApi(Api api) { + A.api = api; + } + + public static Api getApi() { + return A.api; + } + } + + public static class B { + + public static void readApi() { + System.out.println(A.getApi() == null ? "null" : "Api"); + } + + public static void setApi(Object obj) { + A.setApi((Api) obj); + } + } + + public static class Main { + + public static void main(String[] args) { + if (args.length > 0) { + B.setApi(args[0]); + } else { + B.setApi(new Api()); + } + B.readApi(); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoClassInliningFieldTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoClassInliningFieldTest.java index 777b250..f4609d4 100644 --- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoClassInliningFieldTest.java +++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoClassInliningFieldTest.java
@@ -4,6 +4,7 @@ package com.android.tools.r8.apimodel; +import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer; import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForField; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; import static org.hamcrest.CoreMatchers.not; @@ -47,12 +48,17 @@ .enableInliningAnnotations() .enableNoHorizontalClassMergingAnnotations() .apply(setMockApiLevelForField(apiField, AndroidApiLevel.L_MR1)) + .apply(setMockApiLevelForDefaultInstanceInitializer(Api.class, AndroidApiLevel.L_MR1)) .apply(ApiModelingTestHelper::enableApiCallerIdentification) .compile() .inspect( inspector -> { - // TODO(b/138781768): Should not be class inlined. - assertThat(inspector.clazz(ApiCaller.class), not(isPresent())); + if (parameters.isDexRuntime() + && parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.L_MR1)) { + assertThat(inspector.clazz(ApiCaller.class), not(isPresent())); + } else { + assertThat(inspector.clazz(ApiCaller.class), isPresent()); + } }) .addRunClasspathClasses(Api.class) .run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoClassInliningMethodTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoClassInliningMethodTest.java index ac42465..22ecf86 100644 --- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoClassInliningMethodTest.java +++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoClassInliningMethodTest.java
@@ -5,13 +5,15 @@ package com.android.tools.r8.apimodel; import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod; -import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat; +import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.MatcherAssert.assertThat; -import com.android.tools.r8.NeverInline; import com.android.tools.r8.NoHorizontalClassMerging; import com.android.tools.r8.TestBase; import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.apimodel.ApiModelNoClassInliningFieldTest.ApiCallerCaller; import com.android.tools.r8.utils.AndroidApiLevel; import java.lang.reflect.Method; import org.junit.Test; @@ -36,8 +38,6 @@ @Test public void testR8() throws Exception { Method apiMethod = Api.class.getDeclaredMethod("apiLevel22"); - Method apiCaller = ApiCaller.class.getDeclaredMethod("callApi"); - Method apiCallerCaller = ApiCallerCaller.class.getDeclaredMethod("callCallApi"); testForR8(parameters.getBackend()) .addProgramClasses(ApiCaller.class, ApiCallerCaller.class, Main.class) .addLibraryClasses(Api.class) @@ -50,8 +50,14 @@ .apply(ApiModelingTestHelper::enableApiCallerIdentification) .compile() .inspect( - verifyThat(parameters, apiCaller) - .inlinedIntoFromApiLevel(apiCallerCaller, AndroidApiLevel.L_MR1)) + inspector -> { + if (parameters.isDexRuntime() + && parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.L_MR1)) { + assertThat(inspector.clazz(ApiCaller.class), not(isPresent())); + } else { + assertThat(inspector.clazz(ApiCaller.class), isPresent()); + } + }) .addRunClasspathClasses(Api.class) .run(parameters.getRuntime(), Main.class) .assertSuccessWithOutputLines("Api::apiLevel22"); @@ -72,19 +78,10 @@ } } - @NoHorizontalClassMerging - public static class ApiCallerCaller { - - @NeverInline - public static void callCallApi() { - new ApiCaller().callApi(); - } - } - public static class Main { public static void main(String[] args) { - ApiCallerCaller.callCallApi(); + new ApiCaller().callApi(); } } }
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfDefaultInterfaceMethodsTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfDefaultInterfaceMethodsTest.java index cd86ade..e997894 100644 --- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfDefaultInterfaceMethodsTest.java +++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfDefaultInterfaceMethodsTest.java
@@ -6,8 +6,9 @@ import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod; import static com.android.tools.r8.utils.AndroidApiLevel.L_MR1; +import static com.android.tools.r8.utils.codeinspector.Matchers.isAbstract; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; -import static org.hamcrest.CoreMatchers.not; +import static junit.framework.TestCase.assertEquals; import static org.hamcrest.MatcherAssert.assertThat; import com.android.tools.r8.TestBase; @@ -15,6 +16,7 @@ import com.android.tools.r8.TestParametersCollection; import com.android.tools.r8.utils.codeinspector.ClassSubject; import com.android.tools.r8.utils.codeinspector.CodeMatchers; +import com.android.tools.r8.utils.codeinspector.MethodSubject; import java.lang.reflect.Method; import org.junit.Test; import org.junit.runner.RunWith; @@ -46,26 +48,36 @@ .addKeepMainRule(Main.class) .apply(setMockApiLevelForMethod(apiMethod, L_MR1)) .apply(ApiModelingTestHelper::enableApiCallerIdentification) + .noMinification() .compile() .inspect( inspector -> { - ClassSubject aSubject = inspector.clazz(A.class); - assertThat(aSubject, isPresent()); - aSubject.forAllMethods( - method -> { - // TODO(b/191013385): noApiCall is inlined into Main, but the synthesized - // A.callApiLevel that dispatches to $CC is not. This should change after - // desugaring is moved up to the enqueuer. - if (method - .getOriginalName() - .equals(ApiCaller.class.getTypeName() + ".callApiLevel") - && !method.getAccessFlags().isBridge()) { - // TODO(b/191008231): Should not invoke api here. - assertThat(method, CodeMatchers.invokesMethodWithName("apiLevel22")); - return; - } - assertThat(method, not(CodeMatchers.invokesMethodWithName("apiLevel"))); - }); + assertThat(inspector.clazz(Main.class), isPresent()); + if (parameters.isDexRuntime() + && parameters.getApiLevel().isGreaterThanOrEqualTo(L_MR1)) { + assertEquals(1, inspector.allClasses().size()); + } else { + ClassSubject aSubject = inspector.clazz(A.class); + ClassSubject apiCaller = inspector.clazz(ApiCaller.class); + assertThat(apiCaller, isPresent()); + MethodSubject callApiLevel = apiCaller.uniqueMethodWithName("callApiLevel"); + if (parameters.isCfRuntime()) { + assertThat(aSubject, isPresent()); + assertThat(callApiLevel, CodeMatchers.invokesMethodWithName("apiLevel22")); + } else { + assert parameters.isDexRuntime(); + // TODO(b/191013385): A has a virtual method that calls callApiLevel on $CC, but + // that call should be inlined. + assertThat(aSubject, isPresent()); + assertThat(callApiLevel, isAbstract()); + ClassSubject classSubject = apiCaller.toCompanionClass(); + assertThat(classSubject, isPresent()); + assertEquals(1, classSubject.allMethods().size()); + assertThat( + classSubject.allMethods().get(0), + CodeMatchers.invokesMethodWithName("apiLevel22")); + } + } }) .addRunClasspathClasses(Api.class) .run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfLambdaTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfLambdaTest.java index c8f7caa..0525cd5 100644 --- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfLambdaTest.java +++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfLambdaTest.java
@@ -79,11 +79,9 @@ assertThat(apiCaller, not(isPresent())); } else { assertThat(apiCaller, isPresent()); - MethodSubject apiCaller$lambdagetAction$0 = - apiCaller.uniqueMethodWithName("lambda$getAction$0"); - assertThat(apiCaller$lambdagetAction$0, isPresent()); - assertThat( - apiCaller$lambdagetAction$0, CodeMatchers.invokesMethodWithName("apiLevel22")); + MethodSubject callApi = apiCaller.uniqueMethodWithName("callApi"); + assertThat(callApi, isPresent()); + assertThat(callApi, CodeMatchers.invokesMethodWithName("apiLevel22")); } }) .addRunClasspathClasses(Api.class)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoVerticalMergingSubReferenceApiTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoVerticalMergingSubReferenceApiTest.java index f01e1b0..98b4e92 100644 --- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoVerticalMergingSubReferenceApiTest.java +++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoVerticalMergingSubReferenceApiTest.java
@@ -17,9 +17,9 @@ import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestParametersCollection; import com.android.tools.r8.utils.codeinspector.ClassSubject; +import com.android.tools.r8.utils.codeinspector.CodeMatchers; import com.android.tools.r8.utils.codeinspector.FoundMethodSubject; import java.lang.reflect.Method; -import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -70,12 +70,12 @@ && parameters.getApiLevel().isGreaterThanOrEqualTo(L_MR1)) { assertThat(base, not(isPresent())); ClassSubject sub = inspector.clazz(Sub.class); - List<FoundMethodSubject> callApis = - sub.allMethods( - method -> - method.getOriginalName().equals(Base.class.getTypeName() + ".callApi")); - // TODO(b/191013233): Remove synthetic bridge. Remove noMinification after fixed. - assertEquals(2, callApis.size()); + assertThat(sub, isPresent()); + assertThat(sub.uniqueInstanceInitializer(), isPresent()); + assertEquals(1, sub.virtualMethods().size()); + FoundMethodSubject callCallApi = sub.virtualMethods().get(0); + assertEquals("callCallApi", callCallApi.getOriginalName()); + assertThat(callCallApi, CodeMatchers.invokesMethodWithName("apiLevel22")); } else { assertThat(base, isPresent()); }
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoVerticalMergingTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoVerticalMergingTest.java index b29e694..b7cd0b1 100644 --- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoVerticalMergingTest.java +++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoVerticalMergingTest.java
@@ -17,9 +17,9 @@ import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestParametersCollection; import com.android.tools.r8.utils.codeinspector.ClassSubject; +import com.android.tools.r8.utils.codeinspector.CodeMatchers; import com.android.tools.r8.utils.codeinspector.FoundMethodSubject; import java.lang.reflect.Method; -import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -61,7 +61,6 @@ inspector.assertNoClassesMerged(); } }) - .noMinification() .compile() .inspect( inspector -> { @@ -70,12 +69,12 @@ && parameters.getApiLevel().isGreaterThanOrEqualTo(L_MR1)) { assertThat(base, not(isPresent())); ClassSubject sub = inspector.clazz(Sub.class); - List<FoundMethodSubject> callApis = - sub.allMethods( - method -> - method.getOriginalName().equals(Base.class.getTypeName() + ".callApi")); - // TODO(b/191013233): Remove synthetic bridge. Remove noMinification after fixed. - assertEquals(2, callApis.size()); + assertThat(sub, isPresent()); + assertThat(sub.uniqueInstanceInitializer(), isPresent()); + assertEquals(1, sub.virtualMethods().size()); + FoundMethodSubject callCallApi = sub.virtualMethods().get(0); + assertEquals("callCallApi", callCallApi.getOriginalName()); + assertThat(callCallApi, CodeMatchers.invokesMethodWithName("apiLevel22")); } else { assertThat(base, isPresent()); }
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchInterfaceOverrideTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchInterfaceOverrideTest.java new file mode 100644 index 0000000..d262834 --- /dev/null +++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchInterfaceOverrideTest.java
@@ -0,0 +1,78 @@ +// 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.apimodel; + +import static com.android.tools.r8.apimodel.ApiModelingTestHelper.addTracedApiReferenceLevelCallBack; +import static com.android.tools.r8.utils.AndroidApiLevel.LATEST; +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.ToolHelper; +import com.android.tools.r8.references.Reference; +import com.android.tools.r8.utils.AndroidApiLevel; +import java.lang.reflect.Method; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ApiModelVirtualDispatchInterfaceOverrideTest extends TestBase { + + private final TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); + } + + public ApiModelVirtualDispatchInterfaceOverrideTest(TestParameters parameters) { + this.parameters = parameters; + } + + @Test() + public void testR8() throws Exception { + // android/content/res/AssetManager exists from AndroidApiLevel.B but in 21 it implements + // java/lang/AutoCloseable. However, close()V has always been defined, so the api level should + // always be min api. + Method main = + ApiModelVirtualDispatchSuperTypeTest.Main.class.getDeclaredMethod("main", String[].class); + testForR8(parameters.getBackend()) + .addProgramClassFileData( + transformer(Main.class) + .replaceClassDescriptorInMethodInstructions( + descriptor(AssetManager.class), "Landroid/content/res/AssetManager;") + .transform()) + .addLibraryFiles(ToolHelper.getAndroidJar(LATEST)) + .setMinApi(parameters.getApiLevel()) + .addKeepMainRule(Main.class) + .apply(ApiModelingTestHelper::enableApiCallerIdentification) + .apply( + addTracedApiReferenceLevelCallBack( + (method, apiLevel) -> { + if (Reference.methodFromMethod(main).equals(method)) { + assertEquals( + parameters.isCfRuntime() ? AndroidApiLevel.B : parameters.getApiLevel(), + apiLevel); + } + })) + .compile(); + } + + public static class AssetManager { + + public void close() {} + } + + public static class Main { + + public static void main(String[] args) throws Exception { + AssetManager manager = null; + manager.close(); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchInterfaceTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchInterfaceTest.java new file mode 100644 index 0000000..22c0702 --- /dev/null +++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchInterfaceTest.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.apimodel; + +import static com.android.tools.r8.apimodel.ApiModelingTestHelper.addTracedApiReferenceLevelCallBack; +import static com.android.tools.r8.utils.AndroidApiLevel.UNKNOWN; +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertEquals; + +import com.android.tools.r8.CompilationFailedException; +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.references.Reference; +import java.lang.reflect.Method; +import java.util.ArrayList; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ApiModelVirtualDispatchInterfaceTest extends TestBase { + + private final TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); + } + + public ApiModelVirtualDispatchInterfaceTest(TestParameters parameters) { + this.parameters = parameters; + } + + @Test(expected = CompilationFailedException.class) + public void testR8() throws Exception { + Method main = Main.class.getDeclaredMethod("main", String[].class); + testForR8(parameters.getBackend()) + .addProgramClasses(Main.class) + .addDefaultRuntimeLibrary(parameters) + .setMinApi(parameters.getApiLevel()) + .addKeepMainRule(Main.class) + .apply(ApiModelingTestHelper::enableApiCallerIdentification) + .apply( + addTracedApiReferenceLevelCallBack( + (method, apiLevel) -> { + if (Reference.methodFromMethod(main).equals(method)) { + // TODO(b/193414761): Should not be UNKNOWN. + assertEquals(UNKNOWN, apiLevel); + } + })) + .compileWithExpectedDiagnostics( + diagnostics -> { + // TODO(b/193414761): We should analyze all members. + diagnostics.assertErrorMessageThatMatches( + containsString("Every member should have been analyzed")); + }); + } + + public static class Main { + + public static void main(String[] args) { + // Iterator is inherited from java/lang/Iterable which was introduced at AndroidApiLevel.B. + new ArrayList<>().iterator(); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchLinkInterfaceTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchLinkInterfaceTest.java new file mode 100644 index 0000000..3f8bed1 --- /dev/null +++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchLinkInterfaceTest.java
@@ -0,0 +1,85 @@ +// 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.apimodel; + +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.UNKNOWN; +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertEquals; + +import com.android.tools.r8.CompilationFailedException; +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.ToolHelper; +import com.android.tools.r8.references.Reference; +import java.lang.reflect.Method; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ApiModelVirtualDispatchLinkInterfaceTest extends TestBase { + + private final TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); + } + + public ApiModelVirtualDispatchLinkInterfaceTest(TestParameters parameters) { + this.parameters = parameters; + } + + @Test(expected = CompilationFailedException.class) + public void testR8() throws Exception { + // Landroid/view/accessibility/AccessibilityNodeInfo$AccessibilityAction; is introduced at api + // level 21 and on api level 30 it implements android.os.Parcelable. + // android.os.Parcelable.describeContents() has api level B. Since the invoke goes through the + // link established at level 30, the api reference level should be 30. + Method main = Main.class.getDeclaredMethod("main", String[].class); + testForR8(parameters.getBackend()) + .addProgramClassFileData( + transformer(Main.class) + .replaceClassDescriptorInMethodInstructions( + descriptor(AccessibilityNodeInfo$AccessibilityAction.class), + "Landroid/view/accessibility/AccessibilityNodeInfo$AccessibilityAction;") + .transform()) + .addLibraryFiles(ToolHelper.getAndroidJar(LATEST)) + .setMinApi(parameters.getApiLevel()) + .addKeepMainRule(Main.class) + .apply(ApiModelingTestHelper::enableApiCallerIdentification) + .apply( + addTracedApiReferenceLevelCallBack( + (method, apiLevel) -> { + if (Reference.methodFromMethod(main).equals(method)) { + // TODO(b/193414761): Should be 30. + assertEquals(UNKNOWN, apiLevel); + } + })) + .compileWithExpectedDiagnostics( + diagnostics -> { + // TODO(b/193414761): We should analyze all members. + diagnostics.assertErrorMessageThatMatches( + containsString("Every member should have been analyzed")); + }); + } + + public static class AccessibilityNodeInfo$AccessibilityAction { + int describeContents() { + return 42; + } + } + + public static class Main { + + public static void main(String[] args) { + new AccessibilityNodeInfo$AccessibilityAction().describeContents(); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchSuperTypeTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchSuperTypeTest.java new file mode 100644 index 0000000..2c5868e --- /dev/null +++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelVirtualDispatchSuperTypeTest.java
@@ -0,0 +1,83 @@ +// 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.apimodel; + +import static com.android.tools.r8.apimodel.ApiModelingTestHelper.addTracedApiReferenceLevelCallBack; +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertEquals; + +import com.android.tools.r8.CompilationFailedException; +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.ToolHelper; +import com.android.tools.r8.references.Reference; +import com.android.tools.r8.utils.AndroidApiLevel; +import java.lang.reflect.Method; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ApiModelVirtualDispatchSuperTypeTest extends TestBase { + + private final TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); + } + + public ApiModelVirtualDispatchSuperTypeTest(TestParameters parameters) { + this.parameters = parameters; + } + + @Test(expected = CompilationFailedException.class) + public void testR8() throws Exception { + Method main = Main.class.getDeclaredMethod("main", String[].class); + testForR8(parameters.getBackend()) + .addProgramClassFileData( + transformer(Main.class) + .replaceClassDescriptorInMethodInstructions( + descriptor(AccessibilityService.class), + "Landroid/accessibilityservice/AccessibilityService;") + .transform()) + .addLibraryFiles( + ToolHelper.getFirstSupportedAndroidJar( + parameters.isCfRuntime() ? AndroidApiLevel.B : parameters.getApiLevel())) + .setMinApi(parameters.getApiLevel()) + .addKeepMainRule(Main.class) + .apply(ApiModelingTestHelper::enableApiCallerIdentification) + .apply( + addTracedApiReferenceLevelCallBack( + (method, apiLevel) -> { + if (Reference.methodFromMethod(main).equals(method)) { + // TODO(b/193414761): Should not be UNKNOWN. + assertEquals(AndroidApiLevel.UNKNOWN, apiLevel); + } + })) + .compileWithExpectedDiagnostics( + diagnostics -> { + // TODO(b/193414761): We should analyze all members. + diagnostics.assertErrorMessageThatMatches( + containsString("Every member should have been analyzed")); + }); + } + + /* Only here to get the test to compile */ + public static class AccessibilityService { + + public void stopSelf() {} + } + + public static class Main { + + public static void main(String[] args) { + // stopSelf() is inherited from android/app/Service which was introduced at AndroidApiLevel.B. + new /* android.accessibilityservice */ AccessibilityService().stopSelf(); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java index 4e02aff..76a4d56 100644 --- a/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java +++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java
@@ -89,6 +89,14 @@ }); } + static void disableCheckAllApiReferencesAreNotUnknown( + TestCompilerBuilder<?, ?, ?, ?, ?> compilerBuilder) { + compilerBuilder.addOptionsModification( + options -> { + options.apiModelingOptions().checkAllApiReferencesAreSet = false; + }); + } + static <T extends TestCompilerBuilder<?, ?, ?, ?, ?>> ThrowableConsumer<T> addTracedApiReferenceLevelCallBack( BiConsumer<MethodReference, AndroidApiLevel> consumer) {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java index c7544d5..f0f4e90 100644 --- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java +++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java
@@ -9,6 +9,7 @@ import static org.hamcrest.CoreMatchers.startsWith; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import com.android.tools.r8.L8Command; import com.android.tools.r8.OutputMode; @@ -17,8 +18,11 @@ import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestParametersCollection; import com.android.tools.r8.ToolHelper; +import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.codeinspector.CodeInspector; +import com.android.tools.r8.utils.codeinspector.FoundMethodSubject; +import com.android.tools.r8.utils.codeinspector.InstructionSubject; import java.nio.file.Path; import java.util.ArrayList; import org.junit.Assume; @@ -104,6 +108,21 @@ } assertThat(inspector.clazz("j$.util.Optional"), isPresent()); assertThat(inspector.clazz("j$.util.function.Function"), isPresent()); + if (parameters.getApiLevel().isLessThan(AndroidApiLevel.K)) { + inspector.forAllClasses(clazz -> clazz.forAllMethods(this::assertNoSupressedInvocations)); + } + } + + private void assertNoSupressedInvocations(FoundMethodSubject method) { + if (method.isAbstract()) { + return; + } + for (InstructionSubject instruction : method.instructions()) { + if (instruction.isInvoke() && instruction.getMethod() != null) { + assertNotEquals( + instruction.getMethod(), new DexItemFactory().throwableMethods.addSuppressed); + } + } } }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java index 6453792..f75e870 100644 --- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java +++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java
@@ -158,14 +158,16 @@ builder.inspectDiagnosticMessages( diagnostics -> assertTrue( - diagnostics.getInfos().stream() - .noneMatch( - string -> - string - .getDiagnosticMessage() - .startsWith( - "Invalid parameter counts in MethodParameter" - + " attributes."))))) + // TODO(b/193597730): Fix JDK11 desugared library message, + isJDK11DesugaredLibrary() + || diagnostics.getInfos().stream() + .noneMatch( + string -> + string + .getDiagnosticMessage() + .startsWith( + "Invalid parameter counts in MethodParameter" + + " attributes."))))) .writeToZip(); } catch (CompilationFailedException | ExecutionException | IOException e) { throw new RuntimeException(e);
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/kotlin/KotlinMetadataTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/kotlin/KotlinMetadataTest.java index c7fc371..c10af51 100644 --- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/kotlin/KotlinMetadataTest.java +++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/kotlin/KotlinMetadataTest.java
@@ -21,6 +21,7 @@ import com.android.tools.r8.R8TestCompileResult; import com.android.tools.r8.R8TestRunResult; import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestCompileResult; import com.android.tools.r8.TestParameters; import com.android.tools.r8.ToolHelper; import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase; @@ -146,7 +147,11 @@ testBuilder .compile() .assertNoErrorMessages() - .apply(TestBase::verifyAllInfoFromGenericSignatureTypeParameterValidation) + // -keepattributes Signature is added in kotlin-reflect from version 1.4.20. + .applyIf( + kotlinParameters.getCompiler().isNot(KOTLINC_1_3_72), + TestBase::verifyAllInfoFromGenericSignatureTypeParameterValidation, + TestCompileResult::assertNoInfoMessages) .apply(KotlinMetadataTestBase::verifyExpectedWarningsFromKotlinReflectAndStdLib); if (desugarLibrary) { assertNotNull(keepRuleConsumer);
diff --git a/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignatureCorrectnessHelperTests.java b/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignatureCorrectnessHelperTests.java index 969a59f..588ad23 100644 --- a/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignatureCorrectnessHelperTests.java +++ b/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignatureCorrectnessHelperTests.java
@@ -8,6 +8,7 @@ import static org.junit.Assert.assertNotNull; import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestDiagnosticMessagesImpl; import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestParametersCollection; import com.android.tools.r8.ToolHelper; @@ -17,8 +18,12 @@ import com.android.tools.r8.graph.GenericSignatureContextBuilder; import com.android.tools.r8.graph.GenericSignatureCorrectnessHelper; import com.android.tools.r8.graph.GenericSignatureCorrectnessHelper.SignatureEvaluationResult; +import com.android.tools.r8.shaking.AppInfoWithLiveness; +import com.android.tools.r8.shaking.ProguardConfiguration; +import com.android.tools.r8.shaking.ProguardKeepAttributes; import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate; import com.android.tools.r8.utils.DescriptorUtils; +import com.android.tools.r8.utils.Reporter; import com.google.common.collect.ImmutableList; import java.util.List; import org.junit.Test; @@ -41,12 +46,18 @@ @Test public void testAllValid() throws Exception { AppView<AppInfoWithClassHierarchy> appView = - computeAppViewWithClassHierachy( + computeAppViewWithClassHierarchy( buildInnerClasses(GenericSignatureCorrectnessHelperTests.class) .addLibraryFile(ToolHelper.getJava8RuntimeJar()) - .build()); - GenericSignatureContextBuilder contextBuilder = - GenericSignatureContextBuilder.create(appView.appInfo().classes()); + .build(), + factory -> { + ProguardConfiguration.Builder builder = + ProguardConfiguration.builder( + factory, new Reporter(new TestDiagnosticMessagesImpl())); + builder.addKeepAttributePatterns(ImmutableList.of(ProguardKeepAttributes.SIGNATURE)); + return builder.build(); + }); + GenericSignatureContextBuilder contextBuilder = GenericSignatureContextBuilder.create(appView); GenericSignatureCorrectnessHelper.createForVerification(appView, contextBuilder) .run(appView.appInfo().classes()); } @@ -178,14 +189,20 @@ Class<?> classToVerify, SignatureEvaluationResult expected) throws Exception { - AppView<AppInfoWithClassHierarchy> appView = - computeAppViewWithClassHierachy( + AppView<AppInfoWithLiveness> appView = + computeAppViewWithLiveness( buildClasses(classes) .addClassProgramData(transformations) .addLibraryFile(ToolHelper.getJava8RuntimeJar()) - .build()); - GenericSignatureContextBuilder contextBuilder = - GenericSignatureContextBuilder.create(appView.appInfo().classes()); + .build(), + factory -> { + ProguardConfiguration.Builder builder = + ProguardConfiguration.builder( + factory, new Reporter(new TestDiagnosticMessagesImpl())); + builder.addKeepAttributePatterns(ImmutableList.of(ProguardKeepAttributes.SIGNATURE)); + return builder.build(); + }); + GenericSignatureContextBuilder contextBuilder = GenericSignatureContextBuilder.create(appView); GenericSignatureCorrectnessHelper check = GenericSignatureCorrectnessHelper.createForInitialCheck(appView, contextBuilder); DexProgramClass clazz =
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataFirstToLatestTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataFirstToLatestTest.java new file mode 100644 index 0000000..c030f80 --- /dev/null +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataFirstToLatestTest.java
@@ -0,0 +1,150 @@ +// 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.kotlin.metadata; + +import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar; +import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertThrows; + +import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler; +import com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion; +import com.android.tools.r8.KotlinTestParameters; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.ToolHelper; +import com.android.tools.r8.utils.DescriptorUtils; +import com.android.tools.r8.utils.StringUtils; +import java.nio.file.Path; +import java.util.Collection; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +/** + * Kotlin has limited support for metadata of older versions. In particular, kotlinc 1.5 has + * deprecated byte-code version which is expected by kotlinc 1.3. The expectation is that if we + * compile with kotlinc 1.3 and then compile with R8 with a new version of the kolin-metadata-jvm + * library, the kotlin library is no longer usable in kotlinc 1.3. However, it should be usable in + * kotlinc 1.5. + */ +@RunWith(Parameterized.class) +public class MetadataFirstToLatestTest extends KotlinMetadataTestBase { + + private final String EXPECTED = StringUtils.lines("foo"); + private static final String PKG_LIB = PKG + ".crossinline_anon_lib"; + private static final String PKG_APP = PKG + ".crossinline_anon_app"; + private final TestParameters parameters; + + private static final KotlinCompileMemoizer libJars = + getCompileMemoizer( + getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib")); + + @Parameterized.Parameters(name = "{0}, {1}") + public static Collection<Object[]> data() { + return buildParameters( + getTestParameters().withCfRuntimes().build(), + getKotlinTestParameters() + .withCompiler(KotlinCompilerVersion.KOTLINC_1_3_72) + .withAllTargetVersions() + .build()); + } + + public MetadataFirstToLatestTest( + TestParameters parameters, KotlinTestParameters kotlinParameters) { + super(kotlinParameters); + this.parameters = parameters; + } + + @Test + public void smokeTest() throws Exception { + runTest( + KotlinCompilerVersion.KOTLINC_1_5_0, + libJars.getForConfiguration(kotlinc, targetVersion), + getKotlinStdlibJar(kotlinc)); + } + + @Test + public void testOnFirst() throws Exception { + Path libJar = + testForR8(parameters.getBackend()) + .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion)) + .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc)) + .addKeepAllClassesRule() + .addKeepAllAttributes() + .addOptionsModification( + options -> { + // Ensure that we rewrite the metadata with kotlin-metadata-jvm library. + options.testing.keepMetadataInR8IfNotRewritten = false; + }) + .compile() + .writeToZip(); + Path stdLibJar = + testForR8(parameters.getBackend()) + .addProgramFiles( + ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinAnnotationJar(kotlinc)) + .addKeepAllClassesRule() + .addKeepAllAttributes() + .allowDiagnosticWarningMessages() + .compile() + .assertAllWarningMessagesMatch( + equalTo("Resource 'META-INF/MANIFEST.MF' already exists.")) + .writeToZip(); + AssertionError assertionError = + assertThrows( + AssertionError.class, + () -> { + runTest(KotlinCompilerVersion.KOTLINC_1_3_72, libJar, stdLibJar); + }); + assertThat( + assertionError.getMessage(), + containsString("compiled with an incompatible version of Kotlin")); + } + + @Test + public void testOnLatest() throws Exception { + Path libJar = + testForR8(parameters.getBackend()) + .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion)) + .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc)) + .addKeepAllClassesRule() + .addKeepAllAttributes() + .compile() + .writeToZip(); + Path stdLibJar = + testForR8(parameters.getBackend()) + .addProgramFiles( + ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinAnnotationJar(kotlinc)) + .addKeepAllClassesRule() + .addKeepAllAttributes() + .allowDiagnosticWarningMessages() + .compile() + .assertAllWarningMessagesMatch( + equalTo("Resource 'META-INF/MANIFEST.MF' already exists.")) + .writeToZip(); + runTest(KotlinCompilerVersion.KOTLINC_1_5_0, libJar, stdLibJar); + } + + private void runTest(KotlinCompilerVersion kotlinCompilerVersion, Path libJar, Path stdLibJar) + throws Exception { + Path output = + kotlinc( + parameters.getRuntime().asCf(), + new KotlinCompiler(kotlinCompilerVersion), + targetVersion) + .addClasspathFiles(libJar, stdLibJar) + .addSourceFiles( + getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main")) + .setOutputPath(temp.newFolder().toPath()) + .noStdLib() + .compile(); + testForJvm() + .addRunClasspathFiles(stdLibJar, libJar) + .addClasspath(output) + .run(parameters.getRuntime(), PKG_APP + ".MainKt") + .assertSuccessWithOutput(EXPECTED); + } +}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrimitiveTypeRewriteTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrimitiveTypeRewriteTest.java index cfa333f..a9732a4 100644 --- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrimitiveTypeRewriteTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrimitiveTypeRewriteTest.java
@@ -4,6 +4,7 @@ package com.android.tools.r8.kotlin.metadata; +import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION; import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar; import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed; @@ -35,7 +36,10 @@ public static Collection<Object[]> data() { return buildParameters( getTestParameters().withCfRuntimes().build(), - getKotlinTestParameters().withAllCompilersAndTargetVersions().build()); + getKotlinTestParameters() + .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION) + .withAllTargetVersions() + .build()); } public MetadataPrimitiveTypeRewriteTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java index cccbde4..5c9a639 100644 --- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java
@@ -4,6 +4,7 @@ package com.android.tools.r8.kotlin.metadata; +import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION; import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed; @@ -62,7 +63,10 @@ public static Collection<Object[]> data() { return buildParameters( getTestParameters().withCfRuntimes().build(), - getKotlinTestParameters().withAllCompilersAndTargetVersions().build()); + getKotlinTestParameters() + .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION) + .withAllTargetVersions() + .build()); } public MetadataRewriteAnnotationTest( @@ -167,14 +171,14 @@ assertEquals( DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB) + "/AnnoWithClassArr", annotation.getClassName()); - Map<String, KmAnnotationArgument<?>> arguments = annotation.getArguments(); + Map<String, KmAnnotationArgument> arguments = annotation.getArguments(); assertEquals(1, arguments.size()); ArrayValue classes = (ArrayValue) arguments.get("classes"); assertEquals( - "KClassValue(value=" + foo.getFinalBinaryName() + ")", - classes.getValue().get(0).toString()); + "KClassValue(className=" + foo.getFinalBinaryName() + ", arrayDimensionCount=0)", + classes.getElements().get(0).toString()); assertEquals( - "KClassValue(value=" + bar.getFinalBinaryName() + ")", - classes.getValue().get(1).toString()); + "KClassValue(className=" + bar.getFinalBinaryName() + ", arrayDimensionCount=0)", + classes.getElements().get(1).toString()); } }
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnonymousTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnonymousTest.java index 0822971..03c8d5a 100644 --- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnonymousTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnonymousTest.java
@@ -4,6 +4,7 @@ package com.android.tools.r8.kotlin.metadata; +import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION; import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar; import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed; @@ -30,7 +31,10 @@ public static Collection<Object[]> data() { return buildParameters( getTestParameters().withCfRuntimes().build(), - getKotlinTestParameters().withAllCompilersAndTargetVersions().build()); + getKotlinTestParameters() + .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION) + .withAllTargetVersions() + .build()); } public MetadataRewriteAnonymousTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDoNotEmitValuesIfEmpty.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDoNotEmitValuesIfEmpty.java index 2558cbb..08de164 100644 --- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDoNotEmitValuesIfEmpty.java +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDoNotEmitValuesIfEmpty.java
@@ -49,7 +49,7 @@ testForR8(parameters.getBackend()) .addProgramFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc)) .setMinApi(parameters.getApiLevel()) - .addKeepAllClassesRule() + .addKeepAllClassesRuleWithAllowObfuscation() .addKeepKotlinMetadata() .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS) .allowDiagnosticWarningMessages()
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteFlexibleUpperBoundTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteFlexibleUpperBoundTest.java index 527269c..e37b5fd 100644 --- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteFlexibleUpperBoundTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteFlexibleUpperBoundTest.java
@@ -4,6 +4,7 @@ package com.android.tools.r8.kotlin.metadata; +import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION; import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar; import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; @@ -43,7 +44,10 @@ public static Collection<Object[]> data() { return buildParameters( getTestParameters().withCfRuntimes().build(), - getKotlinTestParameters().withAllCompilersAndTargetVersions().build()); + getKotlinTestParameters() + .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION) + .withAllTargetVersions() + .build()); } public MetadataRewriteFlexibleUpperBoundTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInClasspathTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInClasspathTypeTest.java index 4c712d3..0785411 100644 --- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInClasspathTypeTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInClasspathTypeTest.java
@@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.kotlin.metadata; +import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION; import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar; import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar; import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction; @@ -38,7 +39,10 @@ public static Collection<Object[]> data() { return buildParameters( getTestParameters().withCfRuntimes().build(), - getKotlinTestParameters().withAllCompilersAndTargetVersions().build()); + getKotlinTestParameters() + .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION) + .withAllTargetVersions() + .build()); } public MetadataRewriteInClasspathTypeTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInCompanionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInCompanionTest.java index 0cedda8..6e754e1 100644 --- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInCompanionTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInCompanionTest.java
@@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.kotlin.metadata; +import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION; import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar; import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; @@ -47,7 +48,10 @@ public static Collection<Object[]> data() { return buildParameters( getTestParameters().withCfRuntimes().build(), - getKotlinTestParameters().withAllCompilersAndTargetVersions().build()); + getKotlinTestParameters() + .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION) + .withAllTargetVersions() + .build()); } public MetadataRewriteInCompanionTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionFunctionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionFunctionTest.java index bc5f909..a95ed25 100644 --- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionFunctionTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionFunctionTest.java
@@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.kotlin.metadata; +import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION; import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar; import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; @@ -44,7 +45,10 @@ public static Collection<Object[]> data() { return buildParameters( getTestParameters().withCfRuntimes().build(), - getKotlinTestParameters().withAllCompilersAndTargetVersions().build()); + getKotlinTestParameters() + .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION) + .withAllTargetVersions() + .build()); } public MetadataRewriteInExtensionFunctionTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionPropertyTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionPropertyTest.java index 90e914d..c418067 100644 --- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionPropertyTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionPropertyTest.java
@@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.kotlin.metadata; +import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION; import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar; import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar; import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction; @@ -43,7 +44,10 @@ public static Collection<Object[]> data() { return buildParameters( getTestParameters().withCfRuntimes().build(), - getKotlinTestParameters().withAllCompilersAndTargetVersions().build()); + getKotlinTestParameters() + .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION) + .withAllTargetVersions() + .build()); } public MetadataRewriteInExtensionPropertyTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionTest.java index 24a19d3..14d1497 100644 --- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionTest.java
@@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.kotlin.metadata; +import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION; import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar; import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar; import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction; @@ -42,7 +43,10 @@ public static Collection<Object[]> data() { return buildParameters( getTestParameters().withCfRuntimes().build(), - getKotlinTestParameters().withAllCompilersAndTargetVersions().build()); + getKotlinTestParameters() + .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION) + .withAllTargetVersions() + .build()); } public MetadataRewriteInFunctionTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithVarargTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithVarargTest.java index ec249cb..c2c61a6 100644 --- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithVarargTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithVarargTest.java
@@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.kotlin.metadata; +import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION; import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar; import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar; import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction; @@ -43,7 +44,10 @@ public static Collection<Object[]> data() { return buildParameters( getTestParameters().withCfRuntimes().build(), - getKotlinTestParameters().withAllCompilersAndTargetVersions().build()); + getKotlinTestParameters() + .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION) + .withAllTargetVersions() + .build()); } public MetadataRewriteInFunctionWithVarargTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInNestedClassTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInNestedClassTest.java index f2aa77d..24e7a56 100644 --- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInNestedClassTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInNestedClassTest.java
@@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.kotlin.metadata; +import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION; import static com.android.tools.r8.utils.DescriptorUtils.descriptorToJavaType; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed; @@ -36,7 +37,10 @@ public static Collection<Object[]> data() { return buildParameters( getTestParameters().withCfRuntimes().build(), - getKotlinTestParameters().withAllCompilersAndTargetVersions().build()); + getKotlinTestParameters() + .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION) + .withAllTargetVersions() + .build()); } public MetadataRewriteInNestedClassTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInParameterTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInParameterTypeTest.java index 27ee400..59d3258 100644 --- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInParameterTypeTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInParameterTypeTest.java
@@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.kotlin.metadata; +import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION; import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar; import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; @@ -35,7 +36,10 @@ public static Collection<Object[]> data() { return buildParameters( getTestParameters().withCfRuntimes().build(), - getKotlinTestParameters().withAllCompilersAndTargetVersions().build()); + getKotlinTestParameters() + .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION) + .withAllTargetVersions() + .build()); } public MetadataRewriteInParameterTypeTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTest.java index 6bb1804..ebafde8 100644 --- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTest.java
@@ -4,6 +4,7 @@ package com.android.tools.r8.kotlin.metadata; import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_1_5_0; +import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION; import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar; import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar; import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionProperty; @@ -42,7 +43,10 @@ public static Collection<Object[]> data() { return buildParameters( getTestParameters().withCfRuntimes().build(), - getKotlinTestParameters().withAllCompilersAndTargetVersions().build()); + getKotlinTestParameters() + .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION) + .withAllTargetVersions() + .build()); } public MetadataRewriteInPropertyTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTypeTest.java index 28721c8..e0233d9 100644 --- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTypeTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTypeTest.java
@@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.kotlin.metadata; +import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION; import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar; import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; @@ -35,7 +36,10 @@ public static Collection<Object[]> data() { return buildParameters( getTestParameters().withCfRuntimes().build(), - getKotlinTestParameters().withAllCompilersAndTargetVersions().build()); + getKotlinTestParameters() + .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION) + .withAllTargetVersions() + .build()); } public MetadataRewriteInPropertyTypeTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInReturnTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInReturnTypeTest.java index 225ac74..ac35453 100644 --- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInReturnTypeTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInReturnTypeTest.java
@@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.kotlin.metadata; +import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION; import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar; import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; @@ -35,7 +36,10 @@ public static Collection<Object[]> data() { return buildParameters( getTestParameters().withCfRuntimes().build(), - getKotlinTestParameters().withAllCompilersAndTargetVersions().build()); + getKotlinTestParameters() + .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION) + .withAllTargetVersions() + .build()); } public MetadataRewriteInReturnTypeTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSuperTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSuperTypeTest.java index ccc94e5..ffa0888 100644 --- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSuperTypeTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSuperTypeTest.java
@@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.kotlin.metadata; +import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed; @@ -35,7 +36,10 @@ public static Collection<Object[]> data() { return buildParameters( getTestParameters().withCfRuntimes().build(), - getKotlinTestParameters().withAllCompilersAndTargetVersions().build()); + getKotlinTestParameters() + .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION) + .withAllTargetVersions() + .build()); } public MetadataRewriteInSuperTypeTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeAliasTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeAliasTest.java index 0585af6..32be357 100644 --- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeAliasTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeAliasTest.java
@@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.kotlin.metadata; +import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION; import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar; import static com.android.tools.r8.ToolHelper.getKotlinReflectJar; import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar; @@ -65,7 +66,10 @@ public static Collection<Object[]> data() { return buildParameters( getTestParameters().withCfRuntimes().build(), - getKotlinTestParameters().withAllCompilersAndTargetVersions().build()); + getKotlinTestParameters() + .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION) + .withAllTargetVersions() + .build()); } public MetadataRewriteInTypeAliasTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeArgumentsTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeArgumentsTest.java index eddf514..d5342de 100644 --- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeArgumentsTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeArgumentsTest.java
@@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. package com.android.tools.r8.kotlin.metadata; +import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION; import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar; import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar; import static com.android.tools.r8.utils.codeinspector.Matchers.isDexClass; @@ -42,8 +43,8 @@ private static final String LIB_PKG = PKG + ".typeargument_lib."; - private static int FLAG_NONE = 0; - private static int FLAG_REIFIED = 1; + private static final int FLAG_NONE = 0; + private static final int FLAG_REIFIED = 1; private static final String EXPECTED = StringUtils.lines( @@ -80,7 +81,10 @@ public static Collection<Object[]> data() { return buildParameters( getTestParameters().withCfRuntimes().build(), - getKotlinTestParameters().withAllCompilersAndTargetVersions().build()); + getKotlinTestParameters() + .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION) + .withAllTargetVersions() + .build()); } public MetadataRewriteInTypeArgumentsTest(
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java index 263b087..717bf12 100644 --- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java
@@ -11,11 +11,9 @@ import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; -import com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion; import com.android.tools.r8.KotlinTestParameters; import com.android.tools.r8.TestParameters; import com.android.tools.r8.ToolHelper.KotlinTargetVersion; -import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.shaking.ProguardKeepAttributes; import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.codeinspector.CodeInspector; @@ -45,30 +43,6 @@ this.parameters = parameters; } - public int getExpectedAddedCount() { - if (kotlinParameters.getCompiler().is(KotlinCompilerVersion.KOTLINC_1_3_72)) { - return 597; - } else if (kotlinParameters.getCompiler().is(KotlinCompilerVersion.KOTLINC_1_4_20)) { - return 685; - } else if (kotlinParameters.getCompiler().is(KotlinCompilerVersion.KOTLINC_1_5_0)) { - return 696; - } else { - throw new Unreachable("Should not compile in this configuration"); - } - } - - public int getExpectedNonInitAddedCount() { - if (kotlinParameters.getCompiler().is(KotlinCompilerVersion.KOTLINC_1_3_72)) { - return 327; - } else if (kotlinParameters.getCompiler().is(KotlinCompilerVersion.KOTLINC_1_4_20)) { - return 413; - } else if (kotlinParameters.getCompiler().is(KotlinCompilerVersion.KOTLINC_1_5_0)) { - return 419; - } else { - throw new Unreachable("Should not compile in this configuration"); - } - } - @Test public void testKotlinStdLib() throws Exception { assumeFalse(parameters.isNoneRuntime()); @@ -90,8 +64,8 @@ new CodeInspector(getKotlinStdlibJar(kotlinc)), inspector, (addedStrings, addedNonInitStrings) -> { - assertEquals(getExpectedAddedCount(), addedStrings.intValue()); - assertEquals(getExpectedNonInitAddedCount(), addedNonInitStrings.intValue()); + assertEquals(0, addedStrings.intValue()); + assertEquals(0, addedNonInitStrings.intValue()); })); }
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePrunedObjectsTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePrunedObjectsTest.java index e59e318..9b8a8e7 100644 --- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePrunedObjectsTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePrunedObjectsTest.java
@@ -4,6 +4,7 @@ package com.android.tools.r8.kotlin.metadata; +import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; import static junit.framework.TestCase.assertEquals; import static org.hamcrest.CoreMatchers.not; @@ -32,18 +33,17 @@ private static final KotlinCompileMemoizer libJars = getCompileMemoizer( - getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib")) - .configure( - kotlinCompilerTool -> { - kotlinCompilerTool.addClasspathFiles(ToolHelper.getClassPathForTests()); - }); + getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib")); private final TestParameters parameters; @Parameterized.Parameters(name = "{0}, {1}") public static Collection<Object[]> data() { return buildParameters( getTestParameters().withCfRuntimes().build(), - getKotlinTestParameters().withAllCompilersAndTargetVersions().build()); + getKotlinTestParameters() + .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION) + .withAllTargetVersions() + .build()); } public MetadataRewritePrunedObjectsTest( @@ -74,13 +74,14 @@ Path libJar = testForR8(parameters.getBackend()) .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion)) - .enableInliningAnnotations() .addClasspathFiles( ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinAnnotationJar(kotlinc)) .addKeepRules( "-keep class " + PKG_LIB + ".Sub { <init>(); *** kept(); *** keptProperty; }") + .addKeepRules("-neverinline class * { @" + PKG_LIB + ".NeverInline *; }") .addKeepClassAndMembersRules(PKG_LIB + ".SubUser") .addKeepRuntimeVisibleAnnotations() + .enableProguardTestOptions() .noMinification() .compile() .inspect(this::checkPruned)
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteValueClassTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteValueClassTest.java new file mode 100644 index 0000000..cc26b5c --- /dev/null +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteValueClassTest.java
@@ -0,0 +1,143 @@ +// Copyright (c) 2020, 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.kotlin.metadata; + +import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_1_5_0; +import static com.android.tools.r8.ToolHelper.KotlinTargetVersion.JAVA_8; +import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar; +import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar; +import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.StringContains.containsString; +import static org.junit.Assert.assertNull; + +import com.android.tools.r8.KotlinTestParameters; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.ToolHelper; +import com.android.tools.r8.kotlin.KotlinMetadataWriter; +import com.android.tools.r8.shaking.ProguardKeepAttributes; +import com.android.tools.r8.utils.DescriptorUtils; +import com.android.tools.r8.utils.StringUtils; +import com.android.tools.r8.utils.codeinspector.ClassSubject; +import com.android.tools.r8.utils.codeinspector.CodeInspector; +import com.android.tools.r8.utils.codeinspector.FoundClassSubject; +import java.io.IOException; +import java.nio.file.Path; +import java.util.Collection; +import junit.framework.TestCase; +import kotlinx.metadata.jvm.KotlinClassHeader; +import kotlinx.metadata.jvm.KotlinClassMetadata; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class MetadataRewriteValueClassTest extends KotlinMetadataTestBase { + + private static final String EXPECTED = StringUtils.lines("Hello, John Doe", "42", "UInt(x=42)"); + private static final String PKG_LIB = PKG + ".value_class_lib"; + private static final String PKG_APP = PKG + ".value_class_app"; + private final TestParameters parameters; + + @Parameterized.Parameters(name = "{0}, {1}") + public static Collection<Object[]> data() { + return buildParameters( + getTestParameters().withCfRuntimes().build(), + getKotlinTestParameters() + .withCompilersStartingFromIncluding(KOTLINC_1_5_0) + .withTargetVersion(JAVA_8) + .build()); + } + + public MetadataRewriteValueClassTest( + TestParameters parameters, KotlinTestParameters kotlinParameters) { + super(kotlinParameters); + this.parameters = parameters; + } + + private static final KotlinCompileMemoizer kotlincLibJar = + getCompileMemoizer( + getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib")); + + @Test + public void smokeTest() throws Exception { + Path output = + kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion) + .addClasspathFiles(kotlincLibJar.getForConfiguration(kotlinc, targetVersion)) + .addSourceFiles( + getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main")) + .setOutputPath(temp.newFolder().toPath()) + .compile(); + testForJvm() + .addRunClasspathFiles( + getKotlinStdlibJar(kotlinc), kotlincLibJar.getForConfiguration(kotlinc, targetVersion)) + .addClasspath(output) + .run(parameters.getRuntime(), PKG_APP + ".MainKt") + .assertSuccessWithOutput(EXPECTED); + } + + @Test + public void testMetadataForLib() throws Exception { + Path libJar = + testForR8(parameters.getBackend()) + .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc)) + .addProgramFiles(kotlincLibJar.getForConfiguration(kotlinc, targetVersion)) + .addKeepAllClassesRule() + .addKeepAttributes( + ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS, + ProguardKeepAttributes.SIGNATURE, + ProguardKeepAttributes.INNER_CLASSES, + ProguardKeepAttributes.ENCLOSING_METHOD) + .addOptionsModification( + internalOptions -> { + internalOptions.testing.keepMetadataInR8IfNotRewritten = false; + }) + .compile() + .inspect(this::inspect) + .writeToZip(); + Path main = + kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion) + .addClasspathFiles(libJar) + .addSourceFiles( + getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main")) + .setOutputPath(temp.newFolder().toPath()) + .compile(); + testForJvm() + .addRunClasspathFiles( + getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc), libJar) + .addClasspath(main) + .run(parameters.getRuntime(), PKG_APP + ".MainKt") + .assertSuccessWithOutput(EXPECTED); + } + + private void inspect(CodeInspector inspector) throws IOException { + CodeInspector stdLibInspector = + new CodeInspector(kotlincLibJar.getForConfiguration(kotlinc, targetVersion)); + for (FoundClassSubject clazzSubject : stdLibInspector.allClasses()) { + ClassSubject r8Clazz = inspector.clazz(clazzSubject.getOriginalName()); + assertThat(r8Clazz, isPresent()); + KotlinClassMetadata originalMetadata = clazzSubject.getKotlinClassMetadata(); + KotlinClassMetadata rewrittenMetadata = r8Clazz.getKotlinClassMetadata(); + if (originalMetadata == null) { + assertNull(rewrittenMetadata); + continue; + } + TestCase.assertNotNull(rewrittenMetadata); + KotlinClassHeader originalHeader = originalMetadata.getHeader(); + KotlinClassHeader rewrittenHeader = rewrittenMetadata.getHeader(); + TestCase.assertEquals(originalHeader.getKind(), rewrittenHeader.getKind()); + TestCase.assertEquals(originalHeader.getPackageName(), rewrittenHeader.getPackageName()); + // We cannot assert equality of the data since it may be ordered differently. Instead we use + // the KotlinMetadataWriter. + String expected = KotlinMetadataWriter.kotlinMetadataToString("", originalMetadata); + String actual = KotlinMetadataWriter.kotlinMetadataToString("", rewrittenMetadata); + TestCase.assertEquals(expected, actual); + if (r8Clazz.getFinalName().equals(PKG_LIB + ".Name")) { + assertThat(actual, containsString("inlineClassUnderlyingPropertyName")); + assertThat(actual, containsString("inlineClassUnderlyingType")); + } + } + } +}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataVersionNumberBumpTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataVersionNumberBumpTest.java index 4cf9124..b0ea3d9 100644 --- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataVersionNumberBumpTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataVersionNumberBumpTest.java
@@ -5,11 +5,11 @@ package com.android.tools.r8.kotlin.metadata; import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar; -import static com.android.tools.r8.ToolHelper.getKotlinC_1_3_72; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.objectweb.asm.Opcodes.ASM7; +import com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion; import com.android.tools.r8.KotlinTestParameters; import com.android.tools.r8.R8FullTestBuilder; import com.android.tools.r8.TestParameters; @@ -40,12 +40,12 @@ private final TestParameters parameters; - @Parameters(name = "{0}") + @Parameters(name = "{0}, {1}") public static List<Object[]> data() { return buildParameters( getTestParameters().withAllRuntimesAndApiLevels().build(), getKotlinTestParameters() - .withCompiler(getKotlinC_1_3_72()) + .withCompiler(KotlinCompilerVersion.KOTLINC_1_3_72) .withTargetVersion(KotlinTargetVersion.JAVA_8) .build()); } @@ -63,7 +63,8 @@ testBuilder .addProgramFiles(getKotlinAnnotationJar(kotlinc)) .setMinApi(parameters.getApiLevel()) - .addKeepAllClassesRule() + .addOptionsModification(options -> options.testing.keepMetadataInR8IfNotRewritten = false) + .addKeepAllClassesRuleWithAllowObfuscation() .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS) .compile() .inspect(inspector -> inspectMetadataVersion(inspector, "1.4.0")); @@ -76,7 +77,7 @@ testBuilder .addProgramFiles(getKotlinAnnotationJar(kotlinc)) .setMinApi(parameters.getApiLevel()) - .addKeepAllClassesRule() + .addKeepAllClassesRuleWithAllowObfuscation() .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS) .compile() .inspect(inspector -> inspectMetadataVersion(inspector, "1.4.0")); @@ -89,7 +90,7 @@ testBuilder .addProgramFiles(getKotlinAnnotationJar(kotlinc)) .setMinApi(parameters.getApiLevel()) - .addKeepAllClassesRule() + .addKeepAllClassesRuleWithAllowObfuscation() .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS) .compile() .inspect(inspector -> inspectMetadataVersion(inspector, "1.4.2"));
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/pruned_lib/lib.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/pruned_lib/lib.kt index a7672fd..7cb8107 100644 --- a/src/test/java/com/android/tools/r8/kotlin/metadata/pruned_lib/lib.kt +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/pruned_lib/lib.kt
@@ -4,7 +4,7 @@ package com.android.tools.r8.kotlin.metadata.pruned_lib -import com.android.tools.r8.NeverInline +annotation class NeverInline // The Base class will be removed during compilation open class Base
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/value_class_app/main.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/value_class_app/main.kt new file mode 100644 index 0000000..476c6e1 --- /dev/null +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/value_class_app/main.kt
@@ -0,0 +1,13 @@ +// 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.kotlin.metadata.value_class_app + +import com.android.tools.r8.kotlin.metadata.value_class_lib.* + +fun main() { + Name("John Doe").prettyPrint() + compute(42) + compute(UInt(42)) +} \ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/value_class_lib/lib.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/value_class_lib/lib.kt new file mode 100644 index 0000000..0c4d392 --- /dev/null +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/value_class_lib/lib.kt
@@ -0,0 +1,39 @@ +// Copyright (c) 2020, 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.kotlin.metadata.value_class_lib + +// These examples are from the kotlinlang.org website. + +interface Printable { + fun prettyPrint() +} + +@JvmInline +value class Name(val s: String) : Printable { + + init { + require(s.length > 0) { } + } + + val length: Int + get() = s.length + + override fun prettyPrint() { + println("Hello, $s") + } +} + +@JvmInline +value class UInt(val x: Int) + +// Represented as 'public final void compute(int x)' on the JVM +fun compute(x: Int) { + println(x); +} + +// Also represented as 'public final void compute(int x)' on the JVM thus name is mangled! +fun compute(x: UInt) { + println(x); +}
diff --git a/src/test/java/com/android/tools/r8/kotlin/reflection/KotlinReflectTest.java b/src/test/java/com/android/tools/r8/kotlin/reflection/KotlinReflectTest.java index 6ee2517..d448e96 100644 --- a/src/test/java/com/android/tools/r8/kotlin/reflection/KotlinReflectTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/reflection/KotlinReflectTest.java
@@ -11,6 +11,7 @@ import com.android.tools.r8.KotlinTestBase; import com.android.tools.r8.KotlinTestParameters; import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestCompileResult; import com.android.tools.r8.TestParameters; import com.android.tools.r8.ToolHelper; import com.android.tools.r8.kotlin.metadata.KotlinMetadataTestBase; @@ -96,7 +97,11 @@ .allowUnusedDontWarnKotlinReflectJvmInternal(kotlinc.isNot(KOTLINC_1_3_72)) .compile() .assertNoErrorMessages() - .apply(TestBase::verifyAllInfoFromGenericSignatureTypeParameterValidation) + // -keepattributes Signature is added in kotlin-reflect from version 1.4.20. + .applyIf( + kotlinParameters.getCompiler().isNot(KOTLINC_1_3_72), + TestBase::verifyAllInfoFromGenericSignatureTypeParameterValidation, + TestCompileResult::assertNoInfoMessages) .apply(KotlinMetadataTestBase::verifyExpectedWarningsFromKotlinReflectAndStdLib) .writeToZip(foo.toPath()) .run(parameters.getRuntime(), PKG + ".SimpleReflectKt")
diff --git a/src/test/java/com/android/tools/r8/regress/b191296688/Regress191296688.java b/src/test/java/com/android/tools/r8/regress/b191296688/Regress191296688.java index e5ed600..8410836 100644 --- a/src/test/java/com/android/tools/r8/regress/b191296688/Regress191296688.java +++ b/src/test/java/com/android/tools/r8/regress/b191296688/Regress191296688.java
@@ -11,12 +11,12 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertTrue; +import com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion; import com.android.tools.r8.KotlinTestBase; import com.android.tools.r8.KotlinTestParameters; import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestRuntime; import com.android.tools.r8.TestRuntime.CfRuntime; -import com.android.tools.r8.ToolHelper; import com.android.tools.r8.ToolHelper.KotlinTargetVersion; import com.android.tools.r8.utils.DescriptorUtils; import com.android.tools.r8.utils.codeinspector.ClassSubject; @@ -41,8 +41,8 @@ return buildParameters( getTestParameters().withDexRuntimes().withAllApiLevels().build(), getKotlinTestParameters() + .withCompiler(KotlinCompilerVersion.KOTLINC_1_5_0) .withTargetVersion(KotlinTargetVersion.JAVA_8) - .withCompiler(ToolHelper.getKotlinC_1_5_0()) .build()); }
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessTest.java index 62286f9..821bc4c 100644 --- a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessTest.java +++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessTest.java
@@ -166,7 +166,7 @@ } private AppView<AppInfoWithClassHierarchy> getAppView() throws Exception { - return computeAppViewWithClassHierachy( + return computeAppViewWithClassHierarchy( buildClasses(getClasses()) .addClassProgramData(getTransformedClasses()) .addLibraryFile(TestBase.runtimeJar(parameters.getBackend()))
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessTest.java index 20575adb..bec0f69 100644 --- a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessTest.java +++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessTest.java
@@ -142,7 +142,7 @@ } private AppView<AppInfoWithClassHierarchy> getAppView() throws Exception { - return computeAppViewWithClassHierachy( + return computeAppViewWithClassHierarchy( buildClasses(getClasses()).addClassProgramData(getTransformedClasses()).build()); }
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java index 9286245..56258b4 100644 --- a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java +++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java
@@ -175,7 +175,7 @@ } private AppView<AppInfoWithClassHierarchy> getAppView() throws Exception { - return computeAppViewWithClassHierachy( + return computeAppViewWithClassHierarchy( buildClasses(getClasses()).addClassProgramData(getTransformedClasses()).build()); }
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/KeptTargetsIncompleteLookupTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/KeptTargetsIncompleteLookupTest.java index f6836fa..d630f6f 100644 --- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/KeptTargetsIncompleteLookupTest.java +++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/KeptTargetsIncompleteLookupTest.java
@@ -233,7 +233,7 @@ // ----- Program ----- // B extends A { } <-- initial AppView<AppInfoWithClassHierarchy> appView = - computeAppViewWithClassHierachy( + computeAppViewWithClassHierarchy( buildClasses(Collections.singletonList(B.class), Arrays.asList(A.class, I.class)) .build()); AppInfoWithClassHierarchy appInfo = appView.appInfo();
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 0169604..fb2db95 100644 --- a/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java +++ b/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
@@ -56,9 +56,10 @@ public static byte[] transform( byte[] bytes, List<ClassTransformer> classTransformers, - List<MethodTransformer> methodTransformers) { + List<MethodTransformer> methodTransformers, + int flags) { ClassReader reader = new ClassReader(bytes); - ClassWriter writer = new ClassWriter(reader, 0); + ClassWriter writer = new ClassWriter(reader, flags); ClassVisitor subvisitor = new InnerMostClassTransformer(writer, methodTransformers); for (int i = classTransformers.size() - 1; i >= 0; i--) { classTransformers.get(i).setSubVisitor(subvisitor); @@ -144,7 +145,11 @@ } public byte[] transform() { - return ClassFileTransformer.transform(bytes, classTransformers, methodTransformers); + return transform(0); + } + + public byte[] transform(int flags) { + return ClassFileTransformer.transform(bytes, classTransformers, methodTransformers, flags); } /** Base addition of a transformer on the class. */ @@ -992,4 +997,14 @@ } }); } + + public ClassFileTransformer computeMaxs() { + return addMethodTransformer( + new MethodTransformer() { + @Override + public void visitMaxs(int maxStack, int maxLocals) { + super.visitMaxs(maxStack, maxLocals); + } + }); + } }
diff --git a/third_party/android_jar/api-database.tar.gz.sha1 b/third_party/android_jar/api-database.tar.gz.sha1 index 6336e23..97d5f12 100644 --- a/third_party/android_jar/api-database.tar.gz.sha1 +++ b/third_party/android_jar/api-database.tar.gz.sha1
@@ -1 +1 @@ -be72aeca006f1aba8b1fe4d9c3ff4c0e76259960 \ No newline at end of file +a3e0351d71082eb74073576e11c0632191fd8530 \ No newline at end of file
diff --git a/tools/run_on_app.py b/tools/run_on_app.py index cdceb6b..8667a9e 100755 --- a/tools/run_on_app.py +++ b/tools/run_on_app.py
@@ -533,6 +533,9 @@ if options.print_times: extra_args.append('-Dcom.android.tools.r8.printtimes=1') + if not options.no_debug: + extra_args.append('-Dcom.android.tools.r8.enableTestAssertions=1') + outdir = options.out (version_id, data) = get_version_and_data(options)