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)