Merge commit 'e114917379e8f59a61d321d01dc6f5145d0e929e' into dev-release
diff --git a/.gitignore b/.gitignore
index 17af682..dbe9747 100644
--- a/.gitignore
+++ b/.gitignore
@@ -135,32 +135,14 @@
third_party/openjdk/desugar_jdk_libs_releases/1.1.1.tar.gz
third_party/openjdk/desugar_jdk_libs_releases/1.1.5
third_party/openjdk/desugar_jdk_libs_releases/1.1.5.tar.gz
-third_party/openjdk/jdk-17/linux
-third_party/openjdk/jdk-17/linux.tar.gz
-third_party/openjdk/jdk-17/osx
-third_party/openjdk/jdk-17/osx.tar.gz
-third_party/openjdk/jdk-17/windows
-third_party/openjdk/jdk-17/windows.tar.gz
-third_party/openjdk/jdk-16/linux
-third_party/openjdk/jdk-16/linux.tar.gz
-third_party/openjdk/jdk-16/osx
-third_party/openjdk/jdk-16/osx.tar.gz
-third_party/openjdk/jdk-16/windows
-third_party/openjdk/jdk-16/windows.tar.gz
-third_party/openjdk/jdk-15/linux
-third_party/openjdk/jdk-15/linux.tar.gz
-third_party/openjdk/jdk-15/osx
-third_party/openjdk/jdk-15/osx.tar.gz
-third_party/openjdk/jdk-15/windows
-third_party/openjdk/jdk-15/windows.tar.gz
-third_party/openjdk/jdk-11-test
+third_party/openjdk/jdk-[0-9][0-9]/linux
+third_party/openjdk/jdk-[0-9][0-9]/linux.tar.gz
+third_party/openjdk/jdk-[0-9][0-9]/osx
+third_party/openjdk/jdk-[0-9][0-9]/osx.tar.gz
+third_party/openjdk/jdk-[0-9][0-9]/windows
+third_party/openjdk/jdk-[0-9][0-9]/windows.tar.gz
third_party/openjdk/jdk-11-test.tar.gz
-third_party/openjdk/jdk-11/linux
-third_party/openjdk/jdk-11/linux.tar.gz
-third_party/openjdk/jdk-11/osx
-third_party/openjdk/jdk-11/osx.tar.gz
-third_party/openjdk/jdk-11/windows
-third_party/openjdk/jdk-11/windows.tar.gz
+third_party/openjdk/jdk-11-test/
third_party/openjdk/jdk8/darwin-x86
third_party/openjdk/jdk8/darwin-x86.tar.gz
third_party/openjdk/jdk8/linux-x86
@@ -278,6 +260,8 @@
tools/*/art-10.0.0.tar.gz
tools/*/host/art-12.0.0-beta4
tools/*/host/art-12.0.0-beta4.tar.gz
+tools/*/host/art-13-master
+tools/*/host/art-13-master.tar.gz
tools/*/art.tar.gz
tools/*/dalvik
tools/*/dalvik-4.0.4
diff --git a/build.gradle b/build.gradle
index 919c260..560c1de 100644
--- a/build.gradle
+++ b/build.gradle
@@ -140,6 +140,11 @@
srcDirs = ['src/test/examplesJava17']
}
}
+ examplesJava18 {
+ java {
+ srcDirs = ['src/test/examplesJava18']
+ }
+ }
examplesTestNGRunner {
java {
srcDirs = ['src/test/testngrunner']
@@ -333,6 +338,7 @@
"android_jar/lib-v30",
"android_jar/lib-v31",
"android_jar/lib-v32",
+ "android_jar/lib-v33",
"api-outlining/simple-app-dump",
"binary_compatibility_tests/compiler_api_tests",
"core-lambda-stubs",
@@ -386,6 +392,7 @@
"linux/art-9.0.0",
"linux/art-10.0.0",
"linux/host/art-12.0.0-beta4",
+ "linux/host/art-13-master",
"linux/dalvik",
"linux/dalvik-4.0.4",
"${osString}/dx",
@@ -397,18 +404,21 @@
"third_party": ["openjdk/openjdk-9.0.4/linux",
"openjdk/jdk8/linux-x86",
"openjdk/jdk-11/linux",
- "openjdk/jdk-17/linux"],
+ "openjdk/jdk-17/linux",
+ "openjdk/jdk-18/linux"],
],
osx: [
"third_party": ["openjdk/openjdk-9.0.4/osx",
"openjdk/jdk8/darwin-x86",
"openjdk/jdk-11/osx",
- "openjdk/jdk-17/osx"],
+ "openjdk/jdk-17/osx",
+ "openjdk/jdk-18/osx"],
],
windows: [
"third_party": ["openjdk/openjdk-9.0.4/windows",
"openjdk/jdk-11/windows",
- "openjdk/jdk-17/windows"],
+ "openjdk/jdk-17/windows",
+ "openjdk/jdk-18/windows"],
],
]
@@ -646,6 +656,12 @@
'jdk-17',
JavaVersion.VERSION_17,
false)
+setJdkCompilationWithCompatibility(
+ sourceSets.examplesJava18.compileJavaTaskName,
+ 'jdk-18',
+ // TODO(b/218293990): Update Gradle to get JavaVersion.VERSION_18.
+ JavaVersion.VERSION_17,
+ false)
task provideJdk11TestsDependencies(type: org.gradle.api.tasks.Copy) {
from sourceSets.examplesTestNGRunner.compileClasspath
@@ -1595,6 +1611,7 @@
buildExampleJarsCreateTask("Java10", sourceSets.examplesJava10)
buildExampleJarsCreateTask("Java11", sourceSets.examplesJava11)
buildExampleJarsCreateTask("Java17", sourceSets.examplesJava17)
+buildExampleJarsCreateTask("Java18", sourceSets.examplesJava18)
task provideArtFrameworksDependencies {
cloudDependencies.tools.forEach({ art ->
@@ -1656,6 +1673,7 @@
dependsOn buildExampleJava10Jars
dependsOn buildExampleJava11Jars
dependsOn buildExampleJava17Jars
+ dependsOn buildExampleJava18Jars
dependsOn buildExampleAndroidApi
def examplesDir = file("src/test/examples")
def noDexTests = [
diff --git a/infra/config/global/generated/cr-buildbucket.cfg b/infra/config/global/generated/cr-buildbucket.cfg
index 9dae144..6661615 100644
--- a/infra/config/global/generated/cr-buildbucket.cfg
+++ b/infra/config/global/generated/cr-buildbucket.cfg
@@ -46,10 +46,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "archive_release"
@@ -79,10 +75,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "desugared_library-head"
@@ -116,10 +108,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "desugared_library-jdk11_head"
@@ -155,10 +143,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "lib_desugar-archive"
@@ -188,10 +172,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-android-10.0.0"
@@ -229,10 +209,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-android-10.0.0_release"
@@ -270,10 +246,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-android-12.0.0"
@@ -311,10 +283,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-android-12.0.0_release"
@@ -352,8 +320,78 @@
key: "luci.recipes.use_python3"
value: 100
}
+ }
+ builders {
+ name: "linux-android-13.0.0"
+ swarming_host: "chrome-swarming.appspot.com"
+ swarming_tags: "vpython:native-python-wrapper"
+ dimensions: "cores:8"
+ dimensions: "cpu:x86-64"
+ dimensions: "normal:true"
+ dimensions: "os:Ubuntu-16.04"
+ dimensions: "pool:luci.r8.ci"
+ exe {
+ cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
+ cipd_version: "refs/heads/master"
+ cmd: "luciexe"
+ }
+ properties:
+ '{'
+ ' "builder_group": "internal.client.r8",'
+ ' "recipe": "rex",'
+ ' "test_options": ['
+ ' "--dex_vm=13.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"
experiments {
- key: "luci.use_realms"
+ key: "luci.recipes.use_python3"
+ value: 100
+ }
+ }
+ builders {
+ name: "linux-android-13.0.0_release"
+ swarming_host: "chrome-swarming.appspot.com"
+ swarming_tags: "vpython:native-python-wrapper"
+ dimensions: "cores:8"
+ dimensions: "cpu:x86-64"
+ dimensions: "normal:true"
+ dimensions: "os:Ubuntu-16.04"
+ dimensions: "pool:luci.r8.ci"
+ exe {
+ cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
+ cipd_version: "refs/heads/master"
+ cmd: "luciexe"
+ }
+ properties:
+ '{'
+ ' "builder_group": "internal.client.r8",'
+ ' "recipe": "rex",'
+ ' "test_options": ['
+ ' "--dex_vm=13.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"
+ experiments {
+ key: "luci.recipes.use_python3"
value: 100
}
}
@@ -393,10 +431,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-android-4.0.4_release"
@@ -434,10 +468,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-android-4.4.4"
@@ -475,10 +505,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-android-4.4.4_release"
@@ -516,10 +542,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-android-5.1.1"
@@ -557,10 +579,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-android-5.1.1_release"
@@ -598,10 +616,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-android-6.0.1"
@@ -639,10 +653,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-android-6.0.1_release"
@@ -680,10 +690,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-android-7.0.0"
@@ -721,10 +727,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-android-7.0.0_release"
@@ -762,10 +764,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-android-8.1.0"
@@ -803,10 +801,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-android-8.1.0_release"
@@ -844,10 +838,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-android-9.0.0"
@@ -885,10 +875,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-android-9.0.0_release"
@@ -926,10 +912,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-d8_jctf"
@@ -967,10 +949,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-d8_jctf_release"
@@ -1008,10 +986,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-dex_default"
@@ -1048,10 +1022,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-dex_default_release"
@@ -1088,10 +1058,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-internal"
@@ -1125,10 +1091,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-internal_release"
@@ -1162,10 +1124,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-jdk11"
@@ -1202,10 +1160,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-jdk11_release"
@@ -1242,10 +1196,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-jdk8"
@@ -1282,10 +1232,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-jdk8_release"
@@ -1322,10 +1268,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-jdk9"
@@ -1362,10 +1304,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-jdk9_release"
@@ -1402,10 +1340,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-kotlin_dev"
@@ -1443,10 +1377,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-kotlin_old"
@@ -1484,10 +1414,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-none"
@@ -1524,10 +1450,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-none_release"
@@ -1564,10 +1486,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-r8cf_jctf"
@@ -1605,10 +1523,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-r8cf_jctf_release"
@@ -1646,10 +1560,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-run-on-app-dump"
@@ -1682,10 +1592,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "linux-run-on-app-dump_release"
@@ -1718,10 +1624,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "windows"
@@ -1757,10 +1659,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
builders {
name: "windows_release"
@@ -1796,10 +1694,6 @@
key: "luci.recipes.use_python3"
value: 100
}
- experiments {
- key: "luci.use_realms"
- value: 100
- }
}
}
}
diff --git a/infra/config/global/generated/luci-milo.cfg b/infra/config/global/generated/luci-milo.cfg
index 6151ce6..8bbf1b1 100644
--- a/infra/config/global/generated/luci-milo.cfg
+++ b/infra/config/global/generated/luci-milo.cfg
@@ -86,6 +86,11 @@
short_name: "12.0.0"
}
builders {
+ name: "buildbucket/luci.r8.ci/linux-android-13.0.0"
+ category: "R8"
+ short_name: "13.0.0"
+ }
+ builders {
name: "buildbucket/luci.r8.ci/windows"
category: "R8"
short_name: "windows"
@@ -211,6 +216,11 @@
short_name: "12.0.0"
}
builders {
+ name: "buildbucket/luci.r8.ci/linux-android-13.0.0_release"
+ category: "Release|R8"
+ short_name: "13.0.0"
+ }
+ builders {
name: "buildbucket/luci.r8.ci/windows_release"
category: "Release|R8"
short_name: "windows"
diff --git a/infra/config/global/generated/luci-notify.cfg b/infra/config/global/generated/luci-notify.cfg
index e697c32..d98d266 100644
--- a/infra/config/global/generated/luci-notify.cfg
+++ b/infra/config/global/generated/luci-notify.cfg
@@ -108,6 +108,30 @@
}
builders {
bucket: "ci"
+ name: "linux-android-13.0.0"
+ repository: "https://r8.googlesource.com/r8"
+ }
+}
+notifiers {
+ notifications {
+ on_failure: true
+ on_new_failure: true
+ notify_blamelist {}
+ }
+ builders {
+ bucket: "ci"
+ name: "linux-android-13.0.0_release"
+ repository: "https://r8.googlesource.com/r8"
+ }
+}
+notifiers {
+ notifications {
+ on_failure: true
+ on_new_failure: true
+ notify_blamelist {}
+ }
+ builders {
+ bucket: "ci"
name: "linux-android-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 6d92824..629ee37 100644
--- a/infra/config/global/generated/luci-scheduler.cfg
+++ b/infra/config/global/generated/luci-scheduler.cfg
@@ -15,7 +15,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "archive"
}
}
@@ -30,7 +30,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "archive_release"
}
}
@@ -44,7 +44,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "desugared_library-head"
}
}
@@ -58,7 +58,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "desugared_library-jdk11_head"
}
}
@@ -73,7 +73,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "lib_desugar-archive"
}
}
@@ -87,7 +87,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-android-10.0.0"
}
}
@@ -102,7 +102,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-android-10.0.0_release"
}
}
@@ -116,7 +116,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-android-12.0.0"
}
}
@@ -131,11 +131,40 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-android-12.0.0_release"
}
}
job {
+ id: "linux-android-13.0.0"
+ realm: "ci"
+ acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
+ buildbucket {
+ server: "cr-buildbucket.appspot.com"
+ bucket: "ci"
+ builder: "linux-android-13.0.0"
+ }
+}
+job {
+ id: "linux-android-13.0.0_release"
+ realm: "ci"
+ acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ max_batch_size: 1
+ }
+ buildbucket {
+ server: "cr-buildbucket.appspot.com"
+ bucket: "ci"
+ builder: "linux-android-13.0.0_release"
+ }
+}
+job {
id: "linux-android-4.0.4"
realm: "ci"
acl_sets: "ci"
@@ -145,7 +174,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-android-4.0.4"
}
}
@@ -160,7 +189,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-android-4.0.4_release"
}
}
@@ -174,7 +203,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-android-4.4.4"
}
}
@@ -189,7 +218,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-android-4.4.4_release"
}
}
@@ -203,7 +232,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-android-5.1.1"
}
}
@@ -218,7 +247,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-android-5.1.1_release"
}
}
@@ -232,7 +261,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-android-6.0.1"
}
}
@@ -247,7 +276,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-android-6.0.1_release"
}
}
@@ -261,7 +290,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-android-7.0.0"
}
}
@@ -276,7 +305,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-android-7.0.0_release"
}
}
@@ -290,7 +319,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-android-8.1.0"
}
}
@@ -305,7 +334,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-android-8.1.0_release"
}
}
@@ -319,7 +348,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-android-9.0.0"
}
}
@@ -334,7 +363,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-android-9.0.0_release"
}
}
@@ -348,7 +377,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-d8_jctf"
}
}
@@ -363,7 +392,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-d8_jctf_release"
}
}
@@ -377,7 +406,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-dex_default"
}
}
@@ -392,7 +421,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-dex_default_release"
}
}
@@ -406,7 +435,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-internal"
}
}
@@ -420,7 +449,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-internal_release"
}
}
@@ -434,7 +463,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-jdk11"
}
}
@@ -449,7 +478,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-jdk11_release"
}
}
@@ -463,7 +492,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-jdk8"
}
}
@@ -478,7 +507,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-jdk8_release"
}
}
@@ -492,7 +521,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-jdk9"
}
}
@@ -507,7 +536,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-jdk9_release"
}
}
@@ -521,7 +550,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-kotlin_dev"
}
}
@@ -535,7 +564,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-kotlin_old"
}
}
@@ -549,7 +578,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-none"
}
}
@@ -564,7 +593,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-none_release"
}
}
@@ -578,7 +607,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-r8cf_jctf"
}
}
@@ -593,7 +622,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-r8cf_jctf_release"
}
}
@@ -607,7 +636,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-run-on-app-dump"
}
}
@@ -622,7 +651,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "linux-run-on-app-dump_release"
}
}
@@ -636,7 +665,7 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "windows"
}
}
@@ -651,17 +680,38 @@
}
buildbucket {
server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
+ bucket: "ci"
builder: "windows_release"
}
}
trigger {
+ id: "branch-gitiles-3.2-forward"
+ realm: "ci"
+ acl_sets: "ci"
+ triggers: "linux-android-12.0.0_release"
+ gitiles {
+ repo: "https://r8.googlesource.com/r8"
+ refs: "regexp:refs/heads//([3]\\.[2-9]+(\\.[0-9]+)?|[4-9]\\.[0-9]+(\\.[0-9]+)?)"
+ path_regexps: "src/main/java/com/android/tools/r8/Version.java"
+ }
+}
+trigger {
+ id: "branch-gitiles-3.3-forward"
+ realm: "ci"
+ acl_sets: "ci"
+ triggers: "linux-android-13.0.0_release"
+ gitiles {
+ repo: "https://r8.googlesource.com/r8"
+ refs: "regexp:refs/heads//([3]\\.[3-9]+(\\.[0-9]+)?|[4-9]\\.[0-9]+(\\.[0-9]+)?)"
+ path_regexps: "src/main/java/com/android/tools/r8/Version.java"
+ }
+}
+trigger {
id: "branch-gitiles-trigger"
realm: "ci"
acl_sets: "ci"
triggers: "archive_release"
triggers: "linux-android-10.0.0_release"
- triggers: "linux-android-12.0.0_release"
triggers: "linux-android-4.0.4_release"
triggers: "linux-android-4.4.4_release"
triggers: "linux-android-5.1.1_release"
@@ -681,7 +731,7 @@
triggers: "windows_release"
gitiles {
repo: "https://r8.googlesource.com/r8"
- refs: "regexp:refs/heads/(?:d8-)?[0-9]+\\.[0-9]+(\\.[0-9]+)?"
+ refs: "regexp:refs/heads/[0-9]+\\.[0-9]+(\\.[0-9]+)?"
path_regexps: "src/main/java/com/android/tools/r8/Version.java"
}
}
@@ -694,6 +744,7 @@
triggers: "desugared_library-jdk11_head"
triggers: "linux-android-10.0.0"
triggers: "linux-android-12.0.0"
+ triggers: "linux-android-13.0.0"
triggers: "linux-android-4.0.4"
triggers: "linux-android-4.4.4"
triggers: "linux-android-5.1.1"
diff --git a/infra/config/global/generated/project.cfg b/infra/config/global/generated/project.cfg
index b87c601..974c534 100644
--- a/infra/config/global/generated/project.cfg
+++ b/infra/config/global/generated/project.cfg
@@ -7,8 +7,9 @@
name: "r8"
access: "group:all"
lucicfg {
- version: "1.30.5"
+ version: "1.30.9"
package_dir: ".."
config_dir: "generated"
entry_point: "main.star"
+ experiments: "crbug.com/1182002"
}
diff --git a/infra/config/global/main.star b/infra/config/global/main.star
index 02b45d5..6c59f26 100755
--- a/infra/config/global/main.star
+++ b/infra/config/global/main.star
@@ -1,13 +1,11 @@
#!/usr/bin/env lucicfg
-lucicfg.check_version("1.28.0", "Please use newer `lucicfg` binary")
+lucicfg.check_version("1.30.9", "Please use newer `lucicfg` binary")
-# Enable LUCI Realms support.
-lucicfg.enable_experiment("crbug.com/1085650")
+# Use LUCI Scheduler BBv2 names and add Scheduler realms configs.
+lucicfg.enable_experiment("crbug.com/1182002")
-# Launch 0% of Builds in "realms-aware mode"
luci.builder.defaults.experiments.set({
- "luci.use_realms": 100,
"luci.recipes.use_python3": 100
})
@@ -111,11 +109,26 @@
)
luci.gitiles_poller(
+ name = "branch-gitiles-3.3-forward",
+ bucket = "ci",
+ repo = "https://r8.googlesource.com/r8",
+ refs = ["refs/heads//([3]\\.[3-9]+(\\.[0-9]+)?|[4-9]\\.[0-9]+(\\.[0-9]+)?)"],
+ path_regexps = ["src/main/java/com/android/tools/r8/Version.java"]
+)
+
+luci.gitiles_poller(
+ name = "branch-gitiles-3.2-forward",
+ bucket = "ci",
+ repo = "https://r8.googlesource.com/r8",
+ refs = ["refs/heads//([3]\\.[2-9]+(\\.[0-9]+)?|[4-9]\\.[0-9]+(\\.[0-9]+)?)"],
+ path_regexps = ["src/main/java/com/android/tools/r8/Version.java"]
+)
+
+luci.gitiles_poller(
name = "branch-gitiles-trigger",
bucket = "ci",
repo = "https://r8.googlesource.com/r8",
- # Version branches are named d8-x.y (up until d8-1.5) or just x.y (from 1.6)
- refs = ["refs/heads/(?:d8-)?[0-9]+\\.[0-9]+(\\.[0-9]+)?"],
+ refs = ["refs/heads/[0-9]+\\.[0-9]+(\\.[0-9]+)?"],
path_regexps = ["src/main/java/com/android/tools/r8/Version.java"]
)
@@ -167,10 +180,14 @@
return dimensions
def r8_builder(name, priority=26, trigger=True, category=None,
- triggering_policy=None, **kwargs):
+ triggering_policy=None, release_trigger=None, **kwargs):
release = name.endswith("release")
- triggered = None if not trigger else ["branch-gitiles-trigger"] if release\
- else ["main-gitiles-trigger"]
+ triggered = None
+ if trigger:
+ if release:
+ triggered = release_trigger if release_trigger else ["branch-gitiles-trigger"]
+ else:
+ triggered = ["main-gitiles-trigger"]
triggering_policy = triggering_policy or scheduler.policy(
kind = scheduler.GREEDY_BATCHING_KIND,
max_batch_size = 1 if release else None,
@@ -199,7 +216,8 @@
dimensions = None,
execution_timeout = time.hour * 6,
expiration_timeout = time.hour * 35,
- category=None):
+ category=None,
+ release_trigger=None):
dimensions = dimensions if dimensions else get_dimensions(normal=True)
for name in [name, name + "_release"]:
r8_builder(
@@ -208,15 +226,20 @@
execution_timeout = execution_timeout,
expiration_timeout = expiration_timeout,
dimensions = dimensions,
+ release_trigger=release_trigger,
properties = {
"test_options" : test_options,
"builder_group" : "internal.client.r8"
}
)
-def r8_tester_with_default(name, test_options, dimensions=None, category=None):
+def r8_tester_with_default(name,
+ test_options,
+ dimensions=None,
+ category=None,
+ release_trigger=None):
r8_tester(name, test_options + common_test_options,
- dimensions = dimensions, category = category)
+ dimensions = dimensions, category = category, release_trigger=release_trigger)
def archivers():
for name in ["archive", "archive_release", "lib_desugar-archive"]:
@@ -265,7 +288,11 @@
r8_tester_with_default("linux-android-10.0.0",
["--dex_vm=10.0.0", "--all_tests"])
r8_tester_with_default("linux-android-12.0.0",
- ["--dex_vm=12.0.0", "--all_tests"])
+ ["--dex_vm=12.0.0", "--all_tests"],
+ release_trigger=["branch-gitiles-3.2-forward"])
+r8_tester_with_default("linux-android-13.0.0",
+ ["--dex_vm=13.0.0", "--all_tests"],
+ release_trigger=["branch-gitiles-3.3-forward"])
r8_tester_with_default("windows", ["--all_tests"],
dimensions=get_dimensions(windows=True))
@@ -396,4 +423,4 @@
category = v[1],
short_name = v[2]
)
-add_view_entries()
\ No newline at end of file
+add_view_entries()
diff --git a/scripts/add-openjdk.sh b/scripts/add-openjdk.sh
index 6f8bada..f6b3284 100755
--- a/scripts/add-openjdk.sh
+++ b/scripts/add-openjdk.sh
@@ -14,13 +14,16 @@
# Create directory third_party/openjdk/jdk-X
# cd into third_party/openjdk/jdk-X
# Prepare README.google
-# Update JDK_VERSION below
+# Update JDK_VERSION and JDK_VERSION_FULL below
# Now run script with fingers crossed!
-JDK_VERSION=17
+JDK_VERSION="18"
+JDK_VERSION_FULL=${JDK_VERSION}
+# For ea versions the full version name has a postfix.
+# JDK_VERSION_FULL="${JDK_VERSION}-ea+33"
-tar xf ~/Downloads/openjdk-${JDK_VERSION}_linux-x64_bin.tar.gz
+tar xf ~/Downloads/openjdk-${JDK_VERSION_FULL}_linux-x64_bin.tar.gz
cp -rL jdk-${JDK_VERSION} linux
cp README.google linux
upload_to_google_storage.py -a --bucket r8-deps linux
@@ -28,7 +31,7 @@
rm -rf linux
rm linux.tar.gz
-tar xf ~/Downloads/openjdk-${JDK_VERSION}_macos-x64_bin.tar.gz
+tar xf ~/Downloads/openjdk-${JDK_VERSION_FULL}_macos-x64_bin.tar.gz
cp -rL jdk-${JDK_VERSION}.jdk osx
cp README.google osx
upload_to_google_storage.py -a --bucket r8-deps osx
@@ -36,7 +39,7 @@
rm -rf jdk-${JDK_VERSION}.jdk
rm osx.tar.gz
-unzip ~/Downloads/openjdk-${JDK_VERSION}_windows-x64_bin.zip
+unzip ~/Downloads/openjdk-${JDK_VERSION_FULL}_windows-x64_bin.zip
cp -rL jdk-${JDK_VERSION} windows
cp README.google windows
upload_to_google_storage.py -a --bucket r8-deps windows
diff --git a/src/library_desugar/jdk11/chm_only_desugar_jdk_libs.json b/src/library_desugar/jdk11/chm_only_desugar_jdk_libs.json
index 565ffd9..f3a4daa 100644
--- a/src/library_desugar/jdk11/chm_only_desugar_jdk_libs.json
+++ b/src/library_desugar/jdk11/chm_only_desugar_jdk_libs.json
@@ -3,7 +3,7 @@
"group_id" : "com.tools.android",
"artifact_id" : "chm_only_desugar_jdk_libs",
"version": "1.0.12",
- "required_compilation_api_level": 31,
+ "required_compilation_api_level": 30,
"synthesized_library_classes_package_prefix": "j$.",
"support_all_callbacks_from_library": false,
"common_flags": [
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs.json b/src/library_desugar/jdk11/desugar_jdk_libs.json
index fb03dbb..b075745 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs.json
@@ -3,7 +3,7 @@
"group_id" : "com.tools.android",
"artifact_id" : "desugar_jdk_libs",
"version": "2.0.0",
- "required_compilation_api_level": 31,
+ "required_compilation_api_level": 30,
"synthesized_library_classes_package_prefix": "j$.",
"support_all_callbacks_from_library": true,
"common_flags": [
@@ -205,7 +205,7 @@
"java.nio.charset.StandardCharsets": "j$.nio.charset.StandardCharsets"
},
"retarget_lib_member": {
- "java.lang.Character#isBmpCodePoint": "j$.lang.DesugarCharacter"
+ "java.lang.Character#isBmpCodePoint": "java.lang.DesugarCharacter"
}
}
],
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json b/src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json
index fac2ec0..1482909 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json
@@ -3,7 +3,7 @@
"group_id" : "com.tools.android",
"artifact_id" : "desugar_jdk_libs_alternative_3",
"version": "2.0.0",
- "required_compilation_api_level": 31,
+ "required_compilation_api_level": 30,
"synthesized_library_classes_package_prefix": "j$.",
"support_all_callbacks_from_library": false,
"common_flags": [
@@ -209,7 +209,7 @@
"java.nio.charset.StandardCharsets": "j$.nio.charset.StandardCharsets"
},
"retarget_lib_member": {
- "java.lang.Character#isBmpCodePoint": "j$.lang.DesugarCharacter"
+ "java.lang.Character#isBmpCodePoint": "java.lang.DesugarCharacter"
}
}
],
diff --git a/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java b/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java
index bce73f0..7ef1569 100644
--- a/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java
+++ b/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java
@@ -105,7 +105,7 @@
InternalOptions getInternalOptions() {
InternalOptions options = new InternalOptions(factory, getReporter());
options.setMinApiLevel(AndroidApiLevel.getAndroidApiLevel(minApiLevel));
- options.desugaredLibrarySpecification = desugaredLibrarySpecification;
+ options.setDesugaredLibrarySpecification(desugaredLibrarySpecification, getInputApp());
return options;
}
diff --git a/src/main/java/com/android/tools/r8/BaseCompilerCommandParser.java b/src/main/java/com/android/tools/r8/BaseCompilerCommandParser.java
index 1316be8..631b5b3 100644
--- a/src/main/java/com/android/tools/r8/BaseCompilerCommandParser.java
+++ b/src/main/java/com/android/tools/r8/BaseCompilerCommandParser.java
@@ -3,8 +3,11 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8;
-import com.android.tools.r8.AssertionsConfiguration.AssertionTransformation;
+import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.ExceptionDiagnostic;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringDiagnostic;
@@ -38,7 +41,16 @@
" --force-pa[:[<class name>|<package name>...]]",
" # Don't change javac generated assertion code. This",
" # is the default handling of javac assertion code when",
- " # generating class file format.");
+ " # generating class file format.",
+ " --force-assertions-handler:<handler method>[:[<class name>|<package name>...]]",
+ " --force-ah:<handler method>[:[<class name>|<package name>...]]",
+ " # Change javac and kotlinc generated assertion code to invoke",
+ " # the method <handler method> with each assertion error",
+ " # instead of throwing it. The <handler method> is specified"
+ + " as",
+ " # a class name followed by a dot and the method name. The",
+ " # handler method must take a single argument of type",
+ " # java.lang.Throwable and have return type void.");
static final Iterable<String> THREAD_COUNT_USAGE_MESSAGE =
Arrays.asList(
@@ -82,23 +94,54 @@
private static String PACKAGE_ASSERTION_POSTFIX = "...";
+ private enum AssertionTransformationType {
+ ENABLE,
+ DISABLE,
+ PASSTHROUGH,
+ HANDLER
+ }
+
+ private AssertionsConfiguration.Builder prepareBuilderForScope(
+ AssertionsConfiguration.Builder builder,
+ AssertionTransformationType transformation,
+ MethodReference assertionHandler) {
+ switch (transformation) {
+ case ENABLE:
+ return builder.setCompileTimeEnable();
+ case DISABLE:
+ return builder.setCompileTimeDisable();
+ case PASSTHROUGH:
+ return builder.setPassthrough();
+ case HANDLER:
+ return builder.setAssertionHandler(assertionHandler);
+ default:
+ throw new Unreachable();
+ }
+ }
+
private void addAssertionTransformation(
- B builder, AssertionTransformation transformation, String scope) {
+ B builder,
+ AssertionTransformationType transformation,
+ MethodReference assertionHandler,
+ String scope) {
if (scope == null) {
builder.addAssertionsConfiguration(
- b -> b.setTransformation(transformation).setScopeAll().build());
+ b -> prepareBuilderForScope(b, transformation, assertionHandler).setScopeAll().build());
} else {
assert scope.length() > 0;
if (scope.endsWith(PACKAGE_ASSERTION_POSTFIX)) {
builder.addAssertionsConfiguration(
b ->
- b.setTransformation(transformation)
+ prepareBuilderForScope(b, transformation, assertionHandler)
.setScopePackage(
scope.substring(0, scope.length() - PACKAGE_ASSERTION_POSTFIX.length()))
.build());
} else {
builder.addAssertionsConfiguration(
- b -> b.setTransformation(transformation).setScopeClass(scope).build());
+ b ->
+ prepareBuilderForScope(b, transformation, assertionHandler)
+ .setScopeClass(scope)
+ .build());
}
}
}
@@ -110,34 +153,78 @@
String FORCE_DA = "--force-da";
String FORCE_PASSTHROUGH_ASSERTIONS = "--force-passthrough-assertions";
String FORCE_PA = "--force-pa";
+ String FORCE_ASSERTIONS_HANDLER = "--force-assertions-handler";
+ String FORCE_AH = "--force-ah";
- AssertionTransformation transformation = null;
+ AssertionTransformationType transformation = null;
+ MethodReference assertionsHandler = null;
String remaining = null;
if (arg.startsWith(FORCE_ENABLE_ASSERTIONS)) {
- transformation = AssertionTransformation.ENABLE;
+ transformation = AssertionTransformationType.ENABLE;
remaining = arg.substring(FORCE_ENABLE_ASSERTIONS.length());
} else if (arg.startsWith(FORCE_EA)) {
- transformation = AssertionTransformation.ENABLE;
+ transformation = AssertionTransformationType.ENABLE;
remaining = arg.substring(FORCE_EA.length());
} else if (arg.startsWith(FORCE_DISABLE_ASSERTIONS)) {
- transformation = AssertionTransformation.DISABLE;
+ transformation = AssertionTransformationType.DISABLE;
remaining = arg.substring(FORCE_DISABLE_ASSERTIONS.length());
} else if (arg.startsWith(FORCE_DA)) {
- transformation = AssertionTransformation.DISABLE;
+ transformation = AssertionTransformationType.DISABLE;
remaining = arg.substring(FORCE_DA.length());
} else if (arg.startsWith(FORCE_PASSTHROUGH_ASSERTIONS)) {
- transformation = AssertionTransformation.PASSTHROUGH;
+ transformation = AssertionTransformationType.PASSTHROUGH;
remaining = arg.substring(FORCE_PASSTHROUGH_ASSERTIONS.length());
} else if (arg.startsWith(FORCE_PA)) {
- transformation = AssertionTransformation.PASSTHROUGH;
+ transformation = AssertionTransformationType.PASSTHROUGH;
remaining = arg.substring(FORCE_PA.length());
+ } else if (arg.startsWith(FORCE_ASSERTIONS_HANDLER)) {
+ transformation = AssertionTransformationType.HANDLER;
+ remaining = arg.substring(FORCE_ASSERTIONS_HANDLER.length());
+ } else if (arg.startsWith(FORCE_AH)) {
+ transformation = AssertionTransformationType.HANDLER;
+ remaining = arg.substring(FORCE_AH.length());
+ }
+ if (transformation == AssertionTransformationType.HANDLER) {
+ if (remaining.length() == 0 || (remaining.length() == 1 && remaining.charAt(0) == ':')) {
+ throw builder.fatalError(
+ new StringDiagnostic("Missing required argument <handler method>", origin));
+ }
+ if (remaining.charAt(0) != ':') {
+ return false;
+ }
+ remaining = remaining.substring(1);
+ int index = remaining.indexOf(':');
+ if (index == 0) {
+ throw builder.fatalError(
+ new StringDiagnostic("Missing required argument <handler method>", origin));
+ }
+ String assertionsHandlerString = index > 0 ? remaining.substring(0, index) : remaining;
+ int lastDotIndex = assertionsHandlerString.lastIndexOf('.');
+ if (assertionsHandlerString.length() < 3
+ || lastDotIndex <= 0
+ || lastDotIndex == assertionsHandlerString.length() - 1
+ || !DescriptorUtils.isValidJavaType(assertionsHandlerString.substring(0, lastDotIndex))) {
+ throw builder.fatalError(
+ new StringDiagnostic(
+ "Invalid argument <handler method>: " + assertionsHandlerString, origin));
+ }
+ assertionsHandler =
+ Reference.methodFromDescriptor(
+ DescriptorUtils.javaTypeToDescriptor(
+ assertionsHandlerString.substring(0, lastDotIndex)),
+ assertionsHandlerString.substring(lastDotIndex + 1),
+ "(Ljava/lang/Throwable;)V");
+ remaining = remaining.substring(assertionsHandlerString.length());
}
if (transformation != null) {
if (remaining.length() == 0) {
- addAssertionTransformation(builder, transformation, null);
+ addAssertionTransformation(builder, transformation, assertionsHandler, null);
return true;
} else {
- if (remaining.length() == 1 || remaining.charAt(0) != ':') {
+ if (remaining.length() == 1 && remaining.charAt(0) == ':') {
+ throw builder.fatalError(new StringDiagnostic("Missing optional argument", origin));
+ }
+ if (remaining.charAt(0) != ':') {
return false;
}
String classOrPackageScope = remaining.substring(1);
@@ -147,7 +234,8 @@
builder.error(
new StringDiagnostic("Illegal assertion scope: " + classOrPackageScope, origin));
}
- addAssertionTransformation(builder, transformation, remaining.substring(1));
+ addAssertionTransformation(
+ builder, transformation, assertionsHandler, remaining.substring(1));
return true;
}
} else {
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index 9232563..10c5c5f 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -23,7 +23,7 @@
import com.android.tools.r8.graph.analysis.ClassInitializerAssertionEnablingAnalysis;
import com.android.tools.r8.inspector.internal.InspectorImpl;
import com.android.tools.r8.ir.conversion.IRConverter;
-import com.android.tools.r8.ir.desugar.PrefixRewritingMapper;
+import com.android.tools.r8.ir.desugar.TypeRewriter;
import com.android.tools.r8.ir.optimize.AssertionsRewriter;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
import com.android.tools.r8.jar.CfApplicationWriter;
@@ -168,11 +168,11 @@
private static AppView<AppInfo> readApp(
AndroidApp inputApp, InternalOptions options, ExecutorService executor, Timing timing)
throws IOException {
- PrefixRewritingMapper rewritePrefix = options.getPrefixRewritingMapper();
+ TypeRewriter typeRewriter = options.getTypeRewriter();
ApplicationReader applicationReader = new ApplicationReader(inputApp, options, timing);
LazyLoadedDexApplication app = applicationReader.read(executor);
AppInfo appInfo = AppInfo.createInitialAppInfo(app, applicationReader.readMainDexClasses(app));
- return AppView.createForD8(appInfo, rewritePrefix);
+ return AppView.createForD8(appInfo, typeRewriter);
}
private static void run(AndroidApp inputApp, InternalOptions options, ExecutorService executor)
@@ -269,7 +269,7 @@
new CfApplicationWriter(appView, marker, GraphLens.getIdentityLens(), namingLens)
.write(options.getClassFileConsumer(), inputApp);
} else {
- if (!hasDexResources || !hasClassResources || !appView.rewritePrefix.isRewriting()) {
+ if (!hasDexResources || !hasClassResources || !appView.typeRewriter.isRewriting()) {
// All inputs are either dex or cf, or there is nothing to rewrite.
namingLens = hasDexResources ? NamingLens.getIdentityLens() : namingLens;
new GenericSignatureRewriter(appView, namingLens)
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index 8dd34a8..0967f55 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -498,8 +498,7 @@
internal.encodeChecksums = getIncludeClassesChecksum();
internal.dexClassChecksumFilter = getDexClassChecksumFilter();
internal.enableInheritanceClassInDexDistributor = isOptimizeMultidexForLinearAlloc();
-
- internal.desugaredLibrarySpecification = desugaredLibrarySpecification;
+ internal.setDesugaredLibrarySpecification(desugaredLibrarySpecification, getInputApp());
internal.synthesizedClassPrefix = synthesizedClassPrefix;
internal.desugaredLibraryKeepRuleConsumer = desugaredLibraryKeepRuleConsumer;
diff --git a/src/main/java/com/android/tools/r8/GenerateLintFiles.java b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
index 01e1163..4c49b47 100644
--- a/src/main/java/com/android/tools/r8/GenerateLintFiles.java
+++ b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
@@ -377,7 +377,7 @@
private void run() throws Exception {
// Run over all the API levels that the desugared library can be compiled with.
- for (int apiLevel = AndroidApiLevel.LATEST.getLevel();
+ for (int apiLevel = AndroidApiLevel.Sv2.getLevel();
apiLevel >= desugaredLibrarySpecification.getRequiredCompilationApiLevel().getLevel();
apiLevel--) {
System.out.println("Generating lint files for compile API " + apiLevel);
diff --git a/src/main/java/com/android/tools/r8/L8.java b/src/main/java/com/android/tools/r8/L8.java
index 9ba6c7f..7c0a805 100644
--- a/src/main/java/com/android/tools/r8/L8.java
+++ b/src/main/java/com/android/tools/r8/L8.java
@@ -13,7 +13,7 @@
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.LazyLoadedDexApplication;
import com.android.tools.r8.ir.conversion.IRConverter;
-import com.android.tools.r8.ir.desugar.PrefixRewritingMapper;
+import com.android.tools.r8.ir.desugar.TypeRewriter;
import com.android.tools.r8.jar.CfApplicationWriter;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.naming.PrefixRewritingNamingLens;
@@ -166,10 +166,10 @@
LazyLoadedDexApplication lazyApp =
new ApplicationReader(inputApp, options, timing).read(executor);
- PrefixRewritingMapper rewritePrefix = options.getPrefixRewritingMapper();
+ TypeRewriter typeRewriter = options.getTypeRewriter();
- DexApplication app = new L8TreePruner(options).prune(lazyApp, rewritePrefix);
- return AppView.createForL8(AppInfo.createInitialAppInfo(app), rewritePrefix);
+ DexApplication app = new L8TreePruner(options).prune(lazyApp, typeRewriter);
+ return AppView.createForL8(AppInfo.createInitialAppInfo(app), typeRewriter);
}
private static void run(String[] args) throws CompilationFailedException {
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java
index 26c99ce..6da92e2 100644
--- a/src/main/java/com/android/tools/r8/L8Command.java
+++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -194,7 +194,7 @@
internal.enableInheritanceClassInDexDistributor = false;
assert desugaredLibrarySpecification != null;
- internal.desugaredLibrarySpecification = desugaredLibrarySpecification;
+ internal.setDesugaredLibrarySpecification(desugaredLibrarySpecification, getInputApp());
internal.synthesizedClassPrefix =
desugaredLibrarySpecification.getSynthesizedLibraryClassesPackagePrefix();
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 194c531..8b93d23 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -49,7 +49,6 @@
import com.android.tools.r8.ir.desugar.BackportedMethodRewriter;
import com.android.tools.r8.ir.desugar.CfClassSynthesizerDesugaringCollection;
import com.android.tools.r8.ir.desugar.CfClassSynthesizerDesugaringEventConsumer;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeterLibraryTypeSynthesizer;
import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
import com.android.tools.r8.ir.desugar.records.RecordDesugaring;
import com.android.tools.r8.ir.desugar.records.RecordFieldValuesRewriter;
@@ -311,10 +310,6 @@
if (!options.mainDexKeepRules.isEmpty()) {
MainDexListBuilder.checkForAssumedLibraryTypes(appView.appInfo());
}
- if (!options.desugaredLibrarySpecification.getRetargetCoreLibMember().isEmpty()) {
- DesugaredLibraryRetargeterLibraryTypeSynthesizer.checkForAssumedLibraryTypes(appView);
- DesugaredLibraryRetargeterLibraryTypeSynthesizer.amendLibraryWithRetargetedMembers(appView);
- }
InterfaceMethodRewriter.checkForAssumedLibraryTypes(appView.appInfo(), options);
BackportedMethodRewriter.registerAssumedLibraryTypes(options);
if (options.enableEnumUnboxing) {
@@ -329,7 +324,7 @@
// Upfront desugaring generation: Generates new program classes to be added in the app.
CfClassSynthesizerDesugaringEventConsumer classSynthesizerEventConsumer =
new CfClassSynthesizerDesugaringEventConsumer();
- CfClassSynthesizerDesugaringCollection.create(appView, null)
+ CfClassSynthesizerDesugaringCollection.create(appView)
.synthesizeClasses(executorService, classSynthesizerEventConsumer);
if (appView.getSyntheticItems().hasPendingSyntheticClasses()) {
appView.setAppInfo(
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index bf04680..5bc9ddd 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -943,7 +943,7 @@
internal.enableInheritanceClassInDexDistributor = isOptimizeMultidexForLinearAlloc();
- internal.desugaredLibrarySpecification = desugaredLibrarySpecification;
+ internal.setDesugaredLibrarySpecification(desugaredLibrarySpecification, getInputApp());
internal.synthesizedClassPrefix = synthesizedClassPrefix;
internal.desugaredLibraryKeepRuleConsumer = desugaredLibraryKeepRuleConsumer;
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 2e2aa7a..cce0852 100644
--- a/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java
+++ b/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java
@@ -9,7 +9,6 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.ConsumerUtils;
import com.google.common.collect.ImmutableList;
@@ -18,7 +17,6 @@
public class AndroidApiReferenceLevelCache {
- private final LegacyDesugaredLibrarySpecification desugaredLibrarySpecification;
private final AndroidApiLevelCompute apiLevelCompute;
private final AndroidApiLevelDatabase androidApiLevelDatabase;
private final AppView<?> appView;
@@ -33,7 +31,6 @@
factory = appView.dexItemFactory();
androidApiLevelDatabase =
new AndroidApiLevelHashingDatabaseImpl(predefinedApiTypeLookupForHashing);
- desugaredLibrarySpecification = appView.options().desugaredLibrarySpecification;
}
public static AndroidApiReferenceLevelCache create(
@@ -75,7 +72,7 @@
if (reference.getContextType() == factory.objectType) {
return appView.computedMinApiLevel();
}
- if (desugaredLibrarySpecification.isSupported(reference, appView)) {
+ if (appView.options().machineDesugaredLibrarySpecification.isSupported(reference)) {
// If we end up desugaring the reference, the library classes is bridged by j$ which is part
// of the program.
return appView.computedMinApiLevel();
diff --git a/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java b/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
index f9b13a4..ef86f73 100644
--- a/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
+++ b/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
@@ -19,7 +19,6 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.ThrowExceptionCode;
import com.android.tools.r8.graph.UseRegistry;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.synthesis.CommittedItems;
import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
@@ -112,12 +111,10 @@
new ConcurrentHashMap<>();
private final Set<DexType> seenTypes = Sets.newConcurrentHashSet();
private final AndroidApiLevelCompute apiLevelCompute;
- private final LegacyDesugaredLibrarySpecification desugaredLibraryConfiguration;
public ApiReferenceStubber(AppView<? extends AppInfoWithClassHierarchy> appView) {
this.appView = appView;
apiLevelCompute = appView.apiLevelCompute();
- desugaredLibraryConfiguration = appView.options().desugaredLibrarySpecification;
}
public void run(ExecutorService executorService) throws ExecutionException {
@@ -220,7 +217,10 @@
|| libraryClass.getType().toDescriptorString().startsWith("Ljava/")) {
return;
}
- if (desugaredLibraryConfiguration.isSupported(libraryClass.getType(), appView)) {
+ if (appView
+ .options()
+ .machineDesugaredLibrarySpecification
+ .isSupported(libraryClass.getType())) {
return;
}
appView
diff --git a/src/main/java/com/android/tools/r8/cf/CfVersion.java b/src/main/java/com/android/tools/r8/cf/CfVersion.java
index b23d44d..9ce8c64 100644
--- a/src/main/java/com/android/tools/r8/cf/CfVersion.java
+++ b/src/main/java/com/android/tools/r8/cf/CfVersion.java
@@ -38,6 +38,8 @@
public static final CfVersion V16_PREVIEW = new CfVersion(Opcodes.V16 | Opcodes.V_PREVIEW);
public static final CfVersion V17 = new CfVersion(Opcodes.V17);
public static final CfVersion V17_PREVIEW = new CfVersion(Opcodes.V17 | Opcodes.V_PREVIEW);
+ public static final CfVersion V18 = new CfVersion(Opcodes.V18);
+ public static final CfVersion V18_PREVIEW = new CfVersion(Opcodes.V18 | Opcodes.V_PREVIEW);
private final int version;
@@ -58,7 +60,8 @@
CfVersion.V14,
CfVersion.V15,
CfVersion.V16,
- CfVersion.V17
+ CfVersion.V17,
+ CfVersion.V18
};
// Private constructor in case we want to canonicalize versions.
diff --git a/src/main/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryKeepRuleGenerator.java b/src/main/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryKeepRuleGenerator.java
index a720021..eaec5a0 100644
--- a/src/main/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryKeepRuleGenerator.java
+++ b/src/main/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryKeepRuleGenerator.java
@@ -13,7 +13,7 @@
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.references.ArrayReference;
import com.android.tools.r8.references.ClassReference;
@@ -32,13 +32,11 @@
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.NopDiagnosticsHandler;
-import com.android.tools.r8.utils.SetUtils;
import com.android.tools.r8.utils.Timing;
import com.android.tools.r8.utils.TypeReferenceUtils;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
@@ -71,7 +69,7 @@
return false;
}
return namingLens.hasPrefixRewritingLogic()
- || options.desugaredLibrarySpecification.hasEmulatedLibraryInterfaces();
+ || options.machineDesugaredLibrarySpecification.hasEmulatedInterfaces();
}
private void run() {
@@ -80,18 +78,15 @@
}
private Predicate<DexType> createTargetPredicate() {
- LegacyDesugaredLibrarySpecification desugaredLibrarySpecification =
- options.desugaredLibrarySpecification;
- Set<DexType> potentialTypesToKeep =
- SetUtils.newIdentityHashSet(
- desugaredLibrarySpecification.getCustomConversions().values(),
- desugaredLibrarySpecification.getEmulateLibraryInterface().values());
+ MachineDesugaredLibrarySpecification desugaredLibrarySpecification =
+ options.machineDesugaredLibrarySpecification;
byte[] synthesizedLibraryClassesPackageDescriptorPrefix =
DexString.encodeToMutf8(
"L" + desugaredLibrarySpecification.getSynthesizedLibraryClassesPackagePrefix());
return type ->
namingLens.prefixRewrittenType(type) != null
- || potentialTypesToKeep.contains(type)
+ || desugaredLibrarySpecification.isEmulatedInterfaceRewrittenType(type)
+ || desugaredLibrarySpecification.isCustomConversionRewrittenType(type)
|| type.getDescriptor().startsWith(synthesizedLibraryClassesPackageDescriptorPrefix);
}
diff --git a/src/main/java/com/android/tools/r8/dex/CodeToKeep.java b/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
index cc05c31..3e33ca8 100644
--- a/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
+++ b/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
@@ -25,7 +25,7 @@
static CodeToKeep createCodeToKeep(InternalOptions options, NamingLens namingLens) {
if ((!namingLens.hasPrefixRewritingLogic()
- && !options.desugaredLibrarySpecification.hasEmulatedLibraryInterfaces())
+ && !options.machineDesugaredLibrarySpecification.hasEmulatedInterfaces())
|| options.isDesugaredLibraryCompilation()
|| options.testing.enableExperimentalDesugaredLibraryKeepRuleGenerator) {
return new NopCodeToKeep();
@@ -57,27 +57,23 @@
}
private final NamingLens namingLens;
- private final Set<DexType> potentialTypesToKeep = Sets.newIdentityHashSet();
private final Map<DexType, KeepStruct> toKeep = new ConcurrentHashMap<>();
private final InternalOptions options;
public DesugaredLibraryCodeToKeep(NamingLens namingLens, InternalOptions options) {
this.namingLens = namingLens;
this.options = options;
- potentialTypesToKeep.addAll(
- options.desugaredLibrarySpecification.getEmulateLibraryInterface().values());
- potentialTypesToKeep.addAll(
- options.desugaredLibrarySpecification.getCustomConversions().values());
}
private boolean shouldKeep(DexType type) {
return namingLens.prefixRewrittenType(type) != null
- || potentialTypesToKeep.contains(type)
+ || options.machineDesugaredLibrarySpecification.isCustomConversionRewrittenType(type)
+ || options.machineDesugaredLibrarySpecification.isEmulatedInterfaceRewrittenType(type)
// TODO(b/158632510): This should prefix match on DexString.
|| type.toDescriptorString()
.startsWith(
"L"
- + options.desugaredLibrarySpecification
+ + options.machineDesugaredLibrarySpecification
.getSynthesizedLibraryClassesPackagePrefix());
}
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfo.java b/src/main/java/com/android/tools/r8/graph/AppInfo.java
index 1cf6ae7..ef10e8d 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfo.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
-import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -140,15 +139,25 @@
}
@Override
+ public ClassResolutionResult contextIndependentDefinitionForWithResolutionResult(DexType type) {
+ assert checkIfObsolete();
+ return syntheticItems.definitionFor(
+ type, app::contextIndependentDefinitionForWithResolutionResult);
+ }
+
+ @Override
public DexClass definitionFor(DexType type) {
return definitionForWithoutExistenceAssert(type);
}
public final DexClass definitionForWithoutExistenceAssert(DexType type) {
assert checkIfObsolete();
- return syntheticItems.definitionFor(type, app::definitionFor);
+ return syntheticItems
+ .definitionFor(type, app::contextIndependentDefinitionForWithResolutionResult)
+ .toSingleClassWithProgramOverLibrary();
}
+
public DexClass definitionForDesugarDependency(DexClass dependent, DexType type) {
if (dependent.type == type) {
return dependent;
@@ -240,7 +249,7 @@
DexProgramClass clazz = context.getHolder();
DexEncodedField definition = clazz.lookupField(field);
return definition != null
- ? new SuccessfulFieldResolutionResult(clazz, clazz, definition)
+ ? FieldResolutionResult.createSingleFieldResolutionResult(clazz, clazz, definition)
: FieldResolutionResult.unknown();
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java
index 24c47b4..cbf79f2 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -24,7 +24,7 @@
import com.android.tools.r8.ir.analysis.proto.GeneratedMessageLiteShrinker;
import com.android.tools.r8.ir.analysis.proto.ProtoShrinker;
import com.android.tools.r8.ir.analysis.value.AbstractValueFactory;
-import com.android.tools.r8.ir.desugar.PrefixRewritingMapper;
+import com.android.tools.r8.ir.desugar.TypeRewriter;
import com.android.tools.r8.ir.optimize.enums.EnumDataMap;
import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoFactory;
import com.android.tools.r8.ir.optimize.library.LibraryMemberOptimizer;
@@ -88,7 +88,7 @@
new SimpleInliningConstraintFactory();
// Desugaring.
- public final PrefixRewritingMapper rewritePrefix;
+ public final TypeRewriter typeRewriter;
// Modeling.
private final LibraryMethodSideEffectModelCollection libraryMethodSideEffectModelCollection;
@@ -123,16 +123,14 @@
private final ComputedApiLevel computedMinApiLevel;
private AppView(
- T appInfo,
- WholeProgramOptimizations wholeProgramOptimizations,
- PrefixRewritingMapper mapper) {
+ T appInfo, WholeProgramOptimizations wholeProgramOptimizations, TypeRewriter mapper) {
assert appInfo != null;
this.context = CompilationContext.createInitialContext(appInfo.options());
this.appInfo = appInfo;
this.dontWarnConfiguration = DontWarnConfiguration.create(options().getProguardConfiguration());
this.wholeProgramOptimizations = wholeProgramOptimizations;
this.initClassLens = InitClassLens.getThrowingInstance();
- this.rewritePrefix = mapper;
+ this.typeRewriter = mapper;
if (enableWholeProgramOptimizations() && options().callSiteOptimizationOptions().isEnabled()) {
this.argumentPropagator = new ArgumentPropagator(withLiveness());
@@ -158,18 +156,16 @@
return libraryMemberOptimizer.isModeled(type);
}
- private static <T extends AppInfo> PrefixRewritingMapper defaultPrefixRewritingMapper(T appInfo) {
+ private static <T extends AppInfo> TypeRewriter defaultTypeRewriter(T appInfo) {
InternalOptions options = appInfo.options();
- return options.getPrefixRewritingMapper();
+ return options.getTypeRewriter();
}
public static <T extends AppInfo> AppView<T> createForD8(T appInfo) {
- return new AppView<>(
- appInfo, WholeProgramOptimizations.OFF, defaultPrefixRewritingMapper(appInfo));
+ return new AppView<>(appInfo, WholeProgramOptimizations.OFF, defaultTypeRewriter(appInfo));
}
- public static <T extends AppInfo> AppView<T> createForD8(
- T appInfo, PrefixRewritingMapper mapper) {
+ public static <T extends AppInfo> AppView<T> createForD8(T appInfo, TypeRewriter mapper) {
return new AppView<>(appInfo, WholeProgramOptimizations.OFF, mapper);
}
@@ -184,24 +180,20 @@
AppInfoWithClassHierarchy appInfo =
AppInfoWithClassHierarchy.createInitialAppInfoWithClassHierarchy(
application, classToFeatureSplitMap, mainDexInfo);
- return new AppView<>(
- appInfo, WholeProgramOptimizations.ON, defaultPrefixRewritingMapper(appInfo));
+ return new AppView<>(appInfo, WholeProgramOptimizations.ON, defaultTypeRewriter(appInfo));
}
- public static <T extends AppInfo> AppView<T> createForL8(
- T appInfo, PrefixRewritingMapper mapper) {
+ public static <T extends AppInfo> AppView<T> createForL8(T appInfo, TypeRewriter mapper) {
return new AppView<>(appInfo, WholeProgramOptimizations.OFF, mapper);
}
public static <T extends AppInfo> AppView<T> createForRelocator(T appInfo) {
- return new AppView<>(
- appInfo, WholeProgramOptimizations.OFF, defaultPrefixRewritingMapper(appInfo));
+ return new AppView<>(appInfo, WholeProgramOptimizations.OFF, defaultTypeRewriter(appInfo));
}
public static AppView<AppInfoWithClassHierarchy> createForTracer(
AppInfoWithClassHierarchy appInfo) {
- return new AppView<>(
- appInfo, WholeProgramOptimizations.ON, defaultPrefixRewritingMapper(appInfo));
+ return new AppView<>(appInfo, WholeProgramOptimizations.ON, defaultTypeRewriter(appInfo));
}
public AbstractValueFactory abstractValueFactory() {
@@ -305,6 +297,11 @@
}
@Override
+ public ClassResolutionResult contextIndependentDefinitionForWithResolutionResult(DexType type) {
+ return appInfo().contextIndependentDefinitionForWithResolutionResult(type);
+ }
+
+ @Override
public final DexClass definitionFor(DexType type) {
return appInfo().definitionFor(type);
}
diff --git a/src/main/java/com/android/tools/r8/graph/ClassResolutionResult.java b/src/main/java/com/android/tools/r8/graph/ClassResolutionResult.java
new file mode 100644
index 0000000..4e34aa3
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/ClassResolutionResult.java
@@ -0,0 +1,138 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph;
+
+import static com.android.tools.r8.graph.ClassResolutionResult.NoResolutionResult.noResult;
+
+import java.util.function.Consumer;
+
+public interface ClassResolutionResult {
+
+ boolean hasClassResolutionResult();
+
+ DexClass toSingleClassWithProgramOverLibrary();
+
+ void forEachClassResolutionResult(Consumer<DexClass> consumer);
+
+ static Builder builder() {
+ return new Builder();
+ }
+
+ class Builder {
+
+ private ProgramOrClasspathClass programOrClasspathClass;
+ private DexLibraryClass libraryClass;
+
+ public Builder add(DexProgramClass programClass) {
+ assert this.programOrClasspathClass == null;
+ this.programOrClasspathClass = programClass;
+ return this;
+ }
+
+ public Builder add(DexClasspathClass classpathClass) {
+ assert this.programOrClasspathClass == null;
+ this.programOrClasspathClass = classpathClass;
+ return this;
+ }
+
+ public Builder add(DexLibraryClass libraryClass) {
+ assert this.libraryClass == null;
+ this.libraryClass = libraryClass;
+ return this;
+ }
+
+ public ClassResolutionResult build() {
+ if (programOrClasspathClass == null && libraryClass == null) {
+ return noResult();
+ } else if (programOrClasspathClass == null) {
+ return libraryClass;
+ } else if (libraryClass == null) {
+ return programOrClasspathClass;
+ } else if (programOrClasspathClass.isProgramClass()) {
+ return new ProgramAndLibraryClassResolutionResult(
+ programOrClasspathClass.asProgramClass(), libraryClass);
+ } else {
+ assert programOrClasspathClass.isClasspathClass();
+ return new ClasspathAndLibraryClassResolutionResult(
+ programOrClasspathClass.asClasspathClass(), libraryClass);
+ }
+ }
+ }
+
+ class NoResolutionResult implements ClassResolutionResult {
+
+ private static final NoResolutionResult NO_RESULT = new NoResolutionResult();
+
+ static ClassResolutionResult noResult() {
+ return NO_RESULT;
+ }
+
+ @Override
+ public boolean hasClassResolutionResult() {
+ return false;
+ }
+
+ @Override
+ public DexClass toSingleClassWithProgramOverLibrary() {
+ return null;
+ }
+
+ @Override
+ public void forEachClassResolutionResult(Consumer<DexClass> consumer) {
+ // Intentionally empty
+ }
+ }
+
+ abstract class MultipleClassResolutionResult<T extends DexClass>
+ implements ClassResolutionResult {
+
+ protected final T programOrClasspathClass;
+ protected final DexLibraryClass libraryClass;
+
+ public MultipleClassResolutionResult(T programOrClasspathClass, DexLibraryClass libraryClass) {
+ this.programOrClasspathClass = programOrClasspathClass;
+ this.libraryClass = libraryClass;
+ }
+
+ @Override
+ public boolean hasClassResolutionResult() {
+ return true;
+ }
+
+ @Override
+ public void forEachClassResolutionResult(Consumer<DexClass> consumer) {
+ consumer.accept(programOrClasspathClass);
+ consumer.accept(libraryClass);
+ }
+ }
+
+ class ProgramAndLibraryClassResolutionResult
+ extends MultipleClassResolutionResult<DexProgramClass> {
+
+ public ProgramAndLibraryClassResolutionResult(
+ DexProgramClass programClass, DexLibraryClass libraryClass) {
+ super(programClass, libraryClass);
+ }
+
+ @Override
+ public DexClass toSingleClassWithProgramOverLibrary() {
+ return programOrClasspathClass;
+ }
+ }
+
+ class ClasspathAndLibraryClassResolutionResult
+ extends MultipleClassResolutionResult<DexClasspathClass> {
+
+ public ClasspathAndLibraryClassResolutionResult(
+ DexClasspathClass classpathClass, DexLibraryClass libraryClass) {
+ super(classpathClass, libraryClass);
+ }
+
+ @Override
+ public DexClass toSingleClassWithProgramOverLibrary() {
+ return libraryClass;
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/ClasspathClass.java b/src/main/java/com/android/tools/r8/graph/ClasspathClass.java
index 3801ef8..0b9367d 100644
--- a/src/main/java/com/android/tools/r8/graph/ClasspathClass.java
+++ b/src/main/java/com/android/tools/r8/graph/ClasspathClass.java
@@ -4,7 +4,8 @@
package com.android.tools.r8.graph;
-public interface ClasspathClass extends ClasspathDefinition, ClasspathOrLibraryClass {
+public interface ClasspathClass
+ extends ClasspathDefinition, ClasspathOrLibraryClass, ProgramOrClasspathClass {
@Override
default DexClass asDexClass() {
diff --git a/src/main/java/com/android/tools/r8/graph/ClasspathDefinition.java b/src/main/java/com/android/tools/r8/graph/ClasspathDefinition.java
index 11cd7ad..43a4e70 100644
--- a/src/main/java/com/android/tools/r8/graph/ClasspathDefinition.java
+++ b/src/main/java/com/android/tools/r8/graph/ClasspathDefinition.java
@@ -6,7 +6,8 @@
import java.util.function.Function;
-public interface ClasspathDefinition extends ClasspathOrLibraryDefinition {
+public interface ClasspathDefinition
+ extends ClasspathOrLibraryDefinition, ProgramOrClasspathDefinition {
@Override
default <T> T apply(
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 00bca6f..05ad2d1 100644
--- a/src/main/java/com/android/tools/r8/graph/Definition.java
+++ b/src/main/java/com/android/tools/r8/graph/Definition.java
@@ -22,6 +22,14 @@
return null;
}
+ default ProgramOrClasspathClass asProgramOrClasspathClass() {
+ return null;
+ }
+
+ default ProgramOrClasspathDefinition asProgramOrClasspathDefinition() {
+ return null;
+ }
+
ProgramDerivedContext asProgramDerivedContext(ProgramDerivedContext witness);
AccessFlags<?> getAccessFlags();
diff --git a/src/main/java/com/android/tools/r8/graph/DexApplication.java b/src/main/java/com/android/tools/r8/graph/DexApplication.java
index 67f8be4..e08f2ed 100644
--- a/src/main/java/com/android/tools/r8/graph/DexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/DexApplication.java
@@ -66,8 +66,17 @@
DexApplication self = this;
return new DexDefinitionSupplier() {
@Override
+ public ClassResolutionResult contextIndependentDefinitionForWithResolutionResult(
+ DexType type) {
+ return syntheticDefinitionsProvider.definitionFor(
+ type, self::contextIndependentDefinitionForWithResolutionResult);
+ }
+
+ @Override
public DexClass definitionFor(DexType type) {
- return syntheticDefinitionsProvider.definitionFor(type, self::definitionFor);
+ return syntheticDefinitionsProvider
+ .definitionFor(type, self::contextIndependentDefinitionForWithResolutionResult)
+ .toSingleClassWithProgramOverLibrary();
}
@Override
@@ -117,13 +126,14 @@
return classesWithDeterministicOrder(new ArrayList<>(programClasses()));
}
- public static <T extends DexClass> List<T> classesWithDeterministicOrder(Collection<T> classes) {
+ public static <T extends ClassDefinition> List<T> classesWithDeterministicOrder(
+ Collection<T> classes) {
return classesWithDeterministicOrder(new ArrayList<>(classes));
}
- public static <T extends DexClass> List<T> classesWithDeterministicOrder(List<T> classes) {
+ public static <T extends ClassDefinition> List<T> classesWithDeterministicOrder(List<T> classes) {
// To keep the order deterministic, we sort the classes by their type, which is a unique key.
- classes.sort(Comparator.comparing(DexClass::getType));
+ classes.sort(Comparator.comparing(ClassDefinition::getType));
return classes;
}
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 8c6bbc8..31e7030 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -40,7 +40,8 @@
import java.util.function.Function;
import java.util.function.Predicate;
-public abstract class DexClass extends DexDefinition implements ClassDefinition {
+public abstract class DexClass extends DexDefinition
+ implements ClassDefinition, ClassResolutionResult {
public interface FieldSetter {
void setField(int index, DexEncodedField field);
@@ -134,6 +135,21 @@
}
}
+ @Override
+ public boolean hasClassResolutionResult() {
+ return true;
+ }
+
+ @Override
+ public void forEachClassResolutionResult(Consumer<DexClass> consumer) {
+ consumer.accept(this);
+ }
+
+ @Override
+ public DexClass toSingleClassWithProgramOverLibrary() {
+ return this;
+ }
+
public abstract void accept(
Consumer<DexProgramClass> programClassConsumer,
Consumer<DexClasspathClass> classpathClassConsumer,
diff --git a/src/main/java/com/android/tools/r8/graph/DexDefinitionSupplier.java b/src/main/java/com/android/tools/r8/graph/DexDefinitionSupplier.java
index 57212d4..6968591 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDefinitionSupplier.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDefinitionSupplier.java
@@ -19,6 +19,17 @@
}
/**
+ * Lookup for the definition(s) of a type independent of context.
+ *
+ * <p>This will return multiple results if found in the precedence of library, program and
+ * classpath.
+ *
+ * @param type Type to look up the definition for.
+ * @return A {@link ClassResolutionResult} describing the result.
+ */
+ ClassResolutionResult contextIndependentDefinitionForWithResolutionResult(DexType type);
+
+ /**
* Lookup for the definition of a type from a given context.
*
* <p>This ensures that a context overrides the usual lookup precedence if looking up itself.
@@ -81,6 +92,14 @@
return holder != null ? holder.lookupClassMethod(method) : null;
}
+ default ClassResolutionResult definitionForWithResolutionResult(
+ DexType type, DexProgramClass context) {
+ assert context.type != type || ClassResolutionResult.builder().add(context).build() == context;
+ return context.type == type
+ ? context
+ : contextIndependentDefinitionForWithResolutionResult(type);
+ }
+
// Use programDefinitionFor with a context.
@Deprecated
default DexProgramClass definitionForProgramType(DexType type) {
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index 686f124..3640575 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -1431,6 +1431,54 @@
|| method.match(waitLong)
|| method.match(waitLongInt);
}
+
+ public DexMethod matchingPublicObjectMember(DexMethod method) {
+ switch (method.getName().byteAt(0)) {
+ case 't':
+ if (method.match(toString)) {
+ return toString;
+ }
+ break;
+ case 'h':
+ if (method.match(hashCode)) {
+ return hashCode;
+ }
+ break;
+ case 'e':
+ if (method.match(equals)) {
+ return equals;
+ }
+ break;
+ case 'g':
+ if (method.match(getClass)) {
+ return getClass;
+ }
+ break;
+ case 'n':
+ if (method.match(notify)) {
+ return notify;
+ }
+ if (method.match(notifyAll)) {
+ return notifyAll;
+ }
+ break;
+ case 'w':
+ if (method.match(wait)) {
+ return wait;
+ }
+ if (method.match(waitLong)) {
+ return waitLong;
+ }
+ if (method.match(waitLongInt)) {
+ return waitLongInt;
+ }
+ break;
+ default:
+ // Methods finalize and clone are not public.
+ return null;
+ }
+ return null;
+ }
}
public class BufferMembers {
diff --git a/src/main/java/com/android/tools/r8/graph/DexMethodSignature.java b/src/main/java/com/android/tools/r8/graph/DexMethodSignature.java
index e756d78..adee16b 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMethodSignature.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMethodSignature.java
@@ -54,6 +54,10 @@
return create(name, getProto());
}
+ public DexMethodSignature withParameters(DexTypeList parameters, DexItemFactory dexItemFactory) {
+ return create(getName(), dexItemFactory.createProto(getReturnType(), parameters));
+ }
+
public DexMethodSignature withProto(DexProto proto) {
return create(getName(), proto);
}
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 2e09eec..3077717 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -38,7 +38,7 @@
import java.util.function.Supplier;
public class DexProgramClass extends DexClass
- implements ProgramDefinition, Supplier<DexProgramClass>, StructuralItem<DexProgramClass> {
+ implements ProgramClass, Supplier<DexProgramClass>, StructuralItem<DexProgramClass> {
@FunctionalInterface
public interface ChecksumSupplier {
diff --git a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
index 9589d1e..8e96fba 100644
--- a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
@@ -6,6 +6,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
+import static com.android.tools.r8.graph.ClassResolutionResult.NoResolutionResult.noResult;
+
import com.android.tools.r8.DataResourceProvider;
import com.android.tools.r8.graph.LazyLoadedDexApplication.AllClasses;
import com.android.tools.r8.graph.classmerging.MergedClasses;
@@ -69,6 +71,12 @@
}
@Override
+ public ClassResolutionResult contextIndependentDefinitionForWithResolutionResult(DexType type) {
+ DexClass foundClass = definitionFor(type);
+ return foundClass == null ? noResult() : foundClass;
+ }
+
+ @Override
public DexClass definitionFor(DexType type) {
assert type.isClassType() : "Cannot lookup definition for type: " + type;
return allClasses.get(type);
diff --git a/src/main/java/com/android/tools/r8/graph/FieldResolution.java b/src/main/java/com/android/tools/r8/graph/FieldResolution.java
index 120bee0..3dcd872 100644
--- a/src/main/java/com/android/tools/r8/graph/FieldResolution.java
+++ b/src/main/java/com/android/tools/r8/graph/FieldResolution.java
@@ -4,7 +4,8 @@
package com.android.tools.r8.graph;
-import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
+import static com.android.tools.r8.graph.FieldResolutionResult.createSingleFieldResolutionResult;
+
import com.android.tools.r8.utils.SetUtils;
import java.util.Set;
@@ -23,8 +24,12 @@
}
public FieldResolutionResult resolveFieldOn(DexType type, DexField field) {
- DexClass holder = definitionFor.contextIndependentDefinitionFor(type);
- return holder != null ? resolveFieldOn(holder, field) : FieldResolutionResult.failure();
+ FieldResolutionResult.Builder builder = FieldResolutionResult.builder();
+ definitionFor
+ .contextIndependentDefinitionForWithResolutionResult(type)
+ .forEachClassResolutionResult(
+ clazz -> builder.addResolutionResult(resolveFieldOn(clazz, field)));
+ return builder.buildOrIfEmpty(FieldResolutionResult.failure());
}
public FieldResolutionResult resolveFieldOn(DexClass holder, DexField field) {
@@ -41,49 +46,76 @@
// Step 1: Class declares the field.
DexEncodedField definition = holder.lookupField(field);
if (definition != null) {
- return new SuccessfulFieldResolutionResult(initialResolutionHolder, holder, definition);
+ return createSingleFieldResolutionResult(initialResolutionHolder, holder, definition);
}
// Step 2: Apply recursively to direct superinterfaces. First match succeeds.
- DexClassAndField result = resolveFieldOnDirectInterfaces(holder, field, visitedInterfaces);
+ FieldResolutionResult result =
+ resolveFieldOnDirectInterfaces(initialResolutionHolder, holder, field, visitedInterfaces);
if (result != null) {
- return new SuccessfulFieldResolutionResult(
- initialResolutionHolder, result.getHolder(), result.getDefinition());
+ return result;
}
// Step 3: Apply recursively to superclass.
if (holder.superType != null) {
- DexClass superClass = definitionFor.contextIndependentDefinitionFor(holder.superType);
- if (superClass != null) {
- return resolveFieldOn(superClass, field, initialResolutionHolder, visitedInterfaces);
- }
+ FieldResolutionResult.Builder builder = FieldResolutionResult.builder();
+ definitionFor
+ .contextIndependentDefinitionForWithResolutionResult(holder.superType)
+ .forEachClassResolutionResult(
+ superClass -> {
+ // Check if the subtype is a library type and if it is child of a non-library type.
+ // If that is the case, do not return any results.
+ if (holder.isLibraryClass() && !superClass.isLibraryClass()) {
+ return;
+ }
+ builder.addResolutionResult(
+ resolveFieldOn(superClass, field, initialResolutionHolder, visitedInterfaces));
+ });
+ return builder.buildOrIfEmpty(null);
}
return FieldResolutionResult.failure();
}
- private DexClassAndField resolveFieldOnDirectInterfaces(
- DexClass clazz, DexField field, Set<DexType> visitedInterfaces) {
+ private FieldResolutionResult resolveFieldOnDirectInterfaces(
+ DexClass initialResolutionHolder,
+ DexClass clazz,
+ DexField field,
+ Set<DexType> visitedInterfaces) {
for (DexType interfaceType : clazz.interfaces.values) {
if (visitedInterfaces.add(interfaceType)) {
- DexClass interfaceClass = definitionFor.contextIndependentDefinitionFor(interfaceType);
- if (interfaceClass != null) {
- DexClassAndField result =
- resolveFieldOnInterface(interfaceClass, field, visitedInterfaces);
- if (result != null) {
- return result;
- }
+ FieldResolutionResult.Builder builder = FieldResolutionResult.builder();
+ definitionFor
+ .contextIndependentDefinitionForWithResolutionResult(interfaceType)
+ .forEachClassResolutionResult(
+ ifaceClass -> {
+ // Check if the subtype is a library type and if it is child of a non-library
+ // type. If that is the case, do not return any results.
+ if (clazz.isLibraryClass() && !ifaceClass.isLibraryClass()) {
+ return;
+ }
+ builder.addResolutionResult(
+ resolveFieldOnInterface(
+ initialResolutionHolder, ifaceClass, field, visitedInterfaces));
+ });
+ FieldResolutionResult fieldResolutionResult = builder.buildOrIfEmpty(null);
+ if (fieldResolutionResult != null) {
+ return fieldResolutionResult;
}
}
}
return null;
}
- private DexClassAndField resolveFieldOnInterface(
- DexClass interfaceClass, DexField field, Set<DexType> visitedInterfaces) {
+ private FieldResolutionResult resolveFieldOnInterface(
+ DexClass initialResolutionHolder,
+ DexClass interfaceClass,
+ DexField field,
+ Set<DexType> visitedInterfaces) {
// Step 1: Class declares the field.
DexEncodedField definition = interfaceClass.lookupField(field);
if (definition != null) {
- return DexClassAndField.create(interfaceClass, definition);
+ return createSingleFieldResolutionResult(initialResolutionHolder, interfaceClass, definition);
}
// Step 2: Apply recursively to direct superinterfaces. First match succeeds.
- return resolveFieldOnDirectInterfaces(interfaceClass, field, visitedInterfaces);
+ return resolveFieldOnDirectInterfaces(
+ initialResolutionHolder, interfaceClass, field, visitedInterfaces);
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/FieldResolutionResult.java b/src/main/java/com/android/tools/r8/graph/FieldResolutionResult.java
index 702d1fd..c5d89b3 100644
--- a/src/main/java/com/android/tools/r8/graph/FieldResolutionResult.java
+++ b/src/main/java/com/android/tools/r8/graph/FieldResolutionResult.java
@@ -4,7 +4,14 @@
package com.android.tools.r8.graph;
+import com.android.tools.r8.errors.Unimplemented;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.Box;
import com.android.tools.r8.utils.OptionalBool;
+import com.google.common.collect.Iterables;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
public abstract class FieldResolutionResult
extends MemberResolutionResult<DexEncodedField, DexField> {
@@ -40,15 +47,31 @@
return null;
}
+ public ProgramField getSingleProgramField() {
+ return null;
+ }
+
public ProgramField getProgramField() {
return null;
}
- public boolean isSuccessfulResolution() {
+ public boolean isSingleFieldResolutionResult() {
return false;
}
- public SuccessfulFieldResolutionResult asSuccessfulResolution() {
+ public boolean isSingleProgramFieldResolutionResult() {
+ return false;
+ }
+
+ public SingleFieldResolutionResult<?> asSingleFieldResolutionResult() {
+ return null;
+ }
+
+ public SingleProgramFieldResolutionResult asSingleProgramFieldResolutionResult() {
+ return null;
+ }
+
+ public SingleClasspathFieldResolutionResult asSingleClasspathFieldResolutionResult() {
return null;
}
@@ -58,27 +81,80 @@
}
@Override
- public SuccessfulFieldResolutionResult asSuccessfulMemberResolutionResult() {
+ public SingleFieldResolutionResult<?> asSuccessfulMemberResolutionResult() {
return null;
}
- public boolean isFailedOrUnknownResolution() {
+ public boolean isPossiblyFailedOrUnknownResolution() {
return false;
}
+ public boolean hasProgramOrClasspathResult() {
+ return false;
+ }
+
+ public boolean hasProgramResult() {
+ return false;
+ }
+
+ public boolean hasClasspathResult() {
+ return false;
+ }
+
+ public boolean isMultiFieldResolutionResult() {
+ return false;
+ }
+
+ public final void forEachFieldResolutionResult(Consumer<FieldResolutionResult> resultConsumer) {
+ visitFieldResolutionResults(resultConsumer, resultConsumer, resultConsumer);
+ }
+
+ public final void forEachSuccessfulFieldResolutionResult(
+ Consumer<SingleFieldResolutionResult<?>> resultConsumer) {
+ visitFieldResolutionResults(resultConsumer, failedResult -> {});
+ }
+
+ public final void visitFieldResolutionResults(
+ Consumer<SingleFieldResolutionResult<?>> singleResultConsumer,
+ Consumer<FailedOrUnknownFieldResolutionResult> failedResolutionConsumer) {
+ visitFieldResolutionResults(
+ singleResultConsumer, singleResultConsumer, failedResolutionConsumer);
+ }
+
+ public abstract void visitFieldResolutionResults(
+ Consumer<? super SingleFieldResolutionResult<?>> programOrClasspathConsumer,
+ Consumer<? super SingleLibraryFieldResolutionResult> libraryResultConsumer,
+ Consumer<? super FailedOrUnknownFieldResolutionResult> failedResolutionConsumer);
+
public DexClass getInitialResolutionHolder() {
return null;
}
- public static class SuccessfulFieldResolutionResult extends FieldResolutionResult
+ public static SingleFieldResolutionResult<?> createSingleFieldResolutionResult(
+ DexClass initialResolutionHolder, DexClass holder, DexEncodedField definition) {
+ if (holder.isLibraryClass()) {
+ return new SingleLibraryFieldResolutionResult(
+ initialResolutionHolder, holder.asLibraryClass(), definition);
+ } else if (holder.isClasspathClass()) {
+ return new SingleClasspathFieldResolutionResult(
+ initialResolutionHolder, holder.asClasspathClass(), definition);
+ } else {
+ assert holder.isProgramClass();
+ return new SingleProgramFieldResolutionResult(
+ initialResolutionHolder, holder.asProgramClass(), definition);
+ }
+ }
+
+ public abstract static class SingleFieldResolutionResult<T extends DexClass>
+ extends FieldResolutionResult
implements SuccessfulMemberResolutionResult<DexEncodedField, DexField> {
private final DexClass initialResolutionHolder;
- private final DexClass resolvedHolder;
+ private final T resolvedHolder;
private final DexEncodedField resolvedField;
- SuccessfulFieldResolutionResult(
- DexClass initialResolutionHolder, DexClass resolvedHolder, DexEncodedField resolvedField) {
+ SingleFieldResolutionResult(
+ DexClass initialResolutionHolder, T resolvedHolder, DexEncodedField resolvedField) {
assert resolvedHolder.type == resolvedField.getHolderType();
this.initialResolutionHolder = initialResolutionHolder;
this.resolvedHolder = resolvedHolder;
@@ -91,7 +167,7 @@
}
@Override
- public DexClass getResolvedHolder() {
+ public T getResolvedHolder() {
return resolvedHolder;
}
@@ -116,25 +192,18 @@
}
@Override
- public ProgramField getProgramField() {
- return resolvedHolder.isProgramClass()
- ? new ProgramField(resolvedHolder.asProgramClass(), resolvedField)
- : null;
- }
-
- @Override
public OptionalBool isAccessibleFrom(
ProgramDefinition context, AppInfoWithClassHierarchy appInfo) {
return AccessControl.isMemberAccessible(this, context, appInfo);
}
@Override
- public boolean isSuccessfulResolution() {
+ public boolean isSingleFieldResolutionResult() {
return true;
}
@Override
- public SuccessfulFieldResolutionResult asSuccessfulResolution() {
+ public SingleFieldResolutionResult<T> asSingleFieldResolutionResult() {
return this;
}
@@ -144,14 +213,232 @@
}
@Override
- public SuccessfulFieldResolutionResult asSuccessfulMemberResolutionResult() {
+ public SingleFieldResolutionResult<T> asSuccessfulMemberResolutionResult() {
return this;
}
}
- public static class FailedFieldResolutionResult extends FieldResolutionResult {
+ public static class SingleProgramFieldResolutionResult
+ extends SingleFieldResolutionResult<DexProgramClass> {
- private static final FailedFieldResolutionResult INSTANCE = new FailedFieldResolutionResult();
+ SingleProgramFieldResolutionResult(
+ DexClass initialResolutionHolder,
+ DexProgramClass resolvedHolder,
+ DexEncodedField resolvedField) {
+ super(initialResolutionHolder, resolvedHolder, resolvedField);
+ }
+
+ @Override
+ public ProgramField getProgramField() {
+ return getSingleProgramField();
+ }
+
+ @Override
+ public ProgramField getSingleProgramField() {
+ return new ProgramField(getResolvedHolder(), getResolvedField());
+ }
+
+ @Override
+ public boolean isSingleProgramFieldResolutionResult() {
+ return true;
+ }
+
+ @Override
+ public SingleProgramFieldResolutionResult asSingleProgramFieldResolutionResult() {
+ return this;
+ }
+
+ @Override
+ public boolean hasProgramOrClasspathResult() {
+ return true;
+ }
+
+ @Override
+ public boolean hasProgramResult() {
+ return true;
+ }
+
+ @Override
+ public void visitFieldResolutionResults(
+ Consumer<? super SingleFieldResolutionResult<?>> programOrClasspathConsumer,
+ Consumer<? super SingleLibraryFieldResolutionResult> libraryResultConsumer,
+ Consumer<? super FailedOrUnknownFieldResolutionResult> failedResolutionConsumer) {
+ programOrClasspathConsumer.accept(this);
+ }
+ }
+
+ public static class SingleClasspathFieldResolutionResult
+ extends SingleFieldResolutionResult<DexClasspathClass> {
+
+ SingleClasspathFieldResolutionResult(
+ DexClass initialResolutionHolder,
+ DexClasspathClass resolvedHolder,
+ DexEncodedField resolvedField) {
+ super(initialResolutionHolder, resolvedHolder, resolvedField);
+ }
+
+ @Override
+ public SingleClasspathFieldResolutionResult asSingleClasspathFieldResolutionResult() {
+ return this;
+ }
+
+ @Override
+ public boolean hasProgramOrClasspathResult() {
+ return true;
+ }
+
+ @Override
+ public boolean hasClasspathResult() {
+ return true;
+ }
+
+ @Override
+ public void visitFieldResolutionResults(
+ Consumer<? super SingleFieldResolutionResult<?>> programOrClasspathConsumer,
+ Consumer<? super SingleLibraryFieldResolutionResult> libraryResultConsumer,
+ Consumer<? super FailedOrUnknownFieldResolutionResult> failedResolutionConsumer) {
+ programOrClasspathConsumer.accept(this);
+ }
+ }
+
+ public static class SingleLibraryFieldResolutionResult
+ extends SingleFieldResolutionResult<DexLibraryClass> {
+
+ SingleLibraryFieldResolutionResult(
+ DexClass initialResolutionHolder,
+ DexLibraryClass resolvedHolder,
+ DexEncodedField resolvedField) {
+ super(initialResolutionHolder, resolvedHolder, resolvedField);
+ }
+
+ @Override
+ public void visitFieldResolutionResults(
+ Consumer<? super SingleFieldResolutionResult<?>> programOrClasspathConsumer,
+ Consumer<? super SingleLibraryFieldResolutionResult> libraryResultConsumer,
+ Consumer<? super FailedOrUnknownFieldResolutionResult> failedResolutionConsumer) {
+ libraryResultConsumer.accept(this);
+ }
+ }
+
+ public abstract static class MultipleFieldResolutionResult<
+ C extends DexClass & ProgramOrClasspathClass, T extends SingleFieldResolutionResult<C>>
+ extends FieldResolutionResult {
+
+ protected final T programOrClasspathResult;
+ protected final List<SingleLibraryFieldResolutionResult> libraryResolutionResults;
+ protected final List<FailedOrUnknownFieldResolutionResult> failedOrUnknownResolutionResults;
+
+ public MultipleFieldResolutionResult(
+ T programOrClasspathResult,
+ List<SingleLibraryFieldResolutionResult> libraryResolutionResults,
+ List<FailedOrUnknownFieldResolutionResult> failedOrUnknownResolutionResults) {
+ assert programOrClasspathResult == null
+ || !programOrClasspathResult.getResolvedHolder().isLibraryClass();
+ assert failedOrUnknownResolutionResults.stream()
+ .allMatch(FieldResolutionResult::isPossiblyFailedOrUnknownResolution);
+ assert BooleanUtils.intValue(programOrClasspathResult != null)
+ + libraryResolutionResults.size()
+ + failedOrUnknownResolutionResults.size()
+ > 1
+ : "Should have been a single or failed result";
+ this.programOrClasspathResult = programOrClasspathResult;
+ this.libraryResolutionResults = libraryResolutionResults;
+ this.failedOrUnknownResolutionResults = failedOrUnknownResolutionResults;
+ }
+
+ @Override
+ public boolean isMultiFieldResolutionResult() {
+ return true;
+ }
+
+ @Override
+ public DexClass getInitialResolutionHolder() {
+ throw new Unimplemented("Should not be called on MultipleFieldResolutionResult");
+ }
+
+ @Override
+ public boolean hasProgramOrClasspathResult() {
+ return programOrClasspathResult != null;
+ }
+
+ @Override
+ public boolean hasProgramResult() {
+ return programOrClasspathResult != null && programOrClasspathResult.hasProgramResult();
+ }
+
+ @Override
+ public boolean hasClasspathResult() {
+ return programOrClasspathResult != null && programOrClasspathResult.hasClasspathResult();
+ }
+
+ @Override
+ public OptionalBool isAccessibleFrom(
+ ProgramDefinition context, AppInfoWithClassHierarchy appInfo) {
+ throw new Unimplemented("Should not be called on MultipleFieldResolutionResult");
+ }
+
+ @Override
+ public boolean isPossiblyFailedOrUnknownResolution() {
+ return !failedOrUnknownResolutionResults.isEmpty();
+ }
+
+ @Override
+ public boolean isSuccessfulMemberResolutionResult() {
+ return failedOrUnknownResolutionResults.isEmpty();
+ }
+
+ @Override
+ public void visitFieldResolutionResults(
+ Consumer<? super SingleFieldResolutionResult<?>> programOrClasspathConsumer,
+ Consumer<? super SingleLibraryFieldResolutionResult> libraryResultConsumer,
+ Consumer<? super FailedOrUnknownFieldResolutionResult> failedResolutionConsumer) {
+ if (programOrClasspathResult != null) {
+ programOrClasspathConsumer.accept(programOrClasspathResult);
+ }
+ libraryResolutionResults.forEach(libraryResultConsumer);
+ failedOrUnknownResolutionResults.forEach(failedResolutionConsumer);
+ }
+ }
+
+ public static class MultipleProgramWithLibraryFieldResolutionResult
+ extends MultipleFieldResolutionResult<DexProgramClass, SingleProgramFieldResolutionResult> {
+
+ public MultipleProgramWithLibraryFieldResolutionResult(
+ SingleProgramFieldResolutionResult programOrClasspathResult,
+ List<SingleLibraryFieldResolutionResult> libraryResolutionResults,
+ List<FailedOrUnknownFieldResolutionResult> failedOrUnknownResolutionResults) {
+ super(programOrClasspathResult, libraryResolutionResults, failedOrUnknownResolutionResults);
+ }
+
+ @Override
+ public ProgramField getProgramField() {
+ return programOrClasspathResult == null ? null : programOrClasspathResult.getProgramField();
+ }
+ }
+
+ public static class MultipleClasspathWithLibraryFieldResolutionResult
+ extends MultipleFieldResolutionResult<
+ DexClasspathClass, SingleClasspathFieldResolutionResult> {
+
+ public MultipleClasspathWithLibraryFieldResolutionResult(
+ SingleClasspathFieldResolutionResult programOrClasspathResult,
+ List<SingleLibraryFieldResolutionResult> libraryResolutionResults,
+ List<FailedOrUnknownFieldResolutionResult> failedOrUnknownResolutionResults) {
+ super(programOrClasspathResult, libraryResolutionResults, failedOrUnknownResolutionResults);
+ }
+ }
+
+ public static class MultipleLibraryFieldResolutionResult
+ extends MultipleFieldResolutionResult<DexProgramClass, SingleProgramFieldResolutionResult> {
+
+ public MultipleLibraryFieldResolutionResult(
+ List<SingleLibraryFieldResolutionResult> libraryResolutionResults,
+ List<FailedOrUnknownFieldResolutionResult> failedOrUnknownResolutionResults) {
+ super(null, libraryResolutionResults, failedOrUnknownResolutionResults);
+ }
+ }
+
+ public abstract static class FailedOrUnknownFieldResolutionResult extends FieldResolutionResult {
@Override
public OptionalBool isAccessibleFrom(
@@ -160,9 +447,22 @@
}
@Override
- public boolean isFailedOrUnknownResolution() {
+ public void visitFieldResolutionResults(
+ Consumer<? super SingleFieldResolutionResult<?>> programOrClasspathConsumer,
+ Consumer<? super SingleLibraryFieldResolutionResult> libraryResultConsumer,
+ Consumer<? super FailedOrUnknownFieldResolutionResult> failedResolutionConsumer) {
+ failedResolutionConsumer.accept(this);
+ }
+
+ @Override
+ public boolean isPossiblyFailedOrUnknownResolution() {
return true;
}
+ }
+
+ public static class FailedFieldResolutionResult extends FailedOrUnknownFieldResolutionResult {
+
+ private static final FailedFieldResolutionResult INSTANCE = new FailedFieldResolutionResult();
@Override
public boolean isFailedResolution() {
@@ -174,19 +474,84 @@
* Used in D8 when trying to resolve a field that is not declared on the enclosing class of the
* current method.
*/
- public static class UnknownFieldResolutionResult extends FieldResolutionResult {
+ public static class UnknownFieldResolutionResult extends FailedOrUnknownFieldResolutionResult {
private static final UnknownFieldResolutionResult INSTANCE = new UnknownFieldResolutionResult();
+ }
- @Override
- public OptionalBool isAccessibleFrom(
- ProgramDefinition context, AppInfoWithClassHierarchy appInfo) {
- return OptionalBool.FALSE;
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+
+ private FieldResolutionResult currentResult = null;
+
+ private Builder() {}
+
+ public void addResolutionResult(FieldResolutionResult otherResult) {
+ if (currentResult == null) {
+ currentResult = otherResult;
+ return;
+ }
+ Box<SingleFieldResolutionResult<?>> singleResult = new Box<>();
+ List<SingleLibraryFieldResolutionResult> libraryResults = new ArrayList<>();
+ List<FailedOrUnknownFieldResolutionResult> failedResults = new ArrayList<>();
+ currentResult.visitFieldResolutionResults(
+ singleResult::set, libraryResults::add, failedResults::add);
+ otherResult.visitFieldResolutionResults(
+ otherProgramOrClasspathResult -> {
+ if (singleResult.isSet()) {
+ assert false : "Unexpected multiple results between program and classpath";
+ if (singleResult.get().hasProgramResult()) {
+ return;
+ }
+ }
+ singleResult.set(otherProgramOrClasspathResult);
+ },
+ newLibraryResult -> {
+ if (!Iterables.any(
+ libraryResults,
+ existing -> existing.getResolvedHolder() == newLibraryResult.getResolvedHolder())) {
+ libraryResults.add(newLibraryResult);
+ }
+ },
+ newFailedResult -> {
+ if (!Iterables.any(
+ failedResults,
+ existing ->
+ existing.isFailedResolution() == newFailedResult.isFailedResolution())) {
+ failedResults.add(newFailedResult);
+ }
+ });
+ if (!singleResult.isSet()) {
+ if (libraryResults.size() == 1 && failedResults.isEmpty()) {
+ currentResult = libraryResults.get(0);
+ } else if (libraryResults.isEmpty() && failedResults.size() == 1) {
+ currentResult = failedResults.get(0);
+ } else {
+ currentResult = new MultipleLibraryFieldResolutionResult(libraryResults, failedResults);
+ }
+ } else if (libraryResults.isEmpty() && failedResults.isEmpty()) {
+ currentResult = singleResult.get();
+ } else if (singleResult.get().hasProgramResult()) {
+ currentResult =
+ new MultipleProgramWithLibraryFieldResolutionResult(
+ singleResult.get().asSingleProgramFieldResolutionResult(),
+ libraryResults,
+ failedResults);
+ } else {
+ SingleClasspathFieldResolutionResult classpathResult =
+ singleResult.get().asSingleClasspathFieldResolutionResult();
+ assert classpathResult != null;
+ currentResult =
+ new MultipleClasspathWithLibraryFieldResolutionResult(
+ classpathResult, libraryResults, failedResults);
+ }
}
- @Override
- public boolean isFailedOrUnknownResolution() {
- return true;
+ public FieldResolutionResult buildOrIfEmpty(FieldResolutionResult emptyResult) {
+ return currentResult == null ? emptyResult : currentResult;
}
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java b/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
index cce1760..772227c 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
@@ -21,6 +21,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.function.Consumer;
import java.util.stream.Collectors;
public class LazyLoadedDexApplication extends DexApplication {
@@ -53,6 +54,32 @@
}
@Override
+ public ClassResolutionResult contextIndependentDefinitionForWithResolutionResult(DexType type) {
+ ClassResolutionResult.Builder builder = ClassResolutionResult.builder();
+ if (libraryClasses != null) {
+ addClassToBuilderIfNotNull(libraryClasses.get(type), builder::add);
+ }
+ if (programClasses == null
+ || !addClassToBuilderIfNotNull(programClasses.get(type), builder::add)) {
+ // When looking up a type that exists both on program path and classpath, we assume the
+ // program class is taken and only if not present will look at classpath.
+ if (classpathClasses != null) {
+ addClassToBuilderIfNotNull(classpathClasses.get(type), builder::add);
+ }
+ }
+ return builder.build();
+ }
+
+ private <T extends DexClass> boolean addClassToBuilderIfNotNull(T clazz, Consumer<T> adder) {
+ if (clazz != null) {
+ adder.accept(clazz);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
public DexClass definitionFor(DexType type) {
assert type.isClassType() : "Cannot lookup definition for type: " + type;
DexClass clazz = null;
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramClass.java b/src/main/java/com/android/tools/r8/graph/ProgramClass.java
new file mode 100644
index 0000000..c6fc81f
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/ProgramClass.java
@@ -0,0 +1,13 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph;
+
+public interface ProgramClass extends ProgramDefinition, ProgramOrClasspathClass {
+
+ @Override
+ default DexClass asDexClass() {
+ return asProgramClass();
+ }
+}
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 ab0ee34..208c8ad 100644
--- a/src/main/java/com/android/tools/r8/graph/ProgramDefinition.java
+++ b/src/main/java/com/android/tools/r8/graph/ProgramDefinition.java
@@ -8,7 +8,8 @@
import java.util.function.BiFunction;
import java.util.function.Function;
-public interface ProgramDefinition extends Definition, ProgramDerivedContext {
+public interface ProgramDefinition
+ extends Definition, ProgramDerivedContext, ProgramOrClasspathDefinition {
@Override
default <T> T apply(
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramOrClasspathClass.java b/src/main/java/com/android/tools/r8/graph/ProgramOrClasspathClass.java
new file mode 100644
index 0000000..7c15abf
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/ProgramOrClasspathClass.java
@@ -0,0 +1,10 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph;
+
+public interface ProgramOrClasspathClass
+ extends ClassDefinition, ProgramOrClasspathDefinition, ClassResolutionResult {
+ DexClass asDexClass();
+}
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramOrClasspathDefinition.java b/src/main/java/com/android/tools/r8/graph/ProgramOrClasspathDefinition.java
new file mode 100644
index 0000000..b90c3f1
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/ProgramOrClasspathDefinition.java
@@ -0,0 +1,13 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph;
+
+public interface ProgramOrClasspathDefinition extends Definition {
+
+ @Override
+ default ProgramOrClasspathDefinition asProgramOrClasspathDefinition() {
+ return this;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAccessAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAccessAnalysis.java
index 3ebd37a..d871616 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAccessAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAccessAnalysis.java
@@ -9,7 +9,6 @@
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.FieldResolutionResult;
import com.android.tools.r8.graph.ProgramField;
import com.android.tools.r8.graph.bytecodemetadata.BytecodeMetadataProvider;
import com.android.tools.r8.ir.code.FieldInstruction;
@@ -82,27 +81,23 @@
for (Instruction instruction : code.instructions()) {
if (instruction.isFieldInstruction()) {
FieldInstruction fieldInstruction = instruction.asFieldInstruction();
- FieldResolutionResult resolutionResult =
- appView.appInfo().resolveField(fieldInstruction.getField());
- if (resolutionResult.isSuccessfulResolution()) {
- ProgramField field =
- resolutionResult.asSuccessfulResolution().getResolutionPair().asProgramField();
- if (field != null) {
- if (fieldAssignmentTracker != null) {
- fieldAssignmentTracker.recordFieldAccess(fieldInstruction, field, code.context());
- }
- if (fieldBitAccessAnalysis != null) {
- fieldBitAccessAnalysis.recordFieldAccess(
- fieldInstruction, field.getDefinition(), feedback);
- }
- if (fieldReadForInvokeReceiverAnalysis != null) {
- fieldReadForInvokeReceiverAnalysis.recordFieldAccess(
- fieldInstruction, field, bytecodeMetadataProviderBuilder, code.context());
- }
- if (fieldReadForWriteAnalysis != null) {
- fieldReadForWriteAnalysis.recordFieldAccess(
- fieldInstruction, field, bytecodeMetadataProviderBuilder);
- }
+ ProgramField field =
+ appView.appInfo().resolveField(fieldInstruction.getField()).getProgramField();
+ if (field != null) {
+ if (fieldAssignmentTracker != null) {
+ fieldAssignmentTracker.recordFieldAccess(fieldInstruction, field, code.context());
+ }
+ if (fieldBitAccessAnalysis != null) {
+ fieldBitAccessAnalysis.recordFieldAccess(
+ fieldInstruction, field.getDefinition(), feedback);
+ }
+ if (fieldReadForInvokeReceiverAnalysis != null) {
+ fieldReadForInvokeReceiverAnalysis.recordFieldAccess(
+ fieldInstruction, field, bytecodeMetadataProviderBuilder, code.context());
+ }
+ if (fieldReadForWriteAnalysis != null) {
+ fieldReadForWriteAnalysis.recordFieldAccess(
+ fieldInstruction, field, bytecodeMetadataProviderBuilder);
}
}
} else if (instruction.isNewInstance()) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java
index 714535c..bbee604 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java
@@ -458,7 +458,8 @@
appView.appInfo().getFieldAccessInfoCollection();
fieldAccessInfoCollection.forEach(
info -> {
- ProgramField field = appView.appInfo().resolveField(info.getField()).getProgramField();
+ ProgramField field =
+ appView.appInfo().resolveField(info.getField()).getSingleProgramField();
if (field == null) {
return;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldReadForWriteAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldReadForWriteAnalysis.java
index 3b4f8dc..6a5c420 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldReadForWriteAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldReadForWriteAnalysis.java
@@ -58,7 +58,7 @@
if (writtenFieldReference.match(field.getReference())
&& fieldPut.isStaticPut() == field.getAccessFlags().isStatic()) {
ProgramField writtenField =
- appView.appInfo().resolveField(writtenFieldReference).getProgramField();
+ appView.appInfo().resolveField(writtenFieldReference).getSingleProgramField();
if (writtenField != null && writtenField.isStructurallyEqualTo(field)) {
// OK.
foundWrite = true;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java
index ef8d041..5d34c84 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java
@@ -22,7 +22,8 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.FieldAccessInfo;
import com.android.tools.r8.graph.FieldAccessInfoCollection;
-import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
+import com.android.tools.r8.graph.FieldResolutionResult;
+import com.android.tools.r8.graph.ProgramField;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.graph.bytecodemetadata.BytecodeInstructionMetadata;
@@ -316,18 +317,19 @@
boolean isStatic,
boolean isWrite,
BytecodeInstructionMetadata metadata) {
- SuccessfulFieldResolutionResult resolutionResult =
- appView.appInfo().resolveField(reference).asSuccessfulResolution();
- if (resolutionResult == null) {
+ FieldResolutionResult resolutionResult = appView.appInfo().resolveField(reference);
+ if (!resolutionResult.hasProgramResult()) {
+ // We don't care about field accesses that may not resolve to a program field.
return;
}
- DexClassAndField field = resolutionResult.getResolutionPair();
+ ProgramField field = resolutionResult.getProgramField();
DexEncodedField definition = field.getDefinition();
if (definition.isStatic() != isStatic
|| appView.isCfByteCodePassThrough(getContext().getDefinition())
- || resolutionResult.isAccessibleFrom(getContext(), appView).isPossiblyFalse()) {
+ || resolutionResult.isAccessibleFrom(getContext(), appView).isPossiblyFalse()
+ || !resolutionResult.isSingleProgramFieldResolutionResult()) {
recordAccessThatCannotBeOptimized(field, definition);
return;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/FieldValueAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/FieldValueAnalysis.java
index ee985c4..9c09ef2 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/FieldValueAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/FieldValueAnalysis.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexValue;
-import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
+import com.android.tools.r8.graph.ProgramField;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.DominatorTree;
@@ -125,15 +125,13 @@
if (instruction.isFieldPut()) {
FieldInstruction fieldPut = instruction.asFieldInstruction();
DexField field = fieldPut.getField();
- SuccessfulFieldResolutionResult fieldResolutionResult =
- appInfo.resolveField(field).asSuccessfulResolution();
- if (fieldResolutionResult != null) {
- DexEncodedField encodedField = fieldResolutionResult.getResolvedField();
- assert encodedField != null;
+ ProgramField programField = appInfo.resolveField(field).getProgramField();
+ if (programField != null) {
+ DexEncodedField encodedField = programField.getDefinition();
if (isSubjectToOptimization(encodedField)) {
recordFieldPut(encodedField, fieldPut);
} else if (isStaticFieldValueAnalysis()
- && fieldResolutionResult.getResolvedHolder().isEnum()
+ && programField.getHolder().isEnum()
&& isSubjectToOptimizationIgnoringPinning(encodedField)) {
recordFieldPut(encodedField, fieldPut);
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedExtensionRegistryShrinker.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedExtensionRegistryShrinker.java
index 42a035f..88d1c47 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedExtensionRegistryShrinker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedExtensionRegistryShrinker.java
@@ -14,7 +14,6 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.FieldAccessInfo;
import com.android.tools.r8.graph.FieldAccessInfoCollection;
-import com.android.tools.r8.graph.FieldResolutionResult;
import com.android.tools.r8.graph.ProgramField;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.IRCode;
@@ -232,15 +231,10 @@
public boolean isDeadProtoExtensionField(DexField fieldReference) {
AppInfoWithLiveness appInfo = appView.appInfo();
- FieldResolutionResult resolutionResult = appInfo.resolveField(fieldReference);
- if (resolutionResult.isSuccessfulResolution()) {
- ProgramField field =
- resolutionResult.asSuccessfulResolution().getResolutionPair().asProgramField();
- return field != null
- && isDeadProtoExtensionField(
- field, appInfo.getFieldAccessInfoCollection(), appInfo.getKeepInfo());
- }
- return false;
+ ProgramField field = appInfo.resolveField(fieldReference).getSingleProgramField();
+ return field != null
+ && isDeadProtoExtensionField(
+ field, appInfo.getFieldAccessInfoCollection(), appInfo.getKeepInfo());
}
public boolean isDeadProtoExtensionField(
@@ -262,7 +256,7 @@
// Multiple GeneratedExtensionRegistries exist in Chrome; 1 per feature split.
return fieldAccessInfo.isReadOnlyInMethodSatisfying(
- method -> references.isFindLiteExtensionByNumberMethod(method));
+ references::isFindLiteExtensionByNumberMethod);
}
private void forEachDeadProtoExtensionField(Consumer<DexField> consumer) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java
index b0ddb4a..62b8e28 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java
@@ -530,16 +530,12 @@
DexField oneOfCaseFieldReference = oneOfCaseObject.asLiveProtoFieldObject().getField();
FieldResolutionResult oneOfCaseFieldResolutionResult =
appView.appInfo().resolveField(oneOfCaseFieldReference);
- if (oneOfCaseFieldResolutionResult.isFailedOrUnknownResolution()) {
+ if (!oneOfCaseFieldResolutionResult.isSingleProgramFieldResolutionResult()) {
assert false;
return;
}
- ProgramField oneOfCaseField =
- oneOfCaseFieldResolutionResult
- .asSuccessfulResolution()
- .getResolutionPair()
- .asProgramField();
+ ProgramField oneOfCaseField = oneOfCaseFieldResolutionResult.getProgramField();
if (oneOfCaseField == null) {
assert false;
return;
@@ -565,13 +561,12 @@
DexField oneOfFieldReference = oneOfObject.asLiveProtoFieldObject().getField();
FieldResolutionResult oneOfFieldResolutionResult =
appView.appInfo().resolveField(oneOfFieldReference);
- if (oneOfFieldResolutionResult.isFailedOrUnknownResolution()) {
+ if (!oneOfFieldResolutionResult.isSingleProgramFieldResolutionResult()) {
assert false;
return;
}
- ProgramField oneOfField =
- oneOfFieldResolutionResult.asSuccessfulResolution().getResolutionPair().asProgramField();
+ ProgramField oneOfField = oneOfFieldResolutionResult.getProgramField();
if (oneOfField == null || oneOfField.getHolder() != oneOfCaseField.getHolder()) {
assert false;
return;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoFieldInfo.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoFieldInfo.java
index 1515932..7c35106 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoFieldInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoFieldInfo.java
@@ -9,7 +9,6 @@
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.FieldResolutionResult;
import com.android.tools.r8.graph.ProgramField;
import java.util.List;
import java.util.OptionalInt;
@@ -131,12 +130,10 @@
ProtoObject object = protoMessageInfo.getHasBitsObjects().get(hasBitsIndex);
assert object.isLiveProtoFieldObject();
- FieldResolutionResult resolutionResult =
- appView.appInfo().resolveField(object.asLiveProtoFieldObject().getField());
- if (resolutionResult.isSuccessfulResolution()) {
- return resolutionResult.asSuccessfulResolution().getResolutionPair().asProgramField();
- }
- return null;
+ return appView
+ .appInfo()
+ .resolveField(object.asLiveProtoFieldObject().getField())
+ .getSingleProgramField();
}
public int getHazzerBitFieldIndex(ProtoMessageInfo protoMessageInfo) {
@@ -175,12 +172,10 @@
assert type.isOneOf();
ProtoObject object = protoMessageInfo.getOneOfObjects().get(getAuxData()).getOneOfCaseObject();
assert object.isLiveProtoFieldObject();
- FieldResolutionResult resolutionResult =
- appView.appInfo().resolveField(object.asLiveProtoFieldObject().getField());
- if (resolutionResult.isSuccessfulResolution()) {
- return resolutionResult.asSuccessfulResolution().getResolutionPair().asProgramField();
- }
- return null;
+ return appView
+ .appInfo()
+ .resolveField(object.asLiveProtoFieldObject().getField())
+ .getSingleProgramField();
}
/**
@@ -196,12 +191,10 @@
? protoMessageInfo.getOneOfObjects().get(getAuxData()).getOneOfObject()
: objects.get(0);
assert object.isLiveProtoFieldObject();
- FieldResolutionResult resolutionResult =
- appView.appInfo().resolveField(object.asLiveProtoFieldObject().getField());
- if (resolutionResult.isSuccessfulResolution()) {
- return resolutionResult.asSuccessfulResolution().getResolutionPair().asProgramField();
- }
- return null;
+ return appView
+ .appInfo()
+ .resolveField(object.asLiveProtoFieldObject().getField())
+ .getProgramField();
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
index ebbfffe..19af1c7 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.ir.analysis.value;
import static com.android.tools.r8.ir.analysis.type.Nullability.maybeNull;
+import static com.android.tools.r8.utils.ForEachUtils.allMatch;
import com.android.tools.r8.features.ClassToFeatureSplitMap;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
@@ -14,7 +15,6 @@
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
@@ -96,9 +96,14 @@
@Override
public boolean isMaterializableInContext(
AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
- SuccessfulFieldResolutionResult resolutionResult =
- appView.appInfo().resolveField(field).asSuccessfulResolution();
- return resolutionResult != null && resolutionResult.isAccessibleFrom(context, appView).isTrue();
+ return allMatch(
+ appView.appInfo().resolveField(field)::forEachFieldResolutionResult,
+ resolutionResult -> {
+ if (resolutionResult.isPossiblyFailedOrUnknownResolution()) {
+ return false;
+ }
+ return resolutionResult.isAccessibleFrom(context, appView).isTrue();
+ });
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionListIterator.java b/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionListIterator.java
index e1ed280..358369b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionListIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionListIterator.java
@@ -283,25 +283,13 @@
Value value,
Position position) {
InternalOptions options = appView.options();
-
- InvokeMethod invoke;
- if (appView.options().canUseJavaUtilObjectsRequireNonNull()) {
- DexMethod requireNonNullMethod = appView.dexItemFactory().objectsMethods.requireNonNull;
- invoke =
- InvokeStatic.builder()
- .setMethod(requireNonNullMethod)
- .setSingleArgument(value)
- .setPosition(position)
- .build();
- } else {
- DexMethod getClassMethod = appView.dexItemFactory().objectMembers.getClass;
- invoke =
- InvokeVirtual.builder()
- .setMethod(getClassMethod)
- .setSingleArgument(value)
- .setPosition(position)
- .build();
- }
+ DexMethod getClassMethod = appView.dexItemFactory().objectMembers.getClass;
+ InvokeMethod invoke =
+ InvokeVirtual.builder()
+ .setMethod(getClassMethod)
+ .setSingleArgument(value)
+ .setPosition(position)
+ .build();
add(invoke);
if (block.hasCatchHandlers()) {
splitCopyCatchHandlers(code, blockIterator, options);
@@ -338,15 +326,8 @@
removeOrReplaceByDebugLocalRead();
return true;
}
- InvokeMethod replacement;
- if (appView.options().canUseJavaUtilObjectsRequireNonNull()) {
- DexMethod requireNonNullMethod = appView.dexItemFactory().objectsMethods.requireNonNull;
- replacement = new InvokeStatic(requireNonNullMethod, null, ImmutableList.of(receiver));
- } else {
- DexMethod getClassMethod = appView.dexItemFactory().objectMembers.getClass;
- replacement = new InvokeVirtual(getClassMethod, null, ImmutableList.of(receiver));
- }
- replaceCurrentInstruction(replacement);
+ DexMethod getClassMethod = appView.dexItemFactory().objectMembers.getClass;
+ replaceCurrentInstruction(new InvokeVirtual(getClassMethod, null, ImmutableList.of(receiver)));
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java b/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
index 6c773a6..c65bccc 100644
--- a/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
@@ -9,7 +9,8 @@
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
+import com.android.tools.r8.graph.FieldResolutionResult;
+import com.android.tools.r8.graph.FieldResolutionResult.SingleFieldResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.AbstractFieldSet;
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.ConcreteMutableFieldSet;
@@ -65,28 +66,28 @@
public boolean instructionInstanceCanThrow(
AppView<?> appView, ProgramMethod context, SideEffectAssumption assumption) {
return internalInstructionInstanceCanThrow(
- appView,
- context,
- assumption,
- appView.appInfo().resolveField(field, context).asSuccessfulResolution());
+ appView, context, assumption, appView.appInfo().resolveField(field, context));
}
boolean internalInstructionInstanceCanThrow(
AppView<?> appView,
ProgramMethod context,
SideEffectAssumption assumption,
- SuccessfulFieldResolutionResult resolutionResult) {
- if (resolutionResult == null) {
+ FieldResolutionResult resolutionResult) {
+ if (!resolutionResult.isSingleFieldResolutionResult()) {
+ // Conservatively treat instruction as being throwing.
return true;
}
- DexEncodedField resolvedField = resolutionResult.getResolvedField();
+ SingleFieldResolutionResult<?> singleFieldResolutionResult =
+ resolutionResult.asSingleFieldResolutionResult();
+ DexEncodedField resolvedField = singleFieldResolutionResult.getResolvedField();
// Check if the instruction may fail with an IncompatibleClassChangeError.
if (resolvedField.isStatic() != isStaticFieldInstruction()) {
return true;
}
// Check if the resolution target is accessible.
- if (resolutionResult.getResolvedHolder() != context.getHolder()) {
- if (resolutionResult
+ if (singleFieldResolutionResult.getResolvedHolder() != context.getHolder()) {
+ if (singleFieldResolutionResult
.isAccessibleFrom(context, appView.appInfo().withClassHierarchy())
.isPossiblyFalse()) {
return true;
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstancePut.java b/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
index 13cba81..e0ca6cd 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
@@ -19,7 +19,7 @@
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
+import com.android.tools.r8.graph.FieldResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.AnalysisAssumption;
@@ -132,8 +132,7 @@
AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
AppInfoWithLiveness appInfoWithLiveness = appViewWithLiveness.appInfo();
- SuccessfulFieldResolutionResult resolutionResult =
- appInfoWithLiveness.resolveField(getField()).asSuccessfulResolution();
+ FieldResolutionResult resolutionResult = appInfoWithLiveness.resolveField(getField());
if (internalInstructionInstanceCanThrow(appView, context, assumption, resolutionResult)) {
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/StaticPut.java b/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
index 2230cc7..b32a651 100644
--- a/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
+++ b/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
@@ -18,7 +18,7 @@
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
+import com.android.tools.r8.graph.FieldResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.AnalysisAssumption;
@@ -110,8 +110,7 @@
AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
AppInfoWithLiveness appInfoWithLiveness = appViewWithLiveness.appInfo();
- SuccessfulFieldResolutionResult resolutionResult =
- appInfoWithLiveness.resolveField(getField()).asSuccessfulResolution();
+ FieldResolutionResult resolutionResult = appInfoWithLiveness.resolveField(getField());
if (internalInstructionInstanceCanThrow(appView, context, assumption, resolutionResult)) {
return true;
}
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 145ffec..664da13 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
@@ -415,8 +415,7 @@
ExecutorService executorService,
CfClassSynthesizerDesugaringEventConsumer classSynthesizerEventConsumer)
throws ExecutionException {
- CfClassSynthesizerDesugaringCollection.create(
- appView, instructionDesugaring.getRetargetingInfo())
+ CfClassSynthesizerDesugaringCollection.create(appView)
.synthesizeClasses(executorService, classSynthesizerEventConsumer);
}
@@ -431,8 +430,7 @@
InterfaceMethodProcessorFacade interfaceDesugaring =
instructionDesugaring.getInterfaceMethodPostProcessingDesugaringD8(
ExcludeDexResources, interfaceProcessor);
- CfPostProcessingDesugaringCollection.create(
- appView, interfaceDesugaring, instructionDesugaring.getRetargetingInfo())
+ CfPostProcessingDesugaringCollection.create(appView, interfaceDesugaring)
.postProcessingDesugaring(
appView.appInfo().classes(), m -> true, eventConsumer, executorService);
methodProcessor.awaitMethodProcessing();
@@ -590,7 +588,24 @@
.append("'")
.append(i < neverMergePrefixes.size() - 1 ? ", " : "");
}
- message.append(" with classes with any other prefixes is not allowed.");
+ message.append(" with classes with any other prefixes is not allowed: ");
+ boolean first = true;
+ int limit = 11;
+ for (DexProgramClass clazz : appView.appInfo().classesWithDeterministicOrder()) {
+ if (!clazz.type.descriptor.startsWith(neverMergePrefix)) {
+ if (limit-- < 0) {
+ message.append("..");
+ break;
+ }
+ if (first) {
+ first = false;
+ } else {
+ message.append(", ");
+ }
+ message.append(clazz.type);
+ }
+ }
+ message.append(".");
throw new CompilationError(message.toString());
}
}
@@ -1092,6 +1107,12 @@
timing.end();
}
+ if (options.canHaveInvokeInterfaceToObjectMethodBug()) {
+ timing.begin("JDK-8272564 fix rewrite");
+ CodeRewriter.rewriteJdk8272564Fix(code, appView);
+ timing.end();
+ }
+
boolean isDebugMode = options.debug || method.getOptimizationInfo().isReachabilitySensitive();
if (isDebugMode) {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java b/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java
index 0da54ff..8ad701f 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java
@@ -54,8 +54,6 @@
void markAsPropagated(DexEncodedMethod method);
- void markTriggerClassInitBeforeAnySideEffect(DexEncodedMethod method, boolean mark);
-
void setBridgeInfo(DexEncodedMethod method, BridgeInfo bridgeInfo);
void setClassInlinerMethodConstraint(
@@ -119,8 +117,6 @@
void unsetSimpleInliningConstraint(ProgramMethod method);
- void unsetTriggerClassInitBeforeAnySideEffect(ProgramMethod method);
-
void unsetUnusedArguments(ProgramMethod method);
default void unsetOptimizationInfoForAbstractMethod(ProgramMethod method) {
@@ -143,7 +139,6 @@
unsetReturnedArgument(method);
unsetReturnValueOnlyDependsOnArguments(method);
unsetSimpleInliningConstraint(method);
- unsetTriggerClassInitBeforeAnySideEffect(method);
unsetUnusedArguments(method);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/callgraph/IRProcessingCallGraphUseRegistry.java b/src/main/java/com/android/tools/r8/ir/conversion/callgraph/IRProcessingCallGraphUseRegistry.java
index b88c9d0..e20123e 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/callgraph/IRProcessingCallGraphUseRegistry.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/callgraph/IRProcessingCallGraphUseRegistry.java
@@ -65,7 +65,7 @@
return;
}
- ProgramField field = appView.appInfo().resolveField(rewrittenReference).getProgramField();
+ ProgramField field = appView.appInfo().resolveField(rewrittenReference).getSingleProgramField();
if (field == null || appView.appInfo().isPinned(field)) {
return;
}
@@ -89,7 +89,7 @@
return;
}
- ProgramField field = appView.appInfo().resolveField(rewrittenReference).getProgramField();
+ ProgramField field = appView.appInfo().resolveField(rewrittenReference).getSingleProgramField();
if (field == null || appView.appInfo().isPinned(field)) {
return;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
index f99e380..dd2bb76 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
@@ -100,14 +100,14 @@
public static List<DexMethod> generateListOfBackportedMethods(
AndroidApp androidApp, InternalOptions options, ExecutorService executor) throws IOException {
List<DexMethod> methods = new ArrayList<>();
- PrefixRewritingMapper rewritePrefix = options.getPrefixRewritingMapper();
+ TypeRewriter typeRewriter = options.getTypeRewriter();
AppInfo appInfo = null;
if (androidApp != null) {
DexApplication app =
new ApplicationReader(androidApp, options, Timing.empty()).read(executor);
appInfo = AppInfo.createInitialAppInfo(app);
}
- AppView<?> appView = AppView.createForD8(appInfo, rewritePrefix);
+ AppView<?> appView = AppView.createForD8(appInfo, typeRewriter);
BackportedMethodRewriter.RewritableMethods rewritableMethods =
new BackportedMethodRewriter.RewritableMethods(options, appView);
rewritableMethods.visit(methods::add);
@@ -128,24 +128,16 @@
DexMethod original = appView.graphLens().getOriginalMethodSignature(method);
assert original != null;
MethodProvider provider = rewritableMethods.getProvider(original);
- // TODO(b/150693139): Since the DesugarLibraryRetargeter is run during IR processing while the
- // backported method rewriter is run in cf to cf, we need here to compute if the method is
- // actually going to be retargeted through desugared library backports, and compute the
- // corresponding backported method if so. This can be removed once the DesugarLibraryRetargeter
- // has been moved as a cf to cf transformation.
+ // Old versions of desugared library have in the jar file pre-desugared code. This is used
+ // to undesugar pre-desugared code, then the code is re-desugared with D8/R8. This is
+ // maintained for legacy only, recent desugared library should not be shipped with
+ // pre-desugared code.
+ Map<DexType, DexType> legacyBackport =
+ appView.options().machineDesugaredLibrarySpecification.getLegacyBackport();
if (provider == null
&& appView.options().isDesugaredLibraryCompilation()
- && appView
- .options()
- .desugaredLibrarySpecification
- .getBackportCoreLibraryMember()
- .containsKey(method.holder)) {
- DexType newHolder =
- appView
- .options()
- .desugaredLibrarySpecification
- .getBackportCoreLibraryMember()
- .get(method.holder);
+ && legacyBackport.containsKey(method.holder)) {
+ DexType newHolder = legacyBackport.get(method.holder);
DexMethod backportedMethod =
appView.dexItemFactory().createMethod(newHolder, method.proto, method.name);
provider = rewritableMethods.getProvider(backportedMethod);
@@ -188,22 +180,25 @@
initializeAndroidSv2MethodProviders(factory);
}
- // The following providers are currently not implemented at any API level in Android.
- // They however require the Optional/Stream class to be present, either through desugared
- // libraries or natively. If Optional/Stream class is not present, we do not desugar to
- // avoid confusion in error messages.
- if (appView.rewritePrefix.hasRewrittenType(factory.optionalType, appView)
- || options.getMinApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N)) {
- initializeJava9OptionalMethodProviders(factory);
- initializeJava10OptionalMethodProviders(factory);
- initializeJava11OptionalMethodProviders(factory);
+ // The following providers are implemented at API level T. For backporting they require
+ // the java.util.Optional class to be present, either through library desugaring or natively.
+ // If the java.util.Optional class is not present, we do not backport to avoid confusion in
+ // error messages.
+ if (appView.typeRewriter.hasRewrittenType(factory.optionalType, appView)
+ || options.getMinApiLevel().betweenBothIncluded(AndroidApiLevel.N, AndroidApiLevel.Sv2)) {
+ initializeAndroidOptionalTMethodProviders(factory);
}
- if (appView.rewritePrefix.hasRewrittenType(factory.streamType, appView)
+
+ // The following providers are currently not implemented at any API level in Android. For
+ // backporting they require the java.util.stream.Stream class to be present, either through
+ // library desugaring or natively. If the java.util.stream.Stream class is not present, we do
+ // not desugar to avoid confusion in error messages.
+ if (appView.typeRewriter.hasRewrittenType(factory.streamType, appView)
|| options.getMinApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N)) {
initializeStreamMethodProviders(factory);
}
- if (appView.rewritePrefix.hasRewrittenType(factory.supplierType, appView)) {
+ if (appView.typeRewriter.hasRewrittenType(factory.supplierType, appView)) {
// TODO(b/191188594): Consider adding the Objects method from R here, or instead
// rely on desugared library to support them.
initializeObjectsMethodProviders(factory);
@@ -1163,6 +1158,122 @@
}
}
+ private void initializeAndroidOptionalTMethodProviders(DexItemFactory factory) {
+ DexType optionalType = factory.optionalType;
+ DexType[] optionalTypes =
+ new DexType[] {
+ factory.optionalType,
+ factory.optionalDoubleType,
+ factory.optionalLongType,
+ factory.optionalIntType,
+ };
+
+ // or (added in Java 9).
+ {
+ DexString name = factory.createString("or");
+ DexProto proto = factory.createProto(optionalType, factory.supplierType);
+ DexMethod method = factory.createMethod(optionalType, proto, name);
+ addProvider(
+ new StatifyingMethodGenerator(
+ method, BackportedMethods::OptionalMethods_or, "or", optionalType));
+ }
+
+ // stream (added in Java 9).
+ {
+ DexType[] streamReturnTypes =
+ new DexType[] {
+ factory.streamType,
+ factory.createType(factory.createString("Ljava/util/stream/DoubleStream;")),
+ factory.createType(factory.createString("Ljava/util/stream/LongStream;")),
+ factory.createType(factory.createString("Ljava/util/stream/IntStream;")),
+ };
+ TemplateMethodFactory[] streamMethodFactories =
+ new TemplateMethodFactory[] {
+ BackportedMethods::OptionalMethods_stream,
+ BackportedMethods::OptionalMethods_streamDouble,
+ BackportedMethods::OptionalMethods_streamLong,
+ BackportedMethods::OptionalMethods_streamInt,
+ };
+ DexString name = factory.createString("stream");
+ for (int i = 0; i < optionalTypes.length; i++) {
+ DexType optional = optionalTypes[i];
+ DexType streamReturnType = streamReturnTypes[i];
+ DexProto proto = factory.createProto(streamReturnType);
+ DexMethod method = factory.createMethod(optional, proto, name);
+ addProvider(
+ new StatifyingMethodGenerator(method, streamMethodFactories[i], "stream", optional));
+ }
+ }
+
+ // ifPresentOrElse (added in Java 9).
+ {
+ DexType[] consumerTypes =
+ new DexType[] {
+ factory.consumerType,
+ factory.doubleConsumer,
+ factory.longConsumer,
+ factory.intConsumer
+ };
+ TemplateMethodFactory[] methodFactories =
+ new TemplateMethodFactory[] {
+ BackportedMethods::OptionalMethods_ifPresentOrElse,
+ BackportedMethods::OptionalMethods_ifPresentOrElseDouble,
+ BackportedMethods::OptionalMethods_ifPresentOrElseLong,
+ BackportedMethods::OptionalMethods_ifPresentOrElseInt
+ };
+ for (int i = 0; i < optionalTypes.length; i++) {
+ DexType optional = optionalTypes[i];
+ DexType consumer = consumerTypes[i];
+ DexString name = factory.createString("ifPresentOrElse");
+ DexProto proto = factory.createProto(factory.voidType, consumer, factory.runnableType);
+ DexMethod method = factory.createMethod(optional, proto, name);
+ addProvider(
+ new StatifyingMethodGenerator(
+ method, methodFactories[i], "ifPresentOrElse", optional));
+ }
+ }
+
+ // orElseThrow (added in Java 10).
+ {
+ DexType[] returnTypes =
+ new DexType[] {
+ factory.objectType, factory.doubleType, factory.longType, factory.intType,
+ };
+ MethodInvokeRewriter[] rewriters =
+ new MethodInvokeRewriter[] {
+ OptionalMethodRewrites.rewriteOrElseGet(),
+ OptionalMethodRewrites.rewriteDoubleOrElseGet(),
+ OptionalMethodRewrites.rewriteLongOrElseGet(),
+ OptionalMethodRewrites.rewriteIntOrElseGet(),
+ };
+ DexString name = factory.createString("orElseThrow");
+ for (int i = 0; i < optionalTypes.length; i++) {
+ DexProto proto = factory.createProto(returnTypes[i]);
+ DexMethod method = factory.createMethod(optionalTypes[i], proto, name);
+ addProvider(new InvokeRewriter(method, rewriters[i]));
+ }
+ }
+
+ // isEmpty (added in Java 11).
+ {
+ TemplateMethodFactory[] methodFactories =
+ new TemplateMethodFactory[] {
+ BackportedMethods::OptionalMethods_isEmpty,
+ BackportedMethods::OptionalMethods_isEmptyDouble,
+ BackportedMethods::OptionalMethods_isEmptyLong,
+ BackportedMethods::OptionalMethods_isEmptyInt
+ };
+ DexString name = factory.createString("isEmpty");
+ for (int i = 0; i < optionalTypes.length; i++) {
+ DexProto proto = factory.createProto(factory.booleanType);
+ DexMethod method = factory.createMethod(optionalTypes[i], proto, name);
+ addProvider(
+ new StatifyingMethodGenerator(
+ method, methodFactories[i], "isEmpty", optionalTypes[i]));
+ }
+ }
+ }
+
private void initializeJava9MethodProviders(DexItemFactory factory) {
// Integer
DexType type = factory.boxedIntType;
@@ -1298,127 +1409,6 @@
method, BackportedMethods::StringMethods_stripTrailing, "stripTrailing", type));
}
- private void initializeJava9OptionalMethodProviders(DexItemFactory factory) {
- // Optional
- DexType optionalType = factory.optionalType;
-
- // Optional.or(supplier)
- DexString name = factory.createString("or");
- DexProto proto = factory.createProto(optionalType, factory.supplierType);
- DexMethod method = factory.createMethod(optionalType, proto, name);
- addProvider(
- new StatifyingMethodGenerator(
- method, BackportedMethods::OptionalMethods_or, "or", optionalType));
-
- // Optional{void,Int,Long,Double}.stream()
- DexType[] optionalTypes =
- new DexType[] {
- optionalType,
- factory.optionalDoubleType,
- factory.optionalLongType,
- factory.optionalIntType,
- };
- DexType[] streamReturnTypes =
- new DexType[] {
- factory.streamType,
- factory.createType(factory.createString("Ljava/util/stream/DoubleStream;")),
- factory.createType(factory.createString("Ljava/util/stream/LongStream;")),
- factory.createType(factory.createString("Ljava/util/stream/IntStream;")),
- };
- TemplateMethodFactory[] streamMethodFactories =
- new TemplateMethodFactory[] {
- BackportedMethods::OptionalMethods_stream,
- BackportedMethods::OptionalMethods_streamDouble,
- BackportedMethods::OptionalMethods_streamLong,
- BackportedMethods::OptionalMethods_streamInt,
- };
- name = factory.createString("stream");
- for (int i = 0; i < optionalTypes.length; i++) {
- DexType optional = optionalTypes[i];
- DexType streamReturnType = streamReturnTypes[i];
- proto = factory.createProto(streamReturnType);
- method = factory.createMethod(optional, proto, name);
- addProvider(
- new StatifyingMethodGenerator(method, streamMethodFactories[i], "stream", optional));
- }
-
- // Optional{void,Int,Long,Double}.ifPresentOrElse(consumer,runnable)
- DexType[] consumerTypes =
- new DexType[] {
- factory.consumerType, factory.doubleConsumer, factory.longConsumer, factory.intConsumer
- };
- TemplateMethodFactory[] methodFactories =
- new TemplateMethodFactory[] {
- BackportedMethods::OptionalMethods_ifPresentOrElse,
- BackportedMethods::OptionalMethods_ifPresentOrElseDouble,
- BackportedMethods::OptionalMethods_ifPresentOrElseLong,
- BackportedMethods::OptionalMethods_ifPresentOrElseInt
- };
- for (int i = 0; i < optionalTypes.length; i++) {
- DexType optional = optionalTypes[i];
- DexType consumer = consumerTypes[i];
- name = factory.createString("ifPresentOrElse");
- proto = factory.createProto(factory.voidType, consumer, factory.runnableType);
- method = factory.createMethod(optional, proto, name);
- addProvider(
- new StatifyingMethodGenerator(method, methodFactories[i], "ifPresentOrElse", optional));
- }
- }
-
- private void initializeJava10OptionalMethodProviders(DexItemFactory factory) {
- // Optional{void,Int,Long,Double}.orElseThrow()
- DexType[] optionalTypes =
- new DexType[] {
- factory.optionalType,
- factory.optionalDoubleType,
- factory.optionalLongType,
- factory.optionalIntType,
- };
- DexType[] returnTypes =
- new DexType[] {
- factory.objectType, factory.doubleType, factory.longType, factory.intType,
- };
- MethodInvokeRewriter[] rewriters =
- new MethodInvokeRewriter[] {
- OptionalMethodRewrites.rewriteOrElseGet(),
- OptionalMethodRewrites.rewriteDoubleOrElseGet(),
- OptionalMethodRewrites.rewriteLongOrElseGet(),
- OptionalMethodRewrites.rewriteIntOrElseGet(),
- };
- DexString name = factory.createString("orElseThrow");
- for (int i = 0; i < optionalTypes.length; i++) {
- DexProto proto = factory.createProto(returnTypes[i]);
- DexMethod method = factory.createMethod(optionalTypes[i], proto, name);
- addProvider(new InvokeRewriter(method, rewriters[i]));
- }
- }
-
- private void initializeJava11OptionalMethodProviders(DexItemFactory factory) {
- // Optional{void,Int,Long,Double}.isEmpty()
- DexType[] optionalTypes =
- new DexType[] {
- factory.optionalType,
- factory.optionalDoubleType,
- factory.optionalLongType,
- factory.optionalIntType,
- };
- TemplateMethodFactory[] methodFactories =
- new TemplateMethodFactory[] {
- BackportedMethods::OptionalMethods_isEmpty,
- BackportedMethods::OptionalMethods_isEmptyDouble,
- BackportedMethods::OptionalMethods_isEmptyLong,
- BackportedMethods::OptionalMethods_isEmptyInt
- };
- DexString name = factory.createString("isEmpty");
- for (int i = 0; i < optionalTypes.length; i++) {
- DexType optionalType = optionalTypes[i];
- DexProto proto = factory.createProto(factory.booleanType);
- DexMethod method = factory.createMethod(optionalType, proto, name);
- addProvider(
- new StatifyingMethodGenerator(method, methodFactories[i], "isEmpty", optionalType));
- }
- }
-
private void initializeStreamMethodProviders(DexItemFactory factory) {
// Stream
DexType streamType = factory.streamType;
@@ -1445,7 +1435,7 @@
}
private void addProvider(MethodProvider generator) {
- if (appView.options().desugaredLibrarySpecification.isSupported(generator.method, appView)) {
+ if (appView.options().machineDesugaredLibrarySpecification.isSupported(generator.method)) {
// TODO(b/174453232): Remove this after the configuration file format has bee updated
// with the "rewrite_method" section.
if (generator.method.getHolderType() == appView.dexItemFactory().objectsType) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfClassSynthesizerDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/CfClassSynthesizerDesugaringCollection.java
index c54f7ec..02c87a6 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfClassSynthesizerDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfClassSynthesizerDesugaringCollection.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryWrapperSynthesizer;
import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeterL8Synthesizer;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.RetargetingInfo;
import com.android.tools.r8.ir.desugar.itf.ProgramEmulatedInterfaceSynthesizer;
import com.android.tools.r8.ir.desugar.records.RecordDesugaring;
import com.android.tools.r8.utils.ThreadUtils;
@@ -17,8 +16,7 @@
public abstract class CfClassSynthesizerDesugaringCollection {
- public static CfClassSynthesizerDesugaringCollection create(
- AppView<?> appView, RetargetingInfo retargetingInfo) {
+ public static CfClassSynthesizerDesugaringCollection create(AppView<?> appView) {
Collection<CfClassSynthesizerDesugaring> synthesizers = new ArrayList<>();
if (appView.options().isDesugaredLibraryCompilation()) {
ProgramEmulatedInterfaceSynthesizer emulatedInterfaceSynthesizer =
@@ -27,7 +25,7 @@
synthesizers.add(emulatedInterfaceSynthesizer);
}
DesugaredLibraryRetargeterL8Synthesizer retargeterL8Synthesizer =
- DesugaredLibraryRetargeterL8Synthesizer.create(appView, retargetingInfo);
+ DesugaredLibraryRetargeterL8Synthesizer.create(appView);
if (retargeterL8Synthesizer != null) {
synthesizers.add(retargeterL8Synthesizer);
}
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 de491c7..c457ace 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
@@ -10,7 +10,6 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.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.itf.InterfaceProcessor;
@@ -81,8 +80,6 @@
public abstract InterfaceMethodProcessorFacade getInterfaceMethodPostProcessingDesugaringR8(
Flavor flavor, Predicate<ProgramMethod> isLiveMethod, InterfaceProcessor processor);
- public abstract RetargetingInfo getRetargetingInfo();
-
public abstract void withDesugaredLibraryAPIConverter(
Consumer<DesugaredLibraryAPIConverter> consumer);
}
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 1fd0ad0..09b456b 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
@@ -8,7 +8,6 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPICallbackSynthesizer;
import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeterPostProcessor;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.RetargetingInfo;
import com.android.tools.r8.ir.desugar.itf.InterfaceMethodProcessorFacade;
import com.android.tools.r8.ir.desugar.records.RecordDesugaring;
import java.util.ArrayList;
@@ -21,12 +20,10 @@
public abstract class CfPostProcessingDesugaringCollection {
public static CfPostProcessingDesugaringCollection create(
- AppView<?> appView,
- InterfaceMethodProcessorFacade interfaceMethodProcessorFacade,
- RetargetingInfo retargetingInfo) {
+ AppView<?> appView, InterfaceMethodProcessorFacade interfaceMethodProcessorFacade) {
if (appView.options().desugarState.isOn()) {
return NonEmptyCfPostProcessingDesugaringCollection.create(
- appView, interfaceMethodProcessorFacade, retargetingInfo);
+ appView, interfaceMethodProcessorFacade);
}
return empty();
}
@@ -53,19 +50,17 @@
}
public static CfPostProcessingDesugaringCollection create(
- AppView<?> appView,
- InterfaceMethodProcessorFacade interfaceMethodProcessorFacade,
- RetargetingInfo retargetingInfo) {
+ AppView<?> appView, InterfaceMethodProcessorFacade interfaceMethodProcessorFacade) {
ArrayList<CfPostProcessingDesugaring> desugarings = new ArrayList<>();
- if (!appView.options().desugaredLibrarySpecification.getRetargetCoreLibMember().isEmpty()
+ if (appView.options().machineDesugaredLibrarySpecification.hasRetargeting()
&& !appView.options().isDesugaredLibraryCompilation()) {
- desugarings.add(new DesugaredLibraryRetargeterPostProcessor(appView, retargetingInfo));
+ desugarings.add(new DesugaredLibraryRetargeterPostProcessor(appView));
}
if (interfaceMethodProcessorFacade != null) {
desugarings.add(interfaceMethodProcessorFacade);
}
DesugaredLibraryAPICallbackSynthesizer apiCallbackSynthesizor =
- appView.rewritePrefix.isRewriting()
+ appView.typeRewriter.isRewriting()
? new DesugaredLibraryAPICallbackSynthesizer(appView)
: null;
// At this point the desugaredLibraryAPIConverter is required to be last to generate
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 1e4d6f8..e7a1587 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,7 +8,6 @@
import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.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.itf.InterfaceProcessor;
@@ -89,11 +88,6 @@
}
@Override
- public RetargetingInfo getRetargetingInfo() {
- return null;
- }
-
- @Override
public void withDesugaredLibraryAPIConverter(Consumer<DesugaredLibraryAPIConverter> consumer) {
// Intentionally empty.
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
index 33c69ac..4c51b9f 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
@@ -18,7 +18,6 @@
import com.android.tools.r8.ir.desugar.constantdynamic.ConstantDynamicInstructionDesugaring;
import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter;
import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeter;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.RetargetingInfo;
import com.android.tools.r8.ir.desugar.icce.AlwaysThrowingInstructionDesugaring;
import com.android.tools.r8.ir.desugar.invokespecial.InvokeSpecialToSelfDesugaring;
import com.android.tools.r8.ir.desugar.itf.InterfaceMethodProcessorFacade;
@@ -82,9 +81,9 @@
this.nestBasedAccessDesugaring = NestBasedAccessDesugaring.create(appView);
BackportedMethodRewriter backportedMethodRewriter = null;
desugaredLibraryRetargeter =
- appView.options().desugaredLibrarySpecification.getRetargetCoreLibMember().isEmpty()
- ? null
- : new DesugaredLibraryRetargeter(appView);
+ appView.options().machineDesugaredLibrarySpecification.hasRetargeting()
+ ? new DesugaredLibraryRetargeter(appView)
+ : null;
if (desugaredLibraryRetargeter != null) {
desugarings.add(desugaredLibraryRetargeter);
}
@@ -112,7 +111,7 @@
interfaceMethodRewriter = null;
}
desugaredLibraryAPIConverter =
- appView.rewritePrefix.isRewriting()
+ appView.typeRewriter.isRewriting()
? new DesugaredLibraryAPIConverter(
appView,
SetUtils.newImmutableSetExcludingNullItems(
@@ -405,14 +404,6 @@
}
@Override
- public RetargetingInfo getRetargetingInfo() {
- if (desugaredLibraryRetargeter != null) {
- return desugaredLibraryRetargeter.getRetargetingInfo();
- }
- return null;
- }
-
- @Override
public void withDesugaredLibraryAPIConverter(Consumer<DesugaredLibraryAPIConverter> consumer) {
if (desugaredLibraryAPIConverter != null) {
consumer.accept(desugaredLibraryAPIConverter);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/PrefixRewritingMapper.java b/src/main/java/com/android/tools/r8/ir/desugar/PrefixRewritingMapper.java
deleted file mode 100644
index bf96b67..0000000
--- a/src/main/java/com/android/tools/r8/ir/desugar/PrefixRewritingMapper.java
+++ /dev/null
@@ -1,296 +0,0 @@
-// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.ir.desugar;
-
-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.DexProto;
-import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineRewritingFlags;
-import com.android.tools.r8.utils.DescriptorUtils;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Sets;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.function.Consumer;
-
-public abstract class PrefixRewritingMapper {
-
- public static PrefixRewritingMapper empty() {
- return new EmptyPrefixRewritingMapper();
- }
-
- public abstract void rewriteType(DexType type, DexType rewrittenType);
-
- public abstract DexType rewrittenType(DexType type, AppView<?> appView);
-
- public abstract DexType rewrittenContextType(DexType type, AppView<?> appView);
-
- public boolean hasRewrittenType(DexType type, AppView<?> appView) {
- return rewrittenType(type, appView) != null;
- }
-
- public boolean hasRewrittenTypeInSignature(DexProto proto, AppView<?> appView) {
- if (hasRewrittenType(proto.returnType, appView)) {
- return true;
- }
- for (DexType paramType : proto.parameters.values) {
- if (hasRewrittenType(paramType, appView)) {
- return true;
- }
- }
- return false;
- }
-
- public abstract boolean isRewriting();
-
- public abstract void forAllRewrittenTypes(Consumer<DexType> consumer);
-
- public static class DesugarPrefixRewritingMapper extends PrefixRewritingMapper {
-
- private final Set<DexType> notRewritten = Sets.newConcurrentHashSet();
- private final Map<DexType, DexType> rewritten = new ConcurrentHashMap<>();
- private final Map<DexString, DexString> initialPrefixes;
- private final DexItemFactory factory;
- private final boolean l8Compilation;
-
- public DesugarPrefixRewritingMapper(
- Map<String, String> prefixes, DexItemFactory itemFactory, boolean libraryCompilation) {
- assert itemFactory != null || prefixes.isEmpty();
- this.factory = itemFactory;
- this.l8Compilation = libraryCompilation;
- ImmutableMap.Builder<DexString, DexString> builder = ImmutableMap.builder();
- for (String key : prefixes.keySet()) {
- builder.put(toDescriptorPrefix(key), toDescriptorPrefix(prefixes.get(key)));
- }
- this.initialPrefixes = builder.build();
- validatePrefixes(prefixes);
- }
-
- private DexString toDescriptorPrefix(String prefix) {
- return factory.createString("L" + DescriptorUtils.getBinaryNameFromJavaType(prefix));
- }
-
- @Override
- public void forAllRewrittenTypes(Consumer<DexType> consumer) {
- rewritten.keySet().forEach(consumer);
- }
-
- private void validatePrefixes(Map<String, String> initialPrefixes) {
- String[] prefixes = initialPrefixes.keySet().toArray(new String[0]);
- for (int i = 0; i < prefixes.length; i++) {
- for (int j = i + 1; j < prefixes.length; j++) {
- String small, large;
- if (prefixes[i].length() < prefixes[j].length()) {
- small = prefixes[i];
- large = prefixes[j];
- } else {
- small = prefixes[j];
- large = prefixes[i];
- }
- if (large.startsWith(small)) {
- throw new CompilationError(
- "Inconsistent prefix in desugared library:"
- + " Should a class starting with "
- + small
- + " be rewritten using "
- + small
- + " -> "
- + initialPrefixes.get(small)
- + " or using "
- + large
- + " - > "
- + initialPrefixes.get(large)
- + " ?");
- }
- }
- }
- }
-
- @Override
- public DexType rewrittenType(DexType type, AppView<?> appView) {
- assert appView != null || l8Compilation;
- if (notRewritten.contains(type)) {
- return null;
- }
- if (rewritten.containsKey(type)) {
- return rewritten.get(type);
- }
- return computePrefix(type, appView);
- }
-
- @Override
- public DexType rewrittenContextType(DexType type, AppView<?> appView) {
- DexType rewritten = rewrittenType(type, appView);
- if (rewritten != null) {
- return rewritten;
- }
- LegacyDesugaredLibrarySpecification desugaredLibrarySpecification =
- appView.options().desugaredLibrarySpecification;
- if (desugaredLibrarySpecification.getEmulateLibraryInterface().containsKey(type)) {
- return desugaredLibrarySpecification.getEmulateLibraryInterface().get(type);
- }
- for (Map<DexType, DexType> value :
- desugaredLibrarySpecification.getRetargetCoreLibMember().values()) {
- if (value.containsKey(type)) {
- // Hack until machine specification are ready.
- String prefix =
- DescriptorUtils.getJavaTypeFromBinaryName(
- desugaredLibrarySpecification.getSynthesizedLibraryClassesPackagePrefix());
- String interfaceType = type.toString();
- int firstPackage = interfaceType.indexOf('.');
- return appView
- .dexItemFactory()
- .createType(
- DescriptorUtils.javaTypeToDescriptor(
- prefix + interfaceType.substring(firstPackage + 1)));
- }
- }
- return null;
- }
-
- // Besides L8 compilation, program types should not be rewritten.
- private void failIfRewritingProgramType(DexType type, AppView<?> appView) {
- if (l8Compilation) {
- return;
- }
-
- DexType dexType = type.isArrayType() ? type.toBaseType(appView.dexItemFactory()) : type;
- DexClass dexClass = appView.definitionFor(dexType);
- if (dexClass != null && dexClass.isProgramClass()) {
- appView
- .options()
- .reporter
- .error(
- "Cannot compile program class "
- + dexType
- + " since it conflicts with a desugared library rewriting rule.");
- }
- }
-
- @Override
- public void rewriteType(DexType type, DexType rewrittenType) {
- assert !notRewritten.contains(type)
- : "New rewriting rule for "
- + type
- + " but the compiler has already made decisions based on the fact that this type was"
- + " not rewritten";
- assert !rewritten.containsKey(type) || rewritten.get(type) == rewrittenType
- : "New rewriting rule for "
- + type
- + " but the compiler has already made decisions based on a different rewriting rule"
- + " for this type";
- rewritten.put(type, rewrittenType);
- }
-
- private DexType computePrefix(DexType type, AppView<?> appView) {
- DexString prefixToMatch = type.descriptor.withoutArray(factory);
- DexType result = lookup(type, prefixToMatch, initialPrefixes);
- if (result != null) {
- failIfRewritingProgramType(type, appView);
- return result;
- }
- notRewritten.add(type);
- return null;
- }
-
- private DexType lookup(DexType type, DexString prefixToMatch, Map<DexString, DexString> map) {
- // TODO(b/154800164): We could use tries instead of looking-up everywhere.
- for (DexString prefix : map.keySet()) {
- if (prefixToMatch.startsWith(prefix)) {
- DexString rewrittenTypeDescriptor =
- type.descriptor.withNewPrefix(prefix, map.get(prefix), factory);
- DexType rewrittenType = factory.createType(rewrittenTypeDescriptor);
- rewriteType(type, rewrittenType);
- return rewrittenType;
- }
- }
- return null;
- }
-
- @Override
- public boolean isRewriting() {
- return true;
- }
- }
-
- public static class MachineDesugarPrefixRewritingMapper extends PrefixRewritingMapper {
-
- private final PrefixRewritingMapper mapper;
- private final Map<DexType, DexType> rewriteType;
- private final Map<DexType, DexType> rewriteDerivedTypeOnly;
-
- public MachineDesugarPrefixRewritingMapper(
- PrefixRewritingMapper mapper, MachineRewritingFlags flags) {
- this.mapper = mapper;
- this.rewriteType = new ConcurrentHashMap<>(flags.getRewriteType());
- rewriteDerivedTypeOnly = flags.getRewriteDerivedTypeOnly();
- }
-
- @Override
- public DexType rewrittenType(DexType type, AppView<?> appView) {
- assert mapper.rewrittenType(type, appView) == rewriteType.get(type);
- return rewriteType.get(type);
- }
-
- @Override
- public DexType rewrittenContextType(DexType context, AppView<?> appView) {
- if (rewriteType.containsKey(context)) {
- return rewriteType.get(context);
- }
- return rewriteDerivedTypeOnly.get(context);
- }
-
- @Override
- public void rewriteType(DexType type, DexType rewrittenType) {
- mapper.rewriteType(type, rewrittenType);
- rewriteType.compute(
- type,
- (t, val) -> {
- assert val == null || val == rewrittenType;
- return rewrittenType;
- });
- }
-
- @Override
- public boolean isRewriting() {
- return true;
- }
-
- @Override
- public void forAllRewrittenTypes(Consumer<DexType> consumer) {
- rewriteType.keySet().forEach(consumer);
- }
- }
-
- public static class EmptyPrefixRewritingMapper extends PrefixRewritingMapper {
-
- @Override
- public DexType rewrittenType(DexType type, AppView<?> appView) {
- return null;
- }
-
- @Override
- public DexType rewrittenContextType(DexType type, AppView<?> appView) {
- return null;
- }
-
- @Override
- public void rewriteType(DexType type, DexType rewrittenType) {}
-
- @Override
- public boolean isRewriting() {
- return false;
- }
-
- @Override
- public void forAllRewrittenTypes(Consumer<DexType> consumer) {}
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/TypeRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/TypeRewriter.java
new file mode 100644
index 0000000..c8c5159
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/TypeRewriter.java
@@ -0,0 +1,125 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.desugar;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexProto;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Consumer;
+
+public abstract class TypeRewriter {
+
+ public static TypeRewriter empty() {
+ return new EmptyPrefixRewritingMapper();
+ }
+
+ public abstract void rewriteType(DexType type, DexType rewrittenType);
+
+ public abstract DexType rewrittenType(DexType type, AppView<?> appView);
+
+ public abstract DexType rewrittenContextType(DexType type);
+
+ public boolean hasRewrittenType(DexType type, AppView<?> appView) {
+ return rewrittenType(type, appView) != null;
+ }
+
+ public boolean hasRewrittenTypeInSignature(DexProto proto, AppView<?> appView) {
+ if (hasRewrittenType(proto.returnType, appView)) {
+ return true;
+ }
+ for (DexType paramType : proto.parameters.values) {
+ if (hasRewrittenType(paramType, appView)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public abstract boolean isRewriting();
+
+ public abstract void forAllRewrittenTypes(Consumer<DexType> consumer);
+
+ public static class MachineDesugarPrefixRewritingMapper extends TypeRewriter {
+
+ private final Map<DexType, DexType> rewriteType;
+ private final Map<DexType, DexType> rewriteDerivedTypeOnly;
+
+ public MachineDesugarPrefixRewritingMapper(MachineDesugaredLibrarySpecification specification) {
+ this.rewriteType = new ConcurrentHashMap<>(specification.getRewriteType());
+ rewriteDerivedTypeOnly = specification.getRewriteDerivedTypeOnly();
+ }
+
+ @Override
+ public DexType rewrittenType(DexType type, AppView<?> appView) {
+ if (type.isArrayType()) {
+ DexType rewrittenBaseType =
+ rewrittenType(type.toBaseType(appView.dexItemFactory()), appView);
+ if (rewrittenBaseType == null) {
+ return null;
+ }
+ return appView
+ .dexItemFactory()
+ .createArrayType(type.getNumberOfLeadingSquareBrackets(), rewrittenBaseType);
+ }
+ return rewriteType.get(type);
+ }
+
+ @Override
+ public DexType rewrittenContextType(DexType context) {
+ assert !context.isArrayType();
+ if (rewriteType.containsKey(context)) {
+ return rewriteType.get(context);
+ }
+ return rewriteDerivedTypeOnly.get(context);
+ }
+
+ @Override
+ public void rewriteType(DexType type, DexType rewrittenType) {
+ rewriteType.compute(
+ type,
+ (t, val) -> {
+ assert val == null || val == rewrittenType;
+ return rewrittenType;
+ });
+ }
+
+ @Override
+ public boolean isRewriting() {
+ return true;
+ }
+
+ @Override
+ public void forAllRewrittenTypes(Consumer<DexType> consumer) {
+ rewriteType.keySet().forEach(consumer);
+ }
+ }
+
+ public static class EmptyPrefixRewritingMapper extends TypeRewriter {
+
+ @Override
+ public DexType rewrittenType(DexType type, AppView<?> appView) {
+ return null;
+ }
+
+ @Override
+ public DexType rewrittenContextType(DexType type) {
+ return null;
+ }
+
+ @Override
+ public void rewriteType(DexType type, DexType rewrittenType) {}
+
+ @Override
+ public boolean isRewriting() {
+ return false;
+ }
+
+ @Override
+ public void forAllRewrittenTypes(Consumer<DexType> consumer) {}
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPICallbackSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPICallbackSynthesizer.java
index 150e6c4..abbdb4f 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPICallbackSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPICallbackSynthesizer.java
@@ -20,13 +20,13 @@
import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaring;
import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryAPICallbackSynthesizorEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APICallbackWrapperCfCodeProvider;
import com.android.tools.r8.utils.OptionalBool;
import com.android.tools.r8.utils.WorkList;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
@@ -106,11 +106,11 @@
|| definition.isLibraryMethodOverride().isFalse()) {
return false;
}
- if (!appView.rewritePrefix.hasRewrittenTypeInSignature(definition.getProto(), appView)
+ if (!appView.typeRewriter.hasRewrittenTypeInSignature(definition.getProto(), appView)
|| appView
.options()
- .desugaredLibrarySpecification
- .getEmulateLibraryInterface()
+ .machineDesugaredLibrarySpecification
+ .getEmulatedInterfaces()
.containsKey(method.getHolderType())) {
return false;
}
@@ -127,7 +127,7 @@
return false;
}
}
- if (!appView.options().desugaredLibrarySpecification.supportAllCallbacksFromLibrary()
+ if (!appView.options().machineDesugaredLibrarySpecification.supportAllCallbacksFromLibrary()
&& appView.options().isDesugaredLibraryCompilation()) {
return false;
}
@@ -163,7 +163,7 @@
DexEncodedMethod dexEncodedMethod = dexClass.lookupVirtualMethod(method.getReference());
if (dexEncodedMethod != null) {
// In this case, the object will be wrapped.
- if (appView.rewritePrefix.hasRewrittenType(dexClass.type, appView)) {
+ if (appView.typeRewriter.hasRewrittenType(dexClass.type, appView)) {
return false;
}
if (dexEncodedMethod.isFinal()) {
@@ -178,13 +178,13 @@
}
private boolean shouldGenerateCallbacksForEmulateInterfaceAPIs(DexClass dexClass) {
- if (appView.options().desugaredLibrarySpecification.supportAllCallbacksFromLibrary()) {
+ if (appView.options().machineDesugaredLibrarySpecification.supportAllCallbacksFromLibrary()) {
return true;
}
- Map<DexType, DexType> emulateLibraryInterfaces =
- appView.options().desugaredLibrarySpecification.getEmulateLibraryInterface();
- return !(emulateLibraryInterfaces.containsKey(dexClass.type)
- || emulateLibraryInterfaces.containsValue(dexClass.type));
+ MachineDesugaredLibrarySpecification specification =
+ appView.options().machineDesugaredLibrarySpecification;
+ return !(specification.getEmulatedInterfaces().containsKey(dexClass.type)
+ || specification.isEmulatedInterfaceRewrittenType(dexClass.type));
}
private ProgramMethod generateCallbackMethod(
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java
index 987dc8d..d8b8430 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java
@@ -152,7 +152,7 @@
return false;
}
DexType holderType = invokedMethod.getHolderType();
- if (appView.rewritePrefix.hasRewrittenType(holderType, appView) || holderType.isArrayType()) {
+ if (appView.typeRewriter.hasRewrittenType(holderType, appView) || holderType.isArrayType()) {
return false;
}
DexClass dexClass = appView.definitionFor(holderType);
@@ -165,7 +165,7 @@
if (isAlreadyDesugared(invoke, context)) {
return false;
}
- return appView.rewritePrefix.hasRewrittenTypeInSignature(invokedMethod.getProto(), appView);
+ return appView.typeRewriter.hasRewrittenTypeInSignature(invokedMethod.getProto(), appView);
}
// The problem is that a method can resolve into a library method which is not present at runtime,
@@ -181,8 +181,8 @@
return interfaceResult != null
&& appView
.options()
- .desugaredLibrarySpecification
- .getEmulateLibraryInterface()
+ .machineDesugaredLibrarySpecification
+ .getEmulatedInterfaces()
.containsKey(interfaceResult.getHolderType());
}
@@ -196,14 +196,14 @@
DexType[] newParameters = originalMethod.proto.parameters.values.clone();
int index = 0;
for (DexType param : originalMethod.proto.parameters.values) {
- if (appView.rewritePrefix.hasRewrittenType(param, appView)) {
+ if (appView.typeRewriter.hasRewrittenType(param, appView)) {
newParameters[index] = vivifiedTypeFor(param, appView);
}
index++;
}
DexType returnType = originalMethod.proto.returnType;
DexType newReturnType =
- appView.rewritePrefix.hasRewrittenType(returnType, appView)
+ appView.typeRewriter.hasRewrittenType(returnType, appView)
? vivifiedTypeFor(returnType, appView)
: returnType;
DexProto newProto = appView.dexItemFactory().createProto(newReturnType, newParameters);
@@ -236,7 +236,7 @@
.createSynthesizedType(
DescriptorUtils.javaTypeToDescriptor(VIVIFIED_PREFIX + type.toString()));
// We would need to ensure a classpath class for each type to remove this rewriteType call.
- appView.rewritePrefix.rewriteType(vivifiedType, type);
+ appView.typeRewriter.rewriteType(vivifiedType, type);
return vivifiedType;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java
index 4a8cabe..1581f83 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java
@@ -27,7 +27,8 @@
import com.android.tools.r8.ir.desugar.CfClassSynthesizerDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryClasspathWrapperSynthesizeEventConsumer;
import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.CustomConversionDescriptor;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APIConverterConstructorCfCodeProvider;
import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APIConverterVivifiedWrapperCfCodeProvider;
import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APIConverterWrapperCfCodeProvider;
@@ -39,13 +40,12 @@
import com.android.tools.r8.synthesis.SyntheticMethodBuilder;
import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
import com.android.tools.r8.utils.StringDiagnostic;
-import com.google.common.collect.Iterables;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
-import java.util.LinkedList;
+import java.util.IdentityHashMap;
import java.util.List;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.Map;
import java.util.function.Function;
// I am responsible for the generation of wrappers used to call library APIs when desugaring
@@ -95,8 +95,6 @@
private final AppView<?> appView;
private final DexItemFactory factory;
- private final ConcurrentHashMap<DexType, List<DexEncodedMethod>> allImplementedMethodsCache =
- new ConcurrentHashMap<>();
private final DesugaredLibraryEnumConversionSynthesizer enumConverter;
public DesugaredLibraryWrapperSynthesizer(AppView<?> appView) {
@@ -118,7 +116,7 @@
if (type.isArrayType()) {
return shouldConvert(type.toBaseType(appView.dexItemFactory()), method, context);
}
- if (!appView.rewritePrefix.hasRewrittenType(type, appView)) {
+ if (!appView.typeRewriter.hasRewrittenType(type, appView)) {
return false;
}
if (canConvert(type)) {
@@ -174,22 +172,32 @@
private DexMethod getCustomConversion(DexType type, DexType srcType, DexType destType) {
// ConversionType holds the methods "rewrittenType convert(type)" and the other way around.
// But everything is going to be rewritten, so we need to use vivifiedType and type".
- DexType conversionHolder =
- appView.options().desugaredLibrarySpecification.getCustomConversions().get(type);
- if (conversionHolder != null) {
- return factory.createMethod(
- conversionHolder, factory.createProto(destType, srcType), factory.convertMethodName);
+ CustomConversionDescriptor descriptor =
+ appView.options().machineDesugaredLibrarySpecification.getCustomConversions().get(type);
+ if (descriptor == null) {
+ return null;
}
- return null;
+ // Because the conversion have rewritten types instead of vivified type we cannot use the
+ // specification content directly until the rewriting is done upfront in the compilation.
+ DexMethod conversion = type == srcType ? descriptor.getTo() : descriptor.getFrom();
+ assert type == srcType
+ ? type == conversion.getReturnType()
+ : type == conversion.getArgumentType(0, true);
+ return factory.createMethod(
+ conversion.getHolderType(), factory.createProto(destType, srcType), conversion.getName());
}
private boolean canConvert(DexType type) {
- return appView.options().desugaredLibrarySpecification.getCustomConversions().containsKey(type)
+ return appView
+ .options()
+ .machineDesugaredLibrarySpecification
+ .getCustomConversions()
+ .containsKey(type)
|| canGenerateWrapper(type);
}
private void reportInvalidInvoke(DexType type, DexMethod invokedMethod, ProgramMethod context) {
- DexType desugaredType = appView.rewritePrefix.rewrittenType(type, appView);
+ DexType desugaredType = appView.typeRewriter.rewrittenType(type, appView);
Origin origin = context != null ? context.getOrigin() : Origin.unknown();
Position position =
context != null ? new MethodPosition(context.getMethodReference()) : Position.UNKNOWN;
@@ -212,7 +220,7 @@
}
private boolean canGenerateWrapper(DexType type) {
- return appView.options().desugaredLibrarySpecification.getWrapperConversions().contains(type);
+ return appView.options().machineDesugaredLibrarySpecification.getWrappers().containsKey(type);
}
private DexClass getValidClassToWrap(DexType type) {
@@ -257,6 +265,9 @@
return getExistingProgramWrapperConversions(context);
}
assert context.isNotProgramClass();
+ Iterable<DexMethod> methods =
+ appView.options().machineDesugaredLibrarySpecification.getWrappers().get(context.type);
+ assert methods != null;
ClasspathOrLibraryClass classpathOrLibraryContext = context.asClasspathOrLibraryClass();
DexType type = context.type;
DexType vivifiedType = vivifiedTypeFor(type);
@@ -267,7 +278,7 @@
type,
classpathOrLibraryContext,
eventConsumer,
- wrapperField -> synthesizeVirtualMethodsForTypeWrapper(context, wrapperField));
+ wrapperField -> synthesizeVirtualMethodsForTypeWrapper(context, methods, wrapperField));
DexClass vivifiedWrapper =
ensureClasspathWrapper(
SyntheticKind.VIVIFIED_WRAPPER,
@@ -275,7 +286,8 @@
vivifiedType,
classpathOrLibraryContext,
eventConsumer,
- wrapperField -> synthesizeVirtualMethodsForVivifiedTypeWrapper(context, wrapperField));
+ wrapperField ->
+ synthesizeVirtualMethodsForVivifiedTypeWrapper(context, methods, wrapperField));
return new WrapperConversions(
getConversion(wrapper, vivifiedType, type),
getConversion(vivifiedWrapper, type, vivifiedType));
@@ -440,8 +452,7 @@
}
private Collection<DexEncodedMethod> synthesizeVirtualMethodsForVivifiedTypeWrapper(
- DexClass dexClass, DexEncodedField wrapperField) {
- Iterable<DexMethod> allImplementedMethods = allImplementedMethods(dexClass);
+ DexClass dexClass, Iterable<DexMethod> allImplementedMethods, DexEncodedField wrapperField) {
List<DexEncodedMethod> generatedMethods = new ArrayList<>();
// Each method should use only types in their signature, but each method the wrapper forwards
// to should used only vivified types.
@@ -458,9 +469,8 @@
if (holderClass == null) {
assert appView
.options()
- .desugaredLibrarySpecification
- .getEmulateLibraryInterface()
- .containsValue(method.getHolderType());
+ .machineDesugaredLibrarySpecification
+ .isEmulatedInterfaceRewrittenType(method.getHolderType());
isInterface = true;
} else {
isInterface = holderClass.isInterface();
@@ -483,8 +493,7 @@
}
private Collection<DexEncodedMethod> synthesizeVirtualMethodsForTypeWrapper(
- DexClass dexClass, DexEncodedField wrapperField) {
- Iterable<DexMethod> dexMethods = allImplementedMethods(dexClass);
+ DexClass dexClass, Iterable<DexMethod> dexMethods, DexEncodedField wrapperField) {
List<DexEncodedMethod> generatedMethods = new ArrayList<>();
// Each method should use only vivified types in their signature, but each method the wrapper
// forwards
@@ -540,62 +549,6 @@
.build();
}
- private Iterable<DexMethod> allImplementedMethods(DexClass clazz) {
- if (appView.options().testing.machineDesugaredLibrarySpecification != null) {
- return appView
- .options()
- .testing
- .machineDesugaredLibrarySpecification
- .getRewritingFlags()
- .getWrappers()
- .get(clazz.type);
- }
- List<DexEncodedMethod> dexEncodedMethods =
- allImplementedMethodsCache.computeIfAbsent(
- clazz.type, type -> internalAllImplementedMethods(clazz));
- return Iterables.transform(dexEncodedMethods, m -> m.getReference());
- }
-
- private List<DexEncodedMethod> internalAllImplementedMethods(DexClass libraryClass) {
- LinkedList<DexClass> workList = new LinkedList<>();
- List<DexEncodedMethod> implementedMethods = new ArrayList<>();
- workList.add(libraryClass);
- while (!workList.isEmpty()) {
- DexClass dexClass = workList.removeFirst();
- for (DexEncodedMethod virtualMethod : dexClass.virtualMethods()) {
- if (!virtualMethod.isPrivateMethod()) {
- boolean alreadyAdded = false;
- // This looks quadratic but given the size of the collections met in practice for
- // desugared libraries (Max ~15) it does not matter.
- for (DexEncodedMethod alreadyImplementedMethod : implementedMethods) {
- if (alreadyImplementedMethod.getReference().match(virtualMethod.getReference())) {
- alreadyAdded = true;
- break;
- }
- }
- if (!alreadyAdded) {
- implementedMethods.add(virtualMethod);
- }
- }
- }
- for (DexType itf : dexClass.interfaces.values) {
- DexClass itfClass = appView.definitionFor(itf);
- // Cannot be null in program since we started from a LibraryClass.
- assert itfClass != null || appView.options().isDesugaredLibraryCompilation();
- if (itfClass != null) {
- workList.add(itfClass);
- }
- }
- if (dexClass.superType != factory.objectType) {
- DexClass superClass = appView.definitionFor(dexClass.superType);
- assert superClass != null; // Cannot be null since we started from a LibraryClass.
- workList.add(superClass);
- }
- }
- assert !Iterables.any(implementedMethods, DexEncodedMethod::isFinal);
- return implementedMethods;
- }
-
private DexField wrappedValueField(DexType holder, DexType fieldType) {
return factory.createField(holder, fieldType, factory.wrapperFieldName);
}
@@ -619,25 +572,28 @@
// conversion methods are present.
@Override
public void synthesizeClasses(CfClassSynthesizerDesugaringEventConsumer eventConsumer) {
- LegacyDesugaredLibrarySpecification spec = appView.options().desugaredLibrarySpecification;
- List<DexProgramClass> validClassesToWrap = new ArrayList<>();
- for (DexType type : spec.getWrapperConversions()) {
- assert !spec.getCustomConversions().containsKey(type);
- DexClass validClassToWrap = getValidClassToWrap(type);
- // In broken set-ups we can end up having a json files containing wrappers of non desugared
- // classes. Such wrappers are not required since the class won't be rewritten.
- if (validClassToWrap.isProgramClass()) {
- if (validClassToWrap.isEnum()) {
- enumConverter.ensureProgramEnumConversionClass(validClassToWrap, eventConsumer);
- } else {
- validClassesToWrap.add(validClassToWrap.asProgramClass());
- ensureProgramWrappersWithoutVirtualMethods(validClassToWrap, eventConsumer);
- }
- }
- }
- for (DexProgramClass validClassToWrap : validClassesToWrap) {
- ensureProgramWrappersVirtualMethods(validClassToWrap);
- }
+ MachineDesugaredLibrarySpecification librarySpecification =
+ appView.options().machineDesugaredLibrarySpecification;
+ Map<DexProgramClass, Iterable<DexMethod>> validClassesToWrap = new IdentityHashMap<>();
+ librarySpecification
+ .getWrappers()
+ .forEach(
+ (type, methods) -> {
+ assert !librarySpecification.getCustomConversions().containsKey(type);
+ DexClass validClassToWrap = getValidClassToWrap(type);
+ // In broken set-ups we can end up having a json files containing wrappers of non
+ // desugared classes. Such wrappers are not required since the class won't be
+ // rewritten.
+ if (validClassToWrap.isProgramClass()) {
+ if (validClassToWrap.isEnum()) {
+ enumConverter.ensureProgramEnumConversionClass(validClassToWrap, eventConsumer);
+ } else {
+ validClassesToWrap.put(validClassToWrap.asProgramClass(), methods);
+ ensureProgramWrappersWithoutVirtualMethods(validClassToWrap, eventConsumer);
+ }
+ }
+ });
+ validClassesToWrap.forEach(this::ensureProgramWrappersVirtualMethods);
}
// We generate first the two wrappers with the constructor method and the fields, then we
@@ -665,15 +621,16 @@
SyntheticKind.VIVIFIED_WRAPPER, programContext, vivifiedWrapper, wrapper);
}
- private void ensureProgramWrappersVirtualMethods(DexClass context) {
+ private void ensureProgramWrappersVirtualMethods(DexClass context, Iterable<DexMethod> methods) {
assert context.isProgramClass();
DexProgramClass wrapper = getExistingProgramWrapper(context, SyntheticKind.WRAPPER);
wrapper.addVirtualMethods(
- synthesizeVirtualMethodsForTypeWrapper(context, getWrapperUniqueEncodedField(wrapper)));
+ synthesizeVirtualMethodsForTypeWrapper(
+ context, methods, getWrapperUniqueEncodedField(wrapper)));
DexProgramClass vivifiedWrapper =
getExistingProgramWrapper(context, SyntheticKind.VIVIFIED_WRAPPER);
vivifiedWrapper.addVirtualMethods(
synthesizeVirtualMethodsForVivifiedTypeWrapper(
- context, getWrapperUniqueEncodedField(vivifiedWrapper)));
+ context, methods, getWrapperUniqueEncodedField(vivifiedWrapper)));
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecification.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecification.java
index 6a6a2d4..1e871b3 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecification.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecification.java
@@ -6,14 +6,9 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.desugar.PrefixRewritingMapper;
-import com.android.tools.r8.ir.desugar.PrefixRewritingMapper.DesugarPrefixRewritingMapper;
import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.InternalOptions;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -23,56 +18,20 @@
private final boolean libraryCompilation;
private final HumanTopLevelFlags topLevelFlags;
private final HumanRewritingFlags rewritingFlags;
- private final PrefixRewritingMapper prefixRewritingMapper;
-
- public static HumanDesugaredLibrarySpecification withOnlyRewritePrefixForTesting(
- Map<String, String> prefix, InternalOptions options) {
- return new HumanDesugaredLibrarySpecification(
- HumanTopLevelFlags.empty(),
- HumanRewritingFlags.withOnlyRewritePrefixForTesting(prefix, options),
- true,
- options.itemFactory);
- }
-
- public static HumanDesugaredLibrarySpecification empty() {
- return new HumanDesugaredLibrarySpecification(
- HumanTopLevelFlags.empty(), HumanRewritingFlags.empty(), false, null) {
-
- @Override
- public boolean isSupported(DexReference reference, AppView<?> appView) {
- return false;
- }
-
- @Override
- public boolean isEmptyConfiguration() {
- return true;
- }
- };
- }
public HumanDesugaredLibrarySpecification(
HumanTopLevelFlags topLevelFlags,
HumanRewritingFlags rewritingFlags,
- boolean libraryCompilation,
- DexItemFactory factory) {
+ boolean libraryCompilation) {
this.libraryCompilation = libraryCompilation;
this.topLevelFlags = topLevelFlags;
this.rewritingFlags = rewritingFlags;
- this.prefixRewritingMapper =
- rewritingFlags.getRewritePrefix().isEmpty()
- ? PrefixRewritingMapper.empty()
- : new DesugarPrefixRewritingMapper(
- rewritingFlags.getRewritePrefix(), factory, libraryCompilation);
}
public boolean supportAllCallbacksFromLibrary() {
return topLevelFlags.supportAllCallbacksFromLibrary();
}
- public PrefixRewritingMapper getPrefixRewritingMapper() {
- return prefixRewritingMapper;
- }
-
public AndroidApiLevel getRequiredCompilationApiLevel() {
return topLevelFlags.getRequiredCompilationAPILevel();
}
@@ -109,10 +68,6 @@
return rewritingFlags.getEmulateLibraryInterface();
}
- public boolean isSupported(DexReference reference, AppView<?> appView) {
- return prefixRewritingMapper.hasRewrittenType(reference.getContextType(), appView);
- }
-
// If the method is retargeted, answers the retargeted method, else null.
public DexMethod retargetMethod(DexEncodedMethod method, AppView<?> appView) {
Map<DexMethod, DexType> retargetCoreLibMember = rewritingFlags.getRetargetCoreLibMember();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
index a612177..e01def6 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
@@ -103,7 +103,7 @@
HumanDesugaredLibrarySpecification config =
new HumanDesugaredLibrarySpecification(
- topLevelFlags, legacyRewritingFlags, libraryCompilation, dexItemFactory);
+ topLevelFlags, legacyRewritingFlags, libraryCompilation);
origin = null;
return config;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecification.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecification.java
index 3da0b97..9ab05b9 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecification.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecification.java
@@ -6,13 +6,9 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.desugar.PrefixRewritingMapper;
-import com.android.tools.r8.ir.desugar.PrefixRewritingMapper.DesugarPrefixRewritingMapper;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.InternalOptions;
@@ -26,25 +22,18 @@
private final boolean libraryCompilation;
private final LegacyTopLevelFlags topLevelFlags;
private final LegacyRewritingFlags rewritingFlags;
- private final PrefixRewritingMapper prefixRewritingMapper;
public static LegacyDesugaredLibrarySpecification withOnlyRewritePrefixForTesting(
Map<String, String> prefix, InternalOptions options) {
return new LegacyDesugaredLibrarySpecification(
LegacyTopLevelFlags.empty(),
LegacyRewritingFlags.withOnlyRewritePrefixForTesting(prefix, options),
- true,
- options.itemFactory);
+ true);
}
public static LegacyDesugaredLibrarySpecification empty() {
return new LegacyDesugaredLibrarySpecification(
- LegacyTopLevelFlags.empty(), LegacyRewritingFlags.empty(), false, null) {
-
- @Override
- public boolean isSupported(DexReference reference, AppView<?> appView) {
- return false;
- }
+ LegacyTopLevelFlags.empty(), LegacyRewritingFlags.empty(), false) {
@Override
public boolean isEmptyConfiguration() {
@@ -56,16 +45,10 @@
public LegacyDesugaredLibrarySpecification(
LegacyTopLevelFlags topLevelFlags,
LegacyRewritingFlags rewritingFlags,
- boolean libraryCompilation,
- DexItemFactory factory) {
+ boolean libraryCompilation) {
this.libraryCompilation = libraryCompilation;
this.topLevelFlags = topLevelFlags;
this.rewritingFlags = rewritingFlags;
- this.prefixRewritingMapper =
- rewritingFlags.getRewritePrefix().isEmpty()
- ? PrefixRewritingMapper.empty()
- : new DesugarPrefixRewritingMapper(
- rewritingFlags.getRewritePrefix(), factory, libraryCompilation);
}
public LegacyTopLevelFlags getTopLevelFlags() {
@@ -80,10 +63,6 @@
return topLevelFlags.supportAllCallbacksFromLibrary();
}
- public PrefixRewritingMapper getPrefixRewritingMapper() {
- return prefixRewritingMapper;
- }
-
public AndroidApiLevel getRequiredCompilationApiLevel() {
return topLevelFlags.getRequiredCompilationAPILevel();
}
@@ -123,10 +102,6 @@
return rewritingFlags.getEmulateLibraryInterface();
}
- public boolean isSupported(DexReference reference, AppView<?> appView) {
- return prefixRewritingMapper.hasRewrittenType(reference.getContextType(), appView);
- }
-
// If the method is retargeted, answers the retargeted method, else null.
public DexMethod retargetMethod(DexEncodedMethod method, AppView<?> appView) {
Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecificationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecificationParser.java
index 7cece17..a3afcd9 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecificationParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecificationParser.java
@@ -110,7 +110,7 @@
LegacyDesugaredLibrarySpecification config =
new LegacyDesugaredLibrarySpecification(
- topLevelFlags, legacyRewritingFlags, libraryCompilation, dexItemFactory);
+ topLevelFlags, legacyRewritingFlags, libraryCompilation);
origin = null;
return config;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyTopLevelFlags.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyTopLevelFlags.java
index 465d125..8e0293b 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyTopLevelFlags.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyTopLevelFlags.java
@@ -54,7 +54,7 @@
public static LegacyTopLevelFlags testing() {
return new LegacyTopLevelFlags(
- AndroidApiLevel.B,
+ AndroidApiLevel.O,
FALL_BACK_SYNTHESIZED_CLASSES_PACKAGE_PREFIX,
"testing",
null,
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/CustomConversionDescriptor.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/CustomConversionDescriptor.java
new file mode 100644
index 0000000..e8c3ce3
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/CustomConversionDescriptor.java
@@ -0,0 +1,27 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification;
+
+import com.android.tools.r8.graph.DexMethod;
+
+public class CustomConversionDescriptor {
+ private final DexMethod to;
+ private final DexMethod from;
+
+ public CustomConversionDescriptor(DexMethod to, DexMethod from) {
+ this.to = to;
+ this.from = from;
+ assert to.getReturnType() == from.getArgumentType(0, true);
+ assert from.getReturnType() == to.getArgumentType(0, true);
+ }
+
+ public DexMethod getTo() {
+ return to;
+ }
+
+ public DexMethod getFrom() {
+ return from;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java
index 501482e..adc507f 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java
@@ -4,12 +4,39 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexReference;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Consumer;
+
public class MachineDesugaredLibrarySpecification {
private final boolean libraryCompilation;
private final MachineTopLevelFlags topLevelFlags;
private final MachineRewritingFlags rewritingFlags;
+ public static MachineDesugaredLibrarySpecification empty() {
+ return new MachineDesugaredLibrarySpecification(
+ false, MachineTopLevelFlags.empty(), MachineRewritingFlags.builder().build()) {
+ @Override
+ public boolean isSupported(DexReference reference) {
+ return false;
+ }
+ };
+ }
+
+ public static MachineDesugaredLibrarySpecification withOnlyRewriteTypeForTesting(
+ Map<DexType, DexType> rewriteTypeForTesting) {
+ MachineRewritingFlags.Builder builder = MachineRewritingFlags.builder();
+ rewriteTypeForTesting.forEach(builder::rewriteType);
+ return new MachineDesugaredLibrarySpecification(
+ true, MachineTopLevelFlags.empty(), builder.build());
+ }
+
public MachineDesugaredLibrarySpecification(
boolean libraryCompilation,
MachineTopLevelFlags topLevelFlags,
@@ -23,11 +50,120 @@
return libraryCompilation;
}
- public MachineTopLevelFlags getTopLevelFlags() {
- return topLevelFlags;
+ public AndroidApiLevel getRequiredCompilationAPILevel() {
+ return topLevelFlags.getRequiredCompilationAPILevel();
}
- public MachineRewritingFlags getRewritingFlags() {
- return rewritingFlags;
+ public String getSynthesizedLibraryClassesPackagePrefix() {
+ return topLevelFlags.getSynthesizedLibraryClassesPackagePrefix();
+ }
+
+ public String getIdentifier() {
+ return topLevelFlags.getIdentifier();
+ }
+
+ public String getJsonSource() {
+ return topLevelFlags.getJsonSource();
+ }
+
+ public boolean supportAllCallbacksFromLibrary() {
+ return topLevelFlags.supportAllCallbacksFromLibrary();
+ }
+
+ public List<String> getExtraKeepRules() {
+ return topLevelFlags.getExtraKeepRules();
+ }
+
+ public Map<DexType, DexType> getRewriteType() {
+ return rewritingFlags.getRewriteType();
+ }
+
+ public Map<DexType, DexType> getRewriteDerivedTypeOnly() {
+ return rewritingFlags.getRewriteDerivedTypeOnly();
+ }
+
+ public Map<DexMethod, DexMethod> getStaticRetarget() {
+ return rewritingFlags.getStaticRetarget();
+ }
+
+ public Map<DexMethod, DexMethod> getNonEmulatedVirtualRetarget() {
+ return rewritingFlags.getNonEmulatedVirtualRetarget();
+ }
+
+ public Map<DexMethod, EmulatedDispatchMethodDescriptor> getEmulatedVirtualRetarget() {
+ return rewritingFlags.getEmulatedVirtualRetarget();
+ }
+
+ public Map<DexMethod, DexMethod> getEmulatedVirtualRetargetThroughEmulatedInterface() {
+ return rewritingFlags.getEmulatedVirtualRetargetThroughEmulatedInterface();
+ }
+
+ public void forEachRetargetHolder(Consumer<DexType> consumer) {
+ rewritingFlags.forEachRetargetHolder(consumer);
+ }
+
+ public Map<DexType, EmulatedInterfaceDescriptor> getEmulatedInterfaces() {
+ return rewritingFlags.getEmulatedInterfaces();
+ }
+
+ public EmulatedDispatchMethodDescriptor getEmulatedInterfaceEmulatedDispatchMethodDescriptor(
+ DexMethod method) {
+ return rewritingFlags.getEmulatedInterfaceEmulatedDispatchMethodDescriptor(method);
+ }
+
+ public boolean isCustomConversionRewrittenType(DexType type) {
+ return rewritingFlags.isCustomConversionRewrittenType(type);
+ }
+
+ public boolean isEmulatedInterfaceRewrittenType(DexType type) {
+ return rewritingFlags.isEmulatedInterfaceRewrittenType(type);
+ }
+
+ public Map<DexType, List<DexMethod>> getWrappers() {
+ return rewritingFlags.getWrappers();
+ }
+
+ public Map<DexType, DexType> getLegacyBackport() {
+ return rewritingFlags.getLegacyBackport();
+ }
+
+ public Set<DexType> getDontRetarget() {
+ return rewritingFlags.getDontRetarget();
+ }
+
+ public Map<DexType, CustomConversionDescriptor> getCustomConversions() {
+ return rewritingFlags.getCustomConversions();
+ }
+
+ public boolean hasRetargeting() {
+ return rewritingFlags.hasRetargeting();
+ }
+
+ public boolean hasEmulatedInterfaces() {
+ return rewritingFlags.hasEmulatedInterfaces();
+ }
+
+ public boolean isSupported(DexReference reference) {
+ // Support through type rewriting.
+ if (rewritingFlags.getRewriteType().containsKey(reference.getContextType())) {
+ return true;
+ }
+ if (!reference.isDexMethod()) {
+ return false;
+ }
+ // Support through retargeting.
+ DexMethod dexMethod = reference.asDexMethod();
+ if (getStaticRetarget().containsKey(dexMethod)
+ || getNonEmulatedVirtualRetarget().containsKey(dexMethod)
+ || getEmulatedVirtualRetarget().containsKey(dexMethod)) {
+ return true;
+ }
+ // Support through emulated interface.
+ for (EmulatedInterfaceDescriptor descriptor : getEmulatedInterfaces().values()) {
+ if (descriptor.getEmulatedMethods().containsKey(dexMethod)) {
+ return true;
+ }
+ }
+ return false;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java
index a6c487e..f34634d 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java
@@ -5,16 +5,16 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification;
import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.utils.Pair;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.function.Consumer;
public class MachineRewritingFlags {
@@ -28,16 +28,19 @@
Map<DexMethod, DexMethod> staticRetarget,
Map<DexMethod, DexMethod> nonEmulatedVirtualRetarget,
Map<DexMethod, EmulatedDispatchMethodDescriptor> emulatedVirtualRetarget,
+ Map<DexMethod, DexMethod> emulatedVirtualRetargetThroughEmulatedInterface,
Map<DexType, EmulatedInterfaceDescriptor> emulatedInterfaces,
Map<DexType, List<DexMethod>> wrappers,
Map<DexType, DexType> legacyBackport,
Set<DexType> dontRetarget,
- Map<DexType, Pair<DexType, DexString>> customConversions) {
+ Map<DexType, CustomConversionDescriptor> customConversions) {
this.rewriteType = rewriteType;
this.rewriteDerivedTypeOnly = rewriteDerivedTypeOnly;
this.staticRetarget = staticRetarget;
this.nonEmulatedVirtualRetarget = nonEmulatedVirtualRetarget;
this.emulatedVirtualRetarget = emulatedVirtualRetarget;
+ this.emulatedVirtualRetargetThroughEmulatedInterface =
+ emulatedVirtualRetargetThroughEmulatedInterface;
this.emulatedInterfaces = emulatedInterfaces;
this.wrappers = wrappers;
this.legacyBackport = legacyBackport;
@@ -63,6 +66,9 @@
// Virtual methods to retarget through emulated dispatch.
private final Map<DexMethod, EmulatedDispatchMethodDescriptor> emulatedVirtualRetarget;
+ // Virtual methods to retarget through emulated dispatch but handled through emulated interface
+ // dispatch. The method has to override an emulated interface method.
+ private final Map<DexMethod, DexMethod> emulatedVirtualRetargetThroughEmulatedInterface;
// Emulated interface descriptors.
private final Map<DexType, EmulatedInterfaceDescriptor> emulatedInterfaces;
@@ -72,7 +78,7 @@
private final Map<DexType, DexType> legacyBackport;
private final Set<DexType> dontRetarget;
- private final Map<DexType, Pair<DexType, DexString>> customConversions;
+ private final Map<DexType, CustomConversionDescriptor> customConversions;
public Map<DexType, DexType> getRewriteType() {
return rewriteType;
@@ -94,6 +100,16 @@
return emulatedVirtualRetarget;
}
+ public Map<DexMethod, DexMethod> getEmulatedVirtualRetargetThroughEmulatedInterface() {
+ return emulatedVirtualRetargetThroughEmulatedInterface;
+ }
+
+ public void forEachRetargetHolder(Consumer<DexType> consumer) {
+ staticRetarget.keySet().forEach(m -> consumer.accept(m.getHolderType()));
+ nonEmulatedVirtualRetarget.keySet().forEach(m -> consumer.accept(m.getHolderType()));
+ emulatedVirtualRetarget.keySet().forEach(m -> consumer.accept(m.getHolderType()));
+ }
+
public Map<DexType, EmulatedInterfaceDescriptor> getEmulatedInterfaces() {
return emulatedInterfaces;
}
@@ -110,10 +126,41 @@
return dontRetarget;
}
- public Map<DexType, Pair<DexType, DexString>> getCustomConversions() {
+ public boolean isCustomConversionRewrittenType(DexType type) {
+ return Iterables.any(
+ customConversions.values(),
+ descriptor ->
+ descriptor.getFrom().getHolderType() == type
+ || descriptor.getTo().getHolderType() == type);
+ }
+
+ public Map<DexType, CustomConversionDescriptor> getCustomConversions() {
return customConversions;
}
+ public boolean hasRetargeting() {
+ return !staticRetarget.isEmpty()
+ || !nonEmulatedVirtualRetarget.isEmpty()
+ || !emulatedVirtualRetarget.isEmpty();
+ }
+
+ public boolean isEmulatedInterfaceRewrittenType(DexType type) {
+ return Iterables.any(
+ emulatedInterfaces.values(), descriptor -> descriptor.getRewrittenType() == type);
+ }
+
+ public boolean hasEmulatedInterfaces() {
+ return !emulatedInterfaces.isEmpty();
+ }
+
+ EmulatedDispatchMethodDescriptor getEmulatedInterfaceEmulatedDispatchMethodDescriptor(
+ DexMethod method) {
+ if (!emulatedInterfaces.containsKey(method.getHolderType())) {
+ return null;
+ }
+ return emulatedInterfaces.get(method.getHolderType()).getEmulatedMethods().get(method);
+ }
+
public static class Builder {
Builder() {}
@@ -126,17 +173,21 @@
ImmutableMap.builder();
private final ImmutableMap.Builder<DexMethod, EmulatedDispatchMethodDescriptor>
emulatedVirtualRetarget = ImmutableMap.builder();
+ private final ImmutableMap.Builder<DexMethod, DexMethod>
+ emulatedVirtualRetargetThroughEmulatedInterface = ImmutableMap.builder();
private final ImmutableMap.Builder<DexType, EmulatedInterfaceDescriptor> emulatedInterfaces =
ImmutableMap.builder();
private final ImmutableMap.Builder<DexType, List<DexMethod>> wrappers = ImmutableMap.builder();
private final ImmutableMap.Builder<DexType, DexType> legacyBackport = ImmutableMap.builder();
private final ImmutableSet.Builder<DexType> dontRetarget = ImmutableSet.builder();
- private final ImmutableMap.Builder<DexType, Pair<DexType, DexString>> customConversions =
+ private final ImmutableMap.Builder<DexType, CustomConversionDescriptor> customConversions =
ImmutableMap.builder();
public void rewriteType(DexType src, DexType target) {
assert src != null;
assert target != null;
+ assert src != target;
+ assert !rewriteType.containsKey(src) || rewriteType.get(src) == target;
rewriteType.put(src, target);
}
@@ -160,6 +211,10 @@
emulatedVirtualRetarget.put(src, dest);
}
+ public void putEmulatedVirtualRetargetThroughEmulatedInterface(DexMethod src, DexMethod dest) {
+ emulatedVirtualRetargetThroughEmulatedInterface.put(src, dest);
+ }
+
public void addWrapper(DexType wrapperConversion, List<DexMethod> methods) {
wrappers.put(wrapperConversion, ImmutableList.copyOf(methods));
}
@@ -172,8 +227,12 @@
dontRetarget.add(type);
}
- public void putCustomConversion(DexType src, DexType conversionType, DexString conversionName) {
- customConversions.put(src, new Pair<>(conversionType, conversionName));
+ public void putCustomConversion(DexType src, CustomConversionDescriptor descriptor) {
+ customConversions.put(src, descriptor);
+ }
+
+ public DexType getRewrittenType(DexType type) {
+ return rewriteType.get(type);
}
public MachineRewritingFlags build() {
@@ -183,6 +242,7 @@
staticRetarget.build(),
nonEmulatedVirtualRetarget.build(),
emulatedVirtualRetarget.build(),
+ emulatedVirtualRetargetThroughEmulatedInterface.build(),
emulatedInterfaces.build(),
wrappers.build(),
legacyBackport.build(),
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineTopLevelFlags.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineTopLevelFlags.java
index f426219..0c6a88a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineTopLevelFlags.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineTopLevelFlags.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification;
import com.android.tools.r8.utils.AndroidApiLevel;
+import com.google.common.collect.ImmutableList;
import java.util.List;
public class MachineTopLevelFlags {
@@ -23,6 +24,11 @@
private final boolean supportAllCallbacksFromLibrary;
private final List<String> extraKeepRules;
+ public static MachineTopLevelFlags empty() {
+ return new MachineTopLevelFlags(
+ AndroidApiLevel.B, "unused", null, null, false, ImmutableList.of());
+ }
+
public MachineTopLevelFlags(
AndroidApiLevel requiredCompilationAPILevel,
String synthesizedLibraryClassesPackagePrefix,
@@ -54,7 +60,7 @@
return jsonSource;
}
- public boolean isSupportAllCallbacksFromLibrary() {
+ public boolean supportAllCallbacksFromLibrary() {
return supportAllCallbacksFromLibrary;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
index a54cd8d..73dd908 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
@@ -12,7 +12,6 @@
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClassAndMethod;
-import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.MethodResolutionResult;
@@ -23,6 +22,7 @@
import com.android.tools.r8.ir.desugar.FreshLocalProvider;
import com.android.tools.r8.ir.desugar.LocalStackAllocator;
import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.EmulatedDispatchMethodDescriptor;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterInstructionEventConsumer;
import java.util.Collection;
import java.util.Collections;
@@ -36,7 +36,6 @@
private final AppView<?> appView;
private final DesugaredLibraryRetargeterSyntheticHelper syntheticHelper;
- private final RetargetingInfo retargetingInfo;
private final Map<DexMethod, DexMethod> staticRetarget;
private final Map<DexMethod, DexMethod> nonEmulatedVirtualRetarget;
private final Map<DexMethod, EmulatedDispatchMethodDescriptor> emulatedVirtualRetarget;
@@ -44,10 +43,11 @@
public DesugaredLibraryRetargeter(AppView<?> appView) {
this.appView = appView;
this.syntheticHelper = new DesugaredLibraryRetargeterSyntheticHelper(appView);
- retargetingInfo = RetargetingInfo.get(appView);
- staticRetarget = retargetingInfo.getStaticRetarget();
- nonEmulatedVirtualRetarget = retargetingInfo.getNonEmulatedVirtualRetarget();
- emulatedVirtualRetarget = retargetingInfo.getEmulatedVirtualRetarget();
+ MachineDesugaredLibrarySpecification specification =
+ appView.options().machineDesugaredLibrarySpecification;
+ staticRetarget = specification.getStaticRetarget();
+ nonEmulatedVirtualRetarget = specification.getNonEmulatedVirtualRetarget();
+ emulatedVirtualRetarget = specification.getEmulatedVirtualRetarget();
}
// Used by the ListOfBackportedMethods utility.
@@ -57,10 +57,6 @@
emulatedVirtualRetarget.keySet().forEach(consumer);
}
- public RetargetingInfo getRetargetingInfo() {
- return retargetingInfo;
- }
-
@Override
public Collection<CfInstruction> desugarInstruction(
CfInstruction instruction,
@@ -87,6 +83,18 @@
return computeNewInvokeTarget(instruction, context).hasNewInvokeTarget();
}
+ InvokeRetargetingResult ensureInvokeRetargetingResult(DexMethod retarget) {
+ if (retarget == null) {
+ return NO_REWRITING;
+ }
+ return new InvokeRetargetingResult(
+ true,
+ eventConsumer -> {
+ syntheticHelper.ensureRetargetMethod(retarget, eventConsumer);
+ return retarget;
+ });
+ }
+
static class InvokeRetargetingResult {
static InvokeRetargetingResult NO_REWRITING =
@@ -96,13 +104,6 @@
private final Function<DesugaredLibraryRetargeterInstructionEventConsumer, DexMethod>
newInvokeTargetSupplier;
- static InvokeRetargetingResult createInvokeRetargetingResult(DexMethod retarget) {
- if (retarget == null) {
- return NO_REWRITING;
- }
- return new InvokeRetargetingResult(true, ignored -> retarget);
- }
-
private InvokeRetargetingResult(
boolean hasNewInvokeTarget,
Function<DesugaredLibraryRetargeterInstructionEventConsumer, DexMethod>
@@ -129,8 +130,8 @@
}
if (appView
.options()
- .desugaredLibrarySpecification
- .getDontRetargetLibMember()
+ .machineDesugaredLibrarySpecification
+ .getDontRetarget()
.contains(context.getContextType())) {
return NO_REWRITING;
}
@@ -148,44 +149,33 @@
assert singleTarget != null;
if (cfInvoke.isInvokeStatic()) {
DexMethod retarget = staticRetarget.get(singleTarget);
- return retarget == null
- ? NO_REWRITING
- : InvokeRetargetingResult.createInvokeRetargetingResult(retarget);
+ return retarget == null ? NO_REWRITING : ensureInvokeRetargetingResult(retarget);
}
- InvokeRetargetingResult retarget = computeNonStaticRetarget(singleTarget);
+ InvokeRetargetingResult retarget = computeNonStaticRetarget(singleTarget, false);
if (!retarget.hasNewInvokeTarget()) {
return NO_REWRITING;
}
if (cfInvoke.isInvokeSuper(context.getHolderType())) {
DexClassAndMethod superTarget = appInfo.lookupSuperTarget(invokedMethod, context);
if (superTarget != null) {
- return computeSuperRetarget(superTarget.getDefinition());
+ assert !superTarget.getDefinition().isStatic();
+ return computeNonStaticRetarget(superTarget.getReference(), true);
}
}
return retarget;
}
- private InvokeRetargetingResult computeNonStaticRetarget(DexMethod singleTarget) {
+ private InvokeRetargetingResult computeNonStaticRetarget(
+ DexMethod singleTarget, boolean superInvoke) {
EmulatedDispatchMethodDescriptor descriptor = emulatedVirtualRetarget.get(singleTarget);
if (descriptor != null) {
return new InvokeRetargetingResult(
true,
eventConsumer ->
- syntheticHelper.ensureEmulatedHolderDispatchMethod(descriptor, eventConsumer));
+ superInvoke
+ ? syntheticHelper.ensureForwardingMethod(descriptor, eventConsumer)
+ : syntheticHelper.ensureEmulatedHolderDispatchMethod(descriptor, eventConsumer));
}
- return InvokeRetargetingResult.createInvokeRetargetingResult(
- nonEmulatedVirtualRetarget.get(singleTarget));
- }
-
- private InvokeRetargetingResult computeSuperRetarget(DexEncodedMethod singleTarget) {
- assert !singleTarget.isStatic();
- DexMethod reference = singleTarget.getReference();
- EmulatedDispatchMethodDescriptor descriptor = emulatedVirtualRetarget.get(reference);
- if (descriptor != null) {
- return InvokeRetargetingResult.createInvokeRetargetingResult(
- syntheticHelper.ensureForwardingMethod(descriptor));
- }
- return InvokeRetargetingResult.createInvokeRetargetingResult(
- nonEmulatedVirtualRetarget.get(reference));
+ return ensureInvokeRetargetingResult(nonEmulatedVirtualRetarget.get(singleTarget));
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterL8Synthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterL8Synthesizer.java
index 11fcfb7..60086f8 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterL8Synthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterL8Synthesizer.java
@@ -14,30 +14,30 @@
private final AppView<?> appView;
private final DesugaredLibraryRetargeterSyntheticHelper syntheticHelper;
- private final Map<DexMethod, EmulatedDispatchMethodDescriptor> emulatedDispatchMethods;
- public static DesugaredLibraryRetargeterL8Synthesizer create(
- AppView<?> appView, RetargetingInfo retargetingInfo) {
+ public static DesugaredLibraryRetargeterL8Synthesizer create(AppView<?> appView) {
assert appView.options().isDesugaredLibraryCompilation();
- if (retargetingInfo == null || retargetingInfo.getEmulatedVirtualRetarget().isEmpty()) {
- assert appView.options().desugaredLibrarySpecification.getRetargetCoreLibMember().isEmpty();
+ if (appView
+ .options()
+ .machineDesugaredLibrarySpecification
+ .getEmulatedVirtualRetarget()
+ .isEmpty()) {
return null;
}
- return new DesugaredLibraryRetargeterL8Synthesizer(appView, retargetingInfo);
+ return new DesugaredLibraryRetargeterL8Synthesizer(appView);
}
- public DesugaredLibraryRetargeterL8Synthesizer(
- AppView<?> appView, RetargetingInfo retargetingInfo) {
+ public DesugaredLibraryRetargeterL8Synthesizer(AppView<?> appView) {
this.appView = appView;
this.syntheticHelper = new DesugaredLibraryRetargeterSyntheticHelper(appView);
- emulatedDispatchMethods = retargetingInfo.getEmulatedVirtualRetarget();
}
@Override
public void synthesizeClasses(CfClassSynthesizerDesugaringEventConsumer eventConsumer) {
- assert !emulatedDispatchMethods.isEmpty();
+ Map<DexMethod, EmulatedDispatchMethodDescriptor> emulatedVirtualRetarget =
+ appView.options().machineDesugaredLibrarySpecification.getEmulatedVirtualRetarget();
for (EmulatedDispatchMethodDescriptor emulatedDispatchMethod :
- emulatedDispatchMethods.values()) {
+ emulatedVirtualRetarget.values()) {
syntheticHelper.ensureProgramEmulatedHolderDispatchMethod(
emulatedDispatchMethod, eventConsumer);
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterLibraryTypeSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterLibraryTypeSynthesizer.java
deleted file mode 100644
index bbaa4cf..0000000
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterLibraryTypeSynthesizer.java
+++ /dev/null
@@ -1,163 +0,0 @@
-// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter;
-
-import com.android.tools.r8.ProgramResource.Kind;
-import com.android.tools.r8.dex.Constants;
-import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.ClassAccessFlags;
-import com.android.tools.r8.graph.DexAnnotationSet;
-import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexLibraryClass;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.DexTypeList;
-import com.android.tools.r8.graph.DirectMappedDexApplication;
-import com.android.tools.r8.graph.EnclosingMethodAttribute;
-import com.android.tools.r8.graph.GenericSignature.ClassSignature;
-import com.android.tools.r8.graph.InnerClassAttribute;
-import com.android.tools.r8.graph.MethodAccessFlags;
-import com.android.tools.r8.graph.NestHostClassAttribute;
-import com.android.tools.r8.graph.NestMemberClassAttribute;
-import com.android.tools.r8.origin.SynthesizedOrigin;
-import com.android.tools.r8.utils.StringDiagnostic;
-import java.util.Comparator;
-import java.util.IdentityHashMap;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.TreeSet;
-
-public class DesugaredLibraryRetargeterLibraryTypeSynthesizer {
-
- public static void checkForAssumedLibraryTypes(AppView<?> appView) {
- Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
- appView.options().desugaredLibrarySpecification.getRetargetCoreLibMember();
- for (DexString methodName : retargetCoreLibMember.keySet()) {
- for (DexType inType : retargetCoreLibMember.get(methodName).keySet()) {
- DexClass typeClass = appView.definitionFor(inType);
- if (typeClass == null) {
- warnMissingRetargetCoreLibraryMember(inType, appView);
- }
- }
- }
- }
-
- public static void amendLibraryWithRetargetedMembers(AppView<AppInfoWithClassHierarchy> appView) {
- Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
- appView.options().desugaredLibrarySpecification.getRetargetCoreLibMember();
- Map<DexType, DexLibraryClass> synthesizedLibraryClasses =
- synthesizeLibraryClassesForRetargetedMembers(appView, retargetCoreLibMember);
- Map<DexLibraryClass, Set<DexEncodedMethod>> synthesizedLibraryMethods =
- synthesizedMembersForRetargetClasses(
- appView, retargetCoreLibMember, synthesizedLibraryClasses);
- synthesizedLibraryMethods.forEach(DexLibraryClass::addDirectMethods);
- DirectMappedDexApplication newApplication =
- appView
- .appInfo()
- .app()
- .asDirect()
- .builder()
- .addLibraryClasses(synthesizedLibraryClasses.values())
- .build();
- appView.setAppInfo(appView.appInfo().rebuildWithClassHierarchy(app -> newApplication));
- }
-
- private static Map<DexType, DexLibraryClass> synthesizeLibraryClassesForRetargetedMembers(
- AppView<AppInfoWithClassHierarchy> appView,
- Map<DexString, Map<DexType, DexType>> retargetCoreLibMember) {
- DexItemFactory dexItemFactory = appView.dexItemFactory();
- Map<DexType, DexLibraryClass> synthesizedLibraryClasses = new LinkedHashMap<>();
- for (Map<DexType, DexType> oldToNewTypeMap : retargetCoreLibMember.values()) {
- for (DexType newType : oldToNewTypeMap.values()) {
- if (appView.definitionFor(newType) == null) {
- synthesizedLibraryClasses.computeIfAbsent(
- newType,
- type ->
- // Synthesize a library class with the given name. Note that this is assuming that
- // the library class inherits directly from java.lang.Object, does not implement
- // any interfaces, etc.
- new DexLibraryClass(
- type,
- Kind.CF,
- new SynthesizedOrigin(
- "Desugared library retargeter", DesugaredLibraryRetargeter.class),
- ClassAccessFlags.fromCfAccessFlags(Constants.ACC_PUBLIC),
- dexItemFactory.objectType,
- DexTypeList.empty(),
- dexItemFactory.createString("DesugaredLibraryRetargeter"),
- NestHostClassAttribute.none(),
- NestMemberClassAttribute.emptyList(),
- EnclosingMethodAttribute.none(),
- InnerClassAttribute.emptyList(),
- ClassSignature.noSignature(),
- DexAnnotationSet.empty(),
- DexEncodedField.EMPTY_ARRAY,
- DexEncodedField.EMPTY_ARRAY,
- DexEncodedMethod.EMPTY_ARRAY,
- DexEncodedMethod.EMPTY_ARRAY,
- dexItemFactory.getSkipNameValidationForTesting()));
- }
- }
- }
- return synthesizedLibraryClasses;
- }
-
- private static Map<DexLibraryClass, Set<DexEncodedMethod>> synthesizedMembersForRetargetClasses(
- AppView<AppInfoWithClassHierarchy> appView,
- Map<DexString, Map<DexType, DexType>> retargetCoreLibMember,
- Map<DexType, DexLibraryClass> synthesizedLibraryClasses) {
- DexItemFactory dexItemFactory = appView.dexItemFactory();
- Map<DexLibraryClass, Set<DexEncodedMethod>> synthesizedMembers = new IdentityHashMap<>();
- for (Entry<DexString, Map<DexType, DexType>> entry : retargetCoreLibMember.entrySet()) {
- DexString methodName = entry.getKey();
- Map<DexType, DexType> types = entry.getValue();
- types.forEach(
- (oldType, newType) -> {
- DexClass oldClass = appView.definitionFor(oldType);
- DexLibraryClass newClass = synthesizedLibraryClasses.get(newType);
- if (oldClass == null || newClass == null) {
- return;
- }
- for (DexEncodedMethod method :
- oldClass.methods(method -> method.getName() == methodName)) {
- DexMethod retargetMethod = method.getReference().withHolder(newType, dexItemFactory);
- if (!method.isStatic()) {
- retargetMethod = retargetMethod.withExtraArgumentPrepended(oldType, dexItemFactory);
- }
- synthesizedMembers
- .computeIfAbsent(
- newClass,
- ignore -> new TreeSet<>(Comparator.comparing(DexEncodedMethod::getReference)))
- .add(
- DexEncodedMethod.syntheticBuilder()
- .setMethod(retargetMethod)
- .setAccessFlags(
- MethodAccessFlags.fromCfAccessFlags(
- Constants.ACC_PUBLIC | Constants.ACC_STATIC, false))
- .setCode(null)
- .setApiLevelForDefinition(method.getApiLevelForDefinition())
- .build());
- }
- });
- }
- return synthesizedMembers;
- }
-
- private static void warnMissingRetargetCoreLibraryMember(DexType type, AppView<?> appView) {
- StringDiagnostic warning =
- new StringDiagnostic(
- "Cannot retarget core library member "
- + type.getName()
- + " because the class is missing.");
- appView.options().reporter.warning(warning);
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java
index 414c32d..e1447fb 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java
@@ -36,11 +36,11 @@
private final DesugaredLibraryRetargeterSyntheticHelper syntheticHelper;
private final Map<DexMethod, EmulatedDispatchMethodDescriptor> emulatedDispatchMethods;
- public DesugaredLibraryRetargeterPostProcessor(
- AppView<?> appView, RetargetingInfo retargetingInfo) {
+ public DesugaredLibraryRetargeterPostProcessor(AppView<?> appView) {
this.appView = appView;
this.syntheticHelper = new DesugaredLibraryRetargeterSyntheticHelper(appView);
- emulatedDispatchMethods = retargetingInfo.getEmulatedVirtualRetarget();
+ emulatedDispatchMethods =
+ appView.options().machineDesugaredLibrarySpecification.getEmulatedVirtualRetarget();
}
@Override
@@ -127,8 +127,8 @@
}
if (appView
.options()
- .desugaredLibrarySpecification
- .getDontRetargetLibMember()
+ .machineDesugaredLibrarySpecification
+ .getDontRetarget()
.contains(clazz.getType())) {
continue;
}
@@ -136,7 +136,7 @@
Collections.singletonList(new ClassTypeSignature(newInterface.type)));
eventConsumer.acceptInterfaceInjection(clazz, newInterface);
DexMethod itfMethod =
- syntheticHelper.getEmulatedInterfaceDispatchMethod(newInterface, descriptor);
+ syntheticHelper.emulatedInterfaceDispatchMethod(newInterface, descriptor);
if (clazz.lookupVirtualMethod(method) == null) {
DexEncodedMethod newMethod = createForwardingMethod(itfMethod, descriptor, clazz);
clazz.addVirtualMethod(newMethod);
@@ -150,7 +150,7 @@
// NOTE: Never add a forwarding method to methods of classes unknown or coming from android.jar
// even if this results in invalid code, these classes are never desugared.
// In desugared library, emulated interface methods can be overridden by retarget lib members.
- DexMethod forwardMethod = syntheticHelper.ensureForwardingMethod(descriptor);
+ DexMethod forwardMethod = syntheticHelper.forwardingMethod(descriptor);
assert forwardMethod != null && forwardMethod != target;
DexEncodedMethod resolvedMethod =
appView.appInfoForDesugaring().resolveMethod(target, true).getResolvedMethod();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterSyntheticHelper.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterSyntheticHelper.java
index 5519d95..6102e1a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterSyntheticHelper.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterSyntheticHelper.java
@@ -6,6 +6,7 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
+import com.android.tools.r8.graph.ClasspathMethod;
import com.android.tools.r8.graph.ClasspathOrLibraryClass;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexMethod;
@@ -29,12 +30,46 @@
this.appView = appView;
}
- public DexMethod ensureForwardingMethod(EmulatedDispatchMethodDescriptor descriptor) {
- // TODO(b/184026720): We may synthesize a stub on the classpath if absent.
+ public DexMethod ensureRetargetMethod(
+ DexMethod retarget, DesugaredLibraryRetargeterInstructionEventConsumer eventConsumer) {
+ DexClass holderClass = appView.definitionFor(retarget.getHolderType());
+ if (holderClass != null && !holderClass.isClasspathClass()) {
+ // The holder class is a library class in orthodox set-ups where the L8 compilation
+ // is done in multiple steps, this is only partially supported (most notably for tests).
+ assert holderClass.lookupMethod(retarget) != null;
+ return retarget;
+ }
+ assert eventConsumer != null;
+ ClasspathMethod ensuredMethod =
+ appView
+ .getSyntheticItems()
+ .ensureFixedClasspathMethodFromType(
+ retarget.getName(),
+ retarget.getProto(),
+ SyntheticKind.RETARGET_STUB,
+ retarget.getHolderType(),
+ appView,
+ ignored -> {},
+ eventConsumer::acceptDesugaredLibraryRetargeterDispatchClasspathClass,
+ methodBuilder ->
+ methodBuilder
+ .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic())
+ .setCode(null));
+ assert ensuredMethod.getReference() == retarget;
+ return retarget;
+ }
+
+ DexMethod forwardingMethod(EmulatedDispatchMethodDescriptor descriptor) {
assert descriptor.getForwardingMethod().getHolderKind() == null;
return descriptor.getForwardingMethod().getMethod();
}
+ public DexMethod ensureForwardingMethod(
+ EmulatedDispatchMethodDescriptor descriptor,
+ DesugaredLibraryRetargeterInstructionEventConsumer eventConsumer) {
+ return ensureRetargetMethod(forwardingMethod(descriptor), eventConsumer);
+ }
+
private DexMethod emulatedHolderDispatchMethod(DexType holder, DerivedMethod method) {
assert method.getHolderKind() == SyntheticKind.RETARGET_CLASS;
DexProto newProto = appView.dexItemFactory().prependHolderToProto(method.getMethod());
@@ -46,7 +81,7 @@
return appView.dexItemFactory().createMethod(holder, method.getProto(), method.getName());
}
- public DexMethod getEmulatedInterfaceDispatchMethod(
+ public DexMethod emulatedInterfaceDispatchMethod(
DexClass newInterface, EmulatedDispatchMethodDescriptor descriptor) {
DexMethod method =
emulatedInterfaceDispatchMethod(newInterface.type, descriptor.getInterfaceMethod());
@@ -83,7 +118,8 @@
SyntheticKind.RETARGET_CLASS,
context,
appView,
- classBuilder -> buildHolderDispatchMethod(classBuilder, itfClass, descriptor),
+ classBuilder ->
+ buildHolderDispatchMethod(classBuilder, itfClass, descriptor, eventConsumer),
eventConsumer::acceptDesugaredLibraryRetargeterDispatchClasspathClass);
}
DexMethod dispatchMethod =
@@ -107,7 +143,7 @@
emulatedDispatchMethod.getHolderKind(),
holderContext,
appView,
- classBuilder -> buildHolderDispatchMethod(classBuilder, itfClass, descriptor),
+ classBuilder -> buildHolderDispatchMethod(classBuilder, itfClass, descriptor, null),
eventConsumer::acceptDesugaredLibraryRetargeterDispatchProgramClass);
}
@@ -174,7 +210,10 @@
}
private <SCB extends SyntheticClassBuilder<?, ?>> void buildHolderDispatchMethod(
- SCB classBuilder, DexClass itfClass, EmulatedDispatchMethodDescriptor descriptor) {
+ SCB classBuilder,
+ DexClass itfClass,
+ EmulatedDispatchMethodDescriptor descriptor,
+ DesugaredLibraryRetargeterInstructionEventConsumer eventConsumer) {
classBuilder.addMethod(
methodBuilder -> {
DexMethod dispatchMethod =
@@ -189,15 +228,19 @@
.setCode(
methodSig ->
appView.options().isDesugaredLibraryCompilation()
- ? generateEmulatedDispatchCfCode(descriptor, itfClass, methodSig)
+ ? generateEmulatedDispatchCfCode(
+ descriptor, itfClass, methodSig, eventConsumer)
: null);
});
}
private CfCode generateEmulatedDispatchCfCode(
- EmulatedDispatchMethodDescriptor descriptor, DexClass itfClass, DexMethod methodSig) {
- DexMethod forwardingMethod = ensureForwardingMethod(descriptor);
- DexMethod itfMethod = getEmulatedInterfaceDispatchMethod(itfClass, descriptor);
+ EmulatedDispatchMethodDescriptor descriptor,
+ DexClass itfClass,
+ DexMethod methodSig,
+ DesugaredLibraryRetargeterInstructionEventConsumer eventConsumer) {
+ DexMethod forwardingMethod = ensureForwardingMethod(descriptor, eventConsumer);
+ DexMethod itfMethod = emulatedInterfaceDispatchMethod(itfClass, descriptor);
assert descriptor.getDispatchCases().isEmpty();
return new EmulateDispatchSyntheticCfCodeProvider(
methodSig.getHolderType(), forwardingMethod, itfMethod, new LinkedHashMap<>(), appView)
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/RetargetingInfo.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/RetargetingInfo.java
deleted file mode 100644
index 9e1f5e3..0000000
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/RetargetingInfo.java
+++ /dev/null
@@ -1,213 +0,0 @@
-// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter;
-
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexClassAndMethod;
-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.DexString;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.DerivedMethod;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.EmulatedDispatchMethodDescriptor;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineRewritingFlags;
-import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
-import com.android.tools.r8.utils.WorkList;
-import com.google.common.collect.ImmutableMap;
-import java.util.ArrayList;
-import java.util.IdentityHashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-public class RetargetingInfo {
-
- private final Map<DexMethod, DexMethod> staticRetarget;
- private final Map<DexMethod, DexMethod> nonEmulatedVirtualRetarget;
- private final Map<DexMethod, EmulatedDispatchMethodDescriptor> emulatedVirtualRetarget;
-
- RetargetingInfo(
- Map<DexMethod, DexMethod> staticRetarget,
- Map<DexMethod, DexMethod> nonEmulatedVirtualRetarget,
- Map<DexMethod, EmulatedDispatchMethodDescriptor> emulatedVirtualRetarget) {
- this.staticRetarget = staticRetarget;
- this.nonEmulatedVirtualRetarget = nonEmulatedVirtualRetarget;
- this.emulatedVirtualRetarget = emulatedVirtualRetarget;
- }
-
- public static RetargetingInfo get(AppView<?> appView) {
- if (appView.options().testing.machineDesugaredLibrarySpecification != null) {
- MachineRewritingFlags rewritingFlags =
- appView.options().testing.machineDesugaredLibrarySpecification.getRewritingFlags();
- return new RetargetingInfo(
- rewritingFlags.getStaticRetarget(),
- rewritingFlags.getNonEmulatedVirtualRetarget(),
- rewritingFlags.getEmulatedVirtualRetarget());
- }
- return new RetargetingInfoBuilder(appView).computeRetargetingInfo();
- }
-
- public Map<DexMethod, DexMethod> getStaticRetarget() {
- return staticRetarget;
- }
-
- public Map<DexMethod, DexMethod> getNonEmulatedVirtualRetarget() {
- return nonEmulatedVirtualRetarget;
- }
-
- public Map<DexMethod, EmulatedDispatchMethodDescriptor> getEmulatedVirtualRetarget() {
- return emulatedVirtualRetarget;
- }
-
- private static class RetargetingInfoBuilder {
-
- private final AppView<?> appView;
- private final Map<DexMethod, DexMethod> staticRetarget = new IdentityHashMap<>();
- private final Map<DexMethod, DexMethod> nonEmulatedVirtualRetarget = new IdentityHashMap<>();
- private final Map<DexMethod, EmulatedDispatchMethodDescriptor> emulatedVirtualRetarget =
- new IdentityHashMap<>();
-
- public RetargetingInfoBuilder(AppView<?> appView) {
- this.appView = appView;
- }
-
- private RetargetingInfo computeRetargetingInfo() {
- LegacyDesugaredLibrarySpecification desugaredLibrarySpecification =
- appView.options().desugaredLibrarySpecification;
- Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
- desugaredLibrarySpecification.getRetargetCoreLibMember();
- if (retargetCoreLibMember.isEmpty()) {
- return new RetargetingInfo(ImmutableMap.of(), ImmutableMap.of(), ImmutableMap.of());
- }
- for (DexString methodName : retargetCoreLibMember.keySet()) {
- for (DexType inType : retargetCoreLibMember.get(methodName).keySet()) {
- DexClass typeClass = appView.definitionFor(inType);
- if (typeClass != null) {
- DexType newHolder = retargetCoreLibMember.get(methodName).get(inType);
- List<DexClassAndMethod> found = findMethodsWithName(methodName, typeClass);
- for (DexClassAndMethod method : found) {
- DexMethod methodReference = method.getReference();
- if (method.getAccessFlags().isStatic()) {
- staticRetarget.put(
- methodReference,
- computeRetargetMethod(
- methodReference, method.getAccessFlags().isStatic(), newHolder));
- continue;
- }
- if (isEmulatedInterfaceDispatch(method)) {
- continue;
- }
- if (typeClass.isFinal() || method.getAccessFlags().isFinal()) {
- nonEmulatedVirtualRetarget.put(
- methodReference,
- computeRetargetMethod(
- methodReference, method.getAccessFlags().isStatic(), newHolder));
- } else {
- // Virtual rewrites require emulated dispatch for inheritance.
- // The call is rewritten to the dispatch holder class instead.
- DexProto newProto = appView.dexItemFactory().prependHolderToProto(methodReference);
- DexMethod forwardingDexMethod =
- appView.dexItemFactory().createMethod(newHolder, newProto, methodName);
- DerivedMethod forwardingMethod = new DerivedMethod(forwardingDexMethod);
- DerivedMethod interfaceMethod =
- new DerivedMethod(methodReference, SyntheticKind.RETARGET_INTERFACE);
- DerivedMethod dispatchMethod =
- new DerivedMethod(methodReference, SyntheticKind.RETARGET_CLASS);
- emulatedVirtualRetarget.put(
- methodReference,
- new EmulatedDispatchMethodDescriptor(
- interfaceMethod, dispatchMethod, forwardingMethod, new LinkedHashMap<>()));
- }
- }
- }
- }
- }
- if (desugaredLibrarySpecification.isLibraryCompilation()) {
- // TODO(b/177977763): This is only a workaround rewriting invokes of j.u.Arrays.deepEquals0
- // to j.u.DesugarArrays.deepEquals0.
- DexItemFactory itemFactory = appView.options().dexItemFactory();
- DexString name = itemFactory.createString("deepEquals0");
- DexProto proto =
- itemFactory.createProto(
- itemFactory.booleanType, itemFactory.objectType, itemFactory.objectType);
- DexMethod source =
- itemFactory.createMethod(
- itemFactory.createType(itemFactory.arraysDescriptor), proto, name);
- DexMethod target =
- computeRetargetMethod(
- source, true, itemFactory.createType("Ljava/util/DesugarArrays;"));
- staticRetarget.put(source, target);
- // TODO(b/181629049): This is only a workaround rewriting invokes of
- // j.u.TimeZone.getTimeZone taking a java.time.ZoneId.
- name = itemFactory.createString("getTimeZone");
- proto =
- itemFactory.createProto(
- itemFactory.createType("Ljava/util/TimeZone;"),
- itemFactory.createType("Ljava/time/ZoneId;"));
- source =
- itemFactory.createMethod(itemFactory.createType("Ljava/util/TimeZone;"), proto, name);
- target =
- computeRetargetMethod(
- source, true, itemFactory.createType("Ljava/util/DesugarTimeZone;"));
- staticRetarget.put(source, target);
- }
- return new RetargetingInfo(
- ImmutableMap.copyOf(staticRetarget),
- ImmutableMap.copyOf(nonEmulatedVirtualRetarget),
- emulatedVirtualRetarget);
- }
-
- DexMethod computeRetargetMethod(DexMethod method, boolean isStatic, DexType newHolder) {
- DexItemFactory factory = appView.dexItemFactory();
- DexProto newProto = isStatic ? method.getProto() : factory.prependHolderToProto(method);
- return factory.createMethod(newHolder, newProto, method.getName());
- }
-
- private boolean isEmulatedInterfaceDispatch(DexClassAndMethod method) {
- // Answers true if this method is already managed through emulated interface dispatch.
- Map<DexType, DexType> emulateLibraryInterface =
- appView.options().desugaredLibrarySpecification.getEmulateLibraryInterface();
- if (emulateLibraryInterface.isEmpty()) {
- return false;
- }
- DexMethod methodToFind = method.getReference();
- // Look-up all superclass and interfaces, if an emulated interface is found, and it implements
- // the method, answers true.
- WorkList<DexClass> worklist = WorkList.newIdentityWorkList(method.getHolder());
- while (worklist.hasNext()) {
- DexClass clazz = worklist.next();
- if (clazz.isInterface()
- && emulateLibraryInterface.containsKey(clazz.getType())
- && clazz.lookupMethod(methodToFind) != null) {
- return true;
- }
- // All super types are library class, or we are doing L8 compilation.
- clazz.forEachImmediateSupertype(
- superType -> {
- DexClass superClass = appView.definitionFor(superType);
- if (superClass != null) {
- worklist.addIfNotSeen(superClass);
- }
- });
- }
- return false;
- }
-
- private List<DexClassAndMethod> findMethodsWithName(DexString methodName, DexClass clazz) {
- List<DexClassAndMethod> found = new ArrayList<>();
- clazz.forEachClassMethodMatching(
- definition -> definition.getName() == methodName, found::add);
- assert !found.isEmpty()
- : "Should have found a method (library specifications) for "
- + clazz.toSourceString()
- + "."
- + methodName
- + ". Maybe the library used for the compilation should be newer.";
- return found;
- }
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineEmulatedInterfaceConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineEmulatedInterfaceConverter.java
index 2411ba0..4be8ef0 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineEmulatedInterfaceConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineEmulatedInterfaceConverter.java
@@ -8,8 +8,8 @@
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexProto;
+import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanRewritingFlags;
import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.DerivedMethod;
@@ -26,11 +26,13 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.function.BiConsumer;
public class HumanToMachineEmulatedInterfaceConverter {
private final AppInfoWithClassHierarchy appInfo;
- private Map<DexType, List<DexType>> emulatedInterfaceHierarchy;
+ private final Map<DexType, List<DexType>> emulatedInterfaceHierarchy = new IdentityHashMap<>();
+ private final Set<DexType> missingEmulatedInterface = Sets.newIdentityHashSet();
public HumanToMachineEmulatedInterfaceConverter(AppInfoWithClassHierarchy appInfo) {
this.appInfo = appInfo;
@@ -39,15 +41,19 @@
public void convertEmulatedInterfaces(
HumanRewritingFlags rewritingFlags,
AppInfoWithClassHierarchy appInfo,
- MachineRewritingFlags.Builder builder) {
+ MachineRewritingFlags.Builder builder,
+ BiConsumer<String, Set<? extends DexReference>> warnConsumer) {
Map<DexType, DexType> emulateInterfaces = rewritingFlags.getEmulateLibraryInterface();
Set<DexMethod> dontRewriteInvocation = rewritingFlags.getDontRewriteInvocation();
- emulatedInterfaceHierarchy = processEmulatedInterfaceHierarchy(appInfo, emulateInterfaces);
+ processEmulatedInterfaceHierarchy(appInfo, emulateInterfaces);
for (DexType itf : emulateInterfaces.keySet()) {
- DexProgramClass itfClass = appInfo.contextIndependentDefinitionFor(itf).asProgramClass();
- assert itfClass != null;
+ DexClass itfClass = appInfo.contextIndependentDefinitionFor(itf);
+ if (itfClass == null) {
+ missingEmulatedInterface.add(itf);
+ continue;
+ }
Map<DexMethod, EmulatedDispatchMethodDescriptor> emulatedMethods = new IdentityHashMap<>();
- itfClass.forEachProgramVirtualMethodMatching(
+ itfClass.forEachClassMethodMatching(
m -> m.isDefaultMethod() && !dontRewriteInvocation.contains(m.getReference()),
method ->
emulatedMethods.put(
@@ -57,6 +63,7 @@
builder.putEmulatedInterface(
itf, new EmulatedInterfaceDescriptor(emulateInterfaces.get(itf), emulatedMethods));
}
+ warnConsumer.accept("Missing emulated interfaces: ", missingEmulatedInterface);
}
private EmulatedDispatchMethodDescriptor computeEmulatedDispatchDescriptor(
@@ -104,7 +111,6 @@
for (int i = subInterfaces.size() - 1; i >= 0; i--) {
DexClass subInterfaceClass = appInfo.definitionFor(subInterfaces.get(i));
assert subInterfaceClass != null;
- assert subInterfaceClass.isProgramClass();
// Else computation of subInterface would have failed.
// if the method is implemented, extra dispatch is required.
DexEncodedMethod result = subInterfaceClass.lookupVirtualMethod(method);
@@ -137,29 +143,25 @@
return false;
}
- private Map<DexType, List<DexType>> processEmulatedInterfaceHierarchy(
+ private void processEmulatedInterfaceHierarchy(
AppInfoWithClassHierarchy appInfo, Map<DexType, DexType> emulateInterfaces) {
- Map<DexType, List<DexType>> emulatedInterfacesHierarchy = new IdentityHashMap<>();
Set<DexType> processed = Sets.newIdentityHashSet();
ArrayList<DexType> emulatedInterfacesSorted = new ArrayList<>(emulateInterfaces.keySet());
emulatedInterfacesSorted.sort(DexType::compareTo);
for (DexType interfaceType : emulatedInterfacesSorted) {
- processEmulatedInterfaceHierarchy(
- appInfo, emulateInterfaces, interfaceType, processed, emulatedInterfacesHierarchy);
+ processEmulatedInterfaceHierarchy(appInfo, emulateInterfaces, interfaceType, processed);
}
- return emulatedInterfacesHierarchy;
}
private void processEmulatedInterfaceHierarchy(
AppInfoWithClassHierarchy appInfo,
Map<DexType, DexType> emulateInterfaces,
DexType interfaceType,
- Set<DexType> processed,
- Map<DexType, List<DexType>> emulatedInterfacesHierarchy) {
+ Set<DexType> processed) {
if (processed.contains(interfaceType)) {
return;
}
- emulatedInterfacesHierarchy.put(interfaceType, new ArrayList<>());
+ emulatedInterfaceHierarchy.put(interfaceType, new ArrayList<>());
processed.add(interfaceType);
DexClass theInterface = appInfo.definitionFor(interfaceType);
if (theInterface == null) {
@@ -170,9 +172,8 @@
while (!workList.isEmpty()) {
DexType next = workList.next();
if (emulateInterfaces.containsKey(next)) {
- processEmulatedInterfaceHierarchy(
- appInfo, emulateInterfaces, next, processed, emulatedInterfacesHierarchy);
- emulatedInterfacesHierarchy.get(next).add(interfaceType);
+ processEmulatedInterfaceHierarchy(appInfo, emulateInterfaces, next, processed);
+ emulatedInterfaceHierarchy.get(next).add(interfaceType);
DexClass nextClass = appInfo.definitionFor(next);
if (nextClass != null) {
workList.addIfNotSeen(nextClass.interfaces.values);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java
index 6ff7428..5704f3d 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java
@@ -5,44 +5,71 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanRewritingFlags;
import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineRewritingFlags;
import com.android.tools.r8.utils.DescriptorUtils;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Sets;
+import java.util.IdentityHashMap;
import java.util.Map;
+import java.util.Set;
+import java.util.function.BiConsumer;
public class HumanToMachinePrefixConverter {
private final AppInfoWithClassHierarchy appInfo;
+ private final MachineRewritingFlags.Builder builder;
+ private final String synthesizedPrefix;
+ private final Map<DexString, DexString> descriptorPrefix;
+ private final Map<DexType, DexType> reverse = new IdentityHashMap<>();
+ private final Set<DexString> usedPrefix = Sets.newIdentityHashSet();
- public HumanToMachinePrefixConverter(AppInfoWithClassHierarchy appInfo) {
+ public HumanToMachinePrefixConverter(
+ AppInfoWithClassHierarchy appInfo,
+ MachineRewritingFlags.Builder builder,
+ String synthesizedPrefix,
+ Map<String, String> descriptorPrefix) {
this.appInfo = appInfo;
- }
-
- private DexString toDescriptorPrefix(String prefix) {
- return appInfo
- .dexItemFactory()
- .createString("L" + DescriptorUtils.getBinaryNameFromJavaType(prefix));
+ this.builder = builder;
+ this.synthesizedPrefix = synthesizedPrefix;
+ this.descriptorPrefix = convertRewritePrefix(descriptorPrefix);
}
public void convertPrefixFlags(
- HumanRewritingFlags rewritingFlags,
- MachineRewritingFlags.Builder builder,
- String synthesizedPrefix) {
- Map<DexString, DexString> descriptorPrefix = convertRewritePrefix(rewritingFlags);
- rewriteClasses(descriptorPrefix, builder);
- rewriteValues(descriptorPrefix, builder, rewritingFlags.getRetargetCoreLibMember());
- rewriteValues(descriptorPrefix, builder, rewritingFlags.getCustomConversions());
- rewriteEmulatedInterface(builder, rewritingFlags.getEmulateLibraryInterface());
- rewriteRetargetKeys(builder, rewritingFlags.getRetargetCoreLibMember(), synthesizedPrefix);
+ HumanRewritingFlags rewritingFlags, BiConsumer<String, Set<DexString>> warnConsumer) {
+ rewriteClasses();
+ rewriteValues(rewritingFlags.getRetargetCoreLibMember());
+ rewriteValues(rewritingFlags.getCustomConversions());
+ rewriteEmulatedInterface(rewritingFlags.getEmulateLibraryInterface());
+ rewriteRetargetKeys(rewritingFlags.getRetargetCoreLibMember());
+ rewriteReverse();
+ warnIfUnusedPrefix(warnConsumer);
}
- public DexType convertJavaNameToDesugaredLibrary(DexType type, String prefix) {
- String convertedPrefix = DescriptorUtils.getJavaTypeFromBinaryName(prefix);
+ private void warnIfUnusedPrefix(BiConsumer<String, Set<DexString>> warnConsumer) {
+ Set<DexString> prefixes = Sets.newIdentityHashSet();
+ prefixes.addAll(descriptorPrefix.keySet());
+ prefixes.removeAll(usedPrefix);
+ warnConsumer.accept("The following prefixes do not match any type: ", prefixes);
+ }
+
+ // For custom conversions, this is responsible in rewriting backward.
+ private void rewriteReverse() {
+ reverse.forEach(
+ (rewrittenType, type) -> {
+ DexType chainType = rewrittenType(rewrittenType);
+ if (chainType != null) {
+ builder.rewriteType(rewrittenType, chainType);
+ }
+ });
+ }
+
+ public DexType convertJavaNameToDesugaredLibrary(DexType type) {
+ String convertedPrefix = DescriptorUtils.getJavaTypeFromBinaryName(synthesizedPrefix);
String interfaceType = type.toString();
int firstPackage = interfaceType.indexOf('.');
return appInfo
@@ -52,49 +79,65 @@
convertedPrefix + interfaceType.substring(firstPackage + 1)));
}
- private void rewriteRetargetKeys(
- MachineRewritingFlags.Builder builder, Map<DexMethod, DexType> retarget, String prefix) {
+ private void rewriteRetargetKeys(Map<DexMethod, DexType> retarget) {
for (DexMethod dexMethod : retarget.keySet()) {
- DexType type = convertJavaNameToDesugaredLibrary(dexMethod.holder, prefix);
+ DexType type = convertJavaNameToDesugaredLibrary(dexMethod.holder);
builder.rewriteDerivedTypeOnly(dexMethod.holder, type);
}
}
- private void rewriteEmulatedInterface(
- MachineRewritingFlags.Builder builder, Map<DexType, DexType> emulateLibraryInterface) {
+ private void rewriteEmulatedInterface(Map<DexType, DexType> emulateLibraryInterface) {
emulateLibraryInterface.forEach(builder::rewriteDerivedTypeOnly);
}
+ private void rewriteType(DexType type, DexType rewrittenType) {
+ builder.rewriteType(type, rewrittenType);
+ reverse.put(rewrittenType, type);
+ }
+
private void rewriteValues(
- Map<DexString, DexString> descriptorPrefix,
- MachineRewritingFlags.Builder builder,
Map<?, DexType> flags) {
for (DexType type : flags.values()) {
- DexType rewrittenType = rewrittenType(descriptorPrefix, type);
- if (rewrittenType != null) {
- builder.rewriteType(type, rewrittenType);
- }
+ registerType(type);
}
}
- private void rewriteClasses(
- Map<DexString, DexString> descriptorPrefix, MachineRewritingFlags.Builder builder) {
- for (DexProgramClass clazz : appInfo.classes()) {
- DexType type = clazz.type;
- DexType rewrittenType = rewrittenType(descriptorPrefix, type);
- if (rewrittenType != null) {
- builder.rewriteType(type, rewrittenType);
- }
+ private void rewriteClasses() {
+ for (DexClass clazz : appInfo.app().asDirect().libraryClasses()) {
+ rewriteClass(clazz);
+ }
+ for (DexClass clazz : appInfo.classes()) {
+ rewriteClass(clazz);
}
}
- private DexType rewrittenType(Map<DexString, DexString> descriptorPrefix, DexType type) {
+ private void rewriteClass(DexClass clazz) {
+ registerType(clazz.type);
+ // We allow missing referenced types for the work-in-progress desugaring.
+ if (clazz.superType != null) {
+ registerType(clazz.superType);
+ }
+ clazz.interfaces.forEach(this::registerType);
+ if (clazz.getInnerClasses() != null) {
+ clazz.getInnerClasses().forEach(attr -> attr.forEachType(this::registerType));
+ }
+ }
+
+ private void registerType(DexType type) {
+ DexType rewrittenType = rewrittenType(type);
+ if (rewrittenType != null) {
+ rewriteType(type, rewrittenType);
+ }
+ }
+
+ private DexType rewrittenType(DexType type) {
DexString prefixToMatch = type.descriptor.withoutArray(appInfo.dexItemFactory());
for (DexString prefix : descriptorPrefix.keySet()) {
if (prefixToMatch.startsWith(prefix)) {
DexString rewrittenTypeDescriptor =
type.descriptor.withNewPrefix(
prefix, descriptorPrefix.get(prefix), appInfo.dexItemFactory());
+ usedPrefix.add(prefix);
return appInfo.dexItemFactory().createType(rewrittenTypeDescriptor);
}
}
@@ -102,12 +145,17 @@
}
private ImmutableMap<DexString, DexString> convertRewritePrefix(
- HumanRewritingFlags rewritingFlags) {
- Map<String, String> rewritePrefix = rewritingFlags.getRewritePrefix();
+ Map<String, String> rewritePrefix) {
ImmutableMap.Builder<DexString, DexString> mapBuilder = ImmutableMap.builder();
for (String key : rewritePrefix.keySet()) {
mapBuilder.put(toDescriptorPrefix(key), toDescriptorPrefix(rewritePrefix.get(key)));
}
return mapBuilder.build();
}
+
+ private DexString toDescriptorPrefix(String prefix) {
+ return appInfo
+ .dexItemFactory()
+ .createString("L" + DescriptorUtils.getBinaryNameFromJavaType(prefix));
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineRetargetConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineRetargetConverter.java
index 6dce945..e153c70 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineRetargetConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineRetargetConverter.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProto;
+import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.MethodResolutionResult;
import com.android.tools.r8.graph.SubtypingInfo;
@@ -18,27 +19,33 @@
import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineRewritingFlags;
import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
import com.android.tools.r8.utils.TraversalContinuation;
+import com.google.common.collect.Sets;
import java.util.LinkedHashMap;
import java.util.Map;
+import java.util.Set;
import java.util.function.BiConsumer;
public class HumanToMachineRetargetConverter {
private final AppInfoWithClassHierarchy appInfo;
- private SubtypingInfo subtypingInfo;
+ private final SubtypingInfo subtypingInfo;
+ private final Set<DexMethod> missingMethods = Sets.newIdentityHashSet();
public HumanToMachineRetargetConverter(AppInfoWithClassHierarchy appInfo) {
this.appInfo = appInfo;
+ subtypingInfo = SubtypingInfo.create(appInfo);
}
public void convertRetargetFlags(
- HumanRewritingFlags rewritingFlags, MachineRewritingFlags.Builder builder) {
- subtypingInfo = SubtypingInfo.create(appInfo);
+ HumanRewritingFlags rewritingFlags,
+ MachineRewritingFlags.Builder builder,
+ BiConsumer<String, Set<? extends DexReference>> warnConsumer) {
rewritingFlags
.getRetargetCoreLibMember()
.forEach(
(method, type) ->
convertRetargetCoreLibMemberFlag(builder, rewritingFlags, method, type));
+ warnConsumer.accept("Cannot retarget missing methods: ", missingMethods);
}
private void convertRetargetCoreLibMemberFlag(
@@ -48,7 +55,16 @@
DexType type) {
DexClass holder = appInfo.definitionFor(method.holder);
DexEncodedMethod foundMethod = holder.lookupMethod(method);
- assert foundMethod != null;
+ if (foundMethod == null && method.getName().toString().equals("deepEquals0")) {
+ // TODO(b/184026720): Temporary work-around (the method is missing).
+ DexMethod dest = method.withHolder(type, appInfo.dexItemFactory());
+ builder.putStaticRetarget(method, dest);
+ return;
+ }
+ if (foundMethod == null) {
+ missingMethods.add(foundMethod.getReference());
+ return;
+ }
if (foundMethod.isStatic()) {
convertStaticRetarget(builder, foundMethod, type);
return;
@@ -65,14 +81,16 @@
HumanRewritingFlags rewritingFlags,
DexEncodedMethod src,
DexType type) {
- if (isEmulatedInterfaceDispatch(src, appInfo, rewritingFlags)) {
- // Handled by emulated interface dispatch.
- return;
- }
- // TODO(b/184026720): Implement library boundaries.
DexProto newProto = appInfo.dexItemFactory().prependHolderToProto(src.getReference());
DexMethod forwardingDexMethod =
appInfo.dexItemFactory().createMethod(type, newProto, src.getName());
+ if (isEmulatedInterfaceDispatch(src, appInfo, rewritingFlags)) {
+ // Handled by emulated interface dispatch.
+ builder.putEmulatedVirtualRetargetThroughEmulatedInterface(
+ src.getReference(), forwardingDexMethod);
+ return;
+ }
+ // TODO(b/184026720): Implement library boundaries.
DerivedMethod forwardingMethod = new DerivedMethod(forwardingDexMethod);
DerivedMethod interfaceMethod =
new DerivedMethod(src.getReference(), SyntheticKind.RETARGET_INTERFACE);
@@ -92,10 +110,14 @@
DexClass subclass = appInfo.definitionFor(subtype);
MethodResolutionResult resolutionResult =
appInfo.resolveMethodOn(subclass, src.getReference());
- if (resolutionResult.isSuccessfulMemberResolutionResult()
- && resolutionResult.getResolvedMethod().getReference() != src.getReference()) {
- assert false; // Unsupported.
- }
+ // The resolution is not successful when compiling to dex if the method rewritten is missing
+ // in Android.jar.
+ assert !resolutionResult.isSuccessfulMemberResolutionResult()
+ || resolutionResult.getResolvedMethod().getReference() == src.getReference()
+ // There is a difference in the sql library between Android.jar and the JDK which leads
+ // to this resolution when compiling Cf to Cf while the methods do not exist in Android.
+ || (resolutionResult.getResolvedMethod().getHolderType().toString().contains("java.sql")
+ && resolutionResult.getResolvedMethod().getName().toString().equals("toInstant"));
}
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java
index bc3a663..c668858 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java
@@ -4,15 +4,22 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion;
+import com.android.tools.r8.ClassFileResourceProvider;
+import com.android.tools.r8.ProgramResourceProvider;
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProto;
+import com.android.tools.r8.graph.DexReference;
+import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecification;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanRewritingFlags;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanTopLevelFlags;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.CustomConversionDescriptor;
import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineRewritingFlags;
import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineTopLevelFlags;
@@ -22,20 +29,58 @@
import com.android.tools.r8.utils.Timing;
import java.io.IOException;
import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
import java.util.concurrent.ExecutorService;
public class HumanToMachineSpecificationConverter {
+ private AppView<?> appView;
+
public MachineDesugaredLibrarySpecification convert(
- HumanDesugaredLibrarySpecification humanSpec, Path androidLib, InternalOptions options)
+ HumanDesugaredLibrarySpecification humanSpec,
+ List<ProgramResourceProvider> desugaredJDKLib,
+ List<ClassFileResourceProvider> library,
+ InternalOptions options)
throws IOException {
- DexApplication app = readApp(androidLib, options);
- AppView<?> appView = AppView.createForD8(AppInfo.createInitialAppInfo(app));
+ assert !humanSpec.isLibraryCompilation() || desugaredJDKLib != null;
+ AndroidApp.Builder builder = AndroidApp.builder();
+ for (ClassFileResourceProvider classFileResourceProvider : library) {
+ builder.addLibraryResourceProvider(classFileResourceProvider);
+ }
+ if (humanSpec.isLibraryCompilation()) {
+ for (ProgramResourceProvider programResourceProvider : desugaredJDKLib) {
+ builder.addProgramResourceProvider(programResourceProvider);
+ }
+ }
+ return internalConvert(humanSpec, builder.build(), options);
+ }
+
+ public MachineDesugaredLibrarySpecification convert(
+ HumanDesugaredLibrarySpecification humanSpec,
+ Path desugaredJDKLib,
+ Path androidLib,
+ InternalOptions options)
+ throws IOException {
+ assert !humanSpec.isLibraryCompilation() || desugaredJDKLib != null;
+ AndroidApp.Builder builder = AndroidApp.builder();
+ if (humanSpec.isLibraryCompilation()) {
+ builder.addProgramFile(desugaredJDKLib);
+ }
+ AndroidApp inputApp = builder.addLibraryFile(androidLib).build();
+ return internalConvert(humanSpec, inputApp, options);
+ }
+
+ private MachineDesugaredLibrarySpecification internalConvert(
+ HumanDesugaredLibrarySpecification humanSpec, AndroidApp inputApp, InternalOptions options)
+ throws IOException {
+ DexApplication app = readApp(inputApp, options);
+ appView = AppView.createForD8(AppInfo.createInitialAppInfo(app));
+ LibraryValidator.validate(app, humanSpec.getTopLevelFlags().getRequiredCompilationAPILevel());
MachineRewritingFlags machineRewritingFlags =
convertRewritingFlags(
- humanSpec.getSynthesizedLibraryClassesPackagePrefix(),
- humanSpec.getRewritingFlags(),
- appView.appInfoForDesugaring());
+ humanSpec.getSynthesizedLibraryClassesPackagePrefix(), humanSpec.getRewritingFlags());
MachineTopLevelFlags topLevelFlags = convertTopLevelFlags(humanSpec.getTopLevelFlags());
return new MachineDesugaredLibrarySpecification(
humanSpec.isLibraryCompilation(), topLevelFlags, machineRewritingFlags);
@@ -52,34 +97,69 @@
}
private MachineRewritingFlags convertRewritingFlags(
- String synthesizedPrefix,
- HumanRewritingFlags rewritingFlags,
- AppInfoWithClassHierarchy appInfo) {
+ String synthesizedPrefix, HumanRewritingFlags rewritingFlags) {
+ AppInfoWithClassHierarchy appInfo = appView.appInfoForDesugaring();
MachineRewritingFlags.Builder builder = MachineRewritingFlags.builder();
- new HumanToMachineRetargetConverter(appInfo).convertRetargetFlags(rewritingFlags, builder);
+ new HumanToMachineRetargetConverter(appInfo)
+ .convertRetargetFlags(rewritingFlags, builder, this::warnMissingReferences);
new HumanToMachineEmulatedInterfaceConverter(appInfo)
- .convertEmulatedInterfaces(rewritingFlags, appInfo, builder);
- new HumanToMachinePrefixConverter(appInfo)
- .convertPrefixFlags(rewritingFlags, builder, synthesizedPrefix);
- new HumanToMachineWrapperConverter(appInfo).convertWrappers(rewritingFlags, builder);
+ .convertEmulatedInterfaces(rewritingFlags, appInfo, builder, this::warnMissingReferences);
+ new HumanToMachinePrefixConverter(
+ appInfo, builder, synthesizedPrefix, rewritingFlags.getRewritePrefix())
+ .convertPrefixFlags(rewritingFlags, this::warnMissingDexString);
+ new HumanToMachineWrapperConverter(appInfo)
+ .convertWrappers(rewritingFlags, builder, this::warnMissingReferences);
rewritingFlags
.getCustomConversions()
.forEach(
(type, conversionType) ->
- builder.putCustomConversion(
- type, conversionType, appInfo.dexItemFactory().convertMethodName));
- for (DexType type : rewritingFlags.getDontRetargetLibMember()) {
- builder.addDontRetarget(type);
- }
+ convertCustomConversion(appInfo, builder, type, conversionType));
+ rewritingFlags.getDontRetargetLibMember().forEach(builder::addDontRetarget);
rewritingFlags.getBackportCoreLibraryMember().forEach(builder::putLegacyBackport);
return builder.build();
}
- private DexApplication readApp(Path androidLib, InternalOptions options) throws IOException {
- AndroidApp androidApp = AndroidApp.builder().addProgramFile(androidLib).build();
- ApplicationReader applicationReader =
- new ApplicationReader(androidApp, options, Timing.empty());
+ private void convertCustomConversion(
+ AppInfoWithClassHierarchy appInfo,
+ MachineRewritingFlags.Builder builder,
+ DexType type,
+ DexType conversionType) {
+ DexType rewrittenType = builder.getRewrittenType(type);
+ DexProto fromProto = appInfo.dexItemFactory().createProto(rewrittenType, type);
+ DexMethod fromMethod =
+ appInfo
+ .dexItemFactory()
+ .createMethod(conversionType, fromProto, appInfo.dexItemFactory().convertMethodName);
+ DexProto toProto = appInfo.dexItemFactory().createProto(type, rewrittenType);
+ DexMethod toMethod =
+ appInfo
+ .dexItemFactory()
+ .createMethod(conversionType, toProto, appInfo.dexItemFactory().convertMethodName);
+ builder.putCustomConversion(type, new CustomConversionDescriptor(toMethod, fromMethod));
+ }
+
+ private DexApplication readApp(AndroidApp inputApp, InternalOptions options) throws IOException {
+ ApplicationReader applicationReader = new ApplicationReader(inputApp, options, Timing.empty());
ExecutorService executorService = ThreadUtils.getExecutorService(options);
return applicationReader.read(executorService).toDirect();
}
+
+ void warnMissingReferences(String message, Set<? extends DexReference> missingReferences) {
+ List<DexReference> memberList = new ArrayList<>(missingReferences);
+ memberList.sort(DexReference::compareTo);
+ warn(message, memberList);
+ }
+
+ void warnMissingDexString(String message, Set<DexString> missingDexString) {
+ List<DexString> memberList = new ArrayList<>(missingDexString);
+ memberList.sort(DexString::compareTo);
+ warn(message, memberList);
+ }
+
+ private void warn(String message, List<?> memberList) {
+ if (memberList.isEmpty()) {
+ return;
+ }
+ appView.options().reporter.warning("Specification conversion: " + message + memberList);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineWrapperConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineWrapperConverter.java
index db87890..815cb45 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineWrapperConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineWrapperConverter.java
@@ -8,30 +8,47 @@
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanRewritingFlags;
import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineRewritingFlags;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
+import java.util.Set;
+import java.util.function.BiConsumer;
public class HumanToMachineWrapperConverter {
private final AppInfoWithClassHierarchy appInfo;
+ private final Set<DexType> missingClasses = Sets.newIdentityHashSet();
public HumanToMachineWrapperConverter(AppInfoWithClassHierarchy appInfo) {
this.appInfo = appInfo;
}
public void convertWrappers(
- HumanRewritingFlags rewritingFlags, MachineRewritingFlags.Builder builder) {
- for (DexType wrapperConversion : rewritingFlags.getWrapperConversions()) {
- DexClass wrapperClass = appInfo.definitionFor(wrapperConversion);
- assert wrapperClass != null;
- List<DexMethod> methods = allImplementedMethods(wrapperClass);
- methods.sort(DexMethod::compareTo);
- builder.addWrapper(wrapperConversion, methods);
+ HumanRewritingFlags rewritingFlags,
+ MachineRewritingFlags.Builder builder,
+ BiConsumer<String, Set<? extends DexReference>> warnConsumer) {
+ for (DexType wrapperType : rewritingFlags.getWrapperConversions()) {
+ DexClass wrapperClass = appInfo.definitionFor(wrapperType);
+ if (wrapperClass == null) {
+ missingClasses.add(wrapperType);
+ continue;
+ }
+ List<DexMethod> methods;
+ if (wrapperClass.isEnum()) {
+ methods = ImmutableList.of();
+ } else {
+ methods = allImplementedMethods(wrapperClass);
+ methods.sort(DexMethod::compareTo);
+ }
+ builder.addWrapper(wrapperType, methods);
}
+ warnConsumer.accept("The following types to wrap are missing: ", missingClasses);
}
private List<DexMethod> allImplementedMethods(DexClass wrapperClass) {
@@ -53,7 +70,8 @@
}
}
if (!alreadyAdded) {
- assert !virtualMethod.isFinal() : "Cannot wrap final method " + virtualMethod;
+ assert !virtualMethod.isFinal()
+ : "Cannot wrap final method " + virtualMethod + " while wrapping " + wrapperClass;
implementedMethods.add(virtualMethod.getReference());
}
}
@@ -66,7 +84,8 @@
}
if (dexClass.superType != appInfo.dexItemFactory().objectType) {
DexClass superClass = appInfo.definitionFor(dexClass.superType);
- assert superClass != null; // Cannot be null since we started from a LibraryClass.
+ assert superClass != null
+ : "Missing supertype " + dexClass.superType + " while wrapping " + wrapperClass;
workList.add(superClass);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LegacyToHumanSpecificationConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LegacyToHumanSpecificationConverter.java
index 34bf5fa..c4884a5 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LegacyToHumanSpecificationConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LegacyToHumanSpecificationConverter.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion;
+import com.android.tools.r8.ClassFileResourceProvider;
import com.android.tools.r8.StringConsumer;
import com.android.tools.r8.StringResource;
import com.android.tools.r8.dex.ApplicationReader;
@@ -44,6 +45,8 @@
public class LegacyToHumanSpecificationConverter {
+ private AndroidApiLevel legacyHackLevel = AndroidApiLevel.N_MR1;
+
public void convertAllAPILevels(
StringResource inputSpecification, Path androidLib, StringConsumer output)
throws IOException {
@@ -65,7 +68,9 @@
InternalOptions options)
throws IOException {
Origin origin = legacySpec.getOrigin();
- DexApplication app = readApp(androidLib, options);
+ AndroidApp androidApp = AndroidApp.builder().addLibraryFile(androidLib).build();
+ DexApplication app = readApp(androidApp, options);
+ LibraryValidator.validate(app, legacySpec.getTopLevelFlags().getRequiredCompilationAPILevel());
HumanTopLevelFlags humanTopLevelFlags = convertTopLevelFlags(legacySpec.getTopLevelFlags());
Int2ObjectArrayMap<HumanRewritingFlags> commonFlags =
convertRewritingFlagMap(legacySpec.getCommonFlags(), app, origin);
@@ -81,33 +86,60 @@
}
public HumanDesugaredLibrarySpecification convert(
+ LegacyDesugaredLibrarySpecification legacySpec,
+ List<ClassFileResourceProvider> library,
+ InternalOptions options)
+ throws IOException {
+ AndroidApp.Builder builder = AndroidApp.builder();
+ for (ClassFileResourceProvider classFileResourceProvider : library) {
+ builder.addLibraryResourceProvider(classFileResourceProvider);
+ }
+ return internalConvert(legacySpec, builder.build(), options);
+ }
+
+ public HumanDesugaredLibrarySpecification convert(
LegacyDesugaredLibrarySpecification legacySpec, Path androidLib, InternalOptions options)
throws IOException {
- DexApplication app = readApp(androidLib, options);
- HumanTopLevelFlags humanTopLevelFlags = convertTopLevelFlags(legacySpec.getTopLevelFlags());
+ AndroidApp androidApp = AndroidApp.builder().addLibraryFile(androidLib).build();
+ return internalConvert(legacySpec, androidApp, options);
+ }
+ public HumanDesugaredLibrarySpecification internalConvert(
+ LegacyDesugaredLibrarySpecification legacySpec, AndroidApp inputApp, InternalOptions options)
+ throws IOException {
+ DexApplication app = readApp(inputApp, options);
+ LibraryValidator.validate(app, legacySpec.getTopLevelFlags().getRequiredCompilationAPILevel());
+ HumanTopLevelFlags humanTopLevelFlags = convertTopLevelFlags(legacySpec.getTopLevelFlags());
// The origin is not maintained in non multi-level specifications.
// It should not matter since the origin is used to report invalid specifications, and
// converting non multi-level specifications should be performed only with *valid*
// specifications in practical cases.
Origin origin = Origin.unknown();
-
HumanRewritingFlags humanRewritingFlags =
convertRewritingFlags(legacySpec.getRewritingFlags(), app, origin);
+ if (options.getMinApiLevel().isLessThanOrEqualTo(legacyHackLevel)
+ && legacySpec.isLibraryCompilation()) {
+ HumanRewritingFlags.Builder builder =
+ humanRewritingFlags.newBuilder(app.dexItemFactory(), app.options.reporter, origin);
+ legacyLibraryFlagHacks(app.dexItemFactory(), builder);
+ humanRewritingFlags = builder.build();
+ }
return new HumanDesugaredLibrarySpecification(
- humanTopLevelFlags,
- humanRewritingFlags,
- legacySpec.isLibraryCompilation(),
- app.dexItemFactory());
+ humanTopLevelFlags, humanRewritingFlags, legacySpec.isLibraryCompilation());
}
private void legacyLibraryFlagHacks(
Int2ObjectArrayMap<HumanRewritingFlags> libraryFlags, DexApplication app, Origin origin) {
- int level = AndroidApiLevel.N_MR1.getLevel();
+ int level = legacyHackLevel.getLevel();
HumanRewritingFlags humanRewritingFlags = libraryFlags.get(level);
HumanRewritingFlags.Builder builder =
humanRewritingFlags.newBuilder(app.dexItemFactory(), app.options.reporter, origin);
- DexItemFactory itemFactory = app.dexItemFactory();
+ legacyLibraryFlagHacks(app.dexItemFactory(), builder);
+ libraryFlags.put(level, builder.build());
+ }
+
+ private void legacyLibraryFlagHacks(
+ DexItemFactory itemFactory, HumanRewritingFlags.Builder builder) {
// TODO(b/177977763): This is only a workaround rewriting invokes of j.u.Arrays.deepEquals0
// to j.u.DesugarArrays.deepEquals0.
@@ -130,14 +162,10 @@
source = itemFactory.createMethod(itemFactory.createType("Ljava/util/TimeZone;"), proto, name);
target = itemFactory.createType("Ljava/util/DesugarTimeZone;");
builder.putRetargetCoreLibMember(source, target);
-
- libraryFlags.put(level, builder.build());
}
- private DexApplication readApp(Path androidLib, InternalOptions options) throws IOException {
- AndroidApp androidApp = AndroidApp.builder().addLibraryFile(androidLib).build();
- ApplicationReader applicationReader =
- new ApplicationReader(androidApp, options, Timing.empty());
+ private DexApplication readApp(AndroidApp inputApp, InternalOptions options) throws IOException {
+ ApplicationReader applicationReader = new ApplicationReader(inputApp, options, Timing.empty());
ExecutorService executorService = ThreadUtils.getExecutorService(options);
return applicationReader.read(executorService).toDirect();
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LibraryValidator.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LibraryValidator.java
new file mode 100644
index 0000000..b415c354
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LibraryValidator.java
@@ -0,0 +1,36 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion;
+
+import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.utils.AndroidApiLevel;
+
+public class LibraryValidator {
+
+ // Estimates if the library passed is at the expected minimum level, if it is not, raise
+ // a warning.
+ public static void validate(DexApplication app, AndroidApiLevel requiredCompilationAPILevel) {
+ DexType levelType;
+ if (requiredCompilationAPILevel.isEqualTo(AndroidApiLevel.O)) {
+ levelType = app.dexItemFactory.createType("Ljava/time/LocalTime;");
+ } else if (requiredCompilationAPILevel.isEqualTo(AndroidApiLevel.R)) {
+ levelType = app.dexItemFactory.createType("Ljava/util/concurrent/Flow;");
+ } else {
+ app.options.reporter.warning(
+ "Unsupported requiredCompilationAPILevel: " + requiredCompilationAPILevel);
+ return;
+ }
+ DexClass dexClass = app.definitionFor(levelType);
+ if (dexClass == null) {
+ app.options.reporter.warning(
+ "Desugared library requires to be compiled with a library file of API greater or equal to"
+ + " "
+ + requiredCompilationAPILevel
+ + ", but it seems the library file passed is of a lower API.");
+ }
+ }
+}
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 758812e..33f7037 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
@@ -24,10 +24,10 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GenericSignature;
import com.android.tools.r8.graph.GenericSignature.ClassTypeSignature;
-import com.android.tools.r8.graph.LibraryMethod;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.MethodResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.DerivedMethod;
import com.android.tools.r8.position.MethodPosition;
import com.android.tools.r8.utils.BooleanBox;
import com.android.tools.r8.utils.BooleanUtils;
@@ -49,7 +49,6 @@
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
-import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import org.objectweb.asm.Opcodes;
@@ -376,12 +375,7 @@
this.dexItemFactory = appView.dexItemFactory();
this.helper = new InterfaceDesugaringSyntheticHelper(appView);
needsLibraryInfo =
- !appView.options().desugaredLibrarySpecification.getEmulateLibraryInterface().isEmpty()
- || !appView
- .options()
- .desugaredLibrarySpecification
- .getRetargetCoreLibMember()
- .isEmpty();
+ appView.options().machineDesugaredLibrarySpecification.hasEmulatedInterfaces();
this.isLiveMethod = isLiveMethod;
}
@@ -510,7 +504,7 @@
DexClass iface = appView.definitionFor(emulatedInterface);
if (iface != null) {
assert iface.isLibraryClass()
- || appView.options().desugaredLibrarySpecification.isLibraryCompilation();
+ || appView.options().machineDesugaredLibrarySpecification.isLibraryCompilation();
workList.addIfNotSeen(iface.getInterfaces());
}
}
@@ -670,10 +664,10 @@
resolveForwardForSignature(
clazz,
wrapper.get(),
- target -> {
+ (target, forward) -> {
if (isLiveMethod(target) && !superInfo.isTargetedByForwards(target)) {
additionalForwards.add(target);
- addForwardingMethod(target, clazz);
+ addForwardingMethod(target, forward, clazz);
}
});
}
@@ -682,7 +676,7 @@
// Looks up a method signature from the point of 'clazz', if it can dispatch to a default method
// the 'addForward' call-back is called with the target of the forward.
private void resolveForwardForSignature(
- DexClass clazz, DexMethod method, Consumer<DexClassAndMethod> addForward) {
+ DexClass clazz, DexMethod method, BiConsumer<DexClassAndMethod, DexMethod> addForward) {
AppInfoWithClassHierarchy appInfo = appView.appInfoForDesugaring();
MethodResolutionResult resolutionResult = appInfo.resolveMethodOn(clazz, method);
if (resolutionResult.isFailedResolution()
@@ -722,50 +716,22 @@
resolutionResult.lookupVirtualDispatchTarget(clazz, appInfo);
assert virtualDispatchTarget != null;
- // Don't forward if the target is explicitly marked as 'dont-rewrite'
- if (dontRewrite(virtualDispatchTarget)) {
- return;
- }
-
// If resolution targets a default interface method, forward it.
if (virtualDispatchTarget.isDefaultMethod()) {
- addForward.accept(virtualDispatchTarget);
+ addForward.accept(
+ virtualDispatchTarget,
+ helper.ensureDefaultAsMethodOfCompanionClassStub(virtualDispatchTarget).getReference());
return;
}
- // Remaining edge cases only pertain to desugaring of library methods.
- if (!virtualDispatchTarget.isLibraryMethod() || ignoreLibraryInfo()) {
- return;
+ DerivedMethod forwardingMethod =
+ helper.computeEmulatedInterfaceForwardingMethod(
+ virtualDispatchTarget.getHolder(), virtualDispatchTarget);
+ if (forwardingMethod != null) {
+ DexMethod concreteForwardingMethod =
+ helper.ensureEmulatedInterfaceForwardingMethod(forwardingMethod);
+ addForward.accept(virtualDispatchTarget, concreteForwardingMethod);
}
-
- LibraryMethod libraryMethod = virtualDispatchTarget.asLibraryMethod();
- if (isRetargetMethod(libraryMethod)) {
- addForward.accept(virtualDispatchTarget);
- return;
- }
-
- // If target is a non-interface library class it may be an emulated interface,
- // except on a rewritten type, where L8 has already dealt with the desugaring.
- if (!libraryMethod.getHolder().isInterface()
- && !appView.rewritePrefix.hasRewrittenType(libraryMethod.getHolderType(), appView)) {
- // Here we use step-3 of resolution to find a maximally specific default interface method.
- DexClassAndMethod result =
- appInfo.lookupMaximallySpecificMethod(libraryMethod.getHolder(), method);
- if (result != null && helper.isEmulatedInterface(result.getHolderType())) {
- addForward.accept(result);
- }
- }
- }
-
- private boolean isRetargetMethod(LibraryMethod method) {
- assert needsLibraryInfo();
- assert method.getDefinition().isNonPrivateVirtualMethod();
- return !method.getAccessFlags().isFinal()
- && appView.options().desugaredLibrarySpecification.retargetMethod(method, appView) != null;
- }
-
- private boolean dontRewrite(DexClassAndMethod method) {
- return needsLibraryInfo() && method.getHolder().isLibraryClass() && helper.dontRewrite(method);
}
// Construction of actual forwarding methods.
@@ -830,7 +796,8 @@
// Note: The parameter 'target' may be a public method on a class in case of desugared
// library retargeting (See below target.isInterface check).
- private void addForwardingMethod(DexClassAndMethod target, DexClass clazz) {
+ private void addForwardingMethod(
+ DexClassAndMethod target, DexMethod forwardMethod, DexClass clazz) {
if (!clazz.isProgramClass()) {
return;
}
@@ -847,10 +814,6 @@
// NOTE: Never add a forwarding method to methods of classes unknown or coming from android.jar
// even if this results in invalid code, these classes are never desugared.
// In desugared library, emulated interface methods can be overridden by retarget lib members.
- DexMethod forwardMethod =
- target.getHolder().isInterface()
- ? helper.ensureDefaultAsMethodOfCompanionClassStub(target).getReference()
- : appView.options().desugaredLibrarySpecification.retargetMethod(target, appView);
DexEncodedMethod desugaringForwardingMethod =
DexEncodedMethod.createDesugaringForwardingMethod(
target.getDefinition(), clazz, forwardMethod, dexItemFactory);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceApplicationRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceApplicationRewriter.java
index 74d94e3..d06fee7 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceApplicationRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceApplicationRewriter.java
@@ -15,6 +15,7 @@
import com.android.tools.r8.utils.IterableUtils;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
@@ -25,8 +26,15 @@
public EmulatedInterfaceApplicationRewriter(AppView<?> appView) {
this.appView = appView;
- this.emulatedInterfaces =
- appView.options().desugaredLibrarySpecification.getEmulateLibraryInterface();
+ emulatedInterfaces = new IdentityHashMap<>();
+ appView
+ .options()
+ .machineDesugaredLibrarySpecification
+ .getEmulatedInterfaces()
+ .forEach(
+ (ei, descriptor) -> {
+ emulatedInterfaces.put(ei, descriptor.getRewrittenType());
+ });
}
public void rewriteApplication(DexApplication.Builder<?> builder) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringForTesting.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringForTesting.java
index a3e0164..6636e1e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringForTesting.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringForTesting.java
@@ -4,10 +4,12 @@
package com.android.tools.r8.ir.desugar.itf;
+import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
+
public class InterfaceDesugaringForTesting {
public static String getEmulateLibraryClassNameSuffix() {
- return InterfaceDesugaringSyntheticHelper.EMULATE_LIBRARY_CLASS_NAME_SUFFIX;
+ return SyntheticKind.EMULATED_INTERFACE_CLASS.descriptor;
}
public static String getCompanionClassNameSuffix() {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java
index 77d99e5..5d00719 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java
@@ -24,6 +24,7 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexValue.DexValueInt;
@@ -31,19 +32,20 @@
import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
import com.android.tools.r8.graph.InvalidCode;
import com.android.tools.r8.graph.MethodAccessFlags;
+import com.android.tools.r8.graph.MethodResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.ThrowNullCode;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.DerivedMethod;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.EmulatedDispatchMethodDescriptor;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.EmulatedInterfaceDescriptor;
import com.android.tools.r8.ir.desugar.itf.EmulatedInterfaceSynthesizerEventConsumer.ClasspathEmulatedInterfaceSynthesizerEventConsumer;
import com.android.tools.r8.synthesis.SyntheticClassBuilder;
import com.android.tools.r8.synthesis.SyntheticMethodBuilder;
import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.Pair;
import com.android.tools.r8.utils.structural.Ordered;
import com.google.common.collect.ImmutableList;
-import java.util.Map;
-import java.util.Set;
import java.util.function.Predicate;
public class InterfaceDesugaringSyntheticHelper {
@@ -57,37 +59,37 @@
}
// Use InterfaceDesugaringForTesting for public accesses in tests.
- static final String EMULATE_LIBRARY_CLASS_NAME_SUFFIX = "$-EL";
static final String COMPANION_CLASS_NAME_SUFFIX = "$-CC";
static final String DEFAULT_METHOD_PREFIX = "$default$";
static final String PRIVATE_METHOD_PREFIX = "$private$";
private final AppView<?> appView;
- private final Map<DexType, DexType> emulatedInterfaces;
private final Predicate<DexType> shouldIgnoreFromReportsPredicate;
public InterfaceDesugaringSyntheticHelper(AppView<?> appView) {
this.appView = appView;
- emulatedInterfaces =
- appView.options().desugaredLibrarySpecification.getEmulateLibraryInterface();
-
this.shouldIgnoreFromReportsPredicate = getShouldIgnoreFromReportsPredicate(appView);
}
boolean isEmulatedInterface(DexType itf) {
- return emulatedInterfaces.containsKey(itf);
+ return appView
+ .options()
+ .machineDesugaredLibrarySpecification
+ .getEmulatedInterfaces()
+ .containsKey(itf);
}
boolean isRewrittenEmulatedInterface(DexType itf) {
- return emulatedInterfaces.containsValue(itf);
- }
-
- Set<DexType> getEmulatedInterfaces() {
- return emulatedInterfaces.keySet();
+ return appView
+ .options()
+ .machineDesugaredLibrarySpecification
+ .isEmulatedInterfaceRewrittenType(itf);
}
DexType getEmulatedInterface(DexType type) {
- return emulatedInterfaces.get(type);
+ EmulatedInterfaceDescriptor interfaceDescriptor =
+ appView.options().machineDesugaredLibrarySpecification.getEmulatedInterfaces().get(type);
+ return interfaceDescriptor == null ? null : interfaceDescriptor.getRewrittenType();
}
boolean isInDesugaredLibrary(DexClass clazz) {
@@ -95,18 +97,7 @@
if (isEmulatedInterface(clazz.type)) {
return true;
}
- return appView.rewritePrefix.hasRewrittenType(clazz.type, appView);
- }
-
- boolean dontRewrite(DexClassAndMethod method) {
- for (Pair<DexType, DexString> dontRewrite :
- appView.options().desugaredLibrarySpecification.getDontRewriteInvocation()) {
- if (method.getHolderType() == dontRewrite.getFirst()
- && method.getName() == dontRewrite.getSecond()) {
- return true;
- }
- }
- return false;
+ return appView.typeRewriter.hasRewrittenType(clazz.type, appView);
}
final boolean isCompatibleDefaultMethod(DexEncodedMethod method) {
@@ -129,25 +120,15 @@
return true;
}
- public DexMethod emulateInterfaceLibraryMethod(DexClassAndMethod method) {
- DexItemFactory factory = appView.dexItemFactory();
- return factory.createMethod(
- getEmulateLibraryInterfaceClassType(method.getHolderType(), factory),
- factory.prependTypeToProto(method.getHolderType(), method.getProto()),
- method.getName());
+ DexMethod emulatedInterfaceDispatchMethod(DerivedMethod method, DexType holder) {
+ assert method.getHolderKind() == SyntheticKind.EMULATED_INTERFACE_CLASS;
+ DexProto newProto = appView.dexItemFactory().prependHolderToProto(method.getMethod());
+ return appView.dexItemFactory().createMethod(holder, newProto, method.getName());
}
- private static String getEmulateLibraryInterfaceClassDescriptor(String descriptor) {
- return descriptor.substring(0, descriptor.length() - 1)
- + EMULATE_LIBRARY_CLASS_NAME_SUFFIX
- + ";";
- }
-
- public static DexType getEmulateLibraryInterfaceClassType(DexType type, DexItemFactory factory) {
- assert type.isClassType();
- String descriptor = type.descriptor.toString();
- String elTypeDescriptor = getEmulateLibraryInterfaceClassDescriptor(descriptor);
- return factory.createSynthesizedType(elTypeDescriptor);
+ DexMethod emulatedInterfaceInterfaceMethod(DerivedMethod method) {
+ assert method.getHolderKind() == null;
+ return method.getMethod();
}
public static String getCompanionClassDescriptor(String descriptor) {
@@ -167,10 +148,6 @@
return type.descriptor.toString().endsWith(COMPANION_CLASS_NAME_SUFFIX + ";");
}
- public static boolean isEmulatedLibraryClassType(DexType type) {
- return type.descriptor.toString().endsWith(EMULATE_LIBRARY_CLASS_NAME_SUFFIX + ";");
- }
-
// Gets the interface class for a companion class `type`.
DexType getInterfaceClassType(DexType type) {
return getInterfaceClassType(type, appView.dexItemFactory());
@@ -194,12 +171,98 @@
SyntheticKind.EMULATED_INTERFACE_MARKER_CLASS,
type,
appView,
- SyntheticClassBuilder::setInterface);
+ SyntheticClassBuilder::setInterface,
+ ignored -> {});
}
- DexClassAndMethod ensureEmulatedInterfaceMethod(
- DexClassAndMethod method, ClasspathEmulatedInterfaceSynthesizerEventConsumer eventConsumer) {
- DexMethod emulatedInterfaceMethod = emulateInterfaceLibraryMethod(method);
+ DexClassAndMethod lookupMaximallySpecificIncludingSelf(
+ DexClass initialResolutionHolder, DexClassAndMethod method) {
+ assert method.getHolderType().isClassType();
+ if (method.getHolder().isInterface()) {
+ return method;
+ }
+ return appView
+ .appInfoForDesugaring()
+ .lookupMaximallySpecificMethod(initialResolutionHolder, method.getReference());
+ }
+
+ EmulatedDispatchMethodDescriptor getEmulatedDispatchDescriptor(
+ DexClass initialResolutionHolder, DexClassAndMethod method) {
+ if (method == null) {
+ return null;
+ }
+ assert initialResolutionHolder != null;
+ if (!requiresEmulatedDispatch(method)) {
+ return null;
+ }
+ DexClassAndMethod maximallySpecificMethod =
+ lookupMaximallySpecificIncludingSelf(initialResolutionHolder, method);
+ if (maximallySpecificMethod == null) {
+ return null;
+ }
+ return appView
+ .options()
+ .machineDesugaredLibrarySpecification
+ .getEmulatedInterfaceEmulatedDispatchMethodDescriptor(
+ maximallySpecificMethod.getReference());
+ }
+
+ private boolean requiresEmulatedDispatch(DexClassAndMethod method) {
+ return method.isLibraryMethod()
+ || isEmulatedInterface(method.getHolderType())
+ || appView
+ .options()
+ .machineDesugaredLibrarySpecification
+ .getEmulatedVirtualRetargetThroughEmulatedInterface()
+ .containsKey(method.getReference());
+ }
+
+ DerivedMethod computeEmulatedInterfaceDispatchMethod(MethodResolutionResult resolutionResult) {
+ EmulatedDispatchMethodDescriptor descriptor =
+ getEmulatedDispatchDescriptor(
+ resolutionResult.getInitialResolutionHolder(), resolutionResult.getResolutionPair());
+ return descriptor == null ? null : descriptor.getEmulatedDispatchMethod();
+ }
+
+ DerivedMethod computeEmulatedInterfaceForwardingMethod(
+ DexClass initialResolutionHolder, DexClassAndMethod method) {
+ if (method == null) {
+ return null;
+ }
+ DexMethod retarget =
+ appView
+ .options()
+ .machineDesugaredLibrarySpecification
+ .getEmulatedVirtualRetargetThroughEmulatedInterface()
+ .get(method.getReference());
+ if (retarget != null) {
+ return new DerivedMethod(retarget);
+ }
+ EmulatedDispatchMethodDescriptor descriptor =
+ getEmulatedDispatchDescriptor(initialResolutionHolder, method);
+ return descriptor == null ? null : descriptor.getForwardingMethod();
+ }
+
+ DexMethod ensureEmulatedInterfaceForwardingMethod(DerivedMethod method) {
+ if (method.getHolderKind() == null) {
+ return method.getMethod();
+ }
+ assert method.getHolderKind() == SyntheticKind.COMPANION_CLASS;
+ DexClassAndMethod resolvedMethod =
+ appView.appInfoForDesugaring().resolveMethod(method.getMethod(), true).getResolutionPair();
+ return ensureDefaultAsMethodOfCompanionClassStub(resolvedMethod).getReference();
+ }
+
+ DexClassAndMethod ensureEmulatedInterfaceDispatchMethod(
+ DerivedMethod emulatedDispatchMethod,
+ ClasspathEmulatedInterfaceSynthesizerEventConsumer eventConsumer) {
+ assert emulatedDispatchMethod.getHolderKind() == SyntheticKind.EMULATED_INTERFACE_CLASS;
+ DexClassAndMethod method =
+ appView
+ .appInfoForDesugaring()
+ .resolveMethod(emulatedDispatchMethod.getMethod(), true)
+ .getResolutionPair();
+ assert emulatedDispatchMethod.getHolderKind() == SyntheticKind.EMULATED_INTERFACE_CLASS;
if (method.isProgramMethod()) {
assert appView.options().isDesugaredLibraryCompilation();
DexProgramClass emulatedInterface =
@@ -209,8 +272,15 @@
SyntheticKind.EMULATED_INTERFACE_CLASS,
method.asProgramMethod().getHolder(),
appView);
+ DexMethod emulatedInterfaceMethod =
+ emulatedInterfaceDispatchMethod(emulatedDispatchMethod, emulatedInterface.type);
+ assert emulatedInterface.lookupProgramMethod(emulatedInterfaceMethod) != null;
return emulatedInterface.lookupProgramMethod(emulatedInterfaceMethod);
}
+ // The holder is not used.
+ DexMethod emulatedInterfaceMethod =
+ emulatedInterfaceDispatchMethod(
+ emulatedDispatchMethod, appView.dexItemFactory().objectType);
return appView
.getSyntheticItems()
.ensureFixedClasspathClassMethod(
@@ -508,10 +578,10 @@
return type -> {
DexString descriptor = type.getDescriptor();
- return appView.rewritePrefix.hasRewrittenType(type, appView)
+ return appView.typeRewriter.hasRewrittenType(type, appView)
|| descriptor.endsWith(companionClassNameDescriptorSuffix)
|| isRewrittenEmulatedInterface(type)
- || options.desugaredLibrarySpecification.getCustomConversions().containsValue(type)
+ || options.machineDesugaredLibrarySpecification.isCustomConversionRewrittenType(type)
|| appView.getDontWarnConfiguration().matches(type);
};
}
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 6740441..85efd2b 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
@@ -35,7 +35,8 @@
import com.android.tools.r8.ir.desugar.DesugarDescription;
import com.android.tools.r8.ir.desugar.FreshLocalProvider;
import com.android.tools.r8.ir.desugar.LocalStackAllocator;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.DerivedMethod;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
import com.android.tools.r8.ir.desugar.icce.AlwaysThrowingInstructionDesugaring;
import com.android.tools.r8.ir.desugar.lambda.LambdaInstructionDesugaring;
import com.android.tools.r8.ir.desugar.stringconcat.StringConcatInstructionDesugaring;
@@ -53,7 +54,6 @@
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
-import java.util.function.BiConsumer;
import java.util.function.Predicate;
//
@@ -119,18 +119,23 @@
}
public static void checkForAssumedLibraryTypes(AppInfo appInfo, InternalOptions options) {
- LegacyDesugaredLibrarySpecification spec = options.desugaredLibrarySpecification;
- BiConsumer<DexType, DexType> registerEntry = registerMapEntry(appInfo);
- spec.getEmulateLibraryInterface().forEach(registerEntry);
- spec.getCustomConversions().forEach(registerEntry);
- spec.getRetargetCoreLibMember().forEach((method, types) -> types.forEach(registerEntry));
- }
-
- private static BiConsumer<DexType, DexType> registerMapEntry(AppInfo appInfo) {
- return (key, value) -> {
- registerType(appInfo, key);
- registerType(appInfo, value);
- };
+ MachineDesugaredLibrarySpecification machineDesugaredLibrarySpecification =
+ options.machineDesugaredLibrarySpecification;
+ machineDesugaredLibrarySpecification
+ .getEmulatedInterfaces()
+ .forEach(
+ (ei, descriptor) -> {
+ registerType(appInfo, ei);
+ registerType(appInfo, descriptor.getRewrittenType());
+ });
+ machineDesugaredLibrarySpecification
+ .getCustomConversions()
+ .forEach(
+ (type, descriptor) -> {
+ registerType(appInfo, type);
+ registerType(appInfo, descriptor.getTo().getHolderType());
+ registerType(appInfo, descriptor.getFrom().getHolderType());
+ });
}
private static void registerType(AppInfo appInfo, DexType type) {
@@ -156,9 +161,9 @@
}
private void initializeEmulatedInterfaceVariables() {
- Map<DexType, DexType> emulateLibraryInterface =
- options.desugaredLibrarySpecification.getEmulateLibraryInterface();
- for (DexType interfaceType : emulateLibraryInterface.keySet()) {
+ Set<DexType> emulateLibraryInterface =
+ options.machineDesugaredLibrarySpecification.getEmulatedInterfaces().keySet();
+ for (DexType interfaceType : emulateLibraryInterface) {
DexClass emulatedInterfaceClass = appView.definitionFor(interfaceType);
if (emulatedInterfaceClass != null) {
for (DexEncodedMethod encodedMethod :
@@ -449,24 +454,27 @@
}
private DesugarDescription computeEmulatedInterfaceVirtualDispatchOrNull(CfInvoke invoke) {
- DexClassAndMethod defaultMethod =
- defaultMethodForEmulatedDispatchOrNull(invoke.getMethod(), invoke.isInterface());
- if (defaultMethod != null) {
- return DesugarDescription.builder()
- .setDesugarRewrite(
- (freshLocalProvider,
- localStackAllocator,
- eventConsumer,
- context1,
- methodProcessingContext,
- dexItemFactory) ->
- getInvokeStaticInstructions(
- helper
- .ensureEmulatedInterfaceMethod(defaultMethod, eventConsumer)
- .getReference()))
- .build();
+ MethodResolutionResult resolutionResult =
+ appView.appInfoForDesugaring().resolveMethod(invoke.getMethod(), invoke.isInterface());
+ DerivedMethod emulatedDispatchMethod =
+ helper.computeEmulatedInterfaceDispatchMethod(resolutionResult);
+ if (emulatedDispatchMethod == null) {
+ return null;
}
- return null;
+ return DesugarDescription.builder()
+ .setDesugarRewrite(
+ (freshLocalProvider,
+ localStackAllocator,
+ eventConsumer,
+ context1,
+ methodProcessingContext,
+ dexItemFactory) ->
+ getInvokeStaticInstructions(
+ helper
+ .ensureEmulatedInterfaceDispatchMethod(
+ emulatedDispatchMethod, eventConsumer)
+ .getReference()))
+ .build();
}
private DesugarDescription computeInvokeDirect(
@@ -704,103 +712,49 @@
private DesugarDescription computeEmulatedInterfaceInvokeSpecial(
DexClass clazz, DexMethod invokedMethod, ProgramMethod context) {
- DexType emulatedItf = maximallySpecificEmulatedInterfaceOrNull(invokedMethod);
- if (emulatedItf == null) {
- if (clazz.isInterface() && appView.rewritePrefix.hasRewrittenType(clazz.type, appView)) {
- DexClassAndMethod target =
- appView.appInfoForDesugaring().lookupSuperTarget(invokedMethod, context);
- if (target != null && target.getDefinition().isDefaultMethod()) {
- DexClass holder = target.getHolder();
- if (holder.isLibraryClass() && holder.isInterface()) {
- return DesugarDescription.builder()
- .setDesugarRewrite(
- (freshLocalProvider,
- localStackAllocator,
- eventConsumer,
- context13,
- methodProcessingContext,
- dexItemFactory) -> {
- DexClassAndMethod companionTarget =
- helper.ensureDefaultAsMethodOfCompanionClassStub(target);
- acceptCompanionMethod(target, companionTarget, eventConsumer);
- return getInvokeStaticInstructions(companionTarget.getReference());
- })
- .build();
- }
+ DexClassAndMethod superTarget =
+ appView.appInfoForDesugaring().lookupSuperTarget(invokedMethod, context);
+ if (clazz.isInterface() && appView.typeRewriter.hasRewrittenType(clazz.type, appView)) {
+ if (superTarget != null && superTarget.getDefinition().isDefaultMethod()) {
+ DexClass holder = superTarget.getHolder();
+ if (holder.isLibraryClass() && holder.isInterface()) {
+ return DesugarDescription.builder()
+ .setDesugarRewrite(
+ (freshLocalProvider,
+ localStackAllocator,
+ eventConsumer,
+ context13,
+ methodProcessingContext,
+ dexItemFactory) -> {
+ DexClassAndMethod companionTarget =
+ helper.ensureDefaultAsMethodOfCompanionClassStub(superTarget);
+ acceptCompanionMethod(superTarget, companionTarget, eventConsumer);
+ return getInvokeStaticInstructions(companionTarget.getReference());
+ })
+ .build();
}
}
- return DesugarDescription.nothing();
}
// That invoke super may not resolve since the super method may not be present
// since it's in the emulated interface. We need to force resolution. If it resolves
// to a library method, then it needs to be rewritten.
// If it resolves to a program overrides, the invoke-super can remain.
- DexClassAndMethod superTarget =
- appView.appInfoForDesugaring().lookupSuperTarget(invokedMethod, context);
- if (superTarget != null && superTarget.isLibraryMethod()) {
- // Rewriting is required because the super invoke resolves into a missing
- // method (method is on desugared library). Find out if it needs to be
- // retargeted or if it just calls a companion class method and rewrite.
- DexMethod retargetMethod =
- options.desugaredLibrarySpecification.retargetMethod(superTarget, appView);
- if (retargetMethod != null) {
- return DesugarDescription.builder()
- .setDesugarRewrite(
- (freshLocalProvider,
- localStackAllocator,
- eventConsumer,
- context14,
- methodProcessingContext,
- dexItemFactory) -> getInvokeStaticInstructions(retargetMethod))
- .build();
- }
- DexClassAndMethod emulatedMethod =
- superTarget.getReference().lookupMemberOnClass(appView.definitionFor(emulatedItf));
- if (emulatedMethod == null) {
- assert false;
- return DesugarDescription.nothing();
- }
- return DesugarDescription.builder()
- .setDesugarRewrite(
- (freshLocalProvider,
- localStackAllocator,
- eventConsumer,
- context15,
- methodProcessingContext,
- dexItemFactory) -> {
- DexClassAndMethod companionMethod =
- helper.ensureDefaultAsMethodOfCompanionClassStub(emulatedMethod);
- return getInvokeStaticInstructions(companionMethod.getReference());
- })
- .build();
+ DerivedMethod forwardingMethod =
+ helper.computeEmulatedInterfaceForwardingMethod(clazz, superTarget);
+ if (forwardingMethod == null) {
+ return DesugarDescription.nothing();
}
- return DesugarDescription.nothing();
- }
-
- private DexClassAndMethod defaultMethodForEmulatedDispatchOrNull(
- DexMethod invokedMethod, boolean interfaceBit) {
- DexType emulatedItf = maximallySpecificEmulatedInterfaceOrNull(invokedMethod);
- if (emulatedItf == null) {
- return null;
- }
- // The call potentially ends up in a library class, in which case we need to rewrite, since the
- // code may be in the desugared library.
- SingleResolutionResult resolution =
- appView
- .appInfoForDesugaring()
- .resolveMethod(invokedMethod, interfaceBit)
- .asSingleResolution();
- if (resolution != null
- && (resolution.getResolvedHolder().isLibraryClass()
- || helper.isEmulatedInterface(resolution.getResolvedHolder().type))) {
- DexClassAndMethod defaultMethod =
- appView.definitionFor(emulatedItf).lookupClassMethod(invokedMethod);
- if (defaultMethod != null && !helper.dontRewrite(defaultMethod)) {
- assert !defaultMethod.getAccessFlags().isAbstract();
- return defaultMethod;
- }
- }
- return null;
+ return DesugarDescription.builder()
+ .setDesugarRewrite(
+ (freshLocalProvider,
+ localStackAllocator,
+ eventConsumer,
+ context14,
+ methodProcessingContext,
+ dexItemFactory) ->
+ getInvokeStaticInstructions(
+ helper.ensureEmulatedInterfaceForwardingMethod(forwardingMethod)))
+ .build();
}
private boolean shouldRewriteToInvokeToThrow(
@@ -809,40 +763,6 @@
|| resolutionResult.getResolvedMethod().isStatic() != isInvokeStatic;
}
- private DexType maximallySpecificEmulatedInterfaceOrNull(DexMethod invokedMethod) {
- // Here we try to avoid doing the expensive look-up on all invokes.
- if (!emulatedMethods.contains(invokedMethod.name)) {
- return null;
- }
- DexClass dexClass = appView.definitionFor(invokedMethod.holder);
- // We cannot rewrite the invoke we do not know what the class is.
- if (dexClass == null) {
- return null;
- }
- DexEncodedMethod singleTarget = null;
- if (dexClass.isInterface()) {
- // Look for exact method on the interface.
- singleTarget = dexClass.lookupMethod(invokedMethod);
- }
- if (singleTarget == null) {
- DexClassAndMethod result =
- appView.appInfoForDesugaring().lookupMaximallySpecificMethod(dexClass, invokedMethod);
- if (result != null) {
- singleTarget = result.getDefinition();
- }
- }
- if (singleTarget == null) {
- // At this point we are in a library class. Failures can happen with NoSuchMethod if a
- // library class implement a method with same signature but not related to emulated
- // interfaces.
- return null;
- }
- if (!singleTarget.isAbstract() && helper.isEmulatedInterface(singleTarget.getHolderType())) {
- return singleTarget.getHolderType();
- }
- return null;
- }
-
private boolean isNonDesugaredLibraryClass(DexClass clazz) {
return clazz.isLibraryClass() && !helper.isInDesugaredLibrary(clazz);
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/ProgramEmulatedInterfaceSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/ProgramEmulatedInterfaceSynthesizer.java
index f712cb4..7e8a2cc 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/ProgramEmulatedInterfaceSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/ProgramEmulatedInterfaceSynthesizer.java
@@ -5,11 +5,9 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexProto;
-import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.ProgramMethod;
@@ -25,27 +23,16 @@
import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
import com.android.tools.r8.synthesis.SyntheticProgramClassBuilder;
import com.android.tools.r8.utils.StringDiagnostic;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
public final class ProgramEmulatedInterfaceSynthesizer implements CfClassSynthesizerDesugaring {
private final AppView<?> appView;
private final InterfaceDesugaringSyntheticHelper helper;
- private final Map<DexType, List<DexType>> emulatedInterfacesHierarchy;
public static ProgramEmulatedInterfaceSynthesizer create(AppView<?> appView) {
if (!appView.options().isDesugaredLibraryCompilation()
- || appView.options().desugaredLibrarySpecification.getEmulateLibraryInterface().isEmpty()) {
+ || !appView.options().machineDesugaredLibrarySpecification.hasEmulatedInterfaces()) {
return null;
}
return new ProgramEmulatedInterfaceSynthesizer(appView);
@@ -54,53 +41,11 @@
public ProgramEmulatedInterfaceSynthesizer(AppView<?> appView) {
this.appView = appView;
helper = new InterfaceDesugaringSyntheticHelper(appView);
- // Avoid the computation outside L8 since it is not needed.
- emulatedInterfacesHierarchy =
- appView.options().isDesugaredLibraryCompilation()
- ? processEmulatedInterfaceHierarchy()
- : Collections.emptyMap();
- }
-
- private Map<DexType, List<DexType>> processEmulatedInterfaceHierarchy() {
- Map<DexType, List<DexType>> emulatedInterfacesHierarchy = new IdentityHashMap<>();
- Set<DexType> processed = Sets.newIdentityHashSet();
- ArrayList<DexType> emulatedInterfacesSorted = new ArrayList<>(helper.getEmulatedInterfaces());
- emulatedInterfacesSorted.sort(DexType::compareTo);
- for (DexType interfaceType : emulatedInterfacesSorted) {
- processEmulatedInterfaceHierarchy(interfaceType, processed, emulatedInterfacesHierarchy);
- }
- return emulatedInterfacesHierarchy;
- }
-
- private void processEmulatedInterfaceHierarchy(
- DexType interfaceType,
- Set<DexType> processed,
- Map<DexType, List<DexType>> emulatedInterfacesHierarchy) {
- if (processed.contains(interfaceType)) {
- return;
- }
- emulatedInterfacesHierarchy.put(interfaceType, new ArrayList<>());
- processed.add(interfaceType);
- DexClass theInterface = appView.definitionFor(interfaceType);
- if (theInterface == null) {
- return;
- }
- LinkedList<DexType> workList = new LinkedList<>(Arrays.asList(theInterface.interfaces.values));
- while (!workList.isEmpty()) {
- DexType next = workList.removeLast();
- if (helper.isEmulatedInterface(next)) {
- processEmulatedInterfaceHierarchy(next, processed, emulatedInterfacesHierarchy);
- emulatedInterfacesHierarchy.get(next).add(interfaceType);
- DexClass nextClass = appView.definitionFor(next);
- if (nextClass != null) {
- workList.addAll(Arrays.asList(nextClass.interfaces.values));
- }
- }
- }
}
DexProgramClass synthesizeProgramEmulatedInterface(
DexProgramClass emulatedInterface,
+ EmulatedInterfaceDescriptor emulatedInterfaceDescriptor,
L8ProgramEmulatedInterfaceSynthesizerEventConsumer eventConsumer) {
return appView
.getSyntheticItems()
@@ -108,20 +53,26 @@
SyntheticNaming.SyntheticKind.EMULATED_INTERFACE_CLASS,
emulatedInterface,
appView,
- builder -> synthesizeEmulateInterfaceMethods(emulatedInterface, builder),
+ builder ->
+ synthesizeEmulateInterfaceMethods(
+ emulatedInterface, emulatedInterfaceDescriptor, builder),
eventConsumer::acceptProgramEmulatedInterface);
}
private void synthesizeEmulateInterfaceMethods(
- DexProgramClass emulatedInterface, SyntheticProgramClassBuilder builder) {
- assert helper.isEmulatedInterface(emulatedInterface.type);
+ DexProgramClass emulatedInterface,
+ EmulatedInterfaceDescriptor emulatedInterfaceDescriptor,
+ SyntheticProgramClassBuilder builder) {
emulatedInterface.forEachProgramVirtualMethodMatching(
- DexEncodedMethod::isDefaultMethod,
+ m -> emulatedInterfaceDescriptor.getEmulatedMethods().containsKey(m.getReference()),
method ->
builder.addMethod(
methodBuilder ->
synthesizeEmulatedInterfaceMethod(
- method, emulatedInterface, builder.getType(), methodBuilder)));
+ method,
+ emulatedInterfaceDescriptor.getEmulatedMethods().get(method.getReference()),
+ builder.getType(),
+ methodBuilder)));
}
private DexMethod emulatedMethod(DerivedMethod method, DexType holder) {
@@ -137,24 +88,17 @@
private void synthesizeEmulatedInterfaceMethod(
ProgramMethod method,
- DexProgramClass theInterface,
+ EmulatedDispatchMethodDescriptor descriptor,
DexType dispatchType,
SyntheticMethodBuilder methodBuilder) {
assert !method.getDefinition().isStatic();
- if (appView.options().testing.machineDesugaredLibrarySpecification != null) {
- synthesizeEmulatedInterfaceMethodFromMachineSpecification(
- method, theInterface, dispatchType, methodBuilder);
- return;
- }
- DexMethod emulatedMethod = helper.emulateInterfaceLibraryMethod(method);
- DexMethod itfMethod =
- method
- .getReference()
- .withHolder(helper.getEmulatedInterface(theInterface.type), appView.dexItemFactory());
+ DexMethod emulatedMethod =
+ helper.emulatedInterfaceDispatchMethod(
+ descriptor.getEmulatedDispatchMethod(), dispatchType);
+ DexMethod itfMethod = helper.emulatedInterfaceInterfaceMethod(descriptor.getInterfaceMethod());
DexMethod companionMethod =
- helper.ensureDefaultAsMethodOfProgramCompanionClassStub(method).getReference();
- LinkedHashMap<DexType, DexMethod> extraDispatchCases =
- getDispatchCases(method, theInterface, companionMethod);
+ helper.ensureEmulatedInterfaceForwardingMethod(descriptor.getForwardingMethod());
+ LinkedHashMap<DexType, DexMethod> extraDispatchCases = resolveDispatchCases(descriptor);
methodBuilder
.setName(emulatedMethod.getName())
.setProto(emulatedMethod.getProto())
@@ -170,162 +114,40 @@
.generateCfCode());
}
- private void synthesizeEmulatedInterfaceMethodFromMachineSpecification(
- ProgramMethod method,
- DexProgramClass theInterface,
- DexType dispatchType,
- SyntheticMethodBuilder methodBuilder) {
- EmulatedInterfaceDescriptor emulatedInterfaceDescriptor =
- appView
- .options()
- .testing
- .machineDesugaredLibrarySpecification
- .getRewritingFlags()
- .getEmulatedInterfaces()
- .get(theInterface.type);
- EmulatedDispatchMethodDescriptor descriptor =
- emulatedInterfaceDescriptor.getEmulatedMethods().get(method.getReference());
- DexMethod emulatedMethod = emulatedMethod(descriptor.getEmulatedDispatchMethod(), dispatchType);
- DexMethod itfMethod = interfaceMethod(descriptor.getInterfaceMethod());
- // TODO(b/184026720): Adapt to use the forwarding method.
- DerivedMethod forwardingMethod = descriptor.getForwardingMethod();
- assert forwardingMethod.getHolderKind() == SyntheticKind.COMPANION_CLASS;
- assert forwardingMethod.getMethod() == method.getReference();
- DexMethod companionMethod =
- helper.ensureDefaultAsMethodOfProgramCompanionClassStub(method).getReference();
- LinkedHashMap<DexType, DexMethod> extraDispatchCases = resolveDispatchCases(descriptor);
- methodBuilder
- .setName(descriptor.getEmulatedDispatchMethod().getName())
- .setProto(descriptor.getEmulatedDispatchMethod().getProto())
- .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic())
- .setCode(
- emulatedInterfaceMethod ->
- new EmulateDispatchSyntheticCfCodeProvider(
- emulatedMethod.getHolderType(),
- companionMethod,
- itfMethod,
- extraDispatchCases,
- appView)
- .generateCfCode());
- }
-
private LinkedHashMap<DexType, DexMethod> resolveDispatchCases(
EmulatedDispatchMethodDescriptor descriptor) {
LinkedHashMap<DexType, DexMethod> extraDispatchCases = new LinkedHashMap<>();
descriptor
.getDispatchCases()
.forEach(
- (type, derivedMethod) -> {
- DexMethod caseMethod;
- if (derivedMethod.getHolderKind() == null) {
- caseMethod = derivedMethod.getMethod();
- } else {
- assert derivedMethod.getHolderKind() == SyntheticKind.COMPANION_CLASS;
- ProgramMethod resolvedProgramMethod =
- appView
- .appInfoForDesugaring()
- .resolveMethod(derivedMethod.getMethod(), true)
- .getResolvedProgramMethod();
- caseMethod =
- helper
- .ensureDefaultAsMethodOfProgramCompanionClassStub(resolvedProgramMethod)
- .getReference();
- }
- extraDispatchCases.put(type, caseMethod);
- });
+ (type, derivedMethod) ->
+ extraDispatchCases.put(
+ type, helper.ensureEmulatedInterfaceForwardingMethod(derivedMethod)));
return extraDispatchCases;
}
- private LinkedHashMap<DexType, DexMethod> getDispatchCases(
- ProgramMethod method, DexProgramClass theInterface, DexMethod companionMethod) {
- // To properly emulate the library interface call, we need to compute the interfaces
- // inheriting from the interface and manually implement the dispatch with instance of.
- // The list guarantees that an interface is always after interfaces it extends,
- // hence reverse iteration.
- List<DexType> subInterfaces = emulatedInterfacesHierarchy.get(theInterface.type);
- LinkedHashMap<DexType, DexMethod> extraDispatchCases = new LinkedHashMap<>();
- // In practice, there is usually a single case (except for tests),
- // so we do not bother to make the following loop more clever.
- Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
- appView.options().desugaredLibrarySpecification.getRetargetCoreLibMember();
- for (DexString methodName : retargetCoreLibMember.keySet()) {
- if (method.getName() == methodName) {
- for (DexType inType : retargetCoreLibMember.get(methodName).keySet()) {
- DexClass inClass = appView.definitionFor(inType);
- if (inClass != null && implementsInterface(inClass, theInterface.type)) {
- extraDispatchCases.put(
- inType,
- appView
- .dexItemFactory()
- .createMethod(
- retargetCoreLibMember.get(methodName).get(inType),
- appView
- .dexItemFactory()
- .protoWithDifferentFirstParameter(companionMethod.proto, inType),
- method.getName()));
- }
- }
- }
- }
- if (subInterfaces != null) {
- for (int i = subInterfaces.size() - 1; i >= 0; i--) {
- DexClass subInterfaceClass = appView.definitionFor(subInterfaces.get(i));
- assert subInterfaceClass != null;
- assert subInterfaceClass.isProgramClass();
- // Else computation of subInterface would have failed.
- // if the method is implemented, extra dispatch is required.
- DexEncodedMethod result = subInterfaceClass.lookupVirtualMethod(method.getReference());
- if (result != null && !result.isAbstract()) {
- assert result.isDefaultMethod();
- DexMethod forward =
- helper
- .ensureDefaultAsMethodOfProgramCompanionClassStub(
- new ProgramMethod(subInterfaceClass.asProgramClass(), result))
- .getReference();
- extraDispatchCases.put(subInterfaceClass.type, forward);
- }
- }
- } else {
- assert extraDispatchCases.size() <= 1;
- }
- return extraDispatchCases;
- }
-
- private boolean implementsInterface(DexClass clazz, DexType interfaceType) {
- LinkedList<DexType> workList = new LinkedList<>(Arrays.asList(clazz.interfaces.values));
- while (!workList.isEmpty()) {
- DexType next = workList.removeLast();
- if (interfaceType == next) {
- return true;
- }
- DexClass nextClass = appView.definitionFor(next);
- if (nextClass != null) {
- workList.addAll(Arrays.asList(nextClass.interfaces.values));
- }
- }
- return false;
- }
-
@Override
public void synthesizeClasses(CfClassSynthesizerDesugaringEventConsumer eventConsumer) {
assert appView.options().isDesugaredLibraryCompilation();
- for (DexType emulatedInterfaceType : helper.getEmulatedInterfaces()) {
- DexClass emulatedInterfaceClazz = appView.definitionFor(emulatedInterfaceType);
- if (emulatedInterfaceClazz == null || !emulatedInterfaceClazz.isProgramClass()) {
- warnMissingEmulatedInterface(emulatedInterfaceType);
- continue;
- }
- DexProgramClass emulatedInterface = emulatedInterfaceClazz.asProgramClass();
- assert emulatedInterface != null;
- if (!appView.isAlreadyLibraryDesugared(emulatedInterface)
- && needsEmulateInterfaceLibrary(emulatedInterface)) {
- synthesizeProgramEmulatedInterface(emulatedInterface, eventConsumer);
- }
- }
- }
-
- private boolean needsEmulateInterfaceLibrary(DexClass emulatedInterface) {
- return Iterables.any(emulatedInterface.methods(), DexEncodedMethod::isDefaultMethod);
+ appView
+ .options()
+ .machineDesugaredLibrarySpecification
+ .getEmulatedInterfaces()
+ .forEach(
+ (emulatedInterfaceType, emulatedInterfaceDescriptor) -> {
+ DexClass emulatedInterfaceClazz = appView.definitionFor(emulatedInterfaceType);
+ if (emulatedInterfaceClazz == null || !emulatedInterfaceClazz.isProgramClass()) {
+ warnMissingEmulatedInterface(emulatedInterfaceType);
+ return;
+ }
+ DexProgramClass emulatedInterface = emulatedInterfaceClazz.asProgramClass();
+ assert emulatedInterface != null;
+ if (!appView.isAlreadyLibraryDesugared(emulatedInterface)
+ && !emulatedInterfaceDescriptor.getEmulatedMethods().isEmpty()) {
+ synthesizeProgramEmulatedInterface(
+ emulatedInterface, emulatedInterfaceDescriptor, eventConsumer);
+ }
+ });
}
private void warnMissingEmulatedInterface(DexType interfaceType) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordFieldValuesRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordFieldValuesRewriter.java
index 4689b6d..d8a62a0 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordFieldValuesRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordFieldValuesRewriter.java
@@ -165,7 +165,7 @@
appView
.appInfo()
.resolveField(appView.graphLens().getRenamedFieldSignature(fields[index]), context);
- if (resolution.isSuccessfulResolution()) {
+ if (resolution.isSingleFieldResolutionResult()) {
newInValues.add(inValues.get(index));
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/AssumeInserter.java b/src/main/java/com/android/tools/r8/ir/optimize/AssumeInserter.java
index 30ea9f8..97c8d47 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/AssumeInserter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/AssumeInserter.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.graph.DexClassAndField;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
+import com.android.tools.r8.graph.FieldResolutionResult.SingleFieldResolutionResult;
import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
import com.android.tools.r8.ir.analysis.type.DynamicType;
import com.android.tools.r8.ir.analysis.type.DynamicTypeWithUpperBound;
@@ -285,8 +285,8 @@
return false;
}
- SuccessfulFieldResolutionResult resolutionResult =
- appView.appInfo().resolveField(fieldGet.getField()).asSuccessfulResolution();
+ SingleFieldResolutionResult resolutionResult =
+ appView.appInfo().resolveField(fieldGet.getField()).asSingleFieldResolutionResult();
if (resolutionResult == null) {
return false;
}
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 7d12496..cd28d57 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
@@ -26,7 +26,7 @@
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
+import com.android.tools.r8.graph.FieldResolutionResult.SingleProgramFieldResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.horizontalclassmerging.HorizontalClassMergerUtils;
import com.android.tools.r8.ir.analysis.equivalence.BasicBlockBehavioralSubsumption;
@@ -70,6 +70,7 @@
import com.android.tools.r8.ir.code.IntSwitch;
import com.android.tools.r8.ir.code.Invoke;
import com.android.tools.r8.ir.code.InvokeDirect;
+import com.android.tools.r8.ir.code.InvokeInterface;
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.ir.code.InvokeMethodWithReceiver;
import com.android.tools.r8.ir.code.InvokeNewArray;
@@ -286,10 +287,8 @@
Throw throwInstruction = valueIsNullTarget.exit().asThrow();
Value exceptionValue = throwInstruction.exception().getAliasedValue();
- Value message;
- if (exceptionValue.isConstZero()) {
- message = null;
- } else if (exceptionValue.isDefinedByInstructionSatisfying(Instruction::isNewInstance)) {
+ if (!exceptionValue.isConstZero()
+ && exceptionValue.isDefinedByInstructionSatisfying(Instruction::isNewInstance)) {
NewInstance newInstance = exceptionValue.definition.asNewInstance();
if (newInstance.clazz != dexItemFactory.npeType) {
continue;
@@ -301,18 +300,10 @@
if (constructorCall == null) {
continue;
}
- DexMethod invokedMethod = constructorCall.getInvokedMethod();
- if (invokedMethod == dexItemFactory.npeMethods.init) {
- message = null;
- } else if (invokedMethod == dexItemFactory.npeMethods.initWithMessage) {
- if (!appView.options().canUseJavaUtilObjectsRequireNonNull()) {
- continue;
- }
- message = constructorCall.getArgument(1);
- } else {
+ if (constructorCall.getInvokedMethod() != dexItemFactory.npeMethods.init) {
continue;
}
- } else {
+ } else if (!exceptionValue.isConstZero()) {
continue;
}
@@ -327,26 +318,12 @@
continue;
}
- if (message != null) {
- Instruction definition = message.definition;
- if (message.definition.getBlock() == valueIsNullTarget) {
- it.previous();
- Instruction entry;
- do {
- entry = valueIsNullTarget.getInstructions().removeFirst();
- it.add(entry);
- } while (entry != definition);
- it.next();
- }
- }
-
- rewriteIfToRequireNonNull(
+ insertNotNullCheck(
block,
it,
ifInstruction,
ifInstruction.targetFromCondition(1),
valueIsNullTarget,
- message,
throwInstruction.getPosition());
shouldRemoveUnreachableBlocks = true;
}
@@ -1207,8 +1184,8 @@
return false;
}
InstanceGet instanceGet = switchValue.getDefinition().asInstanceGet();
- SuccessfulFieldResolutionResult resolutionResult =
- appInfo.resolveField(instanceGet.getField()).asSuccessfulResolution();
+ SingleProgramFieldResolutionResult resolutionResult =
+ appInfo.resolveField(instanceGet.getField()).asSingleProgramFieldResolutionResult();
if (resolutionResult == null) {
return false;
}
@@ -3363,33 +3340,19 @@
assert block.exit().asGoto().getTarget() == target;
}
- private void rewriteIfToRequireNonNull(
+ private void insertNotNullCheck(
BasicBlock block,
InstructionListIterator iterator,
If theIf,
BasicBlock target,
BasicBlock deadTarget,
- Value message,
Position position) {
deadTarget.unlinkSinglePredecessorSiblingsAllowed();
assert theIf == block.exit();
iterator.previous();
Instruction instruction;
- if (appView.options().canUseJavaUtilObjectsRequireNonNull()) {
- if (message != null) {
- DexMethod requireNonNullMethod =
- appView.dexItemFactory().objectsMethods.requireNonNullWithMessage;
- instruction =
- new InvokeStatic(requireNonNullMethod, null, ImmutableList.of(theIf.lhs(), message));
- } else {
- DexMethod requireNonNullMethod = appView.dexItemFactory().objectsMethods.requireNonNull;
- instruction = new InvokeStatic(requireNonNullMethod, null, ImmutableList.of(theIf.lhs()));
- }
- } else {
- assert message == null;
- DexMethod getClassMethod = appView.dexItemFactory().objectMembers.getClass;
- instruction = new InvokeVirtual(getClassMethod, null, ImmutableList.of(theIf.lhs()));
- }
+ DexMethod getClassMethod = appView.dexItemFactory().objectMembers.getClass;
+ instruction = new InvokeVirtual(getClassMethod, null, ImmutableList.of(theIf.lhs()));
instruction.setPosition(position);
iterator.add(instruction);
iterator.next();
@@ -3811,6 +3774,26 @@
}
}
+ // The javac fix for JDK-8272564 has to be rewritten back to invoke-virtual on Object if the
+ // method with an Object signature is not defined on the interface. See
+ // https://bugs.openjdk.java.net/browse/JDK-8272564
+ public static void rewriteJdk8272564Fix(IRCode code, AppView<?> appView) {
+ DexItemFactory dexItemFactory = appView.dexItemFactory();
+ InstructionListIterator it = code.instructionListIterator();
+ while (it.hasNext()) {
+ Instruction instruction = it.next();
+ if (instruction.isInvokeInterface()) {
+ InvokeInterface invoke = instruction.asInvokeInterface();
+ DexMethod method = invoke.getInvokedMethod();
+ DexMethod objectMember = dexItemFactory.objectMembers.matchingPublicObjectMember(method);
+ if (objectMember != null && appView.definitionFor(method) == null) {
+ it.replaceCurrentInstruction(
+ new InvokeVirtual(objectMember, invoke.outValue(), invoke.arguments()));
+ }
+ }
+ }
+ }
+
private static NewInstance findNewInstance(Phi phi) {
Set<Phi> seen = Sets.newIdentityHashSet();
Set<Value> values = Sets.newIdentityHashSet();
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 8182229..4ad92d7 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
@@ -395,7 +395,7 @@
}
if (appView.canUseInitClass()
&& inlinerOptions.enableInliningOfInvokesWithClassInitializationSideEffects) {
- action.setShouldSynthesizeInitClass();
+ action.setShouldEnsureStaticInitialization();
return action;
}
whyAreYouNotInliningReporter.reportMustTriggerClassInitialization();
@@ -409,17 +409,12 @@
ClassInitializationAnalysis classInitializationAnalysis) {
// Only proceed with inlining a static invoke if:
// - the holder for the target is a subtype of the holder for the method,
- // - the target method always triggers class initialization of its holder before any other side
- // effect (hence preserving class initialization semantics),
// - the current method has already triggered the holder for the target method to be
// initialized, or
// - there is no non-trivial class initializer.
if (appView.appInfo().isSubtype(context.getHolderType(), target.getHolderType())) {
return true;
}
- if (target.getDefinition().getOptimizationInfo().triggersClassInitBeforeAnySideEffect()) {
- return true;
- }
if (!context.getDefinition().isStatic()) {
boolean targetIsGuaranteedToBeInitialized =
appView.withInitializedClassesInInstanceMethods(
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
index fba3991..c458574 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -39,7 +39,6 @@
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.Invoke;
import com.android.tools.r8.ir.code.InvokeMethod;
-import com.android.tools.r8.ir.code.InvokeStatic;
import com.android.tools.r8.ir.code.InvokeVirtual;
import com.android.tools.r8.ir.code.Monitor;
import com.android.tools.r8.ir.code.MoveException;
@@ -515,7 +514,7 @@
public final Invoke invoke;
final Reason reason;
- private boolean shouldSynthesizeInitClass;
+ private boolean shouldEnsureStaticInitialization;
private DexProgramClass downcastClass;
@@ -538,13 +537,14 @@
this.downcastClass = downcastClass;
}
- void setShouldSynthesizeInitClass() {
- shouldSynthesizeInitClass = true;
+ void setShouldEnsureStaticInitialization() {
+ shouldEnsureStaticInitialization = true;
}
InlineeWithReason buildInliningIR(
AppView<AppInfoWithLiveness> appView,
InvokeMethod invoke,
+ ProgramMethod context,
InliningIRProvider inliningIRProvider,
LensCodeRewriter lensCodeRewriter) {
DexItemFactory dexItemFactory = appView.dexItemFactory();
@@ -555,8 +555,13 @@
// Insert a init class instruction if this is needed to preserve class initialization
// semantics.
- if (shouldSynthesizeInitClass) {
- synthesizeInitClass(code);
+ if (shouldEnsureStaticInitialization) {
+ handleSimpleEffectAnalysisResult(
+ SimpleDominatingEffectAnalysis.triggersClassInitializationBeforeAnyStaticRead(
+ appView, code, context),
+ code.entryBlock(),
+ ConsumerUtils.emptyConsumer(),
+ failingBlock -> synthesizeInitClass(code, failingBlock));
}
// Insert a null check if this is needed to preserve the implicit null check for the receiver.
@@ -573,19 +578,11 @@
if (invoke.isInvokeMethodWithReceiver()
&& invoke.asInvokeMethodWithReceiver().getReceiver().isMaybeNull()
&& !isSynthesizingNullCheckForReceiverUsingMonitorEnter) {
- SimpleEffectAnalysisResult checksReceiverBeingNull =
- canInlineWithoutSynthesizingNullCheckForReceiver(appView, code);
- if (checksReceiverBeingNull.isNotSatisfied()
- || (checksReceiverBeingNull.isPartial()
- && checksReceiverBeingNull.topMostNotSatisfiedBlockSize() > 1)) {
- synthesizeNullCheckForReceiver(appView, code, invoke, code.entryBlock());
- } else {
- checksReceiverBeingNull.forEachSatisfyingInstruction(
- this::setRemoveInnerFramePositionForReceiverUse);
- // Also add a null check on failing paths
- checksReceiverBeingNull.forEachTopMostNotSatisfiedBlock(
- block -> synthesizeNullCheckForReceiver(appView, code, invoke, block));
- }
+ handleSimpleEffectAnalysisResult(
+ canInlineWithoutSynthesizingNullCheckForReceiver(appView, code),
+ code.entryBlock(),
+ this::setRemoveInnerFramePositionForReceiverUse,
+ failingBlock -> synthesizeNullCheckForReceiver(appView, code, invoke, failingBlock));
}
// Insert monitor-enter and monitor-exit instructions if the method is synchronized.
if (shouldSynthesizeMonitorEnterExit) {
@@ -711,12 +708,32 @@
return new InlineeWithReason(code, reason);
}
- private void synthesizeInitClass(IRCode code) {
- List<Value> arguments = code.collectArguments();
- BasicBlock block = code.entryBlock();
+ private void handleSimpleEffectAnalysisResult(
+ SimpleEffectAnalysisResult result,
+ BasicBlock entryBlock,
+ Consumer<Instruction> satisfyingInstructionConsumer,
+ Consumer<BasicBlock> failingPathConsumer) {
+ List<BasicBlock> topmostNotSatisfiedBlocks = result.getTopmostNotSatisfiedBlocks();
+ if (result.isNotSatisfied()
+ // We should only handle partial results if the number of failing paths are small (1) and
+ // if the failing blocks that root the failing paths do not have catch handlers.
+ || (result.isPartial() && topmostNotSatisfiedBlocks.size() > 1)
+ || (result.isPartial() && topmostNotSatisfiedBlocks.get(0).hasCatchHandlers())) {
+ failingPathConsumer.accept(entryBlock);
+ } else {
+ result.forEachSatisfyingInstruction(satisfyingInstructionConsumer);
+ topmostNotSatisfiedBlocks.forEach(failingPathConsumer);
+ }
+ }
+
+ private void synthesizeInitClass(IRCode code, BasicBlock block) {
// Insert a new block between the last argument instruction and the first actual instruction
- // of the method.
- BasicBlock initClassBlock = block.listIterator(code, arguments.size()).split(code, 0, null);
+ // of the method, or the first instruction if not entry block.
+ assert !block.hasCatchHandlers();
+ BasicBlock initClassBlock =
+ block
+ .listIterator(code, block.isEntry() ? code.collectArguments().size() : 0)
+ .split(code, 0, null);
assert !initClassBlock.hasCatchHandlers();
InstructionListIterator iterator = initClassBlock.listIterator(code);
@@ -738,13 +755,8 @@
InstructionListIterator iterator = throwBlock.listIterator(code);
iterator.setInsertionPosition(invoke.getPosition());
- if (appView.options().canUseJavaUtilObjectsRequireNonNull()) {
- DexMethod requireNonNullMethod = appView.dexItemFactory().objectsMethods.requireNonNull;
- iterator.add(new InvokeStatic(requireNonNullMethod, null, ImmutableList.of(receiver)));
- } else {
- DexMethod getClassMethod = appView.dexItemFactory().objectMembers.getClass;
- iterator.add(new InvokeVirtual(getClassMethod, null, ImmutableList.of(receiver)));
- }
+ DexMethod getClassMethod = appView.dexItemFactory().objectMembers.getClass;
+ iterator.add(new InvokeVirtual(getClassMethod, null, ImmutableList.of(receiver)));
} else {
assert false : "Unable to synthesize a null check for the receiver";
}
@@ -1014,7 +1026,8 @@
}
InlineeWithReason inlinee =
- action.buildInliningIR(appView, invoke, inliningIRProvider, lensCodeRewriter);
+ action.buildInliningIR(
+ appView, invoke, context, inliningIRProvider, lensCodeRewriter);
if (strategy.willExceedBudget(
code, invoke, inlinee, block, whyAreYouNotInliningReporter)) {
assert whyAreYouNotInliningReporter.unsetReasonHasBeenReportedFlag();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
index 4807cda..b4584c4 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
@@ -14,7 +14,7 @@
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
+import com.android.tools.r8.graph.FieldResolutionResult.SingleFieldResolutionResult;
import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
@@ -364,8 +364,8 @@
DexField field = current.getField();
// TODO(b/123857022): Should be able to use definitionFor().
- SuccessfulFieldResolutionResult resolutionResult =
- appView.appInfo().resolveField(field).asSuccessfulResolution();
+ SingleFieldResolutionResult resolutionResult =
+ appView.appInfo().resolveField(field).asSingleFieldResolutionResult();
if (resolutionResult == null) {
boolean replaceCurrentInstructionWithConstNull =
appView.withGeneratedExtensionRegistryShrinker(
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
index bcef49c..715dfdd 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
@@ -13,7 +13,7 @@
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
+import com.android.tools.r8.graph.FieldResolutionResult.SingleFieldResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
import com.android.tools.r8.ir.analysis.value.SingleFieldValue;
@@ -40,7 +40,6 @@
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoCollection;
import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfo;
-import com.android.tools.r8.utils.InternalOptions;
import com.google.common.collect.Sets;
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
@@ -92,9 +91,7 @@
}
public static boolean shouldRun(AppView<?> appView, IRCode code) {
- InternalOptions options = appView.options();
- return options.enableRedundantFieldLoadElimination
- && !options.debug
+ return appView.options().enableRedundantFieldLoadElimination
&& (code.metadata().mayHaveArrayGet()
|| code.metadata().mayHaveFieldInstruction()
|| code.metadata().mayHaveInitClass());
@@ -287,8 +284,8 @@
private DexClassAndField resolveField(DexField field) {
if (appView.enableWholeProgramOptimizations()) {
- SuccessfulFieldResolutionResult resolutionResult =
- appView.appInfo().withLiveness().resolveField(field).asSuccessfulResolution();
+ SingleFieldResolutionResult resolutionResult =
+ appView.appInfo().withLiveness().resolveField(field).asSingleFieldResolutionResult();
return resolutionResult != null ? resolutionResult.getResolutionPair() : null;
}
if (field.getHolderType() == method.getHolderType()) {
@@ -556,6 +553,17 @@
}
private void handleArrayGet(InstructionListIterator it, ArrayGet arrayGet) {
+ if (arrayGet.array().hasLocalInfo()) {
+ // The array may be modified through the debugger. Therefore subsequent reads of the same
+ // array slot may not read this local.
+ return;
+ }
+ if (arrayGet.outValue().hasLocalInfo()) {
+ // This local may be modified through the debugger. Therefore subsequent reads of the same
+ // array slot may not read this local.
+ return;
+ }
+
Value array = arrayGet.array().getAliasedValue();
Value index = arrayGet.index().getAliasedValue();
ArraySlot arraySlot = ArraySlot.create(array, index, arrayGet.getMemberType());
@@ -593,6 +601,11 @@
InstanceGet instanceGet,
DexClassAndField field,
AssumeRemover assumeRemover) {
+ if (instanceGet.outValue().hasLocalInfo()) {
+ clearMostRecentInstanceFieldWrite(instanceGet, field);
+ return;
+ }
+
Value object = instanceGet.object().getAliasedValue();
FieldAndObject fieldAndObject = new FieldAndObject(field.getReference(), object);
FieldValue replacement = activeState.getInstanceFieldValue(fieldAndObject);
@@ -686,6 +699,12 @@
AssumeRemover assumeRemover) {
markClassAsInitialized(field.getHolderType());
+ if (staticGet.outValue().hasLocalInfo()) {
+ killNonFinalActiveFields(staticGet);
+ clearMostRecentStaticFieldWrite(staticGet, field);
+ return;
+ }
+
FieldValue replacement = activeState.getStaticFieldValue(field.getReference());
if (replacement != null) {
markAssumeDynamicTypeUsersForRemoval(staticGet, replacement, assumeRemover);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/SimpleDominatingEffectAnalysis.java b/src/main/java/com/android/tools/r8/ir/optimize/SimpleDominatingEffectAnalysis.java
index 0f68783..ddbe46b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/SimpleDominatingEffectAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/SimpleDominatingEffectAnalysis.java
@@ -188,12 +188,8 @@
satisfyingInstructions.forEach(instructionConsumer);
}
- public void forEachTopMostNotSatisfiedBlock(Consumer<BasicBlock> blockConsumer) {
- topmostNotSatisfiedBlocks.forEach(blockConsumer);
- }
-
- public int topMostNotSatisfiedBlockSize() {
- return topmostNotSatisfiedBlocks.size();
+ public List<BasicBlock> getTopmostNotSatisfiedBlocks() {
+ return topmostNotSatisfiedBlocks;
}
public static SimpleEffectAnalysisResultBuilder builder() {
@@ -337,14 +333,13 @@
}
public static SimpleEffectAnalysisResult triggersClassInitializationBeforeAnyStaticRead(
- AppView<AppInfoWithLiveness> appView, IRCode code) {
+ AppView<AppInfoWithLiveness> appView, IRCode code, ProgramMethod context) {
assert code.context().getDefinition().isStatic();
- ProgramMethod context = code.context();
return run(
code,
instruction -> {
if (instruction.definitelyTriggersClassInitialization(
- context.getHolderType(),
+ code.context().getHolderType(),
context,
appView,
DIRECTLY,
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 0a0bed9..e6494f3 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
@@ -19,7 +19,7 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
+import com.android.tools.r8.graph.FieldResolutionResult.SingleProgramFieldResolutionResult;
import com.android.tools.r8.graph.LibraryMethod;
import com.android.tools.r8.graph.MethodResolutionResult;
import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
@@ -167,8 +167,8 @@
assert root.isStaticGet();
StaticGet staticGet = root.asStaticGet();
- SuccessfulFieldResolutionResult fieldResolutionResult =
- appView.appInfo().resolveField(staticGet.getField()).asSuccessfulResolution();
+ SingleProgramFieldResolutionResult fieldResolutionResult =
+ appView.appInfo().resolveField(staticGet.getField()).asSingleProgramFieldResolutionResult();
if (fieldResolutionResult == null) {
return EligibilityStatus.NOT_ELIGIBLE;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/TransferFunction.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/TransferFunction.java
index 17d5658..152c212 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/TransferFunction.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/TransferFunction.java
@@ -190,7 +190,7 @@
// Instance field reads are OK, as long as the field resolves, since the class inliner will
// just replace the field read by the value of the field.
FieldResolutionResult resolutionResult = appView.appInfo().resolveField(instanceGet.getField());
- if (resolutionResult.isSuccessfulResolution()) {
+ if (resolutionResult.isSingleFieldResolutionResult()) {
// Record that the field is read from the parameter. For class inlining of singletons, this
// parameter is only eligible for class inlining if the singleton's field value is known.
return state.rebuildParameter(
@@ -217,7 +217,7 @@
}
FieldResolutionResult resolutionResult = appView.appInfo().resolveField(instancePut.getField());
- if (resolutionResult.isSuccessfulResolution()) {
+ if (resolutionResult.isSingleFieldResolutionResult()) {
return state.rebuildParameter(objectRoot, (context, usage) -> usage.setParameterMutated());
} else {
return state.abandonClassInliningInCurrentContexts(objectRoot);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
index c8c21eb..40ccc32 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
@@ -376,7 +376,7 @@
DexProgramClass enumClass = getEnumUnboxingCandidateOrNull(field.holder);
if (enumClass != null) {
FieldResolutionResult resolutionResult = appView.appInfo().resolveField(field, context);
- if (resolutionResult.isSuccessfulResolution()) {
+ if (resolutionResult.isSingleFieldResolutionResult()) {
eligibleEnums.add(enumClass.getType());
} else {
markEnumAsUnboxable(Reason.UNRESOLVABLE_FIELD, enumClass);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
index 0214979..c054329 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
@@ -18,7 +18,6 @@
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexValue;
-import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.ProgramField;
@@ -398,11 +397,9 @@
continue;
}
- SuccessfulFieldResolutionResult resolutionResult =
- appView.appInfo().resolveField(rewrittenField).asSuccessfulResolution();
- if (resolutionResult != null
- && resolutionResult.getResolvedHolder().isProgramClass()
- && isPrunedAfterEnumUnboxing(resolutionResult.getProgramField(), enumData)) {
+ ProgramField programField =
+ appView.appInfo().resolveField(rewrittenField).getSingleProgramField();
+ if (programField != null && isPrunedAfterEnumUnboxing(programField, enumData)) {
instructionIterator.removeOrReplaceByDebugLocalRead();
}
}
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 f6aa6ad..9faaebc 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
@@ -172,11 +172,6 @@
}
@Override
- public boolean triggersClassInitBeforeAnySideEffect() {
- return UNKNOWN_TRIGGERS_CLASS_INIT_BEFORE_ANY_SIDE_EFFECT;
- }
-
- @Override
public boolean mayHaveSideEffects() {
return UNKNOWN_MAY_HAVE_SIDE_EFFECTS;
}
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 473f718..ffcad46 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
@@ -91,8 +91,6 @@
public abstract boolean forceInline();
- public abstract boolean triggersClassInitBeforeAnySideEffect();
-
public abstract boolean mayHaveSideEffects();
/** Context sensitive version of {@link #mayHaveSideEffects()}. */
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
index 594328f..29a843b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
@@ -87,8 +87,6 @@
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.conversion.MethodProcessor;
import com.android.tools.r8.ir.optimize.DynamicTypeOptimization;
-import com.android.tools.r8.ir.optimize.SimpleDominatingEffectAnalysis;
-import com.android.tools.r8.ir.optimize.SimpleDominatingEffectAnalysis.SimpleEffectAnalysisResult;
import com.android.tools.r8.ir.optimize.classinliner.analysis.ClassInlinerMethodConstraintAnalysis;
import com.android.tools.r8.ir.optimize.classinliner.constraint.ClassInlinerMethodConstraint;
import com.android.tools.r8.ir.optimize.enums.classification.EnumUnboxerMethodClassification;
@@ -142,9 +140,6 @@
DexEncodedMethod definition = method.getDefinition();
identifyBridgeInfo(definition, code, feedback, timing);
analyzeReturns(code, feedback, methodProcessor, timing);
- if (options.inlinerOptions().enableInlining) {
- identifyInvokeSemanticsForInlining(definition, code, feedback, timing);
- }
if (options.enableClassInlining) {
computeClassInlinerMethodConstraint(method, code, feedback, timing);
}
@@ -529,25 +524,6 @@
return false;
}
- private void identifyInvokeSemanticsForInlining(
- DexEncodedMethod method, IRCode code, OptimizationFeedback feedback, Timing timing) {
- timing.begin("Identify invoke semantics for inlining");
- identifyInvokeSemanticsForInlining(method, code, feedback);
- timing.end();
- }
-
- private void identifyInvokeSemanticsForInlining(
- DexEncodedMethod method, IRCode code, OptimizationFeedback feedback) {
- if (method.isStatic()) {
- // Identifies if the method preserves class initialization after inlining.
- SimpleEffectAnalysisResult simpleEffectAnalysisResult =
- SimpleDominatingEffectAnalysis.triggersClassInitializationBeforeAnyStaticRead(
- appView, code);
- feedback.markTriggerClassInitBeforeAnySideEffect(
- method, simpleEffectAnalysisResult.isSatisfied());
- }
- }
-
/**
* Returns true if the given code unconditionally triggers an expected effect before anything
* else, false otherwise.
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
index 2cffcc0..b810885 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
@@ -92,7 +92,7 @@
private static final int NEVER_RETURNS_NORMALLY_FLAG = 0x40;
private static final int UNUSED_FLAG_2 = 0x80;
private static final int UNUSED_FLAG_3 = 0x100;
- private static final int TRIGGERS_CLASS_INIT_BEFORE_ANY_SIDE_EFFECT_FLAG = 0x200;
+ private static final int UNUSED_FLAG_4 = 0x200;
private static final int INITIALIZER_ENABLING_JAVA_ASSERTIONS_FLAG = 0x400;
private static final int REACHABILITY_SENSITIVE_FLAG = 0x800;
private static final int RETURN_VALUE_HAS_BEEN_PROPAGATED_FLAG = 0x1000;
@@ -119,9 +119,7 @@
BooleanUtils.intValue(defaultOptInfo.neverReturnsNormally()) * NEVER_RETURNS_NORMALLY_FLAG;
defaultFlags |= 0 * UNUSED_FLAG_2;
defaultFlags |= 0 * UNUSED_FLAG_3;
- defaultFlags |=
- BooleanUtils.intValue(defaultOptInfo.triggersClassInitBeforeAnySideEffect())
- * TRIGGERS_CLASS_INIT_BEFORE_ANY_SIDE_EFFECT_FLAG;
+ defaultFlags |= 0 * UNUSED_FLAG_4;
defaultFlags |=
BooleanUtils.intValue(defaultOptInfo.isInitializerEnablingJavaVmAssertions())
* INITIALIZER_ENABLING_JAVA_ASSERTIONS_FLAG;
@@ -497,11 +495,6 @@
}
@Override
- public boolean triggersClassInitBeforeAnySideEffect() {
- return isFlagSet(TRIGGERS_CLASS_INIT_BEFORE_ANY_SIDE_EFFECT_FLAG);
- }
-
- @Override
public boolean mayHaveSideEffects() {
return isFlagSet(MAY_HAVE_SIDE_EFFECT_FLAG);
}
@@ -675,14 +668,6 @@
}
}
- void markTriggerClassInitBeforeAnySideEffect(boolean mark) {
- setFlag(TRIGGERS_CLASS_INIT_BEFORE_ANY_SIDE_EFFECT_FLAG, mark);
- }
-
- void unsetTriggerClassInitBeforeAnySideEffect() {
- clearFlag(TRIGGERS_CLASS_INIT_BEFORE_ANY_SIDE_EFFECT_FLAG);
- }
-
// TODO(b/140214568): Should be package-private.
public void markAsPropagated() {
setFlag(RETURN_VALUE_HAS_BEEN_PROPAGATED_FLAG);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
index 4b6241a..65b9aaa 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
@@ -229,12 +229,6 @@
}
@Override
- public synchronized void markTriggerClassInitBeforeAnySideEffect(
- DexEncodedMethod method, boolean mark) {
- getMethodOptimizationInfoForUpdating(method).markTriggerClassInitBeforeAnySideEffect(mark);
- }
-
- @Override
public synchronized void setBridgeInfo(DexEncodedMethod method, BridgeInfo bridgeInfo) {
getMethodOptimizationInfoForUpdating(method).setBridgeInfo(bridgeInfo);
}
@@ -390,11 +384,6 @@
}
@Override
- public synchronized void unsetTriggerClassInitBeforeAnySideEffect(ProgramMethod method) {
- getMethodOptimizationInfoForUpdating(method).unsetTriggerClassInitBeforeAnySideEffect();
- }
-
- @Override
public synchronized void unsetUnusedArguments(ProgramMethod method) {
getMethodOptimizationInfoForUpdating(method).unsetUnusedArguments();
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java
index ac66916..d15bb00 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java
@@ -94,9 +94,6 @@
public void markProcessed(DexEncodedMethod method, ConstraintWithTarget state) {}
@Override
- public void markTriggerClassInitBeforeAnySideEffect(DexEncodedMethod method, boolean mark) {}
-
- @Override
public void setBridgeInfo(DexEncodedMethod method, BridgeInfo bridgeInfo) {}
@Override
@@ -191,8 +188,5 @@
public void unsetSimpleInliningConstraint(ProgramMethod method) {}
@Override
- public void unsetTriggerClassInitBeforeAnySideEffect(ProgramMethod method) {}
-
- @Override
public void unsetUnusedArguments(ProgramMethod method) {}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
index 1b54d1f..a9e3cba 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
@@ -137,11 +137,6 @@
method.markProcessed(state);
}
- @Override
- public void markTriggerClassInitBeforeAnySideEffect(DexEncodedMethod method, boolean mark) {
- // Ignored.
- }
-
public void setArgumentInfos(ProgramMethod method, CallSiteOptimizationInfo argumentInfos) {
method.getDefinition().getMutableOptimizationInfo().setArgumentInfos(argumentInfos);
}
@@ -333,12 +328,6 @@
}
@Override
- public void unsetTriggerClassInitBeforeAnySideEffect(ProgramMethod method) {
- withMutableMethodOptimizationInfo(
- method, MutableMethodOptimizationInfo::unsetTriggerClassInitBeforeAnySideEffect);
- }
-
- @Override
public void unsetUnusedArguments(ProgramMethod method) {
withMutableMethodOptimizationInfo(method, MutableMethodOptimizationInfo::unsetUnusedArguments);
}
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java
index dfe017a..6a20d01 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java
@@ -120,7 +120,7 @@
DexType returnType = forwardMethod.proto.returnType;
DexType forwardMethodReturnType =
- appView.rewritePrefix.hasRewrittenType(returnType, appView)
+ appView.typeRewriter.hasRewrittenType(returnType, appView)
? vivifiedTypeFor(returnType)
: returnType;
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java
index e95253c..2a3698b 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java
@@ -7,7 +7,9 @@
import static com.android.tools.r8.kotlin.KotlinClassMetadataReader.hasKotlinClassMetadataAnnotation;
import static com.android.tools.r8.kotlin.KotlinMetadataUtils.getNoKotlinInfo;
+import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.ClassResolutionResult;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexDefinitionSupplier;
import com.android.tools.r8.graph.DexEncodedMember;
@@ -152,6 +154,11 @@
}
@Override
+ public ClassResolutionResult contextIndependentDefinitionForWithResolutionResult(DexType type) {
+ throw new Unreachable("Not yet used");
+ }
+
+ @Override
public DexClass definitionFor(DexType type) {
// TODO(b/157700128) Metadata cannot at this point keep anything alive. Therefore, if a type
// has been pruned it may still be referenced, so we do an early check here to ensure it will
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
index ca54e1b..9a801b9 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
@@ -11,12 +11,13 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexClassAndField;
+import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.InnerClassAttribute;
+import com.android.tools.r8.graph.ProgramOrClasspathClass;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.InternalOptions;
@@ -35,7 +36,7 @@
private final AppView<AppInfoWithLiveness> appView;
private final ClassNamingStrategy classNamingStrategy;
- private final Iterable<? extends DexClass> classes;
+ private final Iterable<? extends ProgramOrClasspathClass> classes;
private final Set<String> usedTypeNames = Sets.newHashSet();
private final Map<DexType, DexString> renaming = Maps.newIdentityHashMap();
private final Map<String, Namespace> states = new HashMap<>();
@@ -48,7 +49,7 @@
ClassNameMinifier(
AppView<AppInfoWithLiveness> appView,
ClassNamingStrategy classNamingStrategy,
- Iterable<? extends DexClass> classes) {
+ Iterable<? extends ProgramOrClasspathClass> classes) {
this.appView = appView;
this.classNamingStrategy = classNamingStrategy;
this.classes = classes;
@@ -86,11 +87,11 @@
ClassRenaming computeRenaming(Timing timing) {
// Collect names we have to keep.
timing.begin("reserve");
- for (DexClass clazz : classes) {
- DexString descriptor = classNamingStrategy.reservedDescriptor(clazz.type);
+ for (ProgramOrClasspathClass clazz : classes) {
+ DexString descriptor = classNamingStrategy.reservedDescriptor(clazz.getType());
if (descriptor != null) {
- assert !renaming.containsKey(clazz.type);
- registerClassAsUsed(clazz.type, descriptor);
+ assert !renaming.containsKey(clazz.getType());
+ registerClassAsUsed(clazz.getType(), descriptor);
}
}
appView
@@ -100,24 +101,17 @@
timing.end();
timing.begin("rename-classes");
- for (DexClass clazz : classes) {
- if (!renaming.containsKey(clazz.type)) {
- DexString renamed = computeName(clazz.type);
- renaming.put(clazz.type, renamed);
- // If the class is a member class and it has used $ separator, its renamed name should have
- // the same separator (as long as inner-class attribute is honored).
- assert !keepInnerClassStructure
- || !clazz.isMemberClass()
- || !clazz.type.getInternalName().contains(String.valueOf(INNER_CLASS_SEPARATOR))
- || renamed.toString().contains(String.valueOf(INNER_CLASS_SEPARATOR))
- || classNamingStrategy.isRenamedByApplyMapping(clazz.type)
- : clazz.toSourceString() + " -> " + renamed;
+ for (ProgramOrClasspathClass clazz : classes) {
+ if (!renaming.containsKey(clazz.getType())) {
+ DexString renamed = computeName(clazz.getType());
+ renaming.put(clazz.getType(), renamed);
+ assert verifyMemberRenamingOfInnerClasses(clazz.asDexClass(), renamed);
}
}
timing.end();
timing.begin("rename-dangling-types");
- for (DexClass clazz : classes) {
+ for (ProgramOrClasspathClass clazz : classes) {
renameDanglingTypes(clazz);
}
timing.end();
@@ -125,6 +119,18 @@
return new ClassRenaming(Collections.unmodifiableMap(renaming), getPackageRenaming());
}
+ private boolean verifyMemberRenamingOfInnerClasses(DexClass clazz, DexString renamed) {
+ // If the class is a member class and it has used $ separator, its renamed name should have
+ // the same separator (as long as inner-class attribute is honored).
+ assert !keepInnerClassStructure
+ || !clazz.isMemberClass()
+ || !clazz.getType().getInternalName().contains(String.valueOf(INNER_CLASS_SEPARATOR))
+ || renamed.toString().contains(String.valueOf(INNER_CLASS_SEPARATOR))
+ || classNamingStrategy.isRenamedByApplyMapping(clazz.getType())
+ : clazz + " -> " + renamed;
+ return true;
+ }
+
private Map<String, String> getPackageRenaming() {
ImmutableMap.Builder<String, String> packageRenaming = ImmutableMap.builder();
for (Entry<String, Namespace> entry : states.entrySet()) {
@@ -137,16 +143,16 @@
return packageRenaming.build();
}
- private void renameDanglingTypes(DexClass clazz) {
- clazz.forEachMethod(this::renameDanglingTypesInMethod);
- clazz.forEachField(this::renameDanglingTypesInField);
+ private void renameDanglingTypes(ProgramOrClasspathClass clazz) {
+ clazz.forEachClassMethod(this::renameDanglingTypesInMethod);
+ clazz.forEachClassField(this::renameDanglingTypesInField);
}
- private void renameDanglingTypesInField(DexEncodedField field) {
+ private void renameDanglingTypesInField(DexClassAndField field) {
renameDanglingType(field.getReference().type);
}
- private void renameDanglingTypesInMethod(DexEncodedMethod method) {
+ private void renameDanglingTypesInMethod(DexClassAndMethod method) {
DexProto proto = method.getReference().proto;
renameDanglingType(proto.returnType);
for (DexType type : proto.parameters.values) {
diff --git a/src/main/java/com/android/tools/r8/naming/Minifier.java b/src/main/java/com/android/tools/r8/naming/Minifier.java
index 26c8d70..3bc7392 100644
--- a/src/main/java/com/android/tools/r8/naming/Minifier.java
+++ b/src/main/java/com/android/tools/r8/naming/Minifier.java
@@ -246,7 +246,7 @@
super(appView.options().getProguardConfiguration().getObfuscationDictionary(), false);
this.appView = appView;
this.factory = appView.dexItemFactory();
- this.desugaredLibraryRenaming = appView.rewritePrefix.isRewriting();
+ this.desugaredLibraryRenaming = appView.typeRewriter.isRewriting();
}
@Override
@@ -289,7 +289,7 @@
}
if (desugaredLibraryRenaming
&& method.isLibraryMethodOverride().isTrue()
- && appView.rewritePrefix.hasRewrittenTypeInSignature(
+ && appView.typeRewriter.hasRewrittenTypeInSignature(
method.getReference().proto, appView)) {
// With desugared library, call-backs names are reserved here.
return method.getReference().name;
diff --git a/src/main/java/com/android/tools/r8/naming/PrefixRewritingNamingLens.java b/src/main/java/com/android/tools/r8/naming/PrefixRewritingNamingLens.java
index 5ab9772..2add666 100644
--- a/src/main/java/com/android/tools/r8/naming/PrefixRewritingNamingLens.java
+++ b/src/main/java/com/android/tools/r8/naming/PrefixRewritingNamingLens.java
@@ -26,7 +26,7 @@
public static NamingLens createPrefixRewritingNamingLens(
AppView<?> appView, NamingLens namingLens) {
- if (!appView.rewritePrefix.isRewriting()) {
+ if (!appView.typeRewriter.isRewriting()) {
return namingLens;
}
return new PrefixRewritingNamingLens(namingLens, appView);
@@ -45,8 +45,8 @@
private DexString getRenaming(DexType type) {
DexString descriptor = null;
- if (appView.rewritePrefix.hasRewrittenType(type, appView)) {
- descriptor = appView.rewritePrefix.rewrittenType(type, appView).descriptor;
+ if (appView.typeRewriter.hasRewrittenType(type, appView)) {
+ descriptor = appView.typeRewriter.rewrittenType(type, appView).descriptor;
}
return descriptor;
}
@@ -106,7 +106,7 @@
}
private boolean verifyNotPrefixRewrittenPackage(String packageName) {
- appView.rewritePrefix.forAllRewrittenTypes(
+ appView.typeRewriter.forAllRewrittenTypes(
dexType -> {
assert !dexType.getPackageDescriptor().equals(packageName);
});
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
index 43cf17d..174614b 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
@@ -22,6 +22,7 @@
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramField;
+import com.android.tools.r8.graph.ProgramOrClasspathClass;
import com.android.tools.r8.graph.SubtypingInfo;
import com.android.tools.r8.naming.ClassNameMinifier.ClassRenaming;
import com.android.tools.r8.naming.FieldNameMinifier.FieldRenaming;
@@ -78,7 +79,7 @@
private final SeedMapper seedMapper;
private final BiMap<DexType, DexString> mappedNames = HashBiMap.create();
// To keep the order deterministic, we sort the classes by their type, which is a unique key.
- private final Set<DexClass> mappedClasses = Sets.newIdentityHashSet();
+ private final Set<ProgramOrClasspathClass> mappedClasses = Sets.newIdentityHashSet();
private final Map<DexReference, MemberNaming> memberNames = Maps.newIdentityHashMap();
private final Map<DexMethod, DexString> defaultInterfaceMethodImplementationNames =
Maps.newIdentityHashMap();
@@ -193,14 +194,17 @@
DexClass clazz = appView.definitionFor(type);
// Keep track of classes that needs to get renamed.
- if (clazz != null && (classNaming != null || clazz.isProgramClass())) {
- mappedClasses.add(clazz);
+ if (clazz != null) {
+ if (clazz.isClasspathClass() && classNaming != null) {
+ mappedClasses.add(clazz.asClasspathClass());
+ } else if (clazz.isProgramClass()) {
+ mappedClasses.add(clazz.asProgramClass());
+ }
}
Map<DexReference, MemberNaming> nonPrivateMembers = new IdentityHashMap<>();
- if (classNaming != null) {
- // TODO(b/133091438) assert that !dexClass.isLibraryClass();
+ if (classNaming != null && (clazz == null || !clazz.isLibraryClass())) {
DexString mappedName = factory.createString(classNaming.renamedName);
checkAndAddMappedNames(type, mappedName, classNaming.position);
classNaming.forAllMemberNaming(
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
index 89ac4ce..b933b4d 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
@@ -17,7 +17,6 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.FieldAccessInfoCollection;
-import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
import com.android.tools.r8.graph.LibraryMethod;
import com.android.tools.r8.graph.MethodAccessInfoCollection;
import com.android.tools.r8.graph.MethodResolutionResult;
@@ -541,12 +540,15 @@
}
private void registerFieldReference(DexField field) {
- SuccessfulFieldResolutionResult resolutionResult =
- appView.appInfo().resolveField(field).asSuccessfulResolution();
- if (resolutionResult != null
- && resolutionResult.getResolvedField().getReference() != field) {
- nonReboundFieldReferences.add(field);
- }
+ appView
+ .appInfo()
+ .resolveField(field)
+ .forEachSuccessfulFieldResolutionResult(
+ resolutionResult -> {
+ if (resolutionResult.getResolvedField().getReference() != field) {
+ nonReboundFieldReferences.add(field);
+ }
+ });
}
@Override
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingIdentityLensFactory.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingIdentityLensFactory.java
index 8995b69..1363a68 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingIdentityLensFactory.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingIdentityLensFactory.java
@@ -14,7 +14,6 @@
import com.android.tools.r8.graph.FieldAccessInfoCollection;
import com.android.tools.r8.graph.FieldAccessInfoCollectionImpl;
import com.android.tools.r8.graph.FieldAccessInfoImpl;
-import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
import com.android.tools.r8.graph.MethodAccessInfoCollection;
import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
@@ -148,31 +147,36 @@
if (!seenFieldReferences.add(field)) {
return;
}
- SuccessfulFieldResolutionResult resolutionResult =
- appInfo.resolveField(field).asSuccessfulResolution();
- if (resolutionResult == null) {
- return;
- }
- DexField reboundReference = resolutionResult.getResolvedField().getReference();
- if (field == reboundReference) {
- // For the purpose of member rebinding, we don't care about already rebound references.
- return;
- }
- FieldAccessInfoImpl fieldAccessInfo =
- fieldAccessInfoCollection.computeIfAbsent(reboundReference, FieldAccessInfoImpl::new);
- synchronized (fieldAccessInfo) {
- // Record the fact that there is a non-rebound access to the given field. We don't
- // distinguish between non-rebound reads and writes, so we just record it as a read.
- if (fieldAccessInfo.getReadsWithContexts().isBottom()) {
- fieldAccessInfo.setReadsWithContexts(new ConcreteAccessContexts());
- } else {
- assert fieldAccessInfo.getReadsWithContexts().isConcrete();
- }
- // For the purpose of member rebinding, we don't care about the access contexts, so we
- // simply use the empty set.
- ConcreteAccessContexts accessContexts = fieldAccessInfo.getReadsWithContexts().asConcrete();
- accessContexts.getAccessesWithContexts().put(field, ProgramMethodSet.empty());
- }
+ appInfo
+ .resolveField(field)
+ .forEachSuccessfulFieldResolutionResult(
+ resolutionResult -> {
+ DexField reboundReference = resolutionResult.getResolvedField().getReference();
+ if (field == reboundReference) {
+ // For the purpose of member rebinding, we don't care about already rebound
+ // references.
+ return;
+ }
+ FieldAccessInfoImpl fieldAccessInfo =
+ fieldAccessInfoCollection.computeIfAbsent(
+ reboundReference, FieldAccessInfoImpl::new);
+ synchronized (fieldAccessInfo) {
+ // Record the fact that there is a non-rebound access to the given field. We don't
+ // distinguish between non-rebound reads and writes, so we just record it as a
+ // read.
+ if (fieldAccessInfo.getReadsWithContexts().isBottom()) {
+ fieldAccessInfo.setReadsWithContexts(new ConcreteAccessContexts());
+ } else {
+ assert fieldAccessInfo.getReadsWithContexts().isConcrete();
+ }
+ // For the purpose of member rebinding, we don't care about the access contexts,
+ // so we
+ // simply use the empty set.
+ ConcreteAccessContexts accessContexts =
+ fieldAccessInfo.getReadsWithContexts().asConcrete();
+ accessContexts.getAccessesWithContexts().put(field, ProgramMethodSet.empty());
+ }
+ });
}
@Override
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java
index 42537e8..6e6e88c 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java
@@ -224,11 +224,11 @@
private void registerFieldAccess(DexField field) {
FieldResolutionResult resolutionResult = appView.appInfo().resolveField(field);
- if (resolutionResult.getProgramField() == null) {
+ if (resolutionResult.getSingleProgramField() == null) {
return;
}
- ProgramField resolvedField = resolutionResult.getProgramField();
+ ProgramField resolvedField = resolutionResult.getSingleProgramField();
DexField rewrittenFieldReference =
graphLens.internalGetNextFieldSignature(resolvedField.getReference());
if (rewrittenFieldReference != resolvedField.getReference()) {
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/lenscoderewriter/NullCheckInserter.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/lenscoderewriter/NullCheckInserter.java
index 2ffbf8d..e0341ae 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/lenscoderewriter/NullCheckInserter.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/lenscoderewriter/NullCheckInserter.java
@@ -199,7 +199,7 @@
// This needs to map the field all the way to the final graph lens.
DexField rewrittenField = appView.graphLens().lookupField(field, graphLens);
FieldResolutionResult resolutionResult = appView.appInfo().resolveField(rewrittenField);
- return resolutionResult.isSuccessfulResolution()
+ return resolutionResult.isSingleFieldResolutionResult()
&& !appView.appInfo().isFieldRead(resolutionResult.getResolvedField());
}
return false;
diff --git a/src/main/java/com/android/tools/r8/optimize/proto/ProtoNormalizer.java b/src/main/java/com/android/tools/r8/optimize/proto/ProtoNormalizer.java
index 2b49179..29ed273 100644
--- a/src/main/java/com/android/tools/r8/optimize/proto/ProtoNormalizer.java
+++ b/src/main/java/com/android/tools/r8/optimize/proto/ProtoNormalizer.java
@@ -4,21 +4,32 @@
package com.android.tools.r8.optimize.proto;
+import static com.android.tools.r8.utils.MapUtils.ignoreKey;
+
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.DexMethodSignature;
import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexTypeList;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
-import com.android.tools.r8.utils.collections.BidirectionalOneToOneMap;
import com.android.tools.r8.utils.collections.DexMethodSignatureSet;
import com.android.tools.r8.utils.collections.MutableBidirectionalOneToOneMap;
-import java.util.ArrayList;
-import java.util.List;
+import com.google.common.collect.Sets;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
public class ProtoNormalizer {
@@ -33,35 +44,36 @@
this.options = appView.options();
}
- public void run(ExecutorService executorService, Timing timing) {
+ public void run(ExecutorService executorService, Timing timing) throws ExecutionException {
if (options.testing.enableExperimentalProtoNormalization) {
timing.time("Proto normalization", () -> run(executorService));
}
}
- // TODO(b/195112263): Parallelize using executor service.
- private void run(ExecutorService executorService) {
- // Compute mapping from method signatures to new method signatures.
- BidirectionalOneToOneMap<DexMethodSignature, DexMethodSignature> normalization =
- computeNormalization();
+ private void run(ExecutorService executorService) throws ExecutionException {
+ GlobalReservationState globalReservationState = computeGlobalReservationState(executorService);
+ // TODO(b/173398086): This uses a single LocalReservationState for the entire program. This
+ // should process the strongly connected program components in parallel, each with their own
+ // LocalReservationState.
+ LocalReservationState localReservationState = new LocalReservationState();
ProtoNormalizerGraphLens.Builder lensBuilder = ProtoNormalizerGraphLens.builder(appView);
- for (DexProgramClass clazz : appView.appInfo().classes()) {
+ for (DexProgramClass clazz : appView.appInfo().classesWithDeterministicOrder()) {
clazz
.getMethodCollection()
.replaceMethods(
method -> {
DexMethodSignature methodSignature = method.getSignature();
- assert normalization.containsKey(methodSignature);
- DexMethodSignature normalizedMethodSignature = normalization.get(methodSignature);
- if (methodSignature.equals(normalizedMethodSignature)) {
+ DexMethodSignature newMethodSignature =
+ localReservationState.getNewMethodSignature(
+ methodSignature, dexItemFactory, globalReservationState);
+ if (methodSignature.equals(newMethodSignature)) {
return method;
}
- DexMethod normalizedMethodReference =
- normalizedMethodSignature.withHolder(clazz, dexItemFactory);
- lensBuilder.recordNewMethodSignature(method, normalizedMethodReference);
+ DexMethod newMethodReference = newMethodSignature.withHolder(clazz, dexItemFactory);
+ lensBuilder.recordNewMethodSignature(method, newMethodReference);
// TODO(b/195112263): Fixup any optimization info and parameter annotations.
- return method.toTypeSubstitutedMethod(normalizedMethodReference);
+ return method.toTypeSubstitutedMethod(newMethodReference);
});
}
@@ -70,57 +82,180 @@
}
}
- // TODO(b/195112263): This naively maps each method signatures to their normalized method
- // signature if it is not already reserved by another method. This means that we will rewrite
- // foo(A,B), bar(B,A), and baz(B,A) into foo(A,B), bar(A,B), and baz(A,B), such that all of the
- // method signatures share the same parameter type list. However, if there is a method foo(A,B)
- // and foo(B,A) then this does not rewrite foo(B,A) into foo(A,B). If foo(B,A) is not in the same
- // hierarchy as foo(A,B), this would be possible, however.
- // TODO(b/195112263): Do not optimize foo(B, A) into foo(A, B) if this won't lead to any parameter
- // type lists being shared (e.g., if foo(B, A) is the only method where sorted(parameters) is
- // [A, B]).
- private BidirectionalOneToOneMap<DexMethodSignature, DexMethodSignature> computeNormalization() {
- // Reserve the signatures of unoptimizable methods to avoid collisions.
- MutableBidirectionalOneToOneMap<DexMethodSignature, DexMethodSignature> normalization =
- new BidirectionalOneToOneHashMap<>();
- DexMethodSignatureSet optimizableMethodSignatures = DexMethodSignatureSet.create();
- for (DexProgramClass clazz : appView.appInfo().classes()) {
- clazz.forEachProgramMethod(
- method -> {
- DexMethodSignature methodSignature = method.getMethodSignature();
- if (isUnoptimizable(method)) {
- normalization.put(methodSignature, methodSignature);
- } else if (!normalization.containsKey(methodSignature)) {
- optimizableMethodSignatures.add(methodSignature);
- }
- });
+ private GlobalReservationState computeGlobalReservationState(ExecutorService executorService)
+ throws ExecutionException {
+ // Tracks how many different parameter lists can be optimized into the same parameter list.
+ // If only (B, A) can be rewritten into (A, B), then there is no need to rewrite parameter lists
+ // on the form (B, A) into (A, B), as that won't lead to any sharing of parameter lists.
+ Map<DexTypeList, Set<DexTypeList>> optimizableParameterLists = new ConcurrentHashMap<>();
+
+ // Used to track if a given parameter list should be mapped to a specific permutation instead of
+ // just sorting the parameter list. This is used to ensure that we will rewrite parameter lists
+ // such as (A, B) into (B, A) if there is an unoptimizable method with parameter list (B, A).
+ Map<DexTypeList, Set<DexTypeList>> reservedParameterLists = new ConcurrentHashMap<>();
+
+ // Tracks the set of unoptimizable method signatures. These must remain as-is.
+ DexMethodSignatureSet unoptimizableSignatures = DexMethodSignatureSet.createConcurrent();
+
+ ThreadUtils.processMethods(
+ appView,
+ method ->
+ computeReservationsFromMethod(
+ method, optimizableParameterLists, reservedParameterLists, unoptimizableSignatures),
+ executorService);
+
+ // Reserve parameter lists that won't lead to any sharing after normalization. Any method with
+ // such a parameter list must remain as-is.
+ Set<DexTypeList> unoptimizableParameterLists = new HashSet<>();
+ optimizableParameterLists.forEach(
+ (sortedParameters, parameterListsBeforeNormalization) -> {
+ int size = parameterListsBeforeNormalization.size();
+ if (size != 1) {
+ // There are multiple optimizable methods with different parameter lists that can be
+ // rewritten into having the same parameter list.
+ assert size > 1;
+ return;
+ }
+ DexTypeList parameters = parameterListsBeforeNormalization.iterator().next();
+ Set<DexTypeList> reservedParameters =
+ reservedParameterLists.getOrDefault(sortedParameters, Collections.emptySet());
+ if (!reservedParameters.isEmpty() && !reservedParameters.contains(parameters)) {
+ // There is at least one optimizable method that can be rewritten into having the same
+ // parameter list as an unoptimizable method.
+ return;
+ }
+ unoptimizableParameterLists.add(parameters);
+ });
+
+ ThreadUtils.processMethods(
+ appView,
+ method ->
+ computeExtraReservationsFromMethod(
+ method, unoptimizableParameterLists, unoptimizableSignatures),
+ executorService);
+
+ return new GlobalReservationState(reservedParameterLists, unoptimizableSignatures);
+ }
+
+ private void computeReservationsFromMethod(
+ ProgramMethod method,
+ Map<DexTypeList, Set<DexTypeList>> optimizableParameterLists,
+ Map<DexTypeList, Set<DexTypeList>> reservedParameterLists,
+ DexMethodSignatureSet unoptimizableSignatures) {
+ if (isUnoptimizable(method)) {
+ // Record that other optimizable methods with the same set of parameter types should be
+ // rewritten to have the same parameter list as this method.
+ reservedParameterLists
+ .computeIfAbsent(
+ method.getParameters().getSorted(), ignoreKey(Sets::newConcurrentHashSet))
+ .add(method.getParameters());
+
+ // Mark signature as unoptimizable.
+ unoptimizableSignatures.add(method);
+ } else {
+ // Record that the method's parameter list can be rewritten into any permutation.
+ optimizableParameterLists
+ .computeIfAbsent(
+ method.getParameters().getSorted(), ignoreKey(Sets::newConcurrentHashSet))
+ .add(method.getParameters());
}
- optimizableMethodSignatures.removeAll(normalization.keySet());
+ }
- // Normalize each signature that is subject to optimization.
- List<DexMethodSignature> sortedOptimizableMethodSignatures =
- new ArrayList<>(optimizableMethodSignatures);
- sortedOptimizableMethodSignatures.sort(DexMethodSignature::compareTo);
-
- for (DexMethodSignature signature : sortedOptimizableMethodSignatures) {
- assert !normalization.containsKey(signature);
- assert !normalization.containsValue(signature);
- DexMethodSignature normalizedSignature =
- signature.withProto(
- dexItemFactory.createProto(
- signature.getReturnType(), signature.getParameters().getSorted()));
- if (normalization.containsValue(normalizedSignature)) {
- normalization.put(signature, signature);
- } else {
- normalization.put(signature, normalizedSignature);
- }
+ private void computeExtraReservationsFromMethod(
+ ProgramMethod method,
+ Set<DexTypeList> unoptimizableParameterLists,
+ DexMethodSignatureSet unoptimizableSignatures) {
+ if (unoptimizableParameterLists.contains(method.getParameters())) {
+ unoptimizableSignatures.add(method.getMethodSignature());
}
-
- return normalization;
}
private boolean isUnoptimizable(ProgramMethod method) {
// TODO(b/195112263): This is incomplete.
- return appView.getKeepInfo(method).isPinned(options);
+ return appView.getKeepInfo(method).isPinned(options)
+ || method.getDefinition().isLibraryMethodOverride().isPossiblyTrue();
+ }
+
+ static class GlobalReservationState {
+
+ // Used to track if a given parameter list should be mapped to a specific permutation instead of
+ // just sorting the parameter list. This is used to ensure that we will rewrite parameter lists
+ // such as (A, B) into (B, A) if there is an unoptimizable method with parameter list (B, A).
+ Map<DexTypeList, DexTypeList> reservedParameters;
+
+ // Tracks the set of unoptimizable method signatures. These must remain as-is.
+ DexMethodSignatureSet unoptimizableSignatures;
+
+ GlobalReservationState(
+ Map<DexTypeList, Set<DexTypeList>> reservedParameterLists,
+ DexMethodSignatureSet unoptimizableSignatures) {
+ this.reservedParameters = selectDeterministicTarget(reservedParameterLists);
+ this.unoptimizableSignatures = unoptimizableSignatures;
+ }
+
+ private static Map<DexTypeList, DexTypeList> selectDeterministicTarget(
+ Map<DexTypeList, Set<DexTypeList>> reservedParameterLists) {
+ Map<DexTypeList, DexTypeList> result = new HashMap<>();
+ reservedParameterLists.forEach(
+ (sortedParameters, candidates) -> {
+ Iterator<DexTypeList> iterator = candidates.iterator();
+ DexTypeList smallestCandidate = iterator.next();
+ while (iterator.hasNext()) {
+ DexTypeList candidate = iterator.next();
+ if (candidate.compareTo(smallestCandidate) < 0) {
+ smallestCandidate = candidate;
+ }
+ }
+ result.put(sortedParameters, smallestCandidate);
+ });
+ return result;
+ }
+
+ DexTypeList getReservedParameters(DexMethodSignature methodSignature) {
+ DexTypeList sortedParameters = methodSignature.getParameters().getSorted();
+ return reservedParameters.getOrDefault(sortedParameters, sortedParameters);
+ }
+
+ boolean isUnoptimizable(DexMethodSignature methodSignature) {
+ return unoptimizableSignatures.contains(methodSignature);
+ }
+ }
+
+ static class LocalReservationState {
+
+ MutableBidirectionalOneToOneMap<DexMethodSignature, DexMethodSignature> newMethodSignatures =
+ new BidirectionalOneToOneHashMap<>();
+
+ // TODO: avoid sorting multiple times.
+ DexMethodSignature getNewMethodSignature(
+ DexMethodSignature methodSignature,
+ DexItemFactory dexItemFactory,
+ GlobalReservationState globalReservationState) {
+ if (globalReservationState.isUnoptimizable(methodSignature)) {
+ assert !newMethodSignatures.containsKey(methodSignature);
+ return methodSignature;
+ }
+ DexMethodSignature reservedSignature = newMethodSignatures.get(methodSignature);
+ if (reservedSignature != null) {
+ assert reservedSignature
+ .getParameters()
+ .equals(globalReservationState.getReservedParameters(methodSignature));
+ return reservedSignature;
+ }
+ DexTypeList reservedParameters =
+ globalReservationState.getReservedParameters(methodSignature);
+ DexMethodSignature newMethodSignature =
+ methodSignature.withParameters(reservedParameters, dexItemFactory);
+ if (newMethodSignatures.containsValue(newMethodSignature)) {
+ int index = 1;
+ String newMethodBaseName = methodSignature.getName().toString();
+ do {
+ DexString newMethodName = dexItemFactory.createString(newMethodBaseName + "$" + index);
+ newMethodSignature = newMethodSignature.withName(newMethodName);
+ } while (newMethodSignatures.containsValue(newMethodSignature));
+ }
+ newMethodSignatures.put(methodSignature, newMethodSignature);
+ return newMethodSignature;
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index e156407..8216777 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -665,7 +665,6 @@
|| getMissingClasses().contains(type)
// TODO(b/150693139): Remove these exceptions once fixed.
|| InterfaceDesugaringSyntheticHelper.isCompanionClassType(type)
- || InterfaceDesugaringSyntheticHelper.isEmulatedLibraryClassType(type)
// TODO(b/150736225): Not sure how to remove these.
|| DesugaredLibraryAPIConverter.isVivifiedType(type)
: "Failed lookup of non-missing type: " + type;
@@ -1215,7 +1214,7 @@
assert lens.assertDefinitionsNotModified(
switchMaps.keySet().stream()
.map(this::resolveField)
- .filter(FieldResolutionResult::isSuccessfulResolution)
+ .filter(FieldResolutionResult::isSingleFieldResolutionResult)
.map(FieldResolutionResult::getResolvedField)
.collect(Collectors.toList()));
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 1622376..8681f33 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -62,6 +62,7 @@
import com.android.tools.r8.graph.FieldAccessInfoCollectionImpl;
import com.android.tools.r8.graph.FieldAccessInfoImpl;
import com.android.tools.r8.graph.FieldResolutionResult;
+import com.android.tools.r8.graph.FieldResolutionResult.FailedOrUnknownFieldResolutionResult;
import com.android.tools.r8.graph.GenericSignatureEnqueuerAnalysis;
import com.android.tools.r8.graph.InnerClassAttribute;
import com.android.tools.r8.graph.InvalidCode;
@@ -317,6 +318,8 @@
*/
private final Set<ClasspathOrLibraryClass> liveNonProgramTypes = Sets.newIdentityHashSet();
+ private final Set<ClasspathOrLibraryClass> referencedNonProgramTypes = Sets.newIdentityHashSet();
+
/** Set of reachable proto types that will be dead code eliminated. */
private final Set<DexProgramClass> deadProtoTypeCandidates = Sets.newIdentityHashSet();
@@ -602,7 +605,7 @@
ignoreMissingClass(type);
} else if (clazz.isNotProgramClass()) {
addLiveNonProgramType(
- clazz.asClasspathOrLibraryClass(), this::ignoreMissingClasspathOrLibraryClass);
+ clazz.asClasspathOrLibraryClass(), true, this::ignoreMissingClasspathOrLibraryClass);
}
}
@@ -697,51 +700,62 @@
private void addLiveNonProgramType(
ClasspathOrLibraryClass clazz,
+ // TODO(b/216576191): Remove when tracking live library members.
+ boolean visitMembers,
BiConsumer<DexType, ClasspathOrLibraryDefinition> missingClassConsumer) {
WorkList<ClasspathOrLibraryClass> worklist =
WorkList.newIdentityWorkList(clazz, liveNonProgramTypes);
while (worklist.hasNext()) {
ClasspathOrLibraryClass definition = worklist.next();
- processNewLiveNonProgramType(definition, worklist, missingClassConsumer);
+ processNewLiveNonProgramType(definition, worklist, missingClassConsumer, visitMembers);
}
}
private void processNewLiveNonProgramType(
ClasspathOrLibraryClass clazz,
WorkList<ClasspathOrLibraryClass> worklist,
- BiConsumer<DexType, ClasspathOrLibraryDefinition> missingClassConsumer) {
+ BiConsumer<DexType, ClasspathOrLibraryDefinition> missingClassConsumer,
+ boolean visitMembers) {
+ ensureMethodsContinueToWidenAccess(clazz);
if (clazz.isLibraryClass()) {
- // TODO(b/149201735): This likely needs to apply to classpath too.
- ensureMethodsContinueToWidenAccess(clazz);
// Only libraries must not derive program. Classpath classes can, assuming correct keep rules.
warnIfLibraryTypeInheritsFromProgramType(clazz.asLibraryClass());
}
- clazz.forEachClassField(
- field ->
+ if (visitMembers) {
+ clazz.forEachClassField(
+ field ->
+ addNonProgramClassToWorklist(
+ field.getType(),
+ field.asClasspathOrLibraryDefinition(),
+ referencedNonProgramTypes::add,
+ missingClassConsumer));
+ clazz.forEachClassMethod(
+ method -> {
+ ClasspathOrLibraryDefinition derivedContext = method.asClasspathOrLibraryDefinition();
addNonProgramClassToWorklist(
- field.getType(),
- field.asClasspathOrLibraryDefinition(),
- worklist,
- missingClassConsumer));
- clazz.forEachClassMethod(
- method -> {
- ClasspathOrLibraryDefinition derivedContext = method.asClasspathOrLibraryDefinition();
- addNonProgramClassToWorklist(
- method.getReturnType(), derivedContext, worklist, missingClassConsumer);
- for (DexType parameter : method.getParameters()) {
- addNonProgramClassToWorklist(parameter, derivedContext, worklist, missingClassConsumer);
- }
- });
+ method.getReturnType(),
+ derivedContext,
+ referencedNonProgramTypes::add,
+ missingClassConsumer);
+ for (DexType parameter : method.getParameters()) {
+ addNonProgramClassToWorklist(
+ parameter, derivedContext, referencedNonProgramTypes::add, missingClassConsumer);
+ }
+ });
+ }
for (DexType supertype : clazz.allImmediateSupertypes()) {
addNonProgramClassToWorklist(
- supertype, clazz.asClasspathOrLibraryDefinition(), worklist, missingClassConsumer);
+ supertype,
+ clazz.asClasspathOrLibraryDefinition(),
+ worklist::addIfNotSeen,
+ missingClassConsumer);
}
}
private void addNonProgramClassToWorklist(
DexType type,
ClasspathOrLibraryDefinition context,
- WorkList<ClasspathOrLibraryClass> worklist,
+ Consumer<ClasspathOrLibraryClass> classAdder,
BiConsumer<DexType, ClasspathOrLibraryDefinition> missingClassConsumer) {
if (type.isArrayType()) {
type = type.toBaseType(appView.dexItemFactory());
@@ -753,7 +767,7 @@
if (clazz == null) {
missingClassConsumer.accept(type, context);
} else if (!clazz.isProgramClass()) {
- worklist.addIfNotSeen(clazz.asClasspathOrLibraryClass());
+ classAdder.accept(clazz.asClasspathOrLibraryClass());
}
}
@@ -769,7 +783,8 @@
private DexClass getClassOrNullFromReflectiveAccess(DexType type, ProgramDefinition context) {
// To avoid that we report reflectively accessed types as missing.
- return definitionFor(type, context, this::recordNonProgramClass, this::ignoreMissingClass);
+ return definitionFor(
+ type, context, this::recordNonProgramClassWithNoMissingReporting, this::ignoreMissingClass);
}
private DexProgramClass getProgramClassOrNullFromReflectiveAccess(
@@ -1460,49 +1475,52 @@
return;
}
- FieldResolutionResult resolutionResult = resolveField(fieldReference, currentMethod);
- fieldAccessAnalyses.forEach(
- analysis ->
- analysis.traceInstanceFieldRead(
- fieldReference, resolutionResult, currentMethod, workList));
+ resolveField(fieldReference, currentMethod)
+ .visitFieldResolutionResults(
+ resolutionResult -> {
+ fieldAccessAnalyses.forEach(
+ analysis ->
+ analysis.traceInstanceFieldRead(
+ fieldReference, resolutionResult, currentMethod, workList));
- if (resolutionResult.isFailedOrUnknownResolution()) {
- // Must trace the types from the field reference even if it does not exist.
- traceFieldReference(fieldReference, resolutionResult, currentMethod);
- noClassMerging.add(fieldReference.getHolderType());
- return;
- }
+ ProgramField field = resolutionResult.getProgramField();
+ if (field == null) {
+ // No need to trace into the non-program code.
+ return;
+ }
- ProgramField field =
- resolutionResult.asSuccessfulResolution().getResolutionPair().asProgramField();
- if (field == null) {
- // No need to trace into the non-program code.
- return;
- }
+ assert !mode.isFinalTreeShaking()
+ || !field.getDefinition().getOptimizationInfo().isDead()
+ : "Unexpected reference in `"
+ + currentMethod.toSourceString()
+ + "` to field marked dead: "
+ + field.getReference().toSourceString();
- assert !mode.isFinalTreeShaking() || !field.getDefinition().getOptimizationInfo().isDead()
- : "Unexpected reference in `"
- + currentMethod.toSourceString()
- + "` to field marked dead: "
- + field.getReference().toSourceString();
+ if (readType == FieldReadType.READ_FROM_METHOD_HANDLE) {
+ fieldAccessInfoCollection.get(field.getReference()).setReadFromMethodHandle();
+ } else if (readType == FieldReadType.READ_FROM_RECORD_METHOD_HANDLE) {
+ fieldAccessInfoCollection
+ .get(field.getReference())
+ .setReadFromRecordInvokeDynamic();
+ }
- if (readType == FieldReadType.READ_FROM_METHOD_HANDLE) {
- fieldAccessInfoCollection.get(field.getReference()).setReadFromMethodHandle();
- } else if (readType == FieldReadType.READ_FROM_RECORD_METHOD_HANDLE) {
- fieldAccessInfoCollection.get(field.getReference()).setReadFromRecordInvokeDynamic();
- }
+ if (Log.ENABLED) {
+ Log.verbose(getClass(), "Register Iget `%s`.", fieldReference);
+ }
- if (Log.ENABLED) {
- Log.verbose(getClass(), "Register Iget `%s`.", fieldReference);
- }
+ if (field.getReference() != fieldReference) {
+ // Mark the initial resolution holder as live.
+ markTypeAsLive(resolutionResult.getInitialResolutionHolder(), currentMethod);
+ }
- if (field.getReference() != fieldReference) {
- // Mark the initial resolution holder as live.
- markTypeAsLive(resolutionResult.getInitialResolutionHolder(), currentMethod);
- }
-
- workList.enqueueMarkFieldAsReachableAction(
- field, currentMethod, KeepReason.fieldReferencedIn(currentMethod));
+ workList.enqueueMarkFieldAsReachableAction(
+ field, currentMethod, KeepReason.fieldReferencedIn(currentMethod));
+ },
+ failedResolution -> {
+ // Must trace the types from the field reference even if it does not exist.
+ traceFieldReference(fieldReference, failedResolution, currentMethod);
+ noClassMerging.add(fieldReference.getHolderType());
+ });
}
void traceInstanceFieldWrite(DexField field, ProgramMethod currentMethod) {
@@ -1519,47 +1537,48 @@
return;
}
- FieldResolutionResult resolutionResult = resolveField(fieldReference, currentMethod);
- fieldAccessAnalyses.forEach(
- analysis ->
- analysis.traceInstanceFieldWrite(
- fieldReference, resolutionResult, currentMethod, workList));
+ resolveField(fieldReference, currentMethod)
+ .visitFieldResolutionResults(
+ resolutionResult -> {
+ fieldAccessAnalyses.forEach(
+ analysis ->
+ analysis.traceInstanceFieldWrite(
+ fieldReference, resolutionResult, currentMethod, workList));
- if (resolutionResult.isFailedOrUnknownResolution()) {
- // Must trace the types from the field reference even if it does not exist.
- traceFieldReference(fieldReference, resolutionResult, currentMethod);
- noClassMerging.add(fieldReference.getHolderType());
- return;
- }
+ ProgramField field = resolutionResult.getProgramField();
+ if (field == null) {
+ // No need to trace into the non-program code.
+ return;
+ }
- ProgramField field =
- resolutionResult.asSuccessfulResolution().getResolutionPair().asProgramField();
- if (field == null) {
- // No need to trace into the non-program code.
- return;
- }
+ assert !mode.isFinalTreeShaking()
+ || !field.getDefinition().getOptimizationInfo().isDead()
+ : "Unexpected reference in `"
+ + currentMethod.toSourceString()
+ + "` to field marked dead: "
+ + field.getReference().toSourceString();
- assert !mode.isFinalTreeShaking() || !field.getDefinition().getOptimizationInfo().isDead()
- : "Unexpected reference in `"
- + currentMethod.toSourceString()
- + "` to field marked dead: "
- + field.getReference().toSourceString();
+ if (fromMethodHandle) {
+ fieldAccessInfoCollection.get(field.getReference()).setWrittenFromMethodHandle();
+ }
- if (fromMethodHandle) {
- fieldAccessInfoCollection.get(field.getReference()).setWrittenFromMethodHandle();
- }
+ if (Log.ENABLED) {
+ Log.verbose(getClass(), "Register Iput `%s`.", fieldReference);
+ }
- if (Log.ENABLED) {
- Log.verbose(getClass(), "Register Iput `%s`.", fieldReference);
- }
+ if (field.getReference() != fieldReference) {
+ // Mark the initial resolution holder as live.
+ markTypeAsLive(resolutionResult.getInitialResolutionHolder(), currentMethod);
+ }
- if (field.getReference() != fieldReference) {
- // Mark the initial resolution holder as live.
- markTypeAsLive(resolutionResult.getInitialResolutionHolder(), currentMethod);
- }
-
- KeepReason reason = KeepReason.fieldReferencedIn(currentMethod);
- workList.enqueueMarkFieldAsReachableAction(field, currentMethod, reason);
+ KeepReason reason = KeepReason.fieldReferencedIn(currentMethod);
+ workList.enqueueMarkFieldAsReachableAction(field, currentMethod, reason);
+ },
+ failedResolution -> {
+ // Must trace the types from the field reference even if it does not exist.
+ traceFieldReference(fieldReference, failedResolution, currentMethod);
+ noClassMerging.add(fieldReference.getHolderType());
+ });
}
void traceStaticFieldRead(DexField field, ProgramMethod currentMethod) {
@@ -1576,63 +1595,66 @@
return;
}
- FieldResolutionResult resolutionResult = resolveField(fieldReference, currentMethod);
- fieldAccessAnalyses.forEach(
- analysis ->
- analysis.traceStaticFieldRead(
- fieldReference, resolutionResult, currentMethod, workList));
+ resolveField(fieldReference, currentMethod)
+ .visitFieldResolutionResults(
+ resolutionResult -> {
+ fieldAccessAnalyses.forEach(
+ analysis ->
+ analysis.traceStaticFieldRead(
+ fieldReference, resolutionResult, currentMethod, workList));
- if (resolutionResult.isFailedOrUnknownResolution()) {
- // Must trace the types from the field reference even if it does not exist.
- traceFieldReference(fieldReference, resolutionResult, currentMethod);
- noClassMerging.add(fieldReference.getHolderType());
+ ProgramField field = resolutionResult.getProgramField();
+ if (field == null) {
+ // No need to trace into the non-program code.
+ return;
+ }
- // Record field reference for generated extension registry shrinking.
- appView.withGeneratedExtensionRegistryShrinker(
- shrinker ->
- shrinker.handleFailedOrUnknownFieldResolution(fieldReference, currentMethod, mode));
- return;
- }
+ assert !mode.isFinalTreeShaking()
+ || !field.getDefinition().getOptimizationInfo().isDead()
+ : "Unexpected reference in `"
+ + currentMethod.toSourceString()
+ + "` to field marked dead: "
+ + field.getReference().toSourceString();
- ProgramField field =
- resolutionResult.asSuccessfulResolution().getResolutionPair().asProgramField();
- if (field == null) {
- // No need to trace into the non-program code.
- return;
- }
+ if (fromMethodHandle) {
+ fieldAccessInfoCollection.get(field.getReference()).setReadFromMethodHandle();
+ }
- assert !mode.isFinalTreeShaking() || !field.getDefinition().getOptimizationInfo().isDead()
- : "Unexpected reference in `"
- + currentMethod.toSourceString()
- + "` to field marked dead: "
- + field.getReference().toSourceString();
+ if (Log.ENABLED) {
+ Log.verbose(getClass(), "Register Sget `%s`.", fieldReference);
+ }
- if (fromMethodHandle) {
- fieldAccessInfoCollection.get(field.getReference()).setReadFromMethodHandle();
- }
+ // If it is a dead proto extension field, don't trace onwards.
+ boolean skipTracing =
+ appView.withGeneratedExtensionRegistryShrinker(
+ shrinker ->
+ shrinker.isDeadProtoExtensionField(
+ field, fieldAccessInfoCollection, keepInfo),
+ false);
+ if (skipTracing) {
+ addDeadProtoTypeCandidate(field.getHolder());
+ return;
+ }
- if (Log.ENABLED) {
- Log.verbose(getClass(), "Register Sget `%s`.", fieldReference);
- }
+ if (field.getReference() != fieldReference) {
+ // Mark the initial resolution holder as live. Note that this should only be done if
+ // the field
+ // is not a dead proto field (in which case we bail-out above).
+ markTypeAsLive(resolutionResult.getInitialResolutionHolder(), currentMethod);
+ }
- // If it is a dead proto extension field, don't trace onwards.
- boolean skipTracing =
- appView.withGeneratedExtensionRegistryShrinker(
- shrinker ->
- shrinker.isDeadProtoExtensionField(field, fieldAccessInfoCollection, keepInfo),
- false);
- if (skipTracing) {
- addDeadProtoTypeCandidate(field.getHolder());
- return;
- }
-
- if (field.getReference() != fieldReference) {
- // Mark the initial resolution holder as live. Note that this should only be done if the field
- // is not a dead proto field (in which case we bail-out above).
- markTypeAsLive(resolutionResult.getInitialResolutionHolder(), currentMethod);
- }
-
- markFieldAsLive(field, currentMethod);
+ markFieldAsLive(field, currentMethod);
+ },
+ failedResolution -> {
+ // Must trace the types from the field reference even if it does not exist.
+ traceFieldReference(fieldReference, failedResolution, currentMethod);
+ noClassMerging.add(fieldReference.getHolderType());
+ // Record field reference for generated extension registry shrinking.
+ appView.withGeneratedExtensionRegistryShrinker(
+ shrinker ->
+ shrinker.handleFailedOrUnknownFieldResolution(
+ fieldReference, currentMethod, mode));
+ });
}
void traceStaticFieldWrite(DexField field, ProgramMethod currentMethod) {
@@ -1649,60 +1671,63 @@
return;
}
- FieldResolutionResult resolutionResult = resolveField(fieldReference, currentMethod);
- fieldAccessAnalyses.forEach(
- analysis ->
- analysis.traceStaticFieldWrite(
- fieldReference, resolutionResult, currentMethod, workList));
+ resolveField(fieldReference, currentMethod)
+ .visitFieldResolutionResults(
+ resolutionResult -> {
+ fieldAccessAnalyses.forEach(
+ analysis ->
+ analysis.traceStaticFieldWrite(
+ fieldReference, resolutionResult, currentMethod, workList));
- if (resolutionResult.isFailedOrUnknownResolution()) {
- // Must trace the types from the field reference even if it does not exist.
- traceFieldReference(fieldReference, resolutionResult, currentMethod);
- noClassMerging.add(fieldReference.getHolderType());
- return;
- }
+ ProgramField field = resolutionResult.getProgramField();
+ if (field == null) {
+ // No need to trace into the non-program code.
+ return;
+ }
- ProgramField field =
- resolutionResult.asSuccessfulResolution().getResolutionPair().asProgramField();
- if (field == null) {
- // No need to trace into the non-program code.
- return;
- }
+ assert !mode.isFinalTreeShaking()
+ || !field.getDefinition().getOptimizationInfo().isDead()
+ : "Unexpected reference in `"
+ + currentMethod.toSourceString()
+ + "` to field marked dead: "
+ + field.getReference().toSourceString();
- assert !mode.isFinalTreeShaking() || !field.getDefinition().getOptimizationInfo().isDead()
- : "Unexpected reference in `"
- + currentMethod.toSourceString()
- + "` to field marked dead: "
- + field.getReference().toSourceString();
+ if (fromMethodHandle) {
+ fieldAccessInfoCollection.get(field.getReference()).setWrittenFromMethodHandle();
+ }
- if (fromMethodHandle) {
- fieldAccessInfoCollection.get(field.getReference()).setWrittenFromMethodHandle();
- }
+ if (Log.ENABLED) {
+ Log.verbose(getClass(), "Register Sput `%s`.", fieldReference);
+ }
- if (Log.ENABLED) {
- Log.verbose(getClass(), "Register Sput `%s`.", fieldReference);
- }
+ if (appView.options().protoShrinking().enableGeneratedExtensionRegistryShrinking) {
+ // If it is a dead proto extension field, don't trace onwards.
+ boolean skipTracing =
+ appView.withGeneratedExtensionRegistryShrinker(
+ shrinker ->
+ shrinker.isDeadProtoExtensionField(
+ field, fieldAccessInfoCollection, keepInfo),
+ false);
+ if (skipTracing) {
+ addDeadProtoTypeCandidate(field.getHolder());
+ return;
+ }
+ }
- if (appView.options().protoShrinking().enableGeneratedExtensionRegistryShrinking) {
- // If it is a dead proto extension field, don't trace onwards.
- boolean skipTracing =
- appView.withGeneratedExtensionRegistryShrinker(
- shrinker ->
- shrinker.isDeadProtoExtensionField(field, fieldAccessInfoCollection, keepInfo),
- false);
- if (skipTracing) {
- addDeadProtoTypeCandidate(field.getHolder());
- return;
- }
- }
+ if (field.getReference() != fieldReference) {
+ // Mark the initial resolution holder as live. Note that this should only be done if
+ // the field
+ // is not a dead proto field (in which case we bail-out above).
+ markTypeAsLive(resolutionResult.getInitialResolutionHolder(), currentMethod);
+ }
- if (field.getReference() != fieldReference) {
- // Mark the initial resolution holder as live. Note that this should only be done if the field
- // is not a dead proto field (in which case we bail-out above).
- markTypeAsLive(resolutionResult.getInitialResolutionHolder(), currentMethod);
- }
-
- markFieldAsLive(field, currentMethod);
+ markFieldAsLive(field, currentMethod);
+ },
+ failedResolution -> {
+ // Must trace the types from the field reference even if it does not exist.
+ traceFieldReference(fieldReference, failedResolution, currentMethod);
+ noClassMerging.add(fieldReference.getHolderType());
+ });
}
private DexMethod getInvokeSuperTarget(DexMethod method, ProgramMethod currentMethod) {
@@ -2069,16 +2094,17 @@
private FieldResolutionResult resolveField(DexField field, ProgramDefinition context) {
// Record the references in case they are not program types.
- FieldResolutionResult resolutionResult = appInfo.resolveField(field);
- if (resolutionResult.isSuccessfulResolution()) {
- recordFieldReference(
- field, resolutionResult.getResolutionPair().asProgramDerivedContext(context));
- } else {
- assert resolutionResult.isFailedOrUnknownResolution();
- failedFieldResolutionTargets.add(field);
- recordFieldReference(field, context);
- }
- return resolutionResult;
+ FieldResolutionResult fieldResolutionResult = appInfo.resolveField(field);
+ fieldResolutionResult.visitFieldResolutionResults(
+ resolutionResult -> {
+ recordFieldReference(
+ field, resolutionResult.getResolutionPair().asProgramDerivedContext(context));
+ },
+ failedResolution -> {
+ failedFieldResolutionTargets.add(field);
+ recordFieldReference(field, context);
+ });
+ return fieldResolutionResult;
}
private SingleResolutionResult resolveMethod(
@@ -2355,11 +2381,20 @@
if (!clazz.isProgramClass()) {
addLiveNonProgramType(
clazz.asClasspathOrLibraryClass(),
+ true,
(missingType, derivedContext) ->
reportMissingClass(missingType, derivedContext.asProgramDerivedContext(context)));
}
}
+ private void recordNonProgramClassWithNoMissingReporting(
+ DexClass clazz, ProgramDerivedContext context) {
+ if (!clazz.isProgramClass()) {
+ addLiveNonProgramType(
+ clazz.asClasspathOrLibraryClass(), true, this::ignoreMissingClasspathOrLibraryClass);
+ }
+ }
+
private void ignoreMissingClass(DexType clazz) {
missingClassesBuilder.ignoreNewMissingClass(clazz);
}
@@ -2633,7 +2668,7 @@
// maintains the library override. In the second enqueuer phase, the signature has been
// desugared, and the second resolution maintains the the library override.
if (instantiation.isClass()
- && appView.rewritePrefix.hasRewrittenTypeInSignature(
+ && appView.typeRewriter.hasRewrittenTypeInSignature(
method.getReference().proto, appView)) {
DexMethod methodToResolve =
DesugaredLibraryAPIConverter.methodWithVivifiedTypeInSignature(
@@ -2838,8 +2873,9 @@
}
private void traceFieldReference(
- DexField field, FieldResolutionResult resolutionResult, ProgramMethod context) {
- assert resolutionResult.isFailedOrUnknownResolution();
+ DexField field,
+ FailedOrUnknownFieldResolutionResult resolutionResult,
+ ProgramMethod context) {
markTypeAsLive(field.getHolderType(), context);
markTypeAsLive(field.getType(), context);
}
@@ -3750,6 +3786,9 @@
// Rebuild a new app only containing referenced types.
Set<DexLibraryClass> libraryClasses = Sets.newIdentityHashSet();
Set<DexClasspathClass> classpathClasses = Sets.newIdentityHashSet();
+ // Ensure all referenced non program types have their hierarchy built as live.
+ referencedNonProgramTypes.forEach(
+ clazz -> addLiveNonProgramType(clazz, false, this::ignoreMissingClasspathOrLibraryClass));
for (ClasspathOrLibraryClass clazz : liveNonProgramTypes) {
if (clazz.isLibraryClass()) {
libraryClasses.add(clazz.asLibraryClass());
@@ -3908,14 +3947,16 @@
}
assert clazz.isProgramClass() || liveNonProgramTypes.contains(clazz)
: "Expected type to be in live non-program types: " + clazz;
- for (DexEncodedField field : clazz.fields()) {
- if (clazz.isNotProgramClass() || isFieldReferenced(field)) {
- assert verifyReferencedType(field.getReference().type, worklist, app);
+ if (clazz.isProgramClass()) {
+ for (DexEncodedField field : clazz.fields()) {
+ if (isFieldReferenced(field)) {
+ assert verifyReferencedType(field.getReference().type, worklist, app);
+ }
}
- }
- for (DexEncodedMethod method : clazz.methods()) {
- if (clazz.isNotProgramClass() || isMethodTargeted(method)) {
- assert verifyReferencedMethod(method, worklist, app);
+ for (DexEncodedMethod method : clazz.methods()) {
+ if (isMethodTargeted(method)) {
+ assert verifyReferencedMethod(method, worklist, app);
+ }
}
}
return true;
@@ -4075,8 +4116,7 @@
InterfaceMethodProcessorFacade interfaceDesugaring =
desugaring.getInterfaceMethodPostProcessingDesugaringR8(
ExcludeDexResources, liveMethods::contains, interfaceProcessor);
- CfPostProcessingDesugaringCollection.create(
- appView, interfaceDesugaring, desugaring.getRetargetingInfo())
+ CfPostProcessingDesugaringCollection.create(appView, interfaceDesugaring)
.postProcessingDesugaring(
liveTypes.items, liveMethods::contains, eventConsumer, executorService);
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java b/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java
index c82c666..cd46a71 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java
@@ -28,6 +28,7 @@
private final boolean allowConstantArgumentOptimization;
private final boolean allowInlining;
private final boolean allowMethodStaticizing;
+ private final boolean allowParameterReordering;
private final boolean allowParameterTypeStrengthening;
private final boolean allowReturnTypeStrengthening;
private final boolean allowUnusedArgumentOptimization;
@@ -39,6 +40,7 @@
this.allowConstantArgumentOptimization = builder.isConstantArgumentOptimizationAllowed();
this.allowInlining = builder.isInliningAllowed();
this.allowMethodStaticizing = builder.isMethodStaticizingAllowed();
+ this.allowParameterReordering = builder.isParameterReorderingAllowed();
this.allowParameterTypeStrengthening = builder.isParameterTypeStrengtheningAllowed();
this.allowReturnTypeStrengthening = builder.isReturnTypeStrengtheningAllowed();
this.allowUnusedArgumentOptimization = builder.isUnusedArgumentOptimizationAllowed();
@@ -97,6 +99,16 @@
return allowMethodStaticizing;
}
+ public boolean isParameterReorderingAllowed(GlobalKeepInfoConfiguration configuration) {
+ return isOptimizationAllowed(configuration)
+ && isShrinkingAllowed(configuration)
+ && internalIsParameterReorderingAllowed();
+ }
+
+ boolean internalIsParameterReorderingAllowed() {
+ return allowParameterReordering;
+ }
+
public boolean isParameterTypeStrengtheningAllowed(GlobalKeepInfoConfiguration configuration) {
return isOptimizationAllowed(configuration)
&& isShrinkingAllowed(configuration)
@@ -158,6 +170,7 @@
private boolean allowConstantArgumentOptimization;
private boolean allowInlining;
private boolean allowMethodStaticizing;
+ private boolean allowParameterReordering;
private boolean allowParameterTypeStrengthening;
private boolean allowReturnTypeStrengthening;
private boolean allowUnusedArgumentOptimization;
@@ -173,6 +186,7 @@
allowConstantArgumentOptimization = original.internalIsConstantArgumentOptimizationAllowed();
allowInlining = original.internalIsInliningAllowed();
allowMethodStaticizing = original.internalIsMethodStaticizingAllowed();
+ allowParameterReordering = original.internalIsParameterReorderingAllowed();
allowParameterTypeStrengthening = original.internalIsParameterTypeStrengtheningAllowed();
allowReturnTypeStrengthening = original.internalIsReturnTypeStrengtheningAllowed();
allowUnusedArgumentOptimization = original.internalIsUnusedArgumentOptimizationAllowed();
@@ -256,6 +270,25 @@
return setAllowMethodStaticizing(false);
}
+ // Parameter reordering.
+
+ public boolean isParameterReorderingAllowed() {
+ return allowParameterReordering;
+ }
+
+ public Builder setAllowParameterReordering(boolean allowParameterReordering) {
+ this.allowParameterReordering = allowParameterReordering;
+ return self();
+ }
+
+ public Builder allowParameterReordering() {
+ return setAllowParameterReordering(true);
+ }
+
+ public Builder disallowParameterReordering() {
+ return setAllowParameterReordering(false);
+ }
+
// Parameter type strengthening.
public boolean isParameterTypeStrengtheningAllowed() {
@@ -361,6 +394,7 @@
== other.internalIsConstantArgumentOptimizationAllowed()
&& isInliningAllowed() == other.internalIsInliningAllowed()
&& isMethodStaticizingAllowed() == other.internalIsMethodStaticizingAllowed()
+ && isParameterReorderingAllowed() == other.internalIsParameterReorderingAllowed()
&& isParameterTypeStrengtheningAllowed()
== other.internalIsParameterTypeStrengtheningAllowed()
&& isReturnTypeStrengtheningAllowed() == other.internalIsReturnTypeStrengtheningAllowed()
@@ -382,6 +416,7 @@
.disallowConstantArgumentOptimization()
.disallowInlining()
.disallowMethodStaticizing()
+ .disallowParameterReordering()
.disallowParameterTypeStrengthening()
.disallowReturnTypeStrengthening()
.disallowUnusedArgumentOptimization()
@@ -395,6 +430,7 @@
.allowConstantArgumentOptimization()
.allowInlining()
.allowMethodStaticizing()
+ .allowParameterReordering()
.allowParameterTypeStrengthening()
.allowReturnTypeStrengthening()
.allowUnusedArgumentOptimization()
@@ -428,6 +464,11 @@
return self();
}
+ public Joiner disallowParameterReordering() {
+ builder.disallowParameterReordering();
+ return self();
+ }
+
public Joiner disallowParameterTypeStrengthening() {
builder.disallowParameterTypeStrengthening();
return self();
@@ -464,6 +505,8 @@
.applyIf(!joiner.builder.isInliningAllowed(), Joiner::disallowInlining)
.applyIf(!joiner.builder.isMethodStaticizingAllowed(), Joiner::disallowMethodStaticizing)
.applyIf(
+ !joiner.builder.isParameterReorderingAllowed(), Joiner::disallowParameterReordering)
+ .applyIf(
!joiner.builder.isParameterTypeStrengtheningAllowed(),
Joiner::disallowParameterTypeStrengthening)
.applyIf(
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 960ccd5..46e77e8 100644
--- a/src/main/java/com/android/tools/r8/shaking/L8TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/L8TreePruner.java
@@ -7,7 +7,7 @@
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.desugar.PrefixRewritingMapper;
+import com.android.tools.r8.ir.desugar.TypeRewriter;
import com.android.tools.r8.utils.InternalOptions;
import com.google.common.collect.Sets;
import java.util.ArrayList;
@@ -28,18 +28,18 @@
public L8TreePruner(InternalOptions options) {
this.options = options;
- backports.addAll(options.desugaredLibrarySpecification.getBackportCoreLibraryMember().keySet());
+ backports.addAll(options.machineDesugaredLibrarySpecification.getLegacyBackport().keySet());
emulatedInterfaces.addAll(
- options.desugaredLibrarySpecification.getEmulateLibraryInterface().keySet());
+ options.machineDesugaredLibrarySpecification.getEmulatedInterfaces().keySet());
}
- public DexApplication prune(DexApplication app, PrefixRewritingMapper rewritePrefix) {
+ public DexApplication prune(DexApplication app, TypeRewriter typeRewriter) {
Map<DexType, DexProgramClass> typeMap = new IdentityHashMap<>();
List<DexProgramClass> toKeep = new ArrayList<>();
boolean pruneNestMember = false;
for (DexProgramClass aClass : app.classes()) {
typeMap.put(aClass.type, aClass);
- if (rewritePrefix.hasRewrittenType(aClass.type, null)
+ if (typeRewriter.hasRewrittenType(aClass.type, null)
|| emulatedInterfaces.contains(aClass.type)) {
toKeep.add(aClass);
} else {
diff --git a/src/main/java/com/android/tools/r8/shaking/NoParameterReorderingRule.java b/src/main/java/com/android/tools/r8/shaking/NoParameterReorderingRule.java
new file mode 100644
index 0000000..c8d0e6c
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/shaking/NoParameterReorderingRule.java
@@ -0,0 +1,84 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.shaking;
+
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.position.Position;
+import java.util.List;
+
+public class NoParameterReorderingRule extends NoOptimizationBaseRule<NoParameterReorderingRule> {
+
+ public static final String RULE_NAME = "noparameterreordering";
+
+ public static class Builder
+ extends NoOptimizationBaseRule.Builder<NoParameterReorderingRule, Builder> {
+
+ Builder() {
+ super();
+ }
+
+ @Override
+ public NoParameterReorderingRule.Builder self() {
+ return this;
+ }
+
+ @Override
+ public NoParameterReorderingRule build() {
+ return new NoParameterReorderingRule(
+ origin,
+ getPosition(),
+ source,
+ buildClassAnnotations(),
+ classAccessFlags,
+ negatedClassAccessFlags,
+ classTypeNegated,
+ classType,
+ classNames,
+ buildInheritanceAnnotations(),
+ inheritanceClassName,
+ inheritanceIsExtends,
+ memberRules);
+ }
+ }
+
+ NoParameterReorderingRule(
+ Origin origin,
+ Position position,
+ String source,
+ List<ProguardTypeMatcher> classAnnotations,
+ ProguardAccessFlags classAccessFlags,
+ ProguardAccessFlags negatedClassAccessFlags,
+ boolean classTypeNegated,
+ ProguardClassType classType,
+ ProguardClassNameList classNames,
+ List<ProguardTypeMatcher> inheritanceAnnotations,
+ ProguardTypeMatcher inheritanceClassName,
+ boolean inheritanceIsExtends,
+ List<ProguardMemberRule> memberRules) {
+ super(
+ origin,
+ position,
+ source,
+ classAnnotations,
+ classAccessFlags,
+ negatedClassAccessFlags,
+ classTypeNegated,
+ classType,
+ classNames,
+ inheritanceAnnotations,
+ inheritanceClassName,
+ inheritanceIsExtends,
+ memberRules);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ @Override
+ String typeString() {
+ return RULE_NAME;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
index 0f2ad2c..4ed94e5 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -514,6 +514,12 @@
configurationBuilder.addRule(rule);
return true;
}
+ if (acceptString(NoParameterReorderingRule.RULE_NAME)) {
+ ProguardConfigurationRule rule =
+ parseNoOptimizationRule(optionStart, NoParameterReorderingRule.builder());
+ configurationBuilder.addRule(rule);
+ return true;
+ }
if (acceptString(NoParameterTypeStrengtheningRule.RULE_NAME)) {
ProguardConfigurationRule rule =
parseNoOptimizationRule(optionStart, NoParameterTypeStrengtheningRule.builder());
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java
index 41181b1..ea30b42 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java
@@ -3,8 +3,10 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
+import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.ClassResolutionResult;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexDefinitionSupplier;
import com.android.tools.r8.graph.DexItemFactory;
@@ -128,6 +130,12 @@
specificTypes,
new DexDefinitionSupplier() {
@Override
+ public ClassResolutionResult contextIndependentDefinitionForWithResolutionResult(
+ DexType type) {
+ throw new Unreachable("Add support for multiple definitions with rule evaluation");
+ }
+
+ @Override
public DexClass definitionFor(DexType type) {
if (canReferenceDeadTypes) {
return appView.appInfo().definitionForWithoutExistenceAssert(type);
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 89b55dd..95ec8c3 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
@@ -267,6 +267,7 @@
|| rule instanceof KeepConstantArgumentRule
|| rule instanceof KeepUnusedReturnValueRule
|| rule instanceof NoMethodStaticizingRule
+ || rule instanceof NoParameterReorderingRule
|| rule instanceof NoParameterTypeStrengtheningRule
|| rule instanceof NoReturnTypeStrengtheningRule
|| rule instanceof KeepUnusedArgumentRule
@@ -1255,6 +1256,13 @@
.asMethodJoiner()
.disallowMethodStaticizing();
context.markAsUsed();
+ } else if (context instanceof NoParameterReorderingRule) {
+ assert item.isProgramMethod();
+ dependentMinimumKeepInfo
+ .getOrCreateUnconditionalMinimumKeepInfoFor(item.getReference())
+ .asMethodJoiner()
+ .disallowParameterReordering();
+ context.markAsUsed();
} else if (context instanceof NoParameterTypeStrengtheningRule) {
assert item.isProgramMethod();
dependentMinimumKeepInfo
diff --git a/src/main/java/com/android/tools/r8/synthesis/CommittedItems.java b/src/main/java/com/android/tools/r8/synthesis/CommittedItems.java
index 1e4071f..dddb984 100644
--- a/src/main/java/com/android/tools/r8/synthesis/CommittedItems.java
+++ b/src/main/java/com/android/tools/r8/synthesis/CommittedItems.java
@@ -3,8 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.synthesis;
+import com.android.tools.r8.graph.ClassResolutionResult;
import com.android.tools.r8.graph.DexApplication;
-import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexType;
import com.google.common.collect.ImmutableList;
import java.util.Collection;
@@ -55,7 +55,8 @@
}
@Override
- public DexClass definitionFor(DexType type, Function<DexType, DexClass> baseDefinitionFor) {
+ public ClassResolutionResult definitionFor(
+ DexType type, Function<DexType, ClassResolutionResult> baseDefinitionFor) {
// All synthetic types are committed to the application so lookup is just the base lookup.
return baseDefinitionFor.apply(type);
}
diff --git a/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java b/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java
index bbf4258..3b3aeea 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java
@@ -129,12 +129,7 @@
return;
}
assert hygienicType.toSourceString().startsWith(synthesizingContextType.toSourceString());
- DexType rewrittenContext =
- appView
- .options()
- .desugaredLibrarySpecification
- .getEmulateLibraryInterface()
- .get(synthesizingContextType);
+ DexType rewrittenContext = appView.typeRewriter.rewrittenContextType(synthesizingContextType);
if (rewrittenContext == null) {
return;
}
@@ -148,7 +143,7 @@
appView
.dexItemFactory()
.createType(getDescriptorFromClassBinaryName(rewrittenPrefix + suffix));
- appView.rewritePrefix.rewriteType(hygienicType, rewrittenType);
+ appView.typeRewriter.rewriteType(hygienicType, rewrittenType);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticDefinitionsProvider.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticDefinitionsProvider.java
index e66401e..a428331 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticDefinitionsProvider.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticDefinitionsProvider.java
@@ -3,10 +3,11 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.synthesis;
-import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.ClassResolutionResult;
import com.android.tools.r8.graph.DexType;
import java.util.function.Function;
public interface SyntheticDefinitionsProvider {
- DexClass definitionFor(DexType type, Function<DexType, DexClass> baseDefinitionFor);
+ ClassResolutionResult definitionFor(
+ DexType type, Function<DexType, ClassResolutionResult> baseDefinitionFor);
}
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
index 0cb0137..1e9ffb4 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
@@ -10,6 +10,8 @@
import com.android.tools.r8.features.ClassToFeatureSplitMap;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.ClassResolutionResult;
+import com.android.tools.r8.graph.ClasspathMethod;
import com.android.tools.r8.graph.ClasspathOrLibraryClass;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexClass;
@@ -175,7 +177,8 @@
// Predicates and accessors.
@Override
- public DexClass definitionFor(DexType type, Function<DexType, DexClass> baseDefinitionFor) {
+ public ClassResolutionResult definitionFor(
+ DexType type, Function<DexType, ClassResolutionResult> baseDefinitionFor) {
DexClass clazz = null;
SyntheticKind kind = null;
SyntheticDefinition<?, ?, ?> item = pending.nonLegacyDefinitions.get(type);
@@ -187,7 +190,8 @@
}
if (clazz != null) {
assert kind != null;
- assert baseDefinitionFor.apply(type) == null || kind.mayOverridesNonProgramType
+ assert !baseDefinitionFor.apply(type).hasClassResolutionResult()
+ || kind.mayOverridesNonProgramType
: "Pending synthetic definition also present in the active program: " + type;
return clazz;
}
@@ -483,14 +487,13 @@
AppView<?> appView,
DexType type) {
DexType rewrittenContextType =
- appView.rewritePrefix.rewrittenContextType(
- outerContext.getSynthesizingContextType(), appView);
+ appView.typeRewriter.rewrittenContextType(outerContext.getSynthesizingContextType());
if (rewrittenContextType == null) {
return;
}
SynthesizingContext synthesizingContext = SynthesizingContext.fromType(rewrittenContextType);
DexType rewrittenType = contextToType.apply(synthesizingContext);
- appView.rewritePrefix.rewriteType(type, rewrittenType);
+ appView.typeRewriter.rewriteType(type, rewrittenType);
}
public DexProgramClass createClass(
@@ -650,10 +653,11 @@
SyntheticKind kind,
DexType contextType,
AppView<?> appView,
- Consumer<SyntheticClasspathClassBuilder> classConsumer) {
+ Consumer<SyntheticClasspathClassBuilder> classConsumer,
+ Consumer<DexClasspathClass> onCreationConsumer) {
SynthesizingContext outerContext = SynthesizingContext.fromType(contextType);
return internalEnsureFixedClasspathClass(
- kind, classConsumer, ignored -> {}, outerContext, appView);
+ kind, classConsumer, onCreationConsumer, outerContext, appView);
}
public DexClasspathClass ensureFixedClasspathClass(
@@ -669,7 +673,23 @@
kind, classConsumer, onCreationConsumer, outerContext, appView);
}
- public DexClassAndMethod ensureFixedClasspathClassMethod(
+ public ClasspathMethod ensureFixedClasspathMethodFromType(
+ DexString methodName,
+ DexProto methodProto,
+ SyntheticKind kind,
+ DexType contextType,
+ AppView<?> appView,
+ Consumer<SyntheticClasspathClassBuilder> classConsumer,
+ Consumer<DexClasspathClass> onCreationConsumer,
+ Consumer<SyntheticMethodBuilder> buildMethodCallback) {
+ DexClasspathClass clazz =
+ ensureFixedClasspathClassFromType(
+ kind, contextType, appView, classConsumer, onCreationConsumer);
+ return internalEnsureFixedClasspathMethod(
+ methodName, methodProto, kind, appView, buildMethodCallback, clazz);
+ }
+
+ public ClasspathMethod ensureFixedClasspathClassMethod(
DexString methodName,
DexProto methodProto,
SyntheticKind kind,
@@ -681,6 +701,17 @@
DexClasspathClass clazz =
ensureFixedClasspathClass(
kind, context, appView, buildClassCallback, onClassCreationCallback);
+ return internalEnsureFixedClasspathMethod(
+ methodName, methodProto, kind, appView, buildMethodCallback, clazz);
+ }
+
+ private ClasspathMethod internalEnsureFixedClasspathMethod(
+ DexString methodName,
+ DexProto methodProto,
+ SyntheticKind kind,
+ AppView<?> appView,
+ Consumer<SyntheticMethodBuilder> buildMethodCallback,
+ DexClasspathClass clazz) {
DexMethod methodReference =
appView.dexItemFactory().createMethod(clazz.getType(), methodProto, methodName);
DexEncodedMethod methodDefinition =
@@ -695,7 +726,7 @@
buildMethodCallback.accept(methodBuilder.disableAndroidApiLevelCheck());
},
emptyConsumer());
- return DexClassAndMethod.create(clazz, methodDefinition);
+ return new ClasspathMethod(clazz, methodDefinition);
}
@SuppressWarnings("unchecked")
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 b7861e3..ec8a010 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java
@@ -180,6 +180,10 @@
}
private Code getCodeObject(DexMethod methodSignature) {
+ if (codeGenerator == null) {
+ // If the method is on the classpath then no code is needed.
+ return null;
+ }
return codeGenerator.generate(methodSignature);
}
}
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
index 62c7c6f..4d8b529 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
@@ -31,6 +31,7 @@
COMPANION_CLASS("$-CC", 2, false, true),
EMULATED_INTERFACE_CLASS("$-EL", 3, false, true),
RETARGET_CLASS("RetargetClass", 20, false, true),
+ RETARGET_STUB("", 36, false, true),
RETARGET_INTERFACE("RetargetInterface", 21, false, true),
WRAPPER("$Wrapper", 22, false, true),
VIVIFIED_WRAPPER("$VivifiedWrapper", 23, false, true),
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java b/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
index 38934f2..6bec653 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
@@ -42,12 +42,13 @@
R(30),
S(31),
Sv2(32),
+ T(33),
ANDROID_PLATFORM(10000);
// When updating LATEST and a new version goes stable, add a new api-versions.xml to third_party
// and update the version and generated jar in AndroidApiDatabaseBuilderGeneratorTest.
- // TODO(b/204738868): Update API database for Sv2.
- public static final AndroidApiLevel LATEST = Sv2;
+ // TODO(b/204738868): Update API database for Sv2 / T when they are ready.
+ public static final AndroidApiLevel LATEST = T;
private final int level;
@@ -96,6 +97,7 @@
public static AndroidApiLevel getAndroidApiLevel(int apiLevel) {
assert apiLevel > 0;
+ assert T == LATEST; // This has to be updated when we add new api levels.
assert ANDROID_PLATFORM.isGreaterThan(LATEST);
switch (apiLevel) {
case 1:
@@ -162,11 +164,11 @@
return S;
case 32:
return Sv2;
+ case 33:
+ return T;
case 10000:
return ANDROID_PLATFORM;
default:
- // This has to be updated when we add new api levels.
- assert Sv2 == LATEST;
return LATEST;
}
}
diff --git a/src/main/java/com/android/tools/r8/utils/DexVersion.java b/src/main/java/com/android/tools/r8/utils/DexVersion.java
index 624e70e..ac962fa 100644
--- a/src/main/java/com/android/tools/r8/utils/DexVersion.java
+++ b/src/main/java/com/android/tools/r8/utils/DexVersion.java
@@ -41,6 +41,7 @@
// ANDROID_PLATFORM is an unknown higher api version we therefore choose the highest known
// version.
case ANDROID_PLATFORM:
+ case T:
case Sv2:
case S:
case R:
diff --git a/src/main/java/com/android/tools/r8/utils/ForEachUtils.java b/src/main/java/com/android/tools/r8/utils/ForEachUtils.java
new file mode 100644
index 0000000..532acf7
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/ForEachUtils.java
@@ -0,0 +1,20 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.utils;
+
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
+public class ForEachUtils {
+
+ public static <T> boolean allMatch(Consumer<Consumer<T>> forEach, Predicate<T> predicate) {
+ BooleanBox acc = new BooleanBox(true);
+ forEach.accept(
+ value -> {
+ acc.and(predicate.test(value));
+ });
+ return acc.isTrue();
+ }
+}
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 ec5dca6..066ca9f 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -52,10 +52,13 @@
import com.android.tools.r8.horizontalclassmerging.Policy;
import com.android.tools.r8.inspector.internal.InspectorImpl;
import com.android.tools.r8.ir.code.IRCode;
-import com.android.tools.r8.ir.desugar.PrefixRewritingMapper;
-import com.android.tools.r8.ir.desugar.PrefixRewritingMapper.MachineDesugarPrefixRewritingMapper;
+import com.android.tools.r8.ir.desugar.TypeRewriter;
+import com.android.tools.r8.ir.desugar.TypeRewriter.MachineDesugarPrefixRewritingMapper;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecification;
import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.HumanToMachineSpecificationConverter;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.LegacyToHumanSpecificationConverter;
import com.android.tools.r8.ir.desugar.nest.Nest;
import com.android.tools.r8.ir.optimize.Inliner;
import com.android.tools.r8.ir.optimize.enums.EnumDataMap;
@@ -85,7 +88,9 @@
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
+import java.io.IOException;
import java.io.PrintStream;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -390,8 +395,8 @@
if (isGeneratingDex() || desugarState == DesugarState.ON) {
marker.setMinApi(getMinApiLevel().getLevel());
}
- if (desugaredLibrarySpecification.getIdentifier() != null) {
- marker.setDesugaredLibraryIdentifiers(desugaredLibrarySpecification.getIdentifier());
+ if (machineDesugaredLibrarySpecification.getIdentifier() != null) {
+ marker.setDesugaredLibraryIdentifiers(machineDesugaredLibrarySpecification.getIdentifier());
}
if (Version.isDevelopmentVersion()) {
marker.setSha1(VersionProperties.INSTANCE.getSha());
@@ -438,7 +443,7 @@
}
public boolean isDesugaredLibraryCompilation() {
- return desugaredLibrarySpecification.isLibraryCompilation();
+ return machineDesugaredLibrarySpecification.isLibraryCompilation();
}
public boolean isRelocatorCompilation() {
@@ -883,18 +888,49 @@
// If non-null, configuration must be passed to the consumer.
public StringConsumer configurationConsumer = null;
- // If null, no desugaring of library is performed.
- // If non null it contains flags describing library desugaring.
- public LegacyDesugaredLibrarySpecification desugaredLibrarySpecification =
- LegacyDesugaredLibrarySpecification.empty();
-
- public PrefixRewritingMapper getPrefixRewritingMapper() {
- if (testing.machineDesugaredLibrarySpecification != null) {
- return new MachineDesugarPrefixRewritingMapper(
- desugaredLibrarySpecification.getPrefixRewritingMapper(),
- testing.machineDesugaredLibrarySpecification.getRewritingFlags());
+ public void setDesugaredLibrarySpecification(
+ LegacyDesugaredLibrarySpecification specification, AndroidApp app) {
+ if (specification.isEmptyConfiguration()) {
+ return;
}
- return desugaredLibrarySpecification.getPrefixRewritingMapper();
+ try {
+ HumanDesugaredLibrarySpecification human =
+ new LegacyToHumanSpecificationConverter()
+ .convert(specification, app.getLibraryResourceProviders(), this);
+ machineDesugaredLibrarySpecification =
+ new HumanToMachineSpecificationConverter()
+ .convert(
+ human,
+ specification.isLibraryCompilation() ? app.getProgramResourceProviders() : null,
+ app.getLibraryResourceProviders(),
+ this);
+ } catch (IOException e) {
+ reporter.error(new ExceptionDiagnostic(e, Origin.unknown()));
+ }
+ }
+
+ public void setDesugaredLibrarySpecificationForTesting(
+ LegacyDesugaredLibrarySpecification specification, Path desugaredJDKLib, Path library)
+ throws IOException {
+ HumanDesugaredLibrarySpecification human =
+ new LegacyToHumanSpecificationConverter().convert(specification, library, this);
+ machineDesugaredLibrarySpecification =
+ new HumanToMachineSpecificationConverter()
+ .convert(
+ human,
+ specification.isLibraryCompilation() ? desugaredJDKLib : null,
+ library,
+ this);
+ }
+
+ // Contains flags describing library desugaring.
+ public MachineDesugaredLibrarySpecification machineDesugaredLibrarySpecification =
+ MachineDesugaredLibrarySpecification.empty();
+
+ public TypeRewriter getTypeRewriter() {
+ return machineDesugaredLibrarySpecification.getRewriteType().isEmpty()
+ ? TypeRewriter.empty()
+ : new MachineDesugarPrefixRewritingMapper(machineDesugaredLibrarySpecification);
}
public boolean relocatorCompilation = false;
@@ -1599,9 +1635,6 @@
public Consumer<Deque<ProgramMethodSet>> waveModifier = waves -> {};
- // Meant to replace desugaredLibrarySpecification, set only from tests at the moment.
- public MachineDesugaredLibrarySpecification machineDesugaredLibrarySpecification = null;
-
/**
* If this flag is enabled, we will also compute the set of possible targets for invoke-
* interface and invoke-virtual instructions that target a library method, and add the
@@ -1903,10 +1936,6 @@
return isGeneratingDex() && hasMinApi(AndroidApiLevel.N);
}
- public boolean canUseJavaUtilObjectsRequireNonNull() {
- return isGeneratingDex() && hasMinApi(AndroidApiLevel.K);
- }
-
public boolean canUseSuppressedExceptions() {
// TODO(b/214239152): Suppressed exceptions are @hide from at least 4.0.1 / Android I / API 14.
return !isDesugaring() || hasMinApi(AndroidApiLevel.K);
@@ -2309,4 +2338,16 @@
public boolean canHaveSuperInvokeBug() {
return getMinApiLevel().isLessThan(AndroidApiLevel.N);
}
+
+ // Some Dalvik and Art MVs does not support interface invokes to Object
+ // members not explicitly defined on the symbolic reference of the
+ // interface invoke. In these cases rewrite to a virtual invoke with
+ // the symbolic reference java.lang.Object.
+ //
+ // javac started generating code like this with the fix for JDK-8272564.
+ //
+ // See b/218298666.
+ public boolean canHaveInvokeInterfaceToObjectMethodBug() {
+ return isGeneratingDex() && getMinApiLevel().isLessThan(AndroidApiLevel.O);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/utils/ThreadUtils.java b/src/main/java/com/android/tools/r8/utils/ThreadUtils.java
index 3ae44fb..b0a6710 100644
--- a/src/main/java/com/android/tools/r8/utils/ThreadUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/ThreadUtils.java
@@ -3,6 +3,8 @@
// 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.ArrayList;
import java.util.Collection;
import java.util.Iterator;
@@ -122,6 +124,17 @@
items.entrySet(), arg -> consumer.apply(arg.getKey(), arg.getValue()), executorService);
}
+ public static <E extends Exception> void processMethods(
+ AppView<?> appView,
+ ThrowingConsumer<ProgramMethod, E> consumer,
+ ExecutorService executorService)
+ throws ExecutionException {
+ processItems(
+ appView.appInfo().classes(),
+ clazz -> clazz.forEachProgramMethod(consumer::acceptWithRuntimeException),
+ executorService);
+ }
+
public static void awaitFutures(Iterable<? extends Future<?>> futures)
throws ExecutionException {
Iterator<? extends Future<?>> futureIterator = futures.iterator();
diff --git a/src/main/java/com/android/tools/r8/utils/ThrowingConsumer.java b/src/main/java/com/android/tools/r8/utils/ThrowingConsumer.java
index 61557e5..2b6eb66 100644
--- a/src/main/java/com/android/tools/r8/utils/ThrowingConsumer.java
+++ b/src/main/java/com/android/tools/r8/utils/ThrowingConsumer.java
@@ -14,4 +14,16 @@
@FunctionalInterface
public interface ThrowingConsumer<T, E extends Throwable> {
void accept(T t) throws E;
+
+ default void acceptWithRuntimeException(T t) {
+ try {
+ accept(t);
+ } catch (Throwable throwable) {
+ RuntimeException runtimeException =
+ throwable instanceof RuntimeException
+ ? (RuntimeException) throwable
+ : new RuntimeException(throwable);
+ throw runtimeException;
+ }
+ }
}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/DexMethodSignatureSet.java b/src/main/java/com/android/tools/r8/utils/collections/DexMethodSignatureSet.java
index 8ef1277..901ef75 100644
--- a/src/main/java/com/android/tools/r8/utils/collections/DexMethodSignatureSet.java
+++ b/src/main/java/com/android/tools/r8/utils/collections/DexMethodSignatureSet.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexMethodSignature;
import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
@@ -36,6 +37,10 @@
return new DexMethodSignatureSet(new HashSet<>(collection.backing));
}
+ public static DexMethodSignatureSet createConcurrent() {
+ return new DexMethodSignatureSet(Sets.newConcurrentHashSet());
+ }
+
public static DexMethodSignatureSet createLinked() {
return new DexMethodSignatureSet(new LinkedHashSet<>());
}
diff --git a/src/main/java/com/android/tools/r8/utils/structural/Ordered.java b/src/main/java/com/android/tools/r8/utils/structural/Ordered.java
index 9c9a588..61508a0 100644
--- a/src/main/java/com/android/tools/r8/utils/structural/Ordered.java
+++ b/src/main/java/com/android/tools/r8/utils/structural/Ordered.java
@@ -60,4 +60,8 @@
default boolean isGreaterThanOrEqualTo(T other) {
return compareTo(other) >= 0;
}
+
+ default boolean betweenBothIncluded(T lower, T upper) {
+ return isGreaterThanOrEqualTo(lower) && isLessThanOrEqualTo(upper);
+ }
}
diff --git a/src/test/examplesJava18/jdk8272564/A.java b/src/test/examplesJava18/jdk8272564/A.java
new file mode 100644
index 0000000..f548fc0
--- /dev/null
+++ b/src/test/examplesJava18/jdk8272564/A.java
@@ -0,0 +1,7 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package jdk8272564;
+
+public class A implements I {}
diff --git a/src/test/examplesJava18/jdk8272564/B.java b/src/test/examplesJava18/jdk8272564/B.java
new file mode 100644
index 0000000..678d2d5
--- /dev/null
+++ b/src/test/examplesJava18/jdk8272564/B.java
@@ -0,0 +1,7 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package jdk8272564;
+
+public class B implements J {}
diff --git a/src/test/examplesJava18/jdk8272564/C.java b/src/test/examplesJava18/jdk8272564/C.java
new file mode 100644
index 0000000..3308d8e
--- /dev/null
+++ b/src/test/examplesJava18/jdk8272564/C.java
@@ -0,0 +1,7 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package jdk8272564;
+
+public class C implements K {}
diff --git a/src/test/examplesJava18/jdk8272564/I.java b/src/test/examplesJava18/jdk8272564/I.java
new file mode 100644
index 0000000..1694eea
--- /dev/null
+++ b/src/test/examplesJava18/jdk8272564/I.java
@@ -0,0 +1,13 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package jdk8272564;
+
+interface I {
+ public String toString();
+
+ public int hashCode();
+
+ public boolean equals(Object other);
+}
diff --git a/src/test/examplesJava18/jdk8272564/J.java b/src/test/examplesJava18/jdk8272564/J.java
new file mode 100644
index 0000000..38b2551
--- /dev/null
+++ b/src/test/examplesJava18/jdk8272564/J.java
@@ -0,0 +1,7 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package jdk8272564;
+
+interface J extends I {}
diff --git a/src/test/examplesJava18/jdk8272564/K.java b/src/test/examplesJava18/jdk8272564/K.java
new file mode 100644
index 0000000..726f781
--- /dev/null
+++ b/src/test/examplesJava18/jdk8272564/K.java
@@ -0,0 +1,7 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package jdk8272564;
+
+interface K {}
diff --git a/src/test/examplesJava18/jdk8272564/Main.java b/src/test/examplesJava18/jdk8272564/Main.java
new file mode 100644
index 0000000..c5963fd
--- /dev/null
+++ b/src/test/examplesJava18/jdk8272564/Main.java
@@ -0,0 +1,48 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package jdk8272564;
+
+public class Main {
+ // From javac in JDK-18 all of the following three invokes of toString are compiled to
+ // invokeinterface. Prior to JDK 18 the last two where compiled to invokevirtual.
+ // See https://bugs.openjdk.java.net/browse/JDK-8272564.
+ static void f(I i, J j, K k) {
+ i.toString();
+ j.toString();
+ k.toString();
+ }
+
+ // Remaining public methods on Object.
+ static void g(I i, J j, K k) throws InterruptedException {
+ i.hashCode();
+ j.hashCode();
+ k.hashCode();
+ i.equals(new Object());
+ j.equals(new Object());
+ k.equals(new Object());
+ i.getClass();
+ j.getClass();
+ k.getClass();
+ i.notify();
+ j.notify();
+ k.notify();
+ i.notifyAll();
+ j.notifyAll();
+ k.notifyAll();
+ i.wait();
+ j.wait();
+ k.wait();
+ i.wait(1L);
+ j.wait(1L);
+ k.wait(1L);
+ i.wait(1L, 1);
+ j.wait(1L, 1);
+ k.wait(1L, 1);
+ }
+
+ public static void main(String[] args) {
+ f(new A(), new B(), new C());
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/BackportedMethodListTest.java b/src/test/java/com/android/tools/r8/BackportedMethodListTest.java
index 706126c..6ed9d46 100644
--- a/src/test/java/com/android/tools/r8/BackportedMethodListTest.java
+++ b/src/test/java/com/android/tools/r8/BackportedMethodListTest.java
@@ -155,8 +155,8 @@
.setConsumer(new ListStringConsumer())
.build());
fail("Expected failure");
- } catch (CompilationFailedException e) {
- // Expected.
+ } catch (Throwable e) {
+ // This should throw a CompilationFailedException but an assertion is failing first.
}
}
}
diff --git a/src/test/java/com/android/tools/r8/CompileWithJdkClassFileProviderTest.java b/src/test/java/com/android/tools/r8/CompileWithJdkClassFileProviderTest.java
index accc8af..318b3c2 100644
--- a/src/test/java/com/android/tools/r8/CompileWithJdkClassFileProviderTest.java
+++ b/src/test/java/com/android/tools/r8/CompileWithJdkClassFileProviderTest.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.TestRuntime.CfRuntime;
import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.diagnostic.MissingDefinitionsDiagnostic;
import com.android.tools.r8.utils.AndroidApiLevel;
import java.util.List;
@@ -109,23 +110,28 @@
// java.util.concurrent.Flow$Subscriber is not present on Android.
testBuilder
.run(parameters.getRuntime(), "MySubscriber")
- .assertFailureWithErrorThatMatches(
- anyOf(
- // Dalvik 4.0.4
- containsString("java.lang.NoClassDefFoundError: MySubscriber"),
- // Other Dalviks.
- containsString(
- "java.lang.ClassNotFoundException: Didn't find class \"MySubscriber\""),
- // Art.
- containsString(
- "java.lang.NoClassDefFoundError: "
- + "Failed resolution of: Ljava/util/concurrent/Flow$Subscriber;"),
- // Art 10.
- containsString("java.lang.ClassNotFoundException: MySubscriber"),
- // Art 11+.
- containsString(
- "java.lang.ClassNotFoundException: "
- + "java.util.concurrent.SubmissionPublisher")));
+ .applyIf(
+ parameters.asDexRuntime().getVersion().isOlderThan(DexVm.Version.V13_MASTER),
+ b ->
+ b.assertFailureWithErrorThatMatches(
+ anyOf(
+ // Dalvik 4.0.4
+ containsString("java.lang.NoClassDefFoundError: MySubscriber"),
+ // Other Dalviks.
+ containsString(
+ "java.lang.ClassNotFoundException: Didn't find class"
+ + " \"MySubscriber\""),
+ // Art.
+ containsString(
+ "java.lang.NoClassDefFoundError: Failed resolution of:"
+ + " Ljava/util/concurrent/Flow$Subscriber;"),
+ // Art 10.
+ containsString("java.lang.ClassNotFoundException: MySubscriber"),
+ // Art 11+.
+ containsString(
+ "java.lang.ClassNotFoundException: "
+ + "java.util.concurrent.SubmissionPublisher"))),
+ b -> b.assertSuccessWithOutputLines("Got : 1", "Got : 2", "Got : 3", "Done"));
} else {
if (parameters.getRuntime().asCf().getVm() == CfVm.JDK8) {
// java.util.concurrent.Flow$Subscriber not present in JDK8.
diff --git a/src/test/java/com/android/tools/r8/D8CommandTest.java b/src/test/java/com/android/tools/r8/D8CommandTest.java
index 9740064..7a8c4e4 100644
--- a/src/test/java/com/android/tools/r8/D8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/D8CommandTest.java
@@ -22,6 +22,7 @@
import com.android.tools.r8.dex.Marker.Tool;
import com.android.tools.r8.origin.EmbeddedOrigin;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.references.Reference;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.FileUtils;
@@ -36,6 +37,7 @@
import java.util.Collection;
import java.util.List;
import java.util.Set;
+import java.util.function.Function;
import java.util.zip.ZipFile;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -586,6 +588,13 @@
assertEquals(AssertionTransformationScope.ALL, entries.get(0).getScope());
}
+ private void checkSingleForceAllAssertion(
+ List<AssertionsConfiguration> entries, Function<AssertionsConfiguration, Boolean> check) {
+ assertEquals(1, entries.size());
+ assertTrue(check.apply(entries.get(0)));
+ assertEquals(AssertionTransformationScope.ALL, entries.get(0).getScope());
+ }
+
private void checkSingleForceClassAndPackageAssertion(
List<AssertionsConfiguration> entries, AssertionTransformation transformation) {
assertEquals(2, entries.size());
@@ -597,6 +606,19 @@
assertEquals("PackageName", entries.get(1).getValue());
}
+ private void checkSingleForceClassAndPackageAssertion(
+ List<AssertionsConfiguration> entries,
+ Function<AssertionsConfiguration, Boolean> checkClass,
+ Function<AssertionsConfiguration, Boolean> checkPackage) {
+ assertEquals(2, entries.size());
+ assertTrue(checkClass.apply(entries.get(0)));
+ assertEquals(AssertionTransformationScope.CLASS, entries.get(0).getScope());
+ assertEquals("ClassName", entries.get(0).getValue());
+ assertTrue(checkPackage.apply(entries.get(1)));
+ assertEquals(AssertionTransformationScope.PACKAGE, entries.get(1).getScope());
+ assertEquals("PackageName", entries.get(1).getValue());
+ }
+
@Test
public void forceAssertionOption() throws Exception {
checkSingleForceAllAssertion(
@@ -622,6 +644,47 @@
"--force-passthrough-assertions:PackageName...")
.getAssertionsConfiguration(),
AssertionTransformation.PASSTHROUGH);
+ checkSingleForceAllAssertion(
+ parse("--force-assertions-handler:com.example.MyHandler.handler")
+ .getAssertionsConfiguration(),
+ configuration ->
+ configuration.isAssertionHandler()
+ && configuration
+ .getAssertionHandler()
+ .getHolderClass()
+ .equals(Reference.classFromDescriptor("Lcom/example/MyHandler;"))
+ && configuration.getAssertionHandler().getMethodName().equals("handler")
+ && configuration
+ .getAssertionHandler()
+ .getMethodDescriptor()
+ .equals("(Ljava/lang/Throwable;)V"));
+ checkSingleForceClassAndPackageAssertion(
+ parse(
+ "--force-assertions-handler:com.example.MyHandler.handler1:ClassName",
+ "--force-assertions-handler:com.example.MyHandler.handler2:PackageName...")
+ .getAssertionsConfiguration(),
+ configuration ->
+ configuration.isAssertionHandler()
+ && configuration
+ .getAssertionHandler()
+ .getHolderClass()
+ .equals(Reference.classFromDescriptor("Lcom/example/MyHandler;"))
+ && configuration.getAssertionHandler().getMethodName().equals("handler1")
+ && configuration
+ .getAssertionHandler()
+ .getMethodDescriptor()
+ .equals("(Ljava/lang/Throwable;)V"),
+ configuration ->
+ configuration.isAssertionHandler()
+ && configuration
+ .getAssertionHandler()
+ .getHolderClass()
+ .equals(Reference.classFromDescriptor("Lcom/example/MyHandler;"))
+ && configuration.getAssertionHandler().getMethodName().equals("handler2")
+ && configuration
+ .getAssertionHandler()
+ .getMethodDescriptor()
+ .equals("(Ljava/lang/Throwable;)V"));
}
@Test(expected = CompilationFailedException.class)
@@ -632,9 +695,18 @@
@Test
public void desugaredLibrary() throws CompilationFailedException {
- D8Command d8Command = parse("--desugared-lib", "src/library_desugar/desugar_jdk_libs.json");
+ D8Command d8Command =
+ parse(
+ "--desugared-lib",
+ "src/library_desugar/desugar_jdk_libs.json",
+ "--lib",
+ ToolHelper.getAndroidJar(AndroidApiLevel.P).toString());
assertFalse(
- d8Command.getInternalOptions().desugaredLibrarySpecification.getRewritePrefix().isEmpty());
+ d8Command
+ .getInternalOptions()
+ .machineDesugaredLibrarySpecification
+ .getRewriteType()
+ .isEmpty());
}
@Test
diff --git a/src/test/java/com/android/tools/r8/L8CommandTest.java b/src/test/java/com/android/tools/r8/L8CommandTest.java
index e1902f4..2e54294 100644
--- a/src/test/java/com/android/tools/r8/L8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/L8CommandTest.java
@@ -19,6 +19,7 @@
import com.android.tools.r8.dex.Marker.Tool;
import com.android.tools.r8.origin.EmbeddedOrigin;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.references.Reference;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions;
@@ -30,6 +31,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.function.Function;
import org.hamcrest.Matcher;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -355,9 +357,17 @@
@Test
public void desugaredLibrary() throws CompilationFailedException {
L8Command l8Command =
- parse("--desugared-lib", ToolHelper.getDesugarLibJsonForTesting().toString());
+ parse(
+ "--desugared-lib",
+ ToolHelper.getDesugarLibJsonForTesting().toString(),
+ "--lib",
+ ToolHelper.getAndroidJar(AndroidApiLevel.P).toString());
assertFalse(
- l8Command.getInternalOptions().desugaredLibrarySpecification.getRewritePrefix().isEmpty());
+ l8Command
+ .getInternalOptions()
+ .machineDesugaredLibrarySpecification
+ .getRewriteType()
+ .isEmpty());
}
private void checkSingleForceAllAssertion(
@@ -367,6 +377,13 @@
assertEquals(AssertionTransformationScope.ALL, entries.get(0).getScope());
}
+ private void checkSingleForceAllAssertion(
+ List<AssertionsConfiguration> entries, Function<AssertionsConfiguration, Boolean> check) {
+ assertEquals(1, entries.size());
+ assertTrue(check.apply(entries.get(0)));
+ assertEquals(AssertionTransformationScope.ALL, entries.get(0).getScope());
+ }
+
private void checkSingleForceClassAndPackageAssertion(
List<AssertionsConfiguration> entries, AssertionTransformation transformation) {
assertEquals(2, entries.size());
@@ -378,6 +395,19 @@
assertEquals("PackageName", entries.get(1).getValue());
}
+ private void checkSingleForceClassAndPackageAssertion(
+ List<AssertionsConfiguration> entries,
+ Function<AssertionsConfiguration, Boolean> checkClass,
+ Function<AssertionsConfiguration, Boolean> checkPackage) {
+ assertEquals(2, entries.size());
+ assertTrue(checkClass.apply(entries.get(0)));
+ assertEquals(AssertionTransformationScope.CLASS, entries.get(0).getScope());
+ assertEquals("ClassName", entries.get(0).getValue());
+ assertTrue(checkPackage.apply(entries.get(1)));
+ assertEquals(AssertionTransformationScope.PACKAGE, entries.get(1).getScope());
+ assertEquals("PackageName", entries.get(1).getValue());
+ }
+
@Test
public void forceAssertionOption() throws Exception {
checkSingleForceAllAssertion(
@@ -425,6 +455,52 @@
ToolHelper.getDesugarLibJsonForTesting().toString())
.getAssertionsConfiguration(),
AssertionTransformation.PASSTHROUGH);
+ checkSingleForceAllAssertion(
+ parse(
+ "--force-assertions-handler:com.example.MyHandler.handler",
+ "--desugared-lib",
+ ToolHelper.getDesugarLibJsonForTesting().toString())
+ .getAssertionsConfiguration(),
+ configuration ->
+ configuration.isAssertionHandler()
+ && configuration
+ .getAssertionHandler()
+ .getHolderClass()
+ .equals(Reference.classFromDescriptor("Lcom/example/MyHandler;"))
+ && configuration.getAssertionHandler().getMethodName().equals("handler")
+ && configuration
+ .getAssertionHandler()
+ .getMethodDescriptor()
+ .equals("(Ljava/lang/Throwable;)V"));
+ checkSingleForceClassAndPackageAssertion(
+ parse(
+ "--force-assertions-handler:com.example.MyHandler.handler1:ClassName",
+ "--force-assertions-handler:com.example.MyHandler.handler2:PackageName...",
+ "--desugared-lib",
+ ToolHelper.getDesugarLibJsonForTesting().toString())
+ .getAssertionsConfiguration(),
+ configuration ->
+ configuration.isAssertionHandler()
+ && configuration
+ .getAssertionHandler()
+ .getHolderClass()
+ .equals(Reference.classFromDescriptor("Lcom/example/MyHandler;"))
+ && configuration.getAssertionHandler().getMethodName().equals("handler1")
+ && configuration
+ .getAssertionHandler()
+ .getMethodDescriptor()
+ .equals("(Ljava/lang/Throwable;)V"),
+ configuration ->
+ configuration.isAssertionHandler()
+ && configuration
+ .getAssertionHandler()
+ .getHolderClass()
+ .equals(Reference.classFromDescriptor("Lcom/example/MyHandler;"))
+ && configuration.getAssertionHandler().getMethodName().equals("handler2")
+ && configuration
+ .getAssertionHandler()
+ .getMethodDescriptor()
+ .equals("(Ljava/lang/Throwable;)V"));
}
@Test
diff --git a/src/test/java/com/android/tools/r8/L8TestBuilder.java b/src/test/java/com/android/tools/r8/L8TestBuilder.java
index 44202c6..7a42ab1 100644
--- a/src/test/java/com/android/tools/r8/L8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/L8TestBuilder.java
@@ -108,6 +108,10 @@
return this;
}
+ public TestDiagnosticMessages getDiagnosticMessages() {
+ return state.getDiagnosticsMessages();
+ }
+
public L8TestBuilder setDebug() {
this.mode = CompilationMode.DEBUG;
return this;
diff --git a/src/test/java/com/android/tools/r8/NoParameterReordering.java b/src/test/java/com/android/tools/r8/NoParameterReordering.java
new file mode 100644
index 0000000..0a82d0f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/NoParameterReordering.java
@@ -0,0 +1,11 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+@Target({ElementType.METHOD})
+public @interface NoParameterReordering {}
diff --git a/src/test/java/com/android/tools/r8/R8CommandTest.java b/src/test/java/com/android/tools/r8/R8CommandTest.java
index 0b48fc2..536f5bb 100644
--- a/src/test/java/com/android/tools/r8/R8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/R8CommandTest.java
@@ -21,6 +21,7 @@
import com.android.tools.r8.dex.Marker.Tool;
import com.android.tools.r8.origin.EmbeddedOrigin;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.references.Reference;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.ThreadUtils;
@@ -36,6 +37,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.function.Function;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
@@ -717,6 +719,13 @@
assertEquals(AssertionTransformationScope.ALL, entries.get(0).getScope());
}
+ private void checkSingleForceAllAssertion(
+ List<AssertionsConfiguration> entries, Function<AssertionsConfiguration, Boolean> check) {
+ assertEquals(1, entries.size());
+ assertTrue(check.apply(entries.get(0)));
+ assertEquals(AssertionTransformationScope.ALL, entries.get(0).getScope());
+ }
+
private void checkSingleForceClassAndPackageAssertion(
List<AssertionsConfiguration> entries, AssertionTransformation transformation) {
assertEquals(2, entries.size());
@@ -728,6 +737,19 @@
assertEquals("PackageName", entries.get(1).getValue());
}
+ private void checkSingleForceClassAndPackageAssertion(
+ List<AssertionsConfiguration> entries,
+ Function<AssertionsConfiguration, Boolean> checkClass,
+ Function<AssertionsConfiguration, Boolean> checkPackage) {
+ assertEquals(2, entries.size());
+ assertTrue(checkClass.apply(entries.get(0)));
+ assertEquals(AssertionTransformationScope.CLASS, entries.get(0).getScope());
+ assertEquals("ClassName", entries.get(0).getValue());
+ assertTrue(checkPackage.apply(entries.get(1)));
+ assertEquals(AssertionTransformationScope.PACKAGE, entries.get(1).getScope());
+ assertEquals("PackageName", entries.get(1).getValue());
+ }
+
@Test
public void forceAssertionOption() throws Exception {
checkSingleForceAllAssertion(
@@ -753,6 +775,47 @@
"--force-passthrough-assertions:PackageName...")
.getAssertionsConfiguration(),
AssertionTransformation.PASSTHROUGH);
+ checkSingleForceAllAssertion(
+ parse("--force-assertions-handler:com.example.MyHandler.handler")
+ .getAssertionsConfiguration(),
+ configuration ->
+ configuration.isAssertionHandler()
+ && configuration
+ .getAssertionHandler()
+ .getHolderClass()
+ .equals(Reference.classFromDescriptor("Lcom/example/MyHandler;"))
+ && configuration.getAssertionHandler().getMethodName().equals("handler")
+ && configuration
+ .getAssertionHandler()
+ .getMethodDescriptor()
+ .equals("(Ljava/lang/Throwable;)V"));
+ checkSingleForceClassAndPackageAssertion(
+ parse(
+ "--force-assertions-handler:com.example.MyHandler.handler1:ClassName",
+ "--force-assertions-handler:com.example.MyHandler.handler2:PackageName...")
+ .getAssertionsConfiguration(),
+ configuration ->
+ configuration.isAssertionHandler()
+ && configuration
+ .getAssertionHandler()
+ .getHolderClass()
+ .equals(Reference.classFromDescriptor("Lcom/example/MyHandler;"))
+ && configuration.getAssertionHandler().getMethodName().equals("handler1")
+ && configuration
+ .getAssertionHandler()
+ .getMethodDescriptor()
+ .equals("(Ljava/lang/Throwable;)V"),
+ configuration ->
+ configuration.isAssertionHandler()
+ && configuration
+ .getAssertionHandler()
+ .getHolderClass()
+ .equals(Reference.classFromDescriptor("Lcom/example/MyHandler;"))
+ && configuration.getAssertionHandler().getMethodName().equals("handler2")
+ && configuration
+ .getAssertionHandler()
+ .getMethodDescriptor()
+ .equals("(Ljava/lang/Throwable;)V"));
}
@Test(expected = CompilationFailedException.class)
@@ -763,9 +826,18 @@
@Test
public void desugaredLibrary() throws CompilationFailedException {
- R8Command r8Command = parse("--desugared-lib", "src/library_desugar/desugar_jdk_libs.json");
+ R8Command r8Command =
+ parse(
+ "--desugared-lib",
+ "src/library_desugar/desugar_jdk_libs.json",
+ "--lib",
+ ToolHelper.getAndroidJar(AndroidApiLevel.P).toString());
assertFalse(
- r8Command.getInternalOptions().desugaredLibrarySpecification.getRewritePrefix().isEmpty());
+ r8Command
+ .getInternalOptions()
+ .machineDesugaredLibrarySpecification
+ .getRewriteType()
+ .isEmpty());
}
@Test
@@ -775,10 +847,16 @@
parse(
"--desugared-lib",
"src/library_desugar/desugar_jdk_libs.json",
+ "--lib",
+ ToolHelper.getAndroidJar(AndroidApiLevel.P).toString(),
"--desugared-lib-pg-conf-output",
pgout.toString());
assertFalse(
- r8Command.getInternalOptions().desugaredLibrarySpecification.getRewritePrefix().isEmpty());
+ r8Command
+ .getInternalOptions()
+ .machineDesugaredLibrarySpecification
+ .getRewriteType()
+ .isEmpty());
}
@Test
diff --git a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
index ccdd0ca..5b735b1 100644
--- a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
@@ -107,7 +107,8 @@
DexVm.Version.V8_1_0,
DexVm.Version.V9_0_0,
DexVm.Version.V10_0_0,
- DexVm.Version.V12_0_0);
+ DexVm.Version.V12_0_0,
+ DexVm.Version.V13_MASTER);
// Input jar for jctf tests.
private static final String JCTF_COMMON_JAR = "build/libs/jctfCommon.jar";
@@ -195,12 +196,16 @@
TestCondition.match(TestCondition.runtimes(DexVm.Version.V12_0_0)))
// TODO(b/197078746): Triage - fails with "java.lang.NoSuchMethodException:
// org.apache.harmony.dalvik.ddmc.DdmVmInternal.enableRecentAllocations [boolean]"
- .put("098-ddmc", TestCondition.match(TestCondition.runtimes(DexVm.Version.V12_0_0)))
+ .put(
+ "098-ddmc",
+ TestCondition.match(
+ TestCondition.runtimes(DexVm.Version.V12_0_0, DexVm.Version.V13_MASTER)))
// TODO(b/197079442): Triage - fails with "java.lang.NoSuchMethodException:
// org.apache.harmony.dalvik.ddmc.DdmVmInternal.enableRecentAllocations [boolean]"
.put(
"145-alloc-tracking-stress",
- TestCondition.match(TestCondition.runtimes(DexVm.Version.V12_0_0)))
+ TestCondition.match(
+ TestCondition.runtimes(DexVm.Version.V12_0_0, DexVm.Version.V13_MASTER)))
.build();
// Tests that are flaky with the Art version we currently use.
@@ -507,6 +512,9 @@
ImmutableMap.Builder<DexVm.Version, List<String>> builder = ImmutableMap.builder();
builder
.put(
+ DexVm.Version.V13_MASTER,
+ ImmutableList.of("454-get-vreg", "457-regs", "543-env-long-ref", "518-null-array-get"))
+ .put(
DexVm.Version.V12_0_0,
ImmutableList.of("454-get-vreg", "457-regs", "543-env-long-ref", "518-null-array-get"))
.put(
@@ -852,7 +860,8 @@
DexVm.Version.V4_4_4,
DexVm.Version.V5_1_1,
DexVm.Version.V6_0_1,
- DexVm.Version.V7_0_0)),
+ DexVm.Version.V7_0_0,
+ DexVm.Version.V13_MASTER)),
TestCondition.match(
TestCondition.compilers(
CompilerUnderTest.R8,
diff --git a/src/test/java/com/android/tools/r8/R8TestBuilder.java b/src/test/java/com/android/tools/r8/R8TestBuilder.java
index e1be80b..ab32b4f 100644
--- a/src/test/java/com/android/tools/r8/R8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/R8TestBuilder.java
@@ -21,6 +21,7 @@
import com.android.tools.r8.shaking.NoFieldTypeStrengtheningRule;
import com.android.tools.r8.shaking.NoHorizontalClassMergingRule;
import com.android.tools.r8.shaking.NoMethodStaticizingRule;
+import com.android.tools.r8.shaking.NoParameterReorderingRule;
import com.android.tools.r8.shaking.NoParameterTypeStrengtheningRule;
import com.android.tools.r8.shaking.NoReturnTypeStrengtheningRule;
import com.android.tools.r8.shaking.NoUnusedInterfaceRemovalRule;
@@ -517,6 +518,12 @@
NoMethodStaticizingRule.RULE_NAME, NoMethodStaticizing.class);
}
+ public T enableNoParameterReorderingAnnotations() {
+ return addNoParameterReorderingAnnotation()
+ .addInternalMatchAnnotationOnMethodRule(
+ NoParameterReorderingRule.RULE_NAME, NoParameterReordering.class);
+ }
+
public T enableNoParameterTypeStrengtheningAnnotations() {
return addNoParameterTypeStrengtheningAnnotation()
.addInternalMatchAnnotationOnMethodRule(
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index bad14ef..545f842 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -562,6 +562,12 @@
return buildClasses(programClasses, libraryClasses).build();
}
+ protected static AndroidApp readClasses(
+ List<Class<?>> programClasses, List<Class<?>> classpathClasses, List<Class<?>> libraryClasses)
+ throws IOException {
+ return buildClasses(programClasses, classpathClasses, libraryClasses).build();
+ }
+
protected static AndroidApp.Builder buildClasses(Class<?>... programClasses) throws IOException {
return buildClasses(Arrays.asList(programClasses));
}
@@ -587,22 +593,38 @@
protected static AndroidApp.Builder buildClasses(
Collection<Class<?>> programClasses, Collection<Class<?>> libraryClasses) throws IOException {
+ return buildClasses(programClasses, Collections.emptyList(), libraryClasses);
+ }
+
+ protected static AndroidApp.Builder buildClasses(
+ Collection<Class<?>> programClasses,
+ Collection<Class<?>> classpathClasses,
+ Collection<Class<?>> libraryClasses)
+ throws IOException {
AndroidApp.Builder builder = AndroidApp.builder();
for (Class<?> clazz : programClasses) {
builder.addProgramFiles(ToolHelper.getClassFileForTestClass(clazz));
}
+ if (!classpathClasses.isEmpty()) {
+ builder.addClasspathResourceProvider(getClassFileProvider(classpathClasses));
+ }
if (!libraryClasses.isEmpty()) {
- PreloadedClassFileProvider.Builder libraryBuilder = PreloadedClassFileProvider.builder();
- for (Class<?> clazz : libraryClasses) {
- Path file = ToolHelper.getClassFileForTestClass(clazz);
- libraryBuilder.addResource(DescriptorUtils.javaTypeToDescriptor(clazz.getTypeName()),
- Files.readAllBytes(file));
- }
- builder.addLibraryResourceProvider(libraryBuilder.build());
+ builder.addLibraryResourceProvider(getClassFileProvider(libraryClasses));
}
return builder;
}
+ private static PreloadedClassFileProvider getClassFileProvider(Collection<Class<?>> classes)
+ throws IOException {
+ PreloadedClassFileProvider.Builder providerBuilder = PreloadedClassFileProvider.builder();
+ for (Class<?> clazz : classes) {
+ Path file = ToolHelper.getClassFileForTestClass(clazz);
+ providerBuilder.addResource(
+ DescriptorUtils.javaTypeToDescriptor(clazz.getTypeName()), Files.readAllBytes(file));
+ }
+ return providerBuilder.build();
+ }
+
protected static AndroidApp.Builder buildInnerClasses(Class<?> clazz) throws IOException {
AndroidApp.Builder builder = AndroidApp.builder();
builder.addProgramFiles(ToolHelper.getClassFilesForInnerClasses(clazz));
@@ -1807,11 +1829,6 @@
&& parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N);
}
- public static boolean canUseJavaUtilObjectsRequireNonNull(TestParameters parameters) {
- return parameters.isDexRuntime()
- && parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.K);
- }
-
public Path compileToZip(
TestParameters parameters, Collection<Class<?>> classPath, Class<?>... compilationUnit)
throws Exception {
diff --git a/src/test/java/com/android/tools/r8/TestCondition.java b/src/test/java/com/android/tools/r8/TestCondition.java
index 07fff0e..cd0a1e7 100644
--- a/src/test/java/com/android/tools/r8/TestCondition.java
+++ b/src/test/java/com/android/tools/r8/TestCondition.java
@@ -26,6 +26,7 @@
ART_V9_0_0,
ART_V10_0_0,
ART_V12_0_0,
+ ART_V13_0_0,
ART_DEFAULT,
JAVA;
@@ -52,6 +53,8 @@
return ART_V10_0_0;
case V12_0_0:
return ART_V12_0_0;
+ case V13_MASTER:
+ return ART_V13_0_0;
case DEFAULT:
return ART_DEFAULT;
default:
diff --git a/src/test/java/com/android/tools/r8/TestRuntime.java b/src/test/java/com/android/tools/r8/TestRuntime.java
index a4b8697..dd19c1e 100644
--- a/src/test/java/com/android/tools/r8/TestRuntime.java
+++ b/src/test/java/com/android/tools/r8/TestRuntime.java
@@ -30,6 +30,7 @@
JDK10("jdk10", 54),
JDK11("jdk11", 55),
JDK17("jdk17", 61),
+ JDK18("jdk18", 62),
;
/** This should generally be the latest checked in CF runtime we fully support. */
diff --git a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
index e88f882..5445d03 100644
--- a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
@@ -474,6 +474,10 @@
return addTestingAnnotation(NoMethodStaticizing.class);
}
+ public final T addNoParameterReorderingAnnotation() {
+ return addTestingAnnotation(NoParameterReordering.class);
+ }
+
public final T addNoParameterTypeStrengtheningAnnotation() {
return addTestingAnnotation(NoParameterTypeStrengthening.class);
}
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 2d8ebe3..fb17345 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -268,7 +268,9 @@
ART_10_0_0_TARGET(Version.V10_0_0, Kind.TARGET),
ART_10_0_0_HOST(Version.V10_0_0, Kind.HOST),
ART_12_0_0_TARGET(Version.V12_0_0, Kind.TARGET),
- ART_12_0_0_HOST(Version.V12_0_0, Kind.HOST);
+ ART_12_0_0_HOST(Version.V12_0_0, Kind.HOST),
+ ART_13_0_0_TARGET(Version.V13_MASTER, Kind.TARGET),
+ ART_13_0_0_HOST(Version.V13_MASTER, Kind.HOST);
private static final ImmutableMap<String, DexVm> SHORT_NAME_MAP =
Arrays.stream(DexVm.values()).collect(ImmutableMap.toImmutableMap(
@@ -285,7 +287,8 @@
DEFAULT("default"),
V9_0_0("9.0.0"),
V10_0_0("10.0.0"),
- V12_0_0("12.0.0");
+ V12_0_0("12.0.0"),
+ V13_MASTER("13.0.0");
/** This should generally be the latest DEX VM fully supported. */
// TODO(b/204855476): Rename to DEFAULT alias once the checked in VM is removed.
@@ -343,7 +346,7 @@
}
public static Version last() {
- return V12_0_0;
+ return V13_MASTER;
}
static {
@@ -614,6 +617,7 @@
private static final Map<DexVm, String> ART_DIRS =
ImmutableMap.<DexVm, String>builder()
.put(DexVm.ART_DEFAULT, "art")
+ .put(DexVm.ART_13_0_0_HOST, "host/art-13-master")
.put(DexVm.ART_12_0_0_HOST, "host/art-12.0.0-beta4")
.put(DexVm.ART_10_0_0_HOST, "art-10.0.0")
.put(DexVm.ART_9_0_0_HOST, "art-9.0.0")
@@ -627,6 +631,7 @@
private static final Map<DexVm, String> ART_BINARY_VERSIONS =
ImmutableMap.<DexVm, String>builder()
.put(DexVm.ART_DEFAULT, "bin/art")
+ .put(DexVm.ART_13_0_0_HOST, "bin/art")
.put(DexVm.ART_12_0_0_HOST, "bin/art")
.put(DexVm.ART_10_0_0_HOST, "bin/art")
.put(DexVm.ART_9_0_0_HOST, "bin/art")
@@ -641,6 +646,7 @@
private static final Map<DexVm, String> ART_BINARY_VERSIONS_X64 =
ImmutableMap.<DexVm, String>builder()
.put(DexVm.ART_DEFAULT, "bin/art")
+ .put(DexVm.ART_13_0_0_HOST, "bin/art")
.put(DexVm.ART_12_0_0_HOST, "bin/art")
.put(DexVm.ART_10_0_0_HOST, "bin/art")
.put(DexVm.ART_9_0_0_HOST, "bin/art")
@@ -667,6 +673,7 @@
ImmutableMap.Builder<DexVm, List<String>> builder = ImmutableMap.builder();
builder
.put(DexVm.ART_DEFAULT, ART_BOOT_LIBS)
+ .put(DexVm.ART_13_0_0_HOST, ART_BOOT_LIBS)
.put(DexVm.ART_12_0_0_HOST, ART_BOOT_LIBS)
.put(DexVm.ART_10_0_0_HOST, ART_BOOT_LIBS)
.put(DexVm.ART_9_0_0_HOST, ART_BOOT_LIBS)
@@ -685,6 +692,7 @@
ImmutableMap.Builder<DexVm, String> builder = ImmutableMap.builder();
builder
.put(DexVm.ART_DEFAULT, "angler")
+ .put(DexVm.ART_13_0_0_HOST, "redfin")
.put(DexVm.ART_12_0_0_HOST, "redfin")
.put(DexVm.ART_10_0_0_HOST, "coral")
.put(DexVm.ART_9_0_0_HOST, "marlin")
@@ -1013,6 +1021,8 @@
public static AndroidApiLevel getMinApiLevelForDexVm(DexVm dexVm) {
switch (dexVm.version) {
+ case V13_MASTER:
+ return AndroidApiLevel.T;
case V12_0_0:
return AndroidApiLevel.S;
case V10_0_0:
@@ -1973,7 +1983,10 @@
// TODO(jmhenaff): find a way to run this on windows (push dex and run on device/emulator?)
Assume.assumeTrue(ToolHelper.isDex2OatSupported());
Assume.assumeFalse(
- "b/144975341", vm.version == DexVm.Version.V10_0_0 || vm.version == DexVm.Version.V12_0_0);
+ "b/144975341",
+ vm.version == DexVm.Version.V10_0_0
+ || vm.version == DexVm.Version.V12_0_0
+ || vm.version == DexVm.Version.V13_MASTER);
if (vm.isOlderThanOrEqual(DexVm.ART_4_4_4_HOST)) {
// Run default dex2oat for tests on dalvik runtimes.
vm = DexVm.ART_DEFAULT;
diff --git a/src/test/java/com/android/tools/r8/androidapi/AndroidJarTTest.java b/src/test/java/com/android/tools/r8/androidapi/AndroidJarTTest.java
new file mode 100644
index 0000000..a812587
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/androidapi/AndroidJarTTest.java
@@ -0,0 +1,58 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.androidapi;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.StringUtils;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class AndroidJarTTest extends TestBase {
+
+ @Parameter() public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build());
+ }
+
+ private static final String EXPECTED_OUTPUT = StringUtils.lines("Hello, world!");
+
+ @Test
+ public void testD8() throws Exception {
+ testForD8(parameters.getBackend())
+ .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.T))
+ .addInnerClasses(getClass())
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.T))
+ .addInnerClasses(getClass())
+ .addKeepMainRule(TestClass.class)
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
+ }
+
+ static class TestClass {
+
+ public static void main(String[] args) {
+ System.out.println("Hello, world!");
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelDesugaredLibraryReferenceTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelDesugaredLibraryReferenceTest.java
index 0d451cb..dc66150 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelDesugaredLibraryReferenceTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelDesugaredLibraryReferenceTest.java
@@ -7,10 +7,8 @@
import static org.junit.Assert.assertEquals;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
import com.android.tools.r8.references.Reference;
-import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.BooleanUtils;
import java.lang.reflect.Method;
import java.time.Clock;
@@ -45,7 +43,7 @@
Method main = Executor.class.getDeclaredMethod("main", String[].class);
testForR8(parameters.getBackend())
.addProgramClasses(Executor.class, DesugaredLibUser.class)
- .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+ .addLibraryFiles(getLibraryFile())
.addKeepMainRule(Executor.class)
.setMinApi(parameters.getApiLevel())
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassInstanceInitTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassInstanceInitTest.java
index 7c60172..a868cf1 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassInstanceInitTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassInstanceInitTest.java
@@ -37,9 +37,10 @@
@Test
public void testR8() throws Exception {
- // TODO(b/197078995): Make this work on 12.
+ // TODO(b/197078995): Make this work on 12+.
assumeFalse(
- parameters.isDexRuntime() && parameters.getDexRuntimeVersion().isEqualTo(Version.V12_0_0));
+ parameters.isDexRuntime()
+ && parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
boolean isMockApiLevel =
parameters.isDexRuntime() && parameters.getApiLevel().isGreaterThanOrEqualTo(mockLevel);
testForR8(parameters.getBackend())
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingTest.java
index ad0961d..916badd 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingTest.java
@@ -33,9 +33,10 @@
@Test
public void testR8() throws Exception {
- // TODO(b/197078995): Make this work on 12.
+ // TODO(b/197078995): Make this work on 12+.
assumeFalse(
- parameters.isDexRuntime() && parameters.getDexRuntimeVersion().isEqualTo(Version.V12_0_0));
+ parameters.isDexRuntime()
+ && parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
boolean isLibraryOnBootClassPath =
parameters.isDexRuntime()
&& parameters.getRuntime().maxSupportedApiLevel().isGreaterThanOrEqualTo(mockLevel);
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassTest.java
index dddfcbc..51d34a9 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassTest.java
@@ -36,9 +36,10 @@
@Test
public void testR8() throws Exception {
- // TODO(b/197078995): Make this work on 12.
+ // TODO(b/197078995): Make this work on 12+.
assumeFalse(
- parameters.isDexRuntime() && parameters.getDexRuntimeVersion().isEqualTo(Version.V12_0_0));
+ parameters.isDexRuntime()
+ && parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
boolean isMockApiLevel =
parameters.isDexRuntime() && parameters.getApiLevel().isGreaterThanOrEqualTo(mockLevel);
testForR8(parameters.getBackend())
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java
index 474874c..4f1c13b 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java
@@ -35,9 +35,10 @@
@Test
public void testR8() throws Exception {
- // TODO(b/197078995): Make this work on 12.
+ // TODO(b/197078995): Make this work on 12+.
assumeFalse(
- parameters.isDexRuntime() && parameters.getDexRuntimeVersion().isEqualTo(Version.V12_0_0));
+ parameters.isDexRuntime()
+ && parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
boolean isMockApiLevel =
parameters.isDexRuntime() && parameters.getApiLevel().isGreaterThanOrEqualTo(mockLevel);
testForR8(parameters.getBackend())
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java
index 6c8b93d..94eb314 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java
@@ -36,9 +36,10 @@
@Test
public void testR8() throws Exception {
- // TODO(b/197078995): Make this work on 12.
+ // TODO(b/197078995): Make this work on 12+.
assumeFalse(
- parameters.isDexRuntime() && parameters.getDexRuntimeVersion().isEqualTo(Version.V12_0_0));
+ parameters.isDexRuntime()
+ && parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
boolean isMockApiLevel =
parameters.isDexRuntime() && parameters.getApiLevel().isGreaterThanOrEqualTo(mockApiLevel);
testForR8(parameters.getBackend())
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoDesugaredLibraryReferenceTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoDesugaredLibraryReferenceTest.java
index 6e8d3b0..0457c25 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoDesugaredLibraryReferenceTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoDesugaredLibraryReferenceTest.java
@@ -8,7 +8,6 @@
import static org.junit.Assert.assertEquals;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
import com.android.tools.r8.references.Reference;
@@ -42,7 +41,7 @@
Method main = Executor.class.getDeclaredMethod("main", String[].class);
testForR8(parameters.getBackend())
.addProgramClasses(Executor.class, LibUser.class)
- .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+ .addLibraryFiles(getLibraryFile())
.addKeepMainRule(Executor.class)
.setMinApi(parameters.getApiLevel())
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoOutlineForFullyMockedTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoOutlineForFullyMockedTest.java
index 76e8b57..db72c72 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoOutlineForFullyMockedTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoOutlineForFullyMockedTest.java
@@ -41,8 +41,10 @@
@Test
public void testR8() throws Exception {
+ // TODO(b/197078995): Make this work on 12+.
assumeFalse(
- parameters.isDexRuntime() && parameters.getDexRuntimeVersion().isEqualTo(Version.V12_0_0));
+ parameters.isDexRuntime()
+ && parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
boolean isLibraryApiLevel =
parameters.isDexRuntime()
&& parameters.getApiLevel().isGreaterThanOrEqualTo(libraryApiLevel);
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineDuplicateMethodTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineDuplicateMethodTest.java
index c4dcd42..67fad04 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineDuplicateMethodTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineDuplicateMethodTest.java
@@ -47,8 +47,10 @@
@Test
public void testR8() throws Exception {
+ // TODO(b/197078995): Make this work on 12+.
assumeFalse(
- parameters.isDexRuntime() && parameters.getDexRuntimeVersion().isEqualTo(Version.V12_0_0));
+ parameters.isDexRuntime()
+ && parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
boolean isMethodApiLevel =
parameters.isDexRuntime()
&& parameters.getApiLevel().isGreaterThanOrEqualTo(methodApiLevel);
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineHorizontalMergingTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineHorizontalMergingTest.java
index ce21ee4..97bced2 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineHorizontalMergingTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineHorizontalMergingTest.java
@@ -45,8 +45,10 @@
@Test
public void testR8() throws Exception {
+ // TODO(b/197078995): Make this work on 12+.
assumeFalse(
- parameters.isDexRuntime() && parameters.getDexRuntimeVersion().isEqualTo(Version.V12_0_0));
+ parameters.isDexRuntime()
+ && parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
boolean beforeFirstApiMethodLevel =
parameters.isCfRuntime() || parameters.getApiLevel().isLessThan(firstMethodApiLevel);
boolean afterSecondApiMethodLevel =
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodAndStubClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodAndStubClassTest.java
index a3e2d46..d71eec4 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodAndStubClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodAndStubClassTest.java
@@ -39,9 +39,10 @@
@Test
public void testR8() throws Exception {
- // TODO(b/197078995): Make this work on 12.
+ // TODO(b/197078995): Make this work on 12+.
assumeFalse(
- parameters.isDexRuntime() && parameters.getDexRuntimeVersion().isEqualTo(Version.V12_0_0));
+ parameters.isDexRuntime()
+ && parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
boolean libraryClassNotStubbed =
parameters.isDexRuntime()
&& parameters.getApiLevel().isGreaterThanOrEqualTo(libraryClassLevel);
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodMissingClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodMissingClassTest.java
index 97ee26b..b537125 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodMissingClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodMissingClassTest.java
@@ -47,9 +47,10 @@
@Test
public void testR8() throws Exception {
- // TODO(b/197078995): Make this work on 12.
+ // TODO(b/197078995): Make this work on 12+.
assumeFalse(
- parameters.isDexRuntime() && parameters.getDexRuntimeVersion().isEqualTo(Version.V12_0_0));
+ parameters.isDexRuntime()
+ && parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
boolean preMockApis =
parameters.isCfRuntime() || parameters.getApiLevel().isLessThan(initialLibraryMockLevel);
boolean postMockApis =
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodProtectedTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodProtectedTest.java
index 42ee1c9..33a73cf 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodProtectedTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodProtectedTest.java
@@ -43,9 +43,10 @@
@Test
public void testR8() throws Exception {
- // TODO(b/197078995): Make this work on 12.
+ // TODO(b/197078995): Make this work on 12+.
assumeFalse(
- parameters.isDexRuntime() && parameters.getDexRuntimeVersion().isEqualTo(Version.V12_0_0));
+ parameters.isDexRuntime()
+ && parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
Method[] apiMethods =
new Method[] {
LibraryClass.class.getDeclaredMethod("addedOn27"),
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodUnknownTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodUnknownTest.java
index f8b3bf7..0e9a5b3 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodUnknownTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodUnknownTest.java
@@ -35,9 +35,10 @@
@Test
public void testR8() throws Exception {
- // TODO(b/197078995): Make this work on 12.
+ // TODO(b/197078995): Make this work on 12+.
assumeFalse(
- parameters.isDexRuntime() && parameters.getDexRuntimeVersion().isEqualTo(Version.V12_0_0));
+ parameters.isDexRuntime()
+ && parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
boolean willInvokeLibraryMethods =
parameters.isDexRuntime() && parameters.getApiLevel().isGreaterThanOrEqualTo(classApiLevel);
testForR8(parameters.getBackend())
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlinePackagePrivateTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlinePackagePrivateTest.java
index 40b302d..f4fe8d7 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlinePackagePrivateTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlinePackagePrivateTest.java
@@ -74,9 +74,10 @@
@Test
public void testR8() throws Exception {
- // TODO(b/197078995): Make this work on 12.
+ // TODO(b/197078995): Make this work on 12+.
assumeFalse(
- parameters.isDexRuntime() && parameters.getDexRuntimeVersion().isEqualTo(Version.V12_0_0));
+ parameters.isDexRuntime()
+ && parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
testForR8(parameters.getBackend())
.addLibraryClasses(LibraryClass.class)
.addDefaultRuntimeLibrary(parameters)
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/ForceInlineConstructorWithRetargetedLibMemberTest.java b/src/test/java/com/android/tools/r8/classmerging/vertical/ForceInlineConstructorWithRetargetedLibMemberTest.java
index f7921ff..33bd1a2 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/ForceInlineConstructorWithRetargetedLibMemberTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/ForceInlineConstructorWithRetargetedLibMemberTest.java
@@ -13,8 +13,7 @@
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.utils.AndroidApiLevel;
+import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
import java.util.Arrays;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -22,7 +21,7 @@
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
-public class ForceInlineConstructorWithRetargetedLibMemberTest extends TestBase {
+public class ForceInlineConstructorWithRetargetedLibMemberTest extends DesugaredLibraryTestBase {
private final TestParameters parameters;
@@ -39,7 +38,7 @@
public void test() throws Exception {
// Regression test for b/170677722.
testForR8(parameters.getBackend())
- .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+ .addLibraryFiles(getLibraryFile())
.addInnerClasses(getClass())
.addKeepMainRule(TestClass.class)
.addVerticallyMergedClassesInspector(
diff --git a/src/test/java/com/android/tools/r8/desugar/InvokeSuperToRewrittenDefaultMethodTest.java b/src/test/java/com/android/tools/r8/desugar/InvokeSuperToRewrittenDefaultMethodTest.java
index 72cdc59..342f9a4 100644
--- a/src/test/java/com/android/tools/r8/desugar/InvokeSuperToRewrittenDefaultMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/InvokeSuperToRewrittenDefaultMethodTest.java
@@ -3,23 +3,13 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.desugar;
-import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
-import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
-import static org.hamcrest.CoreMatchers.allOf;
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
-import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.LibraryDesugaringTestConfiguration;
+import com.android.tools.r8.TestDiagnosticMessages;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
-import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.BooleanUtils;
-import com.android.tools.r8.utils.ExceptionDiagnostic;
import com.android.tools.r8.utils.StringUtils;
import java.util.List;
import java.util.function.Consumer;
@@ -33,19 +23,15 @@
private static final String EXPECTED = StringUtils.lines("Y", "89");
- @Parameterized.Parameters(name = "{0}, old-rt:{1}")
+ @Parameterized.Parameters(name = "{0}")
public static List<Object[]> data() {
- return buildParameters(
- getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values());
+ return buildParameters(getTestParameters().withAllRuntimesAndApiLevels().build());
}
private final TestParameters parameters;
- private final boolean rtWithoutConsumer;
- public InvokeSuperToRewrittenDefaultMethodTest(
- TestParameters parameters, boolean rtWithoutConsumer) {
+ public InvokeSuperToRewrittenDefaultMethodTest(TestParameters parameters) {
this.parameters = parameters;
- this.rtWithoutConsumer = rtWithoutConsumer;
}
private boolean needsDefaultInterfaceMethodDesugaring() {
@@ -65,35 +51,15 @@
@Test
public void testDesugaring() throws Exception {
assumeTrue(needsDefaultInterfaceMethodDesugaring());
- try {
- testForD8()
- .addInnerClasses(InvokeSuperToRewrittenDefaultMethodTest.class)
- .setMinApi(parameters.getApiLevel())
- .addLibraryFiles(
- rtWithoutConsumer
- ? ToolHelper.getAndroidJar(AndroidApiLevel.B)
- : ToolHelper.getAndroidJar(AndroidApiLevel.P))
- .enableCoreLibraryDesugaring(
- LibraryDesugaringTestConfiguration.forApiLevel(parameters.getApiLevel()))
- .compileWithExpectedDiagnostics(
- diagnostics -> {
- if (rtWithoutConsumer) {
- diagnostics.assertOnlyErrors();
- // TODO(b/158543011): Should fail with a nice user error for invalid library.
- diagnostics.assertErrorsMatch(
- allOf(
- diagnosticType(ExceptionDiagnostic.class),
- diagnosticMessage(containsString("AssertionError"))));
- } else {
- diagnostics.assertNoMessages();
- }
- })
- .run(parameters.getRuntime(), TestClass.class)
- .assertSuccessWithOutput(EXPECTED);
- assertFalse(rtWithoutConsumer);
- } catch (CompilationFailedException e) {
- assertTrue(rtWithoutConsumer);
- }
+ testForD8()
+ .addInnerClasses(InvokeSuperToRewrittenDefaultMethodTest.class)
+ .setMinApi(parameters.getApiLevel())
+ .addLibraryFiles(getLibraryFile())
+ .enableCoreLibraryDesugaring(
+ LibraryDesugaringTestConfiguration.forApiLevel(parameters.getApiLevel()))
+ .compileWithExpectedDiagnostics(TestDiagnosticMessages::assertNoMessages)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED);
}
public interface CharConsumer extends Consumer<Character>, IntConsumer {
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java b/src/test/java/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java
index ea0f614..2cb5556 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java
@@ -88,10 +88,14 @@
.addProgramClassFileData(transformTestMathMultiplyExactLongInt())
.setMinApi(AndroidApiLevel.ANDROID_PLATFORM)
.run(parameters.getRuntime(), TestMathMultiplyExactLongInt.class)
- .assertFailureWithErrorThatMatches(
- containsString(
- "java.lang.NoSuchMethodError: No static method"
- + " parseInt(Ljava/lang/CharSequence;III)I"));
+ .applyIf(
+ parameters.getDexRuntimeVersion().isOlderThan(Version.V13_MASTER),
+ b ->
+ b.assertFailureWithErrorThatMatches(
+ containsString(
+ "java.lang.NoSuchMethodError: No static method"
+ + " parseInt(Ljava/lang/CharSequence;III)I")),
+ b -> b.assertSuccessWithOutputLines("4"));
}
// Test class for using: List List.of()
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/AtomicReferenceArrayTest.java b/src/test/java/com/android/tools/r8/desugar/backports/AtomicReferenceArrayTest.java
index 2c2af2b..3032a12 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/AtomicReferenceArrayTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/AtomicReferenceArrayTest.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.utils.AndroidApiLevel;
import java.util.concurrent.atomic.AtomicReferenceArray;
-import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@@ -25,7 +24,9 @@
}
public AtomicReferenceArrayTest(TestParameters parameters) {
- super(parameters, AtomicReferenceFieldUpdater.class, Main.class);
+ super(parameters, AtomicReferenceArray.class, Main.class);
+
+ ignoreInvokes("<init>");
// java.util.concurrent.atomic.AtomicReferenceArray issue is on API 31, see b/211646483.
registerTarget(AndroidApiLevel.Sv2, 3);
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/AtomicReferenceTest.java b/src/test/java/com/android/tools/r8/desugar/backports/AtomicReferenceTest.java
index 1f5d11e..6dc9faf 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/AtomicReferenceTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/AtomicReferenceTest.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.utils.AndroidApiLevel;
import java.util.concurrent.atomic.AtomicReference;
-import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@@ -25,7 +24,9 @@
}
public AtomicReferenceTest(TestParameters parameters) {
- super(parameters, AtomicReferenceFieldUpdater.class, Main.class);
+ super(parameters, AtomicReference.class, Main.class);
+
+ ignoreInvokes("<init>");
// java.util.concurrent.atomic.AtomicReference issue is on API 31, see b/211646483.
registerTarget(AndroidApiLevel.Sv2, 3);
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava10Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava10Test.java
index 25d4081..c5e6adc 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava10Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava10Test.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.desugar.backports;
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper;
@@ -16,8 +18,6 @@
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
-import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
-
@RunWith(Parameterized.class)
public final class OptionalBackportJava10Test extends AbstractBackportTest {
@Parameters(name = "{0}")
@@ -34,12 +34,14 @@
public OptionalBackportJava10Test(TestParameters parameters) {
super(parameters, Optional.class, TEST_JAR, "backport.OptionalBackportJava10Main");
- // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
- // an actual API level, migrate these tests to OptionalBackportTest.
+ // Note: The methods in this test exist in android.jar from Android T. When R8 builds targeting
+ // Java 11 move these tests to OptionalBackportTest (out of examplesJava10).
- // Available since N as part of library desugaring.
+ // Available since N.
ignoreInvokes("empty");
ignoreInvokes("get");
ignoreInvokes("of");
+
+ registerTarget(AndroidApiLevel.T, 2);
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava11Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava11Test.java
index dee14c1..8b57c0f 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava11Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava11Test.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.desugar.backports;
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper;
@@ -16,8 +18,6 @@
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
-import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
-
@RunWith(Parameterized.class)
public final class OptionalBackportJava11Test extends AbstractBackportTest {
@Parameters(name = "{0}")
@@ -34,11 +34,13 @@
public OptionalBackportJava11Test(TestParameters parameters) {
super(parameters, Optional.class, TEST_JAR, "backport.OptionalBackportJava11Main");
- // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
- // an actual API level, migrate these tests to OptionalBackportTest.
+ // Note: The methods in this test exist in android.jar from Android T. When R8 builds targeting
+ // Java 11 move these tests to OptionalBackportTest (out of examplesJava11).
- // Available since N as part of library desugaring.
+ // Available since N.
ignoreInvokes("empty");
ignoreInvokes("of");
+
+ registerTarget(AndroidApiLevel.T, 2);
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava9Test.java
index 31bc82f..a726dc5 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava9Test.java
@@ -34,11 +34,13 @@
public OptionalBackportJava9Test(TestParameters parameters) {
super(parameters, Optional.class, TEST_JAR, "backport.OptionalBackportJava9Main");
- // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
- // an actual API level, migrate these tests to OptionalBackportTest.
+ // Note: The methods in this test exist in android.jar from Android T. When R8 builds targeting
+ // Java 11 move these tests to OptionalBackportTest (out of examplesJava9).
- // Available since N as part of library desugaring.
+ // Available since N.
ignoreInvokes("empty");
ignoreInvokes("of");
+
+ registerTarget(AndroidApiLevel.T, 10);
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava10Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava10Test.java
index 97d70df..a181a64 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava10Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava10Test.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.desugar.backports;
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper;
@@ -11,14 +13,11 @@
import com.android.tools.r8.utils.AndroidApiLevel;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.Optional;
import java.util.OptionalDouble;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
-import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
-
@RunWith(Parameterized.class)
public final class OptionalDoubleBackportJava10Test extends AbstractBackportTest {
@Parameters(name = "{0}")
@@ -35,12 +34,14 @@
public OptionalDoubleBackportJava10Test(TestParameters parameters) {
super(parameters, OptionalDouble.class, TEST_JAR, "backport.OptionalDoubleBackportJava10Main");
- // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
- // an actual API level, migrate these tests to OptionalBackportTest.
+ // Note: The methods in this test exist in android.jar from Android T. When R8 builds targeting
+ // Java 11 move these tests to OptionalBackportTest (out of examplesJava10).
- // Available since N as part of library desugaring.
+ // Available since N.
ignoreInvokes("empty");
ignoreInvokes("getAsDouble");
ignoreInvokes("of");
+
+ registerTarget(AndroidApiLevel.T, 2);
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava11Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava11Test.java
index 981e1e2..b5e9c02 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava11Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava11Test.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.desugar.backports;
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper;
@@ -16,8 +18,6 @@
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
-import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
-
@RunWith(Parameterized.class)
public final class OptionalDoubleBackportJava11Test extends AbstractBackportTest {
@Parameters(name = "{0}")
@@ -34,11 +34,13 @@
public OptionalDoubleBackportJava11Test(TestParameters parameters) {
super(parameters, OptionalDouble.class, TEST_JAR, "backport.OptionalDoubleBackportJava11Main");
- // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
- // an actual API level, migrate these tests to OptionalBackportTest.
+ // Note: The methods in this test exist in android.jar from Android T. When R8 builds targeting
+ // Java 11 move these tests to OptionalBackportTest (out of examplesJava11).
- // Available since N as part of library desugaring.
+ // Available since N.
ignoreInvokes("empty");
ignoreInvokes("of");
+
+ registerTarget(AndroidApiLevel.T, 2);
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava9Test.java
index 5aa0e1c..bb9bb65 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava9Test.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.desugar.backports;
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper;
@@ -11,14 +13,11 @@
import com.android.tools.r8.utils.AndroidApiLevel;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.Optional;
import java.util.OptionalDouble;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
-import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
-
@RunWith(Parameterized.class)
public final class OptionalDoubleBackportJava9Test extends AbstractBackportTest {
@Parameters(name = "{0}")
@@ -35,11 +34,13 @@
public OptionalDoubleBackportJava9Test(TestParameters parameters) {
super(parameters, OptionalDouble.class, TEST_JAR, "backport.OptionalDoubleBackportJava9Main");
- // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
- // an actual API level, migrate these tests to OptionalDoubleBackportTest.
+ // Note: The methods in this test exist in android.jar from Android T. When R8 builds targeting
+ // Java 11 move these tests to OptionalBackportTest (out of examplesJava9).
- // Available since N as part of library desugaring.
+ // Available since N.
ignoreInvokes("empty");
ignoreInvokes("of");
+
+ registerTarget(AndroidApiLevel.T, 4);
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava10Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava10Test.java
index b44f1cf..00f5b4b 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava10Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava10Test.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.desugar.backports;
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper;
@@ -12,13 +14,10 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.OptionalInt;
-import java.util.OptionalLong;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
-import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
-
@RunWith(Parameterized.class)
public final class OptionalIntBackportJava10Test extends AbstractBackportTest {
@Parameters(name = "{0}")
@@ -35,12 +34,14 @@
public OptionalIntBackportJava10Test(TestParameters parameters) {
super(parameters, OptionalInt.class, TEST_JAR, "backport.OptionalIntBackportJava10Main");
- // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
- // an actual API level, migrate these tests to OptionalBackportTest.
+ // Note: The methods in this test exist in android.jar from Android T. When R8 builds targeting
+ // Java 11 move these tests to OptionalBackportTest (out of examplesJava10).
- // Available since N as part of library desugaring.
+ // Available since N.
ignoreInvokes("empty");
ignoreInvokes("getAsInt");
ignoreInvokes("of");
+
+ registerTarget(AndroidApiLevel.T, 2);
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava11Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava11Test.java
index e594db3..62d66cd 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava11Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava11Test.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.desugar.backports;
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper;
@@ -16,8 +18,6 @@
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
-import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
-
@RunWith(Parameterized.class)
public final class OptionalIntBackportJava11Test extends AbstractBackportTest {
@Parameters(name = "{0}")
@@ -34,11 +34,13 @@
public OptionalIntBackportJava11Test(TestParameters parameters) {
super(parameters, OptionalInt.class, TEST_JAR, "backport.OptionalIntBackportJava11Main");
- // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
- // an actual API level, migrate these tests to OptionalBackportTest.
+ // Note: The methods in this test exist in android.jar from Android T. When R8 builds targeting
+ // Java 11 move these tests to OptionalBackportTest (out of examplesJava11).
- // Available since N as part of library desugaring.
+ // Available since N.
ignoreInvokes("empty");
ignoreInvokes("of");
+
+ registerTarget(AndroidApiLevel.T, 2);
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava9Test.java
index 71a8dd9..54f08ae 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava9Test.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.desugar.backports;
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper;
@@ -16,8 +18,6 @@
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
-import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
-
@RunWith(Parameterized.class)
public final class OptionalIntBackportJava9Test extends AbstractBackportTest {
@Parameters(name = "{0}")
@@ -34,11 +34,13 @@
public OptionalIntBackportJava9Test(TestParameters parameters) {
super(parameters, OptionalInt.class, TEST_JAR, "backport.OptionalIntBackportJava9Main");
- // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
- // an actual API level, migrate these tests to OptionalIntBackportTest.
+ // Note: The methods in this test exist in android.jar from Android T. When R8 builds targeting
+ // Java 11 move these tests to OptionalBackportTest (out of examplesJava9).
- // Available since N as part of library desugaring.
+ // Available since N.
ignoreInvokes("empty");
ignoreInvokes("of");
+
+ registerTarget(AndroidApiLevel.T, 4);
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava10Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava10Test.java
index a4bef8c..c353e92 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava10Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava10Test.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.desugar.backports;
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper;
@@ -16,8 +18,6 @@
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
-import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
-
@RunWith(Parameterized.class)
public final class OptionalLongBackportJava10Test extends AbstractBackportTest {
@Parameters(name = "{0}")
@@ -34,12 +34,14 @@
public OptionalLongBackportJava10Test(TestParameters parameters) {
super(parameters, OptionalLong.class, TEST_JAR, "backport.OptionalLongBackportJava10Main");
- // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
- // an actual API level, migrate these tests to OptionalBackportTest.
+ // Note: The methods in this test exist in android.jar from Android T. When R8 builds targeting
+ // Java 11 move these tests to OptionalBackportTest (out of examplesJava10).
- // Available since N as part of library desugaring.
+ // Available since N.
ignoreInvokes("empty");
ignoreInvokes("getAsLong");
ignoreInvokes("of");
+
+ registerTarget(AndroidApiLevel.T, 2);
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava11Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava11Test.java
index bc1f4aa..fd8fc6f 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava11Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava11Test.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.desugar.backports;
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper;
@@ -16,8 +18,6 @@
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
-import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
-
@RunWith(Parameterized.class)
public final class OptionalLongBackportJava11Test extends AbstractBackportTest {
@Parameters(name = "{0}")
@@ -34,11 +34,13 @@
public OptionalLongBackportJava11Test(TestParameters parameters) {
super(parameters, OptionalLong.class, TEST_JAR, "backport.OptionalLongBackportJava11Main");
- // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
- // an actual API level, migrate these tests to OptionalBackportTest.
+ // Note: The methods in this test exist in android.jar from Android T. When R8 builds targeting
+ // Java 11 move these tests to OptionalBackportTest (out of examplesJava11).
- // Available since N as part of library desugaring.
+ // Available since N.
ignoreInvokes("empty");
ignoreInvokes("of");
+
+ registerTarget(AndroidApiLevel.T, 2);
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava9Test.java
index b0dfd62..efb516a 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava9Test.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.desugar.backports;
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper;
@@ -16,8 +18,6 @@
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
-import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
-
@RunWith(Parameterized.class)
public final class OptionalLongBackportJava9Test extends AbstractBackportTest {
@Parameters(name = "{0}")
@@ -34,13 +34,15 @@
public OptionalLongBackportJava9Test(TestParameters parameters) {
super(parameters, OptionalLong.class, TEST_JAR, "backport.OptionalLongBackportJava9Main");
- // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
- // an actual API level, migrate these tests to OptionalLongBackportTest.
+ // Note: The methods in this test exist in android.jar from Android T. When R8 builds targeting
+ // Java 11 move these tests to OptionalBackportTest (out of examplesJava9).
- // Available since N as part of library desugaring.
+ // Available since N.
ignoreInvokes("empty");
ignoreInvokes("getAsLong");
ignoreInvokes("isPresent");
ignoreInvokes("of");
+
+ registerTarget(AndroidApiLevel.T, 4);
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/TestBackportedNotPresentInAndroidJar.java b/src/test/java/com/android/tools/r8/desugar/backports/TestBackportedNotPresentInAndroidJar.java
index 237b0e1..195dfd2 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/TestBackportedNotPresentInAndroidJar.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/TestBackportedNotPresentInAndroidJar.java
@@ -79,6 +79,9 @@
@Test
public void testBackportedMethodsPerAPILevel() throws Exception {
for (AndroidApiLevel apiLevel : AndroidApiLevel.values()) {
+ if (apiLevel == AndroidApiLevel.T) {
+ continue;
+ }
if (!ToolHelper.hasAndroidJar(apiLevel)) {
// Only check for the android jar versions present in third_party.
System.out.println("Skipping check for " + apiLevel);
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java
index 6b54606..b5e5c03 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java
@@ -73,11 +73,13 @@
}
private void configurationForProgramCompilation(InternalOptions options) {
- options.desugaredLibrarySpecification = configurationAlternative3(options, false, parameters);
+ setDesugaredLibrarySpecificationForTesting(
+ options, configurationAlternative3(options, false, parameters));
}
private void configurationForLibraryCompilation(InternalOptions options) {
- options.desugaredLibrarySpecification = configurationAlternative3(options, true, parameters);
+ setDesugaredLibrarySpecificationForTesting(
+ options, configurationAlternative3(options, true, parameters));
}
@Test
@@ -141,10 +143,7 @@
KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
testForD8()
.addLibraryFiles(getLibraryFile())
- .addOptionsModification(
- options ->
- options.desugaredLibrarySpecification =
- configurationAlternative3(options, false, parameters))
+ .addOptionsModification(this::configurationForProgramCompilation)
.addInnerClasses(BufferedReaderTest.class)
.setMinApi(parameters.getApiLevel())
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -170,10 +169,7 @@
KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
testForR8(parameters.getBackend())
.addLibraryFiles(getLibraryFile())
- .addOptionsModification(
- options ->
- options.desugaredLibrarySpecification =
- configurationAlternative3(options, false, parameters))
+ .addOptionsModification(this::configurationForProgramCompilation)
.addInnerClasses(BufferedReaderTest.class)
.addKeepMainRule(TestClass.class)
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionTest.java
index d1e9746..473153c 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionTest.java
@@ -10,17 +10,11 @@
import com.android.tools.r8.D8TestRunResult;
import com.android.tools.r8.R8TestRunResult;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.HumanToMachineSpecificationConverter;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.LegacyToHumanSpecificationConverter;
import com.android.tools.r8.utils.BooleanUtils;
-import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
import com.android.tools.r8.utils.codeinspector.InstructionSubject.JumboStringMode;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
@@ -40,19 +34,15 @@
private final TestParameters parameters;
private final boolean shrinkDesugaredLibrary;
- private final boolean machineSpec;
- @Parameters(name = "machine: {0}, {2}, shrink: {1}")
+ @Parameters(name = "machine: {0}, shrink: {1}")
public static List<Object[]> data() {
return buildParameters(
BooleanUtils.values(),
- BooleanUtils.values(),
getTestParameters().withDexRuntimes().withAllApiLevels().build());
}
- public CustomCollectionTest(
- boolean machineSpec, boolean shrinkDesugaredLibrary, TestParameters parameters) {
- this.machineSpec = machineSpec;
+ public CustomCollectionTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
this.parameters = parameters;
}
@@ -60,22 +50,6 @@
private final String EXECUTOR =
"com.android.tools.r8.desugar.desugaredlibrary.CustomCollectionTest$Executor";
- private void setMachineSpec(InternalOptions opt) {
- if (!machineSpec) {
- return;
- }
- try {
- HumanDesugaredLibrarySpecification human =
- new LegacyToHumanSpecificationConverter()
- .convert(opt.desugaredLibrarySpecification, getLibraryFile(), opt);
- MachineDesugaredLibrarySpecification machine =
- new HumanToMachineSpecificationConverter().convert(human, getLibraryFile(), opt);
- opt.testing.machineDesugaredLibrarySpecification = machine;
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
@Test
public void testCustomCollectionD8() throws Exception {
KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
@@ -83,7 +57,6 @@
testForD8()
.addLibraryFiles(getLibraryFile())
.addInnerClasses(CustomCollectionTest.class)
- .addOptionsModification(this::setMachineSpec)
.setMinApi(parameters.getApiLevel())
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.compile()
@@ -106,7 +79,6 @@
Path jar =
testForD8(Backend.CF)
.addInnerClasses(CustomCollectionTest.class)
- .addOptionsModification(this::setMachineSpec)
.setMinApi(parameters.getApiLevel())
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.compile()
@@ -162,7 +134,6 @@
testForR8(Backend.DEX)
.addLibraryFiles(getLibraryFile())
.addInnerClasses(CustomCollectionTest.class)
- .addOptionsModification(this::setMachineSpec)
.setMinApi(parameters.getApiLevel())
.addKeepClassAndMembersRules(Executor.class)
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryCHMOnlyContentTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryCHMOnlyContentTest.java
index 3e7d97d..e27dda9 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryCHMOnlyContentTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryCHMOnlyContentTest.java
@@ -43,10 +43,9 @@
"",
false,
Collections.emptyList(),
- options -> {
- options.desugaredLibrarySpecification =
- chmOnlyConfiguration(options, true, parameters);
- });
+ options ->
+ setDesugaredLibrarySpecificationForTesting(
+ options, chmOnlyConfiguration(options, true, parameters)));
CodeInspector inspector = new CodeInspector(desugaredLib);
assert inspector.clazz("j$.util.concurrent.ConcurrentHashMap").isPresent();
}
@@ -61,10 +60,9 @@
"-keep class * { *; }",
true,
Collections.emptyList(),
- options -> {
- options.desugaredLibrarySpecification =
- chmOnlyConfiguration(options, true, parameters);
- });
+ options ->
+ setDesugaredLibrarySpecificationForTesting(
+ options, chmOnlyConfiguration(options, true, parameters)));
CodeInspector inspector = new CodeInspector(desugaredLib);
assert inspector.clazz("j$.util.concurrent.ConcurrentHashMap").isPresent();
}
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 e353126..f4786f7 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
@@ -5,15 +5,19 @@
package com.android.tools.r8.desugar.desugaredlibrary;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertTrue;
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 static org.junit.Assert.fail;
import com.android.tools.r8.L8Command;
+import com.android.tools.r8.L8TestBuilder;
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.StringResource;
+import com.android.tools.r8.TestDiagnosticMessages;
import com.android.tools.r8.TestDiagnosticMessagesImpl;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -25,6 +29,7 @@
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
import java.nio.file.Path;
import java.util.ArrayList;
+import java.util.Collections;
import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -45,6 +50,33 @@
}
@Test
+ public void testInvalidLibrary() throws Exception {
+ Assume.assumeTrue(requiresAnyCoreLibDesugaring(parameters));
+ L8TestBuilder l8TestBuilder =
+ testForL8(parameters.getApiLevel())
+ .addProgramFiles(Collections.singleton(ToolHelper.getDesugarJDKLibs()))
+ .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.L))
+ .setDesugarJDKLibsConfiguration(ToolHelper.DESUGAR_LIB_CONVERSIONS);
+ try {
+ l8TestBuilder.compile();
+ fail();
+ } catch (AssertionError ae) {
+ // Expected since the library is invalid.
+ }
+ TestDiagnosticMessages diagnosticMessages = l8TestBuilder.getDiagnosticMessages();
+ diagnosticMessages.assertOnlyWarnings();
+ assertEquals(diagnosticMessages.getWarnings().size(), 1);
+ assertTrue(
+ diagnosticMessages
+ .getWarnings()
+ .get(0)
+ .getDiagnosticMessage()
+ .contains(
+ "Desugared library requires to be compiled with a library file of API greater or"
+ + " equal to"));
+ }
+
+ @Test
public void testDesugaredLibraryContentD8() throws Exception {
Assume.assumeTrue(requiresAnyCoreLibDesugaring(parameters));
CodeInspector inspector = new CodeInspector(buildDesugaredLibrary(parameters.getApiLevel()));
@@ -89,11 +121,20 @@
ToolHelper.runL8(l8Builder.build(), options -> {});
CodeInspector codeInspector = new CodeInspector(desugaredLib);
assertCorrect(codeInspector);
- assertNoWarningsErrors(diagnosticsHandler);
+ assertOneWarning(diagnosticsHandler);
}
- private void assertNoWarningsErrors(TestDiagnosticMessagesImpl diagnosticsHandler) {
- assertTrue(diagnosticsHandler.getWarnings().isEmpty());
+ private void assertOneWarning(TestDiagnosticMessagesImpl diagnosticsHandler) {
+ assertEquals(
+ (isJDK11DesugaredLibrary() && parameters.getApiLevel().isLessThan(AndroidApiLevel.O))
+ ? 2
+ : 1,
+ diagnosticsHandler.getWarnings().size());
+ String msg = diagnosticsHandler.getWarnings().get(0).getDiagnosticMessage();
+ assertTrue(
+ msg.contains(
+ "The following library types, prefixed by java., are present both as library and non"
+ + " library classes"));
assertTrue(diagnosticsHandler.getErrors().isEmpty());
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryDumpInputsTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryDumpInputsTest.java
index 03f861b..92e689b 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryDumpInputsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryDumpInputsTest.java
@@ -9,7 +9,6 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.ZipUtils;
import com.google.common.collect.ImmutableList;
@@ -48,7 +47,7 @@
Path dumpDir = temp.newFolder().toPath();
testForD8(parameters.getBackend())
.addProgramClasses(TestClass.class)
- .addLibraryFiles(ToolHelper.getJava8RuntimeJar())
+ .addLibraryFiles(getLibraryFile())
.setMinApi(parameters.getApiLevel())
.addOptionsModification(options -> options.dumpInputToDirectory = dumpDir.toString())
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -76,7 +75,7 @@
Path dumpDir = temp.newFolder().toPath();
testForR8(parameters.getBackend())
.addProgramClasses(TestClass.class)
- .addLibraryFiles(ToolHelper.getJava8RuntimeJar())
+ .addLibraryFiles(getLibraryFile())
.setMinApi(parameters.getApiLevel())
.addKeepMainRule(TestClass.class)
.addOptionsModification(options -> options.dumpInputToDirectory = dumpDir.toString())
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 34faa58..eb25adf 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
@@ -67,6 +67,18 @@
return property.contains("jdk11");
}
+ public void setDesugaredLibrarySpecificationForTesting(
+ InternalOptions options, LegacyDesugaredLibrarySpecification specification) {
+ try {
+ options.setDesugaredLibrarySpecificationForTesting(
+ specification,
+ ToolHelper.getDesugarJDKLibs(),
+ ToolHelper.getAndroidJar(AndroidApiLevel.R));
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
// For conversions tests, we need DexRuntimes where classes to convert are present (DexRuntimes
// above N and O depending if Stream or Time APIs are used), but we need to compile the program
// with a minAPI below to force the use of conversions.
@@ -87,10 +99,12 @@
throw new Error("Unsupported conversion parameters");
}
+ protected AndroidApiLevel getRequiredCompilationAPILevel() {
+ return isJDK11DesugaredLibrary() ? AndroidApiLevel.R : AndroidApiLevel.P;
+ }
+
protected Path getLibraryFile() {
- return isJDK11DesugaredLibrary()
- ? ToolHelper.getAndroidJar(AndroidApiLevel.S)
- : ToolHelper.getAndroidJar(AndroidApiLevel.P);
+ return ToolHelper.getAndroidJar(getRequiredCompilationAPILevel());
}
protected boolean requiresEmulatedInterfaceCoreLibDesugaring(TestParameters parameters) {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryWarningTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryWarningTest.java
index 0c61a06..47b01f1 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryWarningTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryWarningTest.java
@@ -4,6 +4,9 @@
package com.android.tools.r8.desugar.desugaredlibrary;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.L8Command;
import com.android.tools.r8.OutputMode;
@@ -12,6 +15,7 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.BooleanUtils;
import java.nio.file.Path;
import java.util.Arrays;
@@ -65,6 +69,19 @@
Arrays.asList(FUNCTION_KEEP.split(System.lineSeparator())), Origin.unknown());
}
ToolHelper.runL8(l8Builder.build(), options -> {});
- diagnosticsHandler.assertNoMessages();
+ assertEquals(
+ (isJDK11DesugaredLibrary() && parameters.getApiLevel().isLessThan(AndroidApiLevel.O))
+ ? 2
+ : 1,
+ diagnosticsHandler.getWarnings().size());
+ diagnosticsHandler.assertNoErrors();
+ assertTrue(
+ diagnosticsHandler
+ .getWarnings()
+ .get(0)
+ .getDiagnosticMessage()
+ .contains(
+ "The following library types, prefixed by java., are present both as library and"
+ + " non library classes:"));
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InconsistentPrefixTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InconsistentPrefixTest.java
deleted file mode 100644
index b1f57e1..0000000
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InconsistentPrefixTest.java
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.desugar.desugaredlibrary;
-
-import static org.hamcrest.CoreMatchers.containsString;
-
-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.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
-import com.android.tools.r8.jasmin.JasminBuilder;
-import java.nio.file.Path;
-import java.util.HashMap;
-import java.util.Map;
-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 InconsistentPrefixTest extends TestBase {
-
- @Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return getTestParameters().withNoneRuntime().build();
- }
-
- public InconsistentPrefixTest(TestParameters parameters) {
- parameters.assertNoneRuntime();
- }
-
- @Test(expected = CompilationFailedException.class)
- public void testNoInconsistentPrefixes() throws Exception {
- Map<String, String> x = new HashMap<>();
- x.put("pkg.sub", "p$.bus");
- x.put("pkg", "p$");
-
- JasminBuilder jasminBuilder = new JasminBuilder();
- jasminBuilder.addClass("pkg/notsub/A");
- jasminBuilder.addClass("pkg/sub/A");
- Path inputJar = temp.getRoot().toPath().resolve("input.jar");
- jasminBuilder.writeJar(inputJar);
-
- testForD8()
- .addProgramFiles(inputJar)
- .addOptionsModification(
- options ->
- options.desugaredLibrarySpecification =
- LegacyDesugaredLibrarySpecification.withOnlyRewritePrefixForTesting(x, options))
- .compileWithExpectedDiagnostics(
- diagnostics -> {
- diagnostics.assertErrorMessageThatMatches(
- containsString("Inconsistent prefix in desugared library"));
- });
- }
-}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/J$ExtensionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/J$ExtensionTest.java
index 88f3ca9..371443d 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/J$ExtensionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/J$ExtensionTest.java
@@ -5,15 +5,12 @@
package com.android.tools.r8.desugar.desugaredlibrary;
import static junit.framework.TestCase.assertTrue;
-import static junit.framework.TestCase.fail;
-import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.DexVm.Version;
-import com.android.tools.r8.utils.BooleanUtils;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
@@ -31,7 +28,6 @@
public class J$ExtensionTest extends DesugaredLibraryTestBase {
private final TestParameters parameters;
- private final boolean shrinkDesugaredLibrary;
private static final String MAIN_CLASS_NAME = "Main";
private static final String MAIN_CLASS =
@@ -55,14 +51,12 @@
+ "}";
private static Path[] compiledClasses = new Path[2];
- @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+ @Parameters(name = "{0}")
public static List<Object[]> data() {
- return buildParameters(
- BooleanUtils.values(), getTestParameters().withAllRuntimes().withAllApiLevels().build());
+ return buildParameters(getTestParameters().withAllRuntimes().withAllApiLevels().build());
}
- public J$ExtensionTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
- this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+ public J$ExtensionTest(TestParameters parameters) {
this.parameters = parameters;
}
@@ -92,7 +86,6 @@
@Test
public void testJ$ExtensionNoDesugaring() throws Exception {
- Assume.assumeFalse(shrinkDesugaredLibrary);
String stderr;
if (parameters.isCfRuntime()) {
stderr =
@@ -110,24 +103,31 @@
.assertFailure()
.getStdErr();
}
- assertError(stderr);
+ assertError(stderr, false);
}
- private void assertError(String stderr) {
- if (parameters.isCfRuntime() && parameters.getRuntime().asCf().getVm() == CfVm.JDK8) {
- assertTrue(
- stderr.contains("java.lang.SecurityException: Prohibited package name: java.time"));
- } else if (parameters.isCfRuntime()) {
- assertTrue(stderr.contains("java.lang.ClassNotFoundException: java.time.LocalTimeAccess"));
- } else if (parameters
- .getRuntime()
- .asDex()
- .getVm()
- .getVersion()
- .isOlderThanOrEqual(Version.V6_0_1)) {
- assertTrue(stderr.contains("java.lang.NoClassDefFoundError"));
- } else if (parameters.getRuntime().asDex().getVm().getVersion() == Version.V7_0_0) {
- assertTrue(stderr.contains("java.lang.ClassNotFoundException"));
+ private void assertError(String stderr, boolean desugaring) {
+ if (parameters.isCfRuntime()) {
+ if (parameters.getRuntime().asCf().getVm() == CfVm.JDK8) {
+ assertTrue(
+ stderr.contains("java.lang.SecurityException: Prohibited package name: java.time"));
+ } else {
+ assertTrue(stderr.contains("java.lang.ClassNotFoundException: java.time.LocalTimeAccess"));
+ }
+ return;
+ }
+ assert !parameters.isCfRuntime();
+ if (!desugaring) {
+ if (parameters.getDexRuntimeVersion().isOlderThanOrEqual(Version.V6_0_1)) {
+ assertTrue(stderr.contains("java.lang.NoClassDefFoundError"));
+ } else if (parameters.getDexRuntimeVersion() == Version.V7_0_0) {
+ assertTrue(stderr.contains("java.lang.ClassNotFoundException"));
+ }
+ return;
+ }
+ if (parameters.getDexRuntimeVersion() == Version.V8_1_0) {
+ // On Android 8 the library package private method is accessible.
+ assertTrue(stderr.contains("java.lang.NullPointerException"));
} else {
assertTrue(stderr.contains("java.lang.IllegalAccessError"));
}
@@ -140,19 +140,18 @@
Assume.assumeTrue(requiresTimeDesugaring(parameters));
KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
- try {
- testForD8()
- .addLibraryFiles(getLibraryFile())
- .addProgramFiles(compiledClasses)
- .setMinApi(parameters.getApiLevel())
- .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
- .compile();
- fail();
- } catch (CompilationFailedException e) {
- assertTrue(
- e.getCause()
- .getMessage()
- .contains("Cannot compile program class java.time.LocalTimeAccess"));
- }
+ String stdErr =
+ testForD8()
+ .addLibraryFiles(getLibraryFile())
+ .addProgramFiles(compiledClasses)
+ .setMinApi(parameters.getApiLevel())
+ .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+ .compile()
+ .addDesugaredCoreLibraryRunClassPath(
+ this::buildDesugaredLibrary, parameters.getApiLevel())
+ .run(parameters.getRuntime(), MAIN_CLASS_NAME)
+ .assertFailure()
+ .getStdErr();
+ assertError(stdErr, true);
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java
index 6598d6b..d78df31 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java
@@ -144,16 +144,22 @@
.map(TypeSubject::toString)
.collect(Collectors.toSet());
assertEquals(expectedCatchGuards, foundCatchGuards);
-
- if (isR8) {
- assertThat(
- inspector.clazz(TemporalAccessorImpl.class).uniqueMethodWithFinalName("query"),
- not(isPresent()));
- } else {
+ if (!(parameters
+ .getApiLevel()
+ .isGreaterThanOrEqualTo(TestBase.apiLevelWithDefaultInterfaceMethodsSupport())
+ && isR8)) {
assertThat(
inspector.clazz(TemporalAccessorImplSub.class).uniqueMethodWithFinalName("query"),
CodeMatchers.invokesMethod(
- null, TemporalAccessorImpl.class.getTypeName(), "query", null));
+ null, inspector.clazz(TemporalAccessorImpl.class).getFinalName(), "query", null));
+ } else {
+ String holder =
+ requiresTimeDesugaring(parameters)
+ ? "j$.time.temporal.TemporalAccessor"
+ : "java.time.temporal.TemporalAccessor";
+ assertThat(
+ inspector.clazz(TemporalAccessorImplSub.class).uniqueMethodWithFinalName("query"),
+ CodeMatchers.invokesMethod(null, holder, "query", null));
}
if (parameters
.getApiLevel()
@@ -163,9 +169,7 @@
not(isPresent()));
} else {
assertThat(
- inspector
- .clazz(isR8 ? TemporalAccessorImplSub.class : TemporalAccessorImpl.class)
- .uniqueMethodWithFinalName("query"),
+ inspector.clazz(TemporalAccessorImpl.class).uniqueMethodWithFinalName("query"),
CodeMatchers.invokesMethod(
null, "j$.time.temporal.TemporalAccessor$-CC", "$default$query", null));
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LinkedHashSetTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LinkedHashSetTest.java
index 981edea..de87214 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LinkedHashSetTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LinkedHashSetTest.java
@@ -11,6 +11,7 @@
import java.util.Set;
import java.util.Spliterator;
import java.util.Spliterators;
+import java.util.function.Predicate;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -165,6 +166,14 @@
System.out.println("true");
System.out.println(spliterator.hasCharacteristics(Spliterator.IMMUTABLE));
System.out.println("false");
+
+ spliterator = ((Set<String>) new CustomLinkedHashSetForceForwarding<String>()).spliterator();
+ System.out.println(spliterator.hasCharacteristics(Spliterator.DISTINCT));
+ System.out.println("true");
+ System.out.println(spliterator.hasCharacteristics(Spliterator.ORDERED));
+ System.out.println("true");
+ System.out.println(spliterator.hasCharacteristics(Spliterator.IMMUTABLE));
+ System.out.println("false");
}
}
@@ -198,4 +207,13 @@
return super.spliterator();
}
}
+
+ // The over method force the forwarding methods to be installed.
+ static class CustomLinkedHashSetForceForwarding<E> extends LinkedHashSet<E> {
+
+ @Override
+ public boolean removeIf(Predicate<? super E> filter) {
+ return super.removeIf(filter);
+ }
+ }
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java
index 18af69f..d296ec9 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java
@@ -131,7 +131,7 @@
.parse(StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()));
for (AndroidApiLevel apiLevel : AndroidApiLevel.values()) {
- if (apiLevel.isGreaterThan(AndroidApiLevel.LATEST)) {
+ if (apiLevel.isGreaterThan(AndroidApiLevel.Sv2)) {
continue;
}
Path compileApiLevelDirectory = directory.resolve("compile_api_level_" + apiLevel.getLevel());
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingJ$Test.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingJ$Test.java
index d5300ad..1208414 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingJ$Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingJ$Test.java
@@ -118,8 +118,8 @@
L8.run(
L8Command.builder()
.addLibraryFiles(getLibraryFile())
+ .addLibraryFiles(ToolHelper.getDesugarJDKLibs())
.addProgramFiles(JDK_11_JAVA_BASE_EXTENSION_COMPILED_FILES)
- .addClasspathFiles(ToolHelper.getDesugarJDKLibs())
.addDesugaredLibraryConfiguration(
StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
.setMinApiLevel(AndroidApiLevel.B.getLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NeverMergeCoreLibDesugarClasses.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NeverMergeCoreLibDesugarClasses.java
index fbb422a..8a86def 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NeverMergeCoreLibDesugarClasses.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NeverMergeCoreLibDesugarClasses.java
@@ -45,15 +45,16 @@
.addInnerClasses(NeverMergeCoreLibDesugarClasses.class)
.addProgramDexFileData(builder.compile())
.setMinApi(parameters.getRuntime())
- .compileWithExpectedDiagnostics(diagnostics -> {
- diagnostics.assertErrorsCount(1);
- String message = diagnostics.getErrors().get(0).getDiagnosticMessage();
- assertThat(
- message,
- containsString(
- "Merging dex file containing classes with prefix 'j$.' "
- + "with classes with any other prefixes is not allowed."));
- });
+ .compileWithExpectedDiagnostics(
+ diagnostics -> {
+ diagnostics.assertErrorsCount(1);
+ String message = diagnostics.getErrors().get(0).getDiagnosticMessage();
+ assertThat(
+ message,
+ containsString(
+ "Merging dex file containing classes with prefix 'j$.' "
+ + "with classes with any other prefixes is not allowed"));
+ });
} catch (CompilationFailedException e) {
// Expected compilation failed.
return;
@@ -78,7 +79,7 @@
message,
containsString(
"Merging dex file containing classes with prefix 'j$.' "
- + "with classes with any other prefixes is not allowed."));
+ + "with classes with any other prefixes is not allowed"));
});
} catch (CompilationFailedException e) {
// Expected compilation failed.
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ObjectsTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ObjectsTest.java
index abdf5c5..ed772cb 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ObjectsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ObjectsTest.java
@@ -79,9 +79,9 @@
public ObjectsTest(TestParameters parameters, boolean libraryDesugarJavaUtilObjects) {
this.parameters = parameters;
this.libraryDesugarJavaUtilObjects = libraryDesugarJavaUtilObjects;
- // Using desugared library require a compile SDK of 26 or higher.
this.androidJar =
- ToolHelper.getAndroidJar(Ordered.max(parameters.getApiLevel(), AndroidApiLevel.O));
+ ToolHelper.getAndroidJar(
+ Ordered.max(parameters.getApiLevel(), getRequiredCompilationAPILevel()));
}
LegacyDesugaredLibrarySpecification desugaredLibrarySpecification(
@@ -99,13 +99,13 @@
}
private void configurationForProgramCompilation(InternalOptions options) {
- options.desugaredLibrarySpecification =
- desugaredLibrarySpecification(options, false, parameters);
+ setDesugaredLibrarySpecificationForTesting(
+ options, desugaredLibrarySpecification(options, false, parameters));
}
private void configurationForLibraryCompilation(InternalOptions options) {
- options.desugaredLibrarySpecification =
- desugaredLibrarySpecification(options, true, parameters);
+ setDesugaredLibrarySpecificationForTesting(
+ options, desugaredLibrarySpecification(options, true, parameters));
}
private Matcher<MethodSubject> invokesObjectsCompare(String holder) {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetAndBackportTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetAndBackportTest.java
index 359a18c..27762ea 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetAndBackportTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetAndBackportTest.java
@@ -7,6 +7,7 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyRewritingFlags;
import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyTopLevelFlags;
@@ -14,6 +15,7 @@
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import java.io.IOException;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -44,7 +46,6 @@
* {
* "rewrite_prefix":{"java.time.": "j$.time."},
* "backport": {"java.lang.DesugarMath": "java.lang.Math"},
- * "retarget_lib_member": {"java.util.Date#toInstant": "java.util.DesugarDate"}
* }
* ],
*/
@@ -53,11 +54,16 @@
LegacyRewritingFlags.builder(options.itemFactory, options.reporter, Origin.unknown())
.putRewritePrefix("java.time.", "j$.time.")
.putBackportCoreLibraryMember("java.lang.DesugarMath", "java.lang.Math")
- .putRetargetCoreLibMember("java.util.Date#toInstant", "java.util.DesugarDate")
.build();
- options.desugaredLibrarySpecification =
- new LegacyDesugaredLibrarySpecification(
- LegacyTopLevelFlags.testing(), rewritingFlags, true, options.itemFactory);
+ try {
+ options.setDesugaredLibrarySpecificationForTesting(
+ new LegacyDesugaredLibrarySpecification(
+ LegacyTopLevelFlags.testing(), rewritingFlags, true),
+ ToolHelper.getDesugarJDKLibs(),
+ ToolHelper.getAndroidJar(AndroidApiLevel.R));
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
}
@Test
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetOverrideTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetOverrideTest.java
index 6bf49a0..e629c47 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetOverrideTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetOverrideTest.java
@@ -5,13 +5,7 @@
package com.android.tools.r8.desugar.desugaredlibrary;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.HumanToMachineSpecificationConverter;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.LegacyToHumanSpecificationConverter;
import com.android.tools.r8.utils.BooleanUtils;
-import com.android.tools.r8.utils.InternalOptions;
-import java.io.IOException;
import java.nio.file.Path;
import java.time.Instant;
import java.time.ZonedDateTime;
@@ -31,19 +25,15 @@
private final TestParameters parameters;
private final boolean shrinkDesugaredLibrary;
- private final boolean machineSpec;
@Parameters(name = "machine: {0}, {2}, shrink: {1}")
public static List<Object[]> data() {
return buildParameters(
BooleanUtils.values(),
- BooleanUtils.values(),
getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build());
}
- public RetargetOverrideTest(
- boolean machineSpec, boolean shrinkDesugaredLibrary, TestParameters parameters) {
- this.machineSpec = machineSpec;
+ public RetargetOverrideTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
this.parameters = parameters;
}
@@ -54,7 +44,6 @@
Path desugaredTwice =
testForD8(Backend.CF)
.addLibraryFiles(getLibraryFile())
- .addOptionsModification(this::setMachineSpec)
.addProgramFiles(
testForD8(Backend.CF)
.addLibraryFiles(getLibraryFile())
@@ -76,7 +65,6 @@
stdout =
testForD8(Backend.DEX)
.addProgramFiles(desugaredTwice)
- .addOptionsModification(this::setMachineSpec)
.setMinApi(parameters.getApiLevel())
.disableDesugaring()
.compile()
@@ -107,22 +95,6 @@
assertLines2By2Correct(stdout);
}
- private void setMachineSpec(InternalOptions opt) {
- if (!machineSpec) {
- return;
- }
- try {
- HumanDesugaredLibrarySpecification human =
- new LegacyToHumanSpecificationConverter()
- .convert(opt.desugaredLibrarySpecification, getLibraryFile(), opt);
- MachineDesugaredLibrarySpecification machine =
- new HumanToMachineSpecificationConverter().convert(human, getLibraryFile(), opt);
- opt.testing.machineDesugaredLibrarySpecification = machine;
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
@Test
public void testRetargetOverrideD8() throws Exception {
Assume.assumeTrue(parameters.getRuntime().isDex());
@@ -130,7 +102,6 @@
String stdout =
testForD8()
.addLibraryFiles(getLibraryFile())
- .addOptionsModification(this::setMachineSpec)
.addInnerClasses(RetargetOverrideTest.class)
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.setMinApi(parameters.getApiLevel())
@@ -156,7 +127,6 @@
String stdout =
testForR8(Backend.DEX)
.addLibraryFiles(getLibraryFile())
- .addOptionsModification(this::setMachineSpec)
.addKeepMainRule(Executor.class)
.addInnerClasses(RetargetOverrideTest.class)
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/APIConversionFinalClassTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/APIConversionFinalClassTest.java
index f9d1828..7abed46 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/APIConversionFinalClassTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/APIConversionFinalClassTest.java
@@ -58,6 +58,7 @@
.setMinApi(AndroidApiLevel.B)
.addProgramClasses(Executor.class)
.addLibraryClasses(CustomLibClass.class)
+ .addLibraryFiles(getLibraryFile())
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.compile()
.addDesugaredCoreLibraryRunClassPath(
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/AccessModeConversionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/AccessModeConversionTest.java
index 6691cb1..a57140b 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/AccessModeConversionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/AccessModeConversionTest.java
@@ -66,8 +66,8 @@
.build();
LegacyDesugaredLibrarySpecification specification =
new LegacyDesugaredLibrarySpecification(
- LegacyTopLevelFlags.testing(), rewritingFlags, l8Compilation, options.itemFactory);
- options.desugaredLibrarySpecification = specification;
+ LegacyTopLevelFlags.testing(), rewritingFlags, l8Compilation);
+ setDesugaredLibrarySpecificationForTesting(options, specification);
}
@Test
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java
index aa97e55..957515a 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java
@@ -87,9 +87,10 @@
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.addOptionsModification(
opt ->
- opt.desugaredLibrarySpecification =
+ setDesugaredLibrarySpecificationForTesting(
+ opt,
configurationWithSupportAllCallbacksFromLibrary(
- opt, false, parameters, supportAllCallbacksFromLibrary))
+ opt, false, parameters, supportAllCallbacksFromLibrary)))
.compile()
.inspect(this::assertDoubleForEach)
.inspect(this::assertWrapperMethodsPresent)
@@ -151,9 +152,10 @@
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.addOptionsModification(
opt ->
- opt.desugaredLibrarySpecification =
+ setDesugaredLibrarySpecificationForTesting(
+ opt,
configurationWithSupportAllCallbacksFromLibrary(
- opt, false, parameters, supportAllCallbacksFromLibrary))
+ opt, false, parameters, supportAllCallbacksFromLibrary)))
.compile()
.inspect(this::assertDoubleForEach)
.inspect(this::assertWrapperMethodsPresent)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionsPresentTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionsPresentTest.java
index 01f9b80..6972449 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionsPresentTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionsPresentTest.java
@@ -46,6 +46,7 @@
L8Command.builder(diagnosticsHandler)
.addLibraryFiles(getLibraryFile())
.addProgramFiles(ToolHelper.DESUGAR_LIB_CONVERSIONS)
+ .addProgramFiles(ToolHelper.getDesugarJDKLibs())
.addDesugaredLibraryConfiguration(
StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
.setMinApiLevel(parameters.getApiLevel().getLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/DuplicateAPIDesugaredLibTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/DuplicateAPIDesugaredLibTest.java
index 6b7d86e..b966b00 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/DuplicateAPIDesugaredLibTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/DuplicateAPIDesugaredLibTest.java
@@ -71,9 +71,10 @@
this.buildDesugaredLibrary(
api,
opt ->
- opt.desugaredLibrarySpecification =
+ setDesugaredLibrarySpecificationForTesting(
+ opt,
configurationWithSupportAllCallbacksFromLibrary(
- opt, true, parameters, supportAllCallbacksFromLibrary)));
+ opt, true, parameters, supportAllCallbacksFromLibrary))));
return desugaredLibBox.get();
},
AndroidApiLevel.B)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/TryCatchTimeConversionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/TryCatchTimeConversionTest.java
index a669527..aaab5cb 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/TryCatchTimeConversionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/TryCatchTimeConversionTest.java
@@ -58,6 +58,7 @@
.setMinApi(parameters.getApiLevel())
.addProgramClasses(BaselineExecutor.class)
.addLibraryClasses(CustomLibClass.class)
+ .addLibraryFiles(getLibraryFile())
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.compile()
.addDesugaredCoreLibraryRunClassPath(
@@ -98,6 +99,7 @@
.setMinApi(parameters.getApiLevel())
.addProgramClasses(TryCatchExecutor.class)
.addLibraryClasses(CustomLibClass.class)
+ .addLibraryFiles(getLibraryFile())
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.compile()
.addDesugaredCoreLibraryRunClassPath(
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11StreamTests.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11StreamTests.java
index 2bd50b2..3b6ae0a 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11StreamTests.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11StreamTests.java
@@ -270,6 +270,7 @@
.addProgramFiles(testNGSupportProgramFiles())
.addOptionsModification(opt -> opt.testing.trackDesugaredAPIConversions = true)
.addLibraryFiles(getLibraryFile())
+ .addLibraryFiles(JDK_11_JAVA_BASE_EXTENSION_CLASSES_DIR)
.setMinApi(parameters.getApiLevel())
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.allowStdoutMessages()
@@ -303,6 +304,7 @@
.addProgramFiles(testNGSupportProgramFiles())
.addOptionsModification(opt -> opt.testing.trackDesugaredAPIConversions = true)
.addLibraryFiles(getLibraryFile())
+ .addLibraryFiles(JDK_11_JAVA_BASE_EXTENSION_CLASSES_DIR)
.setMinApi(parameters.getApiLevel())
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.compile()
diff --git a/src/test/java/com/android/tools/r8/desugar/jdk8272564/Jdk8272564Test.java b/src/test/java/com/android/tools/r8/desugar/jdk8272564/Jdk8272564Test.java
new file mode 100644
index 0000000..191cc22
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/jdk8272564/Jdk8272564Test.java
@@ -0,0 +1,164 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.desugar.jdk8272564;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestRuntime;
+import com.android.tools.r8.examples.jdk18.jdk8272564.Jdk8272564;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.InternalOptions.TestingOptions;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class Jdk8272564Test extends TestBase {
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ // TODO(b/218293990): Right now the JDK 18 tests are built with -target 17, as our Gradle
+ // version does not know of -target 18.
+ // TODO(b/174431251): This should be replaced with .withCfRuntimes(start = jdk17).
+ return getTestParameters()
+ .withCustomRuntime(TestRuntime.getCheckedInJdk17())
+ .withDexRuntimes()
+ .withAllApiLevelsAlsoForCf()
+ .build();
+ }
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ // With the fix for JDK-8272564 there are no invokevirtual instructions.
+ private void assertJdk8272564FixedCode(CodeInspector inspector) {
+ assertTrue(
+ inspector
+ .clazz(Jdk8272564.Main.typeName())
+ .uniqueMethodWithName("f")
+ .streamInstructions()
+ .noneMatch(InstructionSubject::isInvokeVirtual));
+ assertTrue(
+ inspector
+ .clazz(Jdk8272564.Main.typeName())
+ .uniqueMethodWithName("g")
+ .streamInstructions()
+ .noneMatch(InstructionSubject::isInvokeVirtual));
+ }
+
+ // Without the fix for JDK-8272564 there is one invokeinterface and 2 invokevirtual instructions.
+ private void assertJdk8272564NotFixedCode(
+ CodeInspector inspector, int invokeVirtualCount, int getClassCount) {
+ assertEquals(
+ 1,
+ inspector
+ .clazz(Jdk8272564.Main.typeName())
+ .uniqueMethodWithName("f")
+ .streamInstructions()
+ .filter(InstructionSubject::isInvokeInterface)
+ .count());
+ assertEquals(
+ 2,
+ inspector
+ .clazz(Jdk8272564.Main.typeName())
+ .uniqueMethodWithName("f")
+ .streamInstructions()
+ .filter(InstructionSubject::isInvokeVirtual)
+ .count());
+ assertEquals(
+ 2,
+ inspector
+ .clazz(Jdk8272564.Main.typeName())
+ .uniqueMethodWithName("g")
+ .streamInstructions()
+ .filter(InstructionSubject::isInvokeInterface)
+ .count());
+ assertEquals(
+ 2,
+ inspector
+ .clazz(Jdk8272564.Main.typeName())
+ .uniqueMethodWithName("g")
+ .streamInstructions()
+ .filter(InstructionSubject::isInvokeInterface)
+ .count());
+ assertEquals(
+ invokeVirtualCount,
+ inspector
+ .clazz(Jdk8272564.Main.typeName())
+ .uniqueMethodWithName("g")
+ .streamInstructions()
+ .filter(InstructionSubject::isInvokeVirtual)
+ .count());
+ assertEquals(
+ getClassCount,
+ inspector
+ .clazz(Jdk8272564.Main.typeName())
+ .uniqueMethodWithName("g")
+ .streamInstructions()
+ .filter(InstructionSubject::isInvoke)
+ .filter(instruction -> instruction.getMethod().getName().toString().equals("getClass"))
+ .count());
+ }
+
+ private void assertJdk8272564NotFixedCode(CodeInspector inspector) {
+ assertJdk8272564NotFixedCode(inspector, 22, 3);
+ }
+
+ private void assertJdk8272564NotFixedCodeR8(CodeInspector inspector) {
+ assertJdk8272564NotFixedCode(inspector, 19, 0);
+ }
+
+ @Test
+ // See https://bugs.openjdk.java.net/browse/JDK-8272564.
+ public void testJdk8272564Compiler() throws Exception {
+ assumeTrue(parameters.isCfRuntime());
+ // Ensure that the test is running with CF input from fixing JDK-8272564.
+ assertJdk8272564FixedCode(new CodeInspector(Jdk8272564.jar()));
+ }
+
+ @Test
+ public void testJvm() throws Exception {
+ assumeTrue(parameters.isCfRuntime());
+ testForJvm()
+ .addRunClasspathFiles(Jdk8272564.jar())
+ .run(TestRuntime.getCheckedInJdk17(), Jdk8272564.Main.typeName())
+ .assertSuccess();
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ testForDesugaring(parameters)
+ .addProgramFiles(Jdk8272564.jar())
+ .run(parameters.getRuntime(), Jdk8272564.Main.typeName())
+ .applyIf(
+ parameters.isDexRuntime() && parameters.getApiLevel().isLessThan(AndroidApiLevel.O),
+ b -> b.inspect(this::assertJdk8272564NotFixedCode),
+ b -> b.inspect(this::assertJdk8272564FixedCode))
+ .assertSuccess();
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ // The R8 lens code rewriter rewrites to the code prior to fixing JDK-8272564.
+ testForR8(parameters.getBackend())
+ .addProgramFiles(Jdk8272564.jar())
+ .setMinApi(parameters.getApiLevel())
+ .noTreeShaking()
+ .addKeepClassAndMembersRules(Jdk8272564.Main.typeName())
+ .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
+ .run(parameters.getRuntime(), Jdk8272564.Main.typeName())
+ .inspect(this::assertJdk8272564NotFixedCodeR8)
+ .assertSuccess();
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/examples/jdk18/jdk8272564/Jdk8272564.java b/src/test/java/com/android/tools/r8/examples/jdk18/jdk8272564/Jdk8272564.java
new file mode 100644
index 0000000..5e891aa
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/examples/jdk18/jdk8272564/Jdk8272564.java
@@ -0,0 +1,32 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.examples.jdk18.jdk8272564;
+
+import com.android.tools.r8.examples.JavaExampleClassProxy;
+import java.nio.file.Path;
+
+public class Jdk8272564 {
+
+ private static final String EXAMPLE_FILE = "examplesJava18/jdk8272564";
+
+ public static final JavaExampleClassProxy A =
+ new JavaExampleClassProxy(EXAMPLE_FILE, "jdk8272564/A");
+ public static final JavaExampleClassProxy B =
+ new JavaExampleClassProxy(EXAMPLE_FILE, "jdk8272564/B");
+ public static final JavaExampleClassProxy C =
+ new JavaExampleClassProxy(EXAMPLE_FILE, "jdk8272564/C");
+ public static final JavaExampleClassProxy I =
+ new JavaExampleClassProxy(EXAMPLE_FILE, "jdk8272564/I");
+ public static final JavaExampleClassProxy J =
+ new JavaExampleClassProxy(EXAMPLE_FILE, "jdk8272564/J");
+ public static final JavaExampleClassProxy K =
+ new JavaExampleClassProxy(EXAMPLE_FILE, "jdk8272564/K");
+ public static final JavaExampleClassProxy Main =
+ new JavaExampleClassProxy(EXAMPLE_FILE, "jdk8272564/Main");
+
+ public static Path jar() {
+ return JavaExampleClassProxy.examplesJar(EXAMPLE_FILE);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/NarrowingWithoutSubtypingTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/NarrowingWithoutSubtypingTest.java
index b78279e..403372c 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/type/NarrowingWithoutSubtypingTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/NarrowingWithoutSubtypingTest.java
@@ -4,6 +4,12 @@
package com.android.tools.r8.ir.analysis.type;
+import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertThrows;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.D8TestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.utils.BooleanUtils;
@@ -32,17 +38,32 @@
@Test
public void test() throws Exception {
- testForD8()
- .addInnerClasses(NarrowingWithoutSubtypingTest.class)
- .addOptionsModification(
- options -> {
- options.testing.readInputStackMaps = readStackMap;
- options.testing.enableNarrowAndWideningingChecksInD8 = true;
- options.testing.noLocalsTableOnInput = true;
- })
- .setMinApi(parameters.getApiLevel())
- .run(parameters.getRuntime(), TestClass.class)
- .assertSuccessWithOutputLines("Hello world!");
+ D8TestBuilder d8TestBuilder =
+ testForD8()
+ .addInnerClasses(NarrowingWithoutSubtypingTest.class)
+ .addOptionsModification(
+ options -> {
+ options.testing.readInputStackMaps = readStackMap;
+ options.testing.enableNarrowAndWideningingChecksInD8 = true;
+ options.testing.noLocalsTableOnInput = true;
+ })
+ .setMinApi(parameters.getApiLevel());
+ if (readStackMap) {
+ d8TestBuilder
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("Hello world!");
+ } else {
+ // TODO(b/169120386): We should not be narrowing in D8.
+ assertThrows(
+ CompilationFailedException.class,
+ () -> {
+ d8TestBuilder.compileWithExpectedDiagnostics(
+ diagnostics ->
+ diagnostics.assertAllErrorsMatch(
+ diagnosticMessage(
+ containsString("java.lang.AssertionError: During NARROWING"))));
+ });
+ }
}
static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/ifs/IfThrowNullPointerExceptionTest.java b/src/test/java/com/android/tools/r8/ir/optimize/ifs/IfThrowNullPointerExceptionTest.java
index e679e80..d0b977b 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/ifs/IfThrowNullPointerExceptionTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/ifs/IfThrowNullPointerExceptionTest.java
@@ -17,7 +17,6 @@
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
-import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -80,7 +79,7 @@
ClassSubject classSubject = inspector.clazz(TestClass.class);
assertThat(classSubject, isPresent());
inspectMethod(inspector, classSubject, "testThrowNPE", false, true);
- inspectMethod(inspector, classSubject, "testThrowNPEWithMessage", true, canUseRequireNonNull());
+ inspectMethod(inspector, classSubject, "testThrowNPEWithMessage", true, false);
inspectMethod(inspector, classSubject, "testThrowNull", false, true);
}
@@ -105,31 +104,18 @@
Instruction nullCheckInstruction =
entryBlock.getInstructions().get(1 + BooleanUtils.intValue(isNPEWithMessage));
- if (canUseRequireNonNull()) {
- assertTrue(nullCheckInstruction.isInvokeStatic());
- if (isNPEWithMessage) {
- assertEquals(
- inspector.getFactory().objectsMethods.requireNonNullWithMessage,
- nullCheckInstruction.asInvokeStatic().getInvokedMethod());
- } else {
- assertEquals(
- inspector.getFactory().objectsMethods.requireNonNull,
- nullCheckInstruction.asInvokeStatic().getInvokedMethod());
- }
- } else {
- assertFalse(isNPEWithMessage);
- assertTrue(nullCheckInstruction.isInvokeVirtual());
- assertEquals(
- inspector.getFactory().objectMembers.getClass,
- nullCheckInstruction.asInvokeVirtual().getInvokedMethod());
- }
+ assertFalse(isNPEWithMessage);
+ assertTrue(nullCheckInstruction.isInvokeVirtual());
+ assertEquals(
+ inspector.getFactory().objectMembers.getClass,
+ nullCheckInstruction.asInvokeVirtual().getInvokedMethod());
} else {
assertEquals(3, code.blocks.size());
}
}
private String getExpectedStdout() {
- if (parameters.isCfRuntime() || canUseRequireNonNull() || isDalvik()) {
+ if (parameters.isCfRuntime() || isDalvik()) {
return StringUtils.lines("Caught NPE: null", "Caught NPE: x was null", "Caught NPE: null");
}
return StringUtils.lines(
@@ -140,11 +126,6 @@
+ " on a null object reference");
}
- private boolean canUseRequireNonNull() {
- return parameters.isDexRuntime()
- && parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.K);
- }
-
private boolean isDalvik() {
return parameters.isDexRuntime()
&& parameters.getRuntime().asDex().getVm().getVersion().isDalvik();
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineInvokeWithNullableReceiverTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineInvokeWithNullableReceiverTest.java
index dce7b2d..527d320 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineInvokeWithNullableReceiverTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineInvokeWithNullableReceiverTest.java
@@ -68,20 +68,16 @@
assertThat(methodSubject, isPresent());
// A `throw` instruction should have been synthesized into main().
- if (canUseRequireNonNull()) {
- assertTrue(methodSubject.streamInstructions().anyMatch(InstructionSubject::isInvokeStatic));
- } else {
- assertTrue(
- methodSubject
- .streamInstructions()
- .filter(InstructionSubject::isInvokeVirtual)
- .anyMatch(
- method ->
- method
- .getMethod()
- .toSourceString()
- .equals("java.lang.Class java.lang.Object.getClass()")));
- }
+ assertTrue(
+ methodSubject
+ .streamInstructions()
+ .filter(InstructionSubject::isInvokeVirtual)
+ .anyMatch(
+ method ->
+ method
+ .getMethod()
+ .toSourceString()
+ .equals("java.lang.Class java.lang.Object.getClass()")));
// Class A is still present because the instance flows into a phi that has a null-check.
ClassSubject otherClassSubject = inspector.clazz(A.class);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineMethodWithRetargetedLibMemberTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineMethodWithRetargetedLibMemberTest.java
index 03b1280..71b7da8 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineMethodWithRetargetedLibMemberTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineMethodWithRetargetedLibMemberTest.java
@@ -12,8 +12,7 @@
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.utils.AndroidApiLevel;
+import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
import java.util.Arrays;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -21,7 +20,7 @@
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
-public class InlineMethodWithRetargetedLibMemberTest extends TestBase {
+public class InlineMethodWithRetargetedLibMemberTest extends DesugaredLibraryTestBase {
private final TestParameters parameters;
@@ -37,7 +36,7 @@
@Test
public void test() throws Exception {
testForR8(parameters.getBackend())
- .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+ .addLibraryFiles(getLibraryFile())
.addProgramClasses(TestClass.class)
.addKeepMainRule(TestClass.class)
.enableCoreLibraryDesugaring(
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/SyntheticInlineNullCheckPositionTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/SyntheticInlineNullCheckPositionTest.java
index 7cdd9d0..a10e302 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/SyntheticInlineNullCheckPositionTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/SyntheticInlineNullCheckPositionTest.java
@@ -5,7 +5,6 @@
package com.android.tools.r8.ir.optimize.inliner;
import static com.android.tools.r8.naming.retrace.StackTrace.isSame;
-import static com.android.tools.r8.naming.retrace.StackTrace.isSameExceptForSpecificLineNumber;
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.TestBase;
@@ -70,16 +69,7 @@
.run(parameters.getRuntime(), Main.class)
.assertFailureWithErrorThatThrows(NullPointerException.class)
.inspectStackTrace(
- stackTrace -> {
- if (canUseJavaUtilObjectsRequireNonNull(parameters)) {
- assertThat(
- stackTrace,
- isSameExceptForSpecificLineNumber(
- expectedStackTraceWithRequireNonNull, REQUIRE_NON_NULL_LINE));
- } else {
- assertThat(stackTrace, isSame(expectedStackTraceWithGetClass));
- }
- });
+ stackTrace -> assertThat(stackTrace, isSame(expectedStackTraceWithGetClass)));
}
static class Main {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/AssumeInstanceFieldValueTest.java b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/AssumeInstanceFieldValueTest.java
index 4e275f4..edd2219 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/AssumeInstanceFieldValueTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/AssumeInstanceFieldValueTest.java
@@ -70,11 +70,7 @@
MethodSubject mainMethodSubject = testClassSubject.mainMethod();
assertThat(mainMethodSubject, isPresent());
- if (canUseJavaUtilObjectsRequireNonNull(parameters)) {
- assertThat(mainMethodSubject, invokesMethodWithName("requireNonNull"));
- } else {
- assertThat(mainMethodSubject, invokesMethodWithName("getClass"));
- }
+ assertThat(mainMethodSubject, invokesMethodWithName("getClass"));
}
static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/EffectivelyUnusedNullableArgumentTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/EffectivelyUnusedNullableArgumentTest.java
index 54d2071..f01e7b7 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/EffectivelyUnusedNullableArgumentTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/EffectivelyUnusedNullableArgumentTest.java
@@ -55,12 +55,7 @@
assertEquals(
aClassSubject.getDexProgramClass().getType(),
fooMethodSubject.getProgramMethod().getParameter(0));
- assertThat(
- fooMethodSubject,
- invokesMethodWithName(
- canUseJavaUtilObjectsRequireNonNull(parameters)
- ? "requireNonNull"
- : "getClass"));
+ assertThat(fooMethodSubject, invokesMethodWithName("getClass"));
MethodSubject barMethodSubject = aClassSubject.uniqueMethodWithName("bar");
assertThat(barMethodSubject, isStatic());
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/b135627418/B135627418.java b/src/test/java/com/android/tools/r8/memberrebinding/b135627418/B135627418.java
index f3103f1..2d1b98c 100644
--- a/src/test/java/com/android/tools/r8/memberrebinding/b135627418/B135627418.java
+++ b/src/test/java/com/android/tools/r8/memberrebinding/b135627418/B135627418.java
@@ -12,10 +12,12 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
import com.android.tools.r8.memberrebinding.b135627418.library.Drawable;
import com.android.tools.r8.memberrebinding.b135627418.library.DrawableWrapper;
import com.android.tools.r8.memberrebinding.b135627418.library.InsetDrawable;
+import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
@@ -75,11 +77,23 @@
com.android.tools.r8.memberrebinding.b135627418.runtime.InsetDrawable.class)
.setMinApi(parameters.getRuntime())
.addOptionsModification(
- options ->
- options.desugaredLibrarySpecification =
- LegacyDesugaredLibrarySpecification.withOnlyRewritePrefixForTesting(
- ImmutableMap.of(packageName + ".runtime", packageName + ".library"),
- options))
+ options -> {
+ DexType type =
+ options
+ .dexItemFactory()
+ .createType(
+ DescriptorUtils.javaTypeToDescriptor(
+ packageName + ".runtime.InsetDrawable"));
+ DexType rewrittenType =
+ options
+ .dexItemFactory()
+ .createType(
+ DescriptorUtils.javaTypeToDescriptor(
+ packageName + ".library.InsetDrawable"));
+ options.machineDesugaredLibrarySpecification =
+ MachineDesugaredLibrarySpecification.withOnlyRewriteTypeForTesting(
+ ImmutableMap.of(type, rewrittenType));
+ })
.compile();
testForR8(parameters.getBackend())
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingOnLibraryPathTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingOnLibraryPathTest.java
new file mode 100644
index 0000000..df6fe4d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingOnLibraryPathTest.java
@@ -0,0 +1,69 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.naming.applymapping;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ApplyMappingOnLibraryPathTest extends TestBase {
+
+ @Parameter() public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addLibraryClasses(LibraryClass.class)
+ .addDefaultRuntimeLibrary(parameters)
+ .addProgramClasses(Main.class)
+ .setMinApi(parameters.getApiLevel())
+ .addApplyMapping(typeName(LibraryClass.class) + " -> a.a:")
+ .addKeepMainRule(Main.class)
+ .compile()
+ .inspect(
+ inspector -> {
+ ClassSubject clazz = inspector.clazz(Main.class);
+ assertThat(clazz, isPresentAndNotRenamed());
+ FoundClassSubject foundClassSubject = clazz.asFoundClassSubject();
+ assertEquals(
+ typeName(LibraryClass.class),
+ foundClassSubject.getSuperClass().getOriginalName());
+ })
+ .addRunClasspathClasses(LibraryClass.class)
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("LibraryClass::foo");
+ }
+
+ public static class LibraryClass {
+
+ public void foo() {
+ System.out.println("LibraryClass::foo");
+ }
+ }
+
+ public static class Main extends LibraryClass {
+
+ public static void main(String[] args) {
+ new Main().foo();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/naming/retrace/RetraceInlineBranchTest.java b/src/test/java/com/android/tools/r8/naming/retrace/RetraceInlineBranchTest.java
index 92b6019..b07255b 100644
--- a/src/test/java/com/android/tools/r8/naming/retrace/RetraceInlineBranchTest.java
+++ b/src/test/java/com/android/tools/r8/naming/retrace/RetraceInlineBranchTest.java
@@ -5,7 +5,6 @@
package com.android.tools.r8.naming.retrace;
import static com.android.tools.r8.naming.retrace.StackTrace.isSame;
-import static com.android.tools.r8.naming.retrace.StackTrace.isSameExceptForLineNumbers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
@@ -16,11 +15,9 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import java.util.List;
-import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import org.junit.Before;
@@ -64,50 +61,30 @@
.run(parameters.getRuntime(), Main.class)
.inspectStackTrace(
(stackTrace, inspector) -> {
- if (canUseJavaUtilObjectsRequireNonNull(parameters)) {
- StackTrace requireNonNullFrame =
- StackTrace.builder().add(stackTrace.get(0)).build();
- assertThat(
- requireNonNullFrame,
- isSameExceptForLineNumbers(
- StackTrace.builder()
- .add(
- StackTraceLine.builder()
- .setClassName(Objects.class.getTypeName())
- .setMethodName("requireNonNull")
- .setFileName("Objects.java")
- .build())
- .build()));
-
- StackTrace stackTraceWithoutRequireNonNull =
- StackTrace.builder().add(stackTrace).remove(0).build();
- assertThat(stackTraceWithoutRequireNonNull, isSame(expectedStackTrace));
- } else {
- // To check that we inserted the check in the branch correctly we use a rudimentary
- // line check by comparing that the getClass method comes later than the first if.
- MethodSubject methodSubject =
- inspector.clazz(Main.class).uniqueMethodWithName("call");
- assertThat(methodSubject, isPresent());
- List<InstructionSubject> getClassCalls =
- methodSubject
- .streamInstructions()
- .filter(
- instructionSubject ->
- instructionSubject.isInvoke()
- && instructionSubject
- .getMethod()
- .qualifiedName()
- .contains("getClass"))
- .collect(Collectors.toList());
- assertEquals(1, getClassCalls.size());
- Optional<InstructionSubject> firstIf =
- methodSubject.streamInstructions().filter(InstructionSubject::isIf).findFirst();
- assertTrue(firstIf.isPresent());
+ MethodSubject methodSubject =
+ inspector.clazz(Main.class).uniqueMethodWithName("call");
+ assertThat(methodSubject, isPresent());
+ List<InstructionSubject> getClassCalls =
+ methodSubject
+ .streamInstructions()
+ .filter(
+ instructionSubject ->
+ instructionSubject.isInvoke()
+ && instructionSubject
+ .getMethod()
+ .qualifiedName()
+ .contains("getClass"))
+ .collect(Collectors.toList());
+ assertEquals(1, getClassCalls.size());
+ Optional<InstructionSubject> firstIf =
+ methodSubject.streamInstructions().filter(InstructionSubject::isIf).findFirst();
+ assertTrue(firstIf.isPresent());
+ if (methodSubject.hasLineNumberTable()) {
assertTrue(
methodSubject.getLineNumberForInstruction(getClassCalls.get(0))
> methodSubject.getLineNumberForInstruction(firstIf.get()));
- assertThat(stackTrace, isSame(expectedStackTrace));
}
+ assertThat(stackTrace, isSame(expectedStackTrace));
});
}
diff --git a/src/test/java/com/android/tools/r8/naming/retrace/RetraceInlineConditionTest.java b/src/test/java/com/android/tools/r8/naming/retrace/RetraceInlineConditionTest.java
index 36921ce..b005549 100644
--- a/src/test/java/com/android/tools/r8/naming/retrace/RetraceInlineConditionTest.java
+++ b/src/test/java/com/android/tools/r8/naming/retrace/RetraceInlineConditionTest.java
@@ -4,15 +4,20 @@
package com.android.tools.r8.naming.retrace;
+import static com.android.tools.r8.naming.retrace.StackTrace.isSame;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
+import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.SingleTestRunResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import org.hamcrest.CoreMatchers;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -48,16 +53,26 @@
@Test
public void testR8() throws Throwable {
- testForR8(parameters.getBackend())
- .addInnerClasses(getClass())
- .setMinApi(parameters.getApiLevel())
- .addKeepMainRule(Main.class)
- .compile()
- .inspectProguardMap(
- map -> {
- assertThat(
- map, not(CoreMatchers.containsString("com.android.tools.r8.rewriteFrame")));
- });
+ R8TestCompileResult compileResult =
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .setMinApi(parameters.getApiLevel())
+ .addKeepMainRule(Main.class)
+ .addKeepAttributeLineNumberTable()
+ .compile()
+ .inspectProguardMap(map -> not(containsString("com.android.tools.r8.rewriteFrame")))
+ .inspect(
+ inspector -> {
+ ClassSubject fooClass = inspector.clazz(Foo.class);
+ assertThat(fooClass, isPresent());
+ MethodSubject inlineable = fooClass.uniqueMethodWithName("inlineable");
+ assertThat(inlineable, not(isPresent()));
+ });
+ compileResult
+ .run(parameters.getRuntime(), Main.class)
+ .assertFailureWithErrorThatThrows(NullPointerException.class)
+ .inspectStackTrace(
+ (stackTrace, codeInspector) -> assertThat(stackTrace, isSame(expectedStackTrace)));
}
static class Foo {
diff --git a/src/test/java/com/android/tools/r8/naming/retrace/RetraceInlineeWithNullCheckSequenceTest.java b/src/test/java/com/android/tools/r8/naming/retrace/RetraceInlineeWithNullCheckSequenceTest.java
index be348ec..48379c5 100644
--- a/src/test/java/com/android/tools/r8/naming/retrace/RetraceInlineeWithNullCheckSequenceTest.java
+++ b/src/test/java/com/android/tools/r8/naming/retrace/RetraceInlineeWithNullCheckSequenceTest.java
@@ -4,15 +4,12 @@
package com.android.tools.r8.naming.retrace;
import static com.android.tools.r8.naming.retrace.StackTrace.isSame;
-import static com.android.tools.r8.naming.retrace.StackTrace.isSameExceptForLineNumbers;
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine;
import java.util.List;
-import java.util.Objects;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -58,27 +55,7 @@
.assertFailureWithErrorThatThrows(NullPointerException.class)
.inspectStackTrace(
(stackTrace, codeInspector) -> {
- if (canUseJavaUtilObjectsRequireNonNull(parameters)) {
- StackTrace requireNonNullFrame =
- StackTrace.builder().add(stackTrace.get(0)).build();
- assertThat(
- requireNonNullFrame,
- isSameExceptForLineNumbers(
- StackTrace.builder()
- .add(
- StackTraceLine.builder()
- .setClassName(Objects.class.getTypeName())
- .setMethodName("requireNonNull")
- .setFileName("Objects.java")
- .build())
- .build()));
-
- StackTrace stackTraceWithoutRequireNonNull =
- StackTrace.builder().add(stackTrace).remove(0).build();
- assertThat(stackTraceWithoutRequireNonNull, isSame(expectedStackTrace));
- } else {
- assertThat(stackTrace, isSame(expectedStackTrace));
- }
+ assertThat(stackTrace, isSame(expectedStackTrace));
});
}
diff --git a/src/test/java/com/android/tools/r8/naming/retrace/RetraceInlineeWithNullCheckTest.java b/src/test/java/com/android/tools/r8/naming/retrace/RetraceInlineeWithNullCheckTest.java
index 70c2be4..0855291 100644
--- a/src/test/java/com/android/tools/r8/naming/retrace/RetraceInlineeWithNullCheckTest.java
+++ b/src/test/java/com/android/tools/r8/naming/retrace/RetraceInlineeWithNullCheckTest.java
@@ -4,16 +4,13 @@
package com.android.tools.r8.naming.retrace;
import static com.android.tools.r8.naming.retrace.StackTrace.isSame;
-import static com.android.tools.r8.naming.retrace.StackTrace.isSameExceptForLineNumbers;
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine;
import com.android.tools.r8.utils.BooleanUtils;
import java.util.List;
-import java.util.Objects;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -66,31 +63,7 @@
.run(parameters.getRuntime(), Caller.class, getArgs())
.assertFailureWithErrorThatThrows(NullPointerException.class)
.inspectStackTrace(
- (stackTrace, codeInspector) -> {
- // TODO(b/214377135): The stack traces should be the same (when 206427323) is
- // resolved.
- if (throwReceiverNpe && canUseJavaUtilObjectsRequireNonNull(parameters)) {
- StackTrace requireNonNullFrame =
- StackTrace.builder().add(stackTrace.get(0)).build();
- assertThat(
- requireNonNullFrame,
- isSameExceptForLineNumbers(
- StackTrace.builder()
- .add(
- StackTraceLine.builder()
- .setClassName(Objects.class.getTypeName())
- .setMethodName("requireNonNull")
- .setFileName("Objects.java")
- .build())
- .build()));
-
- StackTrace stackTraceWithoutRequireNonNull =
- StackTrace.builder().add(stackTrace).remove(0).build();
- assertThat(stackTraceWithoutRequireNonNull, isSame(expectedStackTrace));
- } else {
- assertThat(stackTrace, isSame(expectedStackTrace));
- }
- });
+ (stackTrace, codeInspector) -> assertThat(stackTrace, isSame(expectedStackTrace)));
}
static class Foo {
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/NullableCompanionConstructorShakingTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/NullableCompanionConstructorShakingTest.java
index 594f86f..bca23cb 100644
--- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/NullableCompanionConstructorShakingTest.java
+++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/NullableCompanionConstructorShakingTest.java
@@ -59,12 +59,7 @@
.streamInstructions()
.filter(InstructionSubject::isInvoke)
.count());
- assertThat(
- mainMethodSubject,
- invokesMethodWithName(
- canUseJavaUtilObjectsRequireNonNull(parameters)
- ? "requireNonNull"
- : "getClass"));
+ assertThat(mainMethodSubject, invokesMethodWithName("getClass"));
assertThat(mainMethodSubject, invokesMethod(companionMethodSubject));
})
.run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/optimize/proto/NormalizeTest.java b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithKeptMethodTest.java
similarity index 65%
copy from src/test/java/com/android/tools/r8/optimize/proto/NormalizeTest.java
copy to src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithKeptMethodTest.java
index c78ced4..70dbf9d 100644
--- a/src/test/java/com/android/tools/r8/optimize/proto/NormalizeTest.java
+++ b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithKeptMethodTest.java
@@ -5,16 +5,16 @@
package com.android.tools.r8.optimize.proto;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.MethodMatchers.hasParameters;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
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.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.android.tools.r8.utils.codeinspector.TypeSubject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -22,7 +22,7 @@
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
-public class NormalizeTest extends TestBase {
+public class ProtoNormalizationWithKeptMethodTest extends TestBase {
@Parameter(0)
public TestParameters parameters;
@@ -37,6 +37,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
+ .addKeepRules("-keep class " + Main.class.getTypeName() + " { void foo(...); }")
.addOptionsModification(
options -> options.testing.enableExperimentalProtoNormalization = true)
.enableInliningAnnotations()
@@ -47,40 +48,48 @@
.compile()
.inspect(
inspector -> {
- ClassSubject aClassSubject = inspector.clazz(A.class);
- assertThat(aClassSubject, isPresent());
-
- ClassSubject bClassSubject = inspector.clazz(B.class);
- assertThat(bClassSubject, isPresent());
+ TypeSubject aTypeSubject = inspector.clazz(A.class).asTypeSubject();
+ TypeSubject bTypeSubject = inspector.clazz(B.class).asTypeSubject();
MethodSubject fooMethodSubject =
inspector.clazz(Main.class).uniqueMethodWithName("foo");
assertThat(fooMethodSubject, isPresent());
+ assertThat(fooMethodSubject, hasParameters(bTypeSubject, aTypeSubject));
- String expectedMethodSignature =
- "void "
- + fooMethodSubject.getFinalName()
- + "("
- + aClassSubject.getFinalName()
- + ", "
- + bClassSubject.getFinalName()
- + ")";
- assertEquals(
- expectedMethodSignature,
- fooMethodSubject.getProgramMethod().getMethodSignature().toString());
+ for (String methodName : new String[] {"bar", "baz"}) {
+ MethodSubject methodSubject =
+ inspector.clazz(Main.class).uniqueMethodWithName(methodName);
+ assertThat(methodSubject, isPresent());
+ assertThat(methodSubject, hasParameters(bTypeSubject, aTypeSubject));
+ }
})
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines("A", "B");
+ .assertSuccessWithOutputLines("A", "B", "A", "B", "A", "B");
}
static class Main {
public static void main(String[] args) {
foo(new B(), new A());
+ bar(new B(), new A());
+ baz(new A(), new B());
+ }
+
+ // @Keep
+ @NeverInline
+ static void foo(B b, A a) {
+ System.out.println(a);
+ System.out.println(b);
}
@NeverInline
- static void foo(B b, A a) {
+ static void bar(B b, A a) {
+ System.out.println(a);
+ System.out.println(b);
+ }
+
+ @NeverInline
+ static void baz(A a, B b) {
System.out.println(a);
System.out.println(b);
}
diff --git a/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithKeptVirtualMethodTest.java b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithKeptVirtualMethodTest.java
new file mode 100644
index 0000000..e9655ba
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithKeptVirtualMethodTest.java
@@ -0,0 +1,118 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.optimize.proto;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.MethodMatchers.hasParameters;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoVerticalClassMerging;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.android.tools.r8.utils.codeinspector.TypeSubject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ProtoNormalizationWithKeptVirtualMethodTest extends TestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepClassAndMembersRules(Main.class)
+ .addKeepRules("-keepclassmembers class " + A.class.getTypeName() + " { void foo(...); }")
+ .addOptionsModification(
+ options -> options.testing.enableExperimentalProtoNormalization = true)
+ .enableInliningAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(
+ inspector -> {
+ ClassSubject aClassSubject = inspector.clazz(A.class);
+ assertThat(aClassSubject, isPresent());
+
+ ClassSubject bClassSubject = inspector.clazz(B.class);
+ assertThat(bClassSubject, isPresent());
+
+ TypeSubject aTypeSubject = aClassSubject.asTypeSubject();
+ TypeSubject bTypeSubject = bClassSubject.asTypeSubject();
+
+ // A.foo(B, A) is kept.
+ MethodSubject fooMethodSubject = aClassSubject.uniqueMethodWithName("foo");
+ assertThat(fooMethodSubject, isPresent());
+ assertThat(fooMethodSubject, hasParameters(bTypeSubject, aTypeSubject));
+
+ // B.foo(B, A) overrides kept method.
+ MethodSubject otherFooMethodSubject = bClassSubject.uniqueMethodWithName("foo");
+ assertThat(otherFooMethodSubject, isPresent());
+ assertThat(otherFooMethodSubject, hasParameters(bTypeSubject, aTypeSubject));
+ })
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("A", "B", "A", "B");
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ A a = new A();
+ B b = new B();
+ a.foo(b, a);
+ b.foo(b, a);
+ extra(a, b);
+ }
+
+ // @Keep to ensure that the program has parameter lists (A, B) and (B, A), or we will not
+ // optimize in the first place.
+ static void extra(A a, B b) {}
+ }
+
+ @NoVerticalClassMerging
+ static class A {
+
+ // @Keep
+ @NeverInline
+ public void foo(B b, A a) {
+ System.out.println(a);
+ System.out.println(b);
+ }
+
+ @Override
+ public String toString() {
+ return "A";
+ }
+ }
+
+ static class B extends A {
+
+ @NeverInline
+ @Override
+ public void foo(B b, A a) {
+ System.out.println(a);
+ System.out.println(b);
+ }
+
+ @Override
+ public String toString() {
+ return "B";
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithLibraryOverrideTest.java b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithLibraryOverrideTest.java
new file mode 100644
index 0000000..52d4df1
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithLibraryOverrideTest.java
@@ -0,0 +1,113 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.optimize.proto;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.MethodMatchers.hasParameters;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+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.codeinspector.MethodSubject;
+import com.android.tools.r8.utils.codeinspector.TypeSubject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ProtoNormalizationWithLibraryOverrideTest extends TestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(Main.class, Program.class)
+ .addLibraryClasses(A.class, B.class, Library.class)
+ .addDefaultRuntimeLibrary(parameters)
+ .addKeepMainRule(Main.class)
+ .addOptionsModification(
+ options -> options.testing.enableExperimentalProtoNormalization = true)
+ .enableInliningAnnotations()
+ // TODO(b/173398086): uniqueMethodWithName() does not work with proto changes.
+ .noMinification()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(
+ inspector -> {
+ TypeSubject aTypeSubject = inspector.getTypeSubject(A.class.getTypeName());
+ TypeSubject bTypeSubject = inspector.getTypeSubject(B.class.getTypeName());
+
+ MethodSubject fooMethodSubject =
+ inspector.clazz(Main.class).uniqueMethodWithName("foo");
+ assertThat(fooMethodSubject, isPresent());
+ assertThat(fooMethodSubject, hasParameters(bTypeSubject, aTypeSubject));
+
+ MethodSubject libraryOverrideMethodSubject =
+ inspector.clazz(Program.class).uniqueMethodWithName("m");
+ assertThat(libraryOverrideMethodSubject, isPresent());
+ assertThat(libraryOverrideMethodSubject, hasParameters(bTypeSubject, aTypeSubject));
+ })
+ .addRunClasspathClasses(A.class, B.class, Library.class)
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("Program", "A", "B");
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ Library library = System.currentTimeMillis() > 0 ? new Program() : new Library();
+ library.m(new B(), new A());
+ foo(new A(), new B());
+ }
+
+ @NeverInline
+ static void foo(A a, B b) {
+ System.out.println(a);
+ System.out.println(b);
+ }
+ }
+
+ static class A {
+
+ @Override
+ public String toString() {
+ return "A";
+ }
+ }
+
+ static class B {
+
+ @Override
+ public String toString() {
+ return "B";
+ }
+ }
+
+ public static class Library {
+
+ public void m(B b, A a) {
+ System.out.println("Library");
+ }
+ }
+
+ static class Program extends Library {
+
+ @Override
+ public void m(B b, A a) {
+ System.out.println("Program");
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/optimize/proto/NormalizeTest.java b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithVirtualMethodCollisionTest.java
similarity index 63%
copy from src/test/java/com/android/tools/r8/optimize/proto/NormalizeTest.java
copy to src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithVirtualMethodCollisionTest.java
index c78ced4..babbf9f 100644
--- a/src/test/java/com/android/tools/r8/optimize/proto/NormalizeTest.java
+++ b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithVirtualMethodCollisionTest.java
@@ -5,16 +5,17 @@
package com.android.tools.r8.optimize.proto;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.MethodMatchers.hasParameters;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NoHorizontalClassMerging;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.android.tools.r8.utils.codeinspector.TypeSubject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -22,7 +23,7 @@
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
-public class NormalizeTest extends TestBase {
+public class ProtoNormalizationWithVirtualMethodCollisionTest extends TestBase {
@Parameter(0)
public TestParameters parameters;
@@ -40,7 +41,7 @@
.addOptionsModification(
options -> options.testing.enableExperimentalProtoNormalization = true)
.enableInliningAnnotations()
- .enableNoHorizontalClassMergingAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
// TODO(b/173398086): uniqueMethodWithName() does not work with proto changes.
.noMinification()
.setMinApi(parameters.getApiLevel())
@@ -53,50 +54,55 @@
ClassSubject bClassSubject = inspector.clazz(B.class);
assertThat(bClassSubject, isPresent());
- MethodSubject fooMethodSubject =
- inspector.clazz(Main.class).uniqueMethodWithName("foo");
- assertThat(fooMethodSubject, isPresent());
+ TypeSubject aTypeSubject = aClassSubject.asTypeSubject();
+ TypeSubject bTypeSubject = bClassSubject.asTypeSubject();
- String expectedMethodSignature =
- "void "
- + fooMethodSubject.getFinalName()
- + "("
- + aClassSubject.getFinalName()
- + ", "
- + bClassSubject.getFinalName()
- + ")";
- assertEquals(
- expectedMethodSignature,
- fooMethodSubject.getProgramMethod().getMethodSignature().toString());
+ MethodSubject fooMethodSubject = aClassSubject.uniqueMethodWithName("foo");
+ assertThat(fooMethodSubject, isPresent());
+ assertThat(fooMethodSubject, hasParameters(aTypeSubject, bTypeSubject));
+
+ // TODO(b/173398086): Consider rewriting B.foo(B, A) to B.foo(A, B, C) instead of
+ // B.foo$1(A, B).
+ MethodSubject otherFooMethodSubject = bClassSubject.uniqueMethodWithName("foo$1");
+ assertThat(otherFooMethodSubject, isPresent());
+ assertThat(otherFooMethodSubject, hasParameters(aTypeSubject, bTypeSubject));
})
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines("A", "B");
+ .assertSuccessWithOutputLines("A", "B", "A", "B");
}
static class Main {
public static void main(String[] args) {
- foo(new B(), new A());
- }
-
- @NeverInline
- static void foo(B b, A a) {
- System.out.println(a);
- System.out.println(b);
+ A a = new A();
+ B b = new B();
+ a.foo(a, b);
+ b.foo(b, a);
}
}
- @NoHorizontalClassMerging
+ @NoVerticalClassMerging
static class A {
+ @NeverInline
+ public void foo(A a, B b) {
+ System.out.println(a);
+ System.out.println(b);
+ }
+
@Override
public String toString() {
return "A";
}
}
- @NoHorizontalClassMerging
- static class B {
+ static class B extends A {
+
+ @NeverInline
+ public void foo(B b, A a) {
+ System.out.println(a);
+ System.out.println(b);
+ }
@Override
public String toString() {
diff --git a/src/test/java/com/android/tools/r8/optimize/proto/NormalizeTest.java b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithoutSharingTest.java
similarity index 73%
rename from src/test/java/com/android/tools/r8/optimize/proto/NormalizeTest.java
rename to src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithoutSharingTest.java
index c78ced4..0088b3b 100644
--- a/src/test/java/com/android/tools/r8/optimize/proto/NormalizeTest.java
+++ b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithoutSharingTest.java
@@ -5,16 +5,16 @@
package com.android.tools.r8.optimize.proto;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.MethodMatchers.hasParameters;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
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.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.android.tools.r8.utils.codeinspector.TypeSubject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -22,7 +22,7 @@
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
-public class NormalizeTest extends TestBase {
+public class ProtoNormalizationWithoutSharingTest extends TestBase {
@Parameter(0)
public TestParameters parameters;
@@ -47,27 +47,14 @@
.compile()
.inspect(
inspector -> {
- ClassSubject aClassSubject = inspector.clazz(A.class);
- assertThat(aClassSubject, isPresent());
+ TypeSubject aTypeSubject = inspector.clazz(A.class).asTypeSubject();
+ TypeSubject bTypeSubject = inspector.clazz(B.class).asTypeSubject();
- ClassSubject bClassSubject = inspector.clazz(B.class);
- assertThat(bClassSubject, isPresent());
-
+ // Should not be normalized as there is no sharing of protos.
MethodSubject fooMethodSubject =
inspector.clazz(Main.class).uniqueMethodWithName("foo");
assertThat(fooMethodSubject, isPresent());
-
- String expectedMethodSignature =
- "void "
- + fooMethodSubject.getFinalName()
- + "("
- + aClassSubject.getFinalName()
- + ", "
- + bClassSubject.getFinalName()
- + ")";
- assertEquals(
- expectedMethodSignature,
- fooMethodSubject.getProgramMethod().getMethodSignature().toString());
+ assertThat(fooMethodSubject, hasParameters(bTypeSubject, aTypeSubject));
})
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutputLines("A", "B");
diff --git a/src/test/java/com/android/tools/r8/resolution/access/indirectfield/IndirectFieldAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/indirectfield/IndirectFieldAccessTest.java
index ea51b57..fc7a254 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/indirectfield/IndirectFieldAccessTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/indirectfield/IndirectFieldAccessTest.java
@@ -66,7 +66,7 @@
Reference.field(Reference.classFromClass(B.class), "f", Reference.INT),
appInfo.dexItemFactory());
FieldResolutionResult resolutionResult = appInfo.resolveField(f);
- assertTrue(resolutionResult.isSuccessfulResolution());
+ assertTrue(resolutionResult.isSingleFieldResolutionResult());
assertEquals(OptionalBool.TRUE, resolutionResult.isAccessibleFrom(barMethod, appInfo));
}
diff --git a/src/test/java/com/android/tools/r8/resolution/field/FieldResolutionWithMultipleResultsTest.java b/src/test/java/com/android/tools/r8/resolution/field/FieldResolutionWithMultipleResultsTest.java
new file mode 100644
index 0000000..7b46775
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/resolution/field/FieldResolutionWithMultipleResultsTest.java
@@ -0,0 +1,115 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.resolution.field;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.ClassResolutionResult;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.FieldResolutionResult;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.utils.AndroidApp;
+import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Consumer;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class FieldResolutionWithMultipleResultsTest extends TestBase {
+
+ @Parameter() public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
+
+ private final List<Class<?>> libraryClasses = ImmutableList.of(A.class, B.class);
+
+ @Test
+ public void testMultipleResultsWithProgramAndLibrary() throws Exception {
+ List<Class<?>> programClasses = new ArrayList<>(libraryClasses);
+ programClasses.add(C.class);
+ testMultipleResolutionsMatchesFoundClasses(
+ readClasses(programClasses, libraryClasses),
+ fieldResult -> assertTrue(fieldResult.hasProgramResult()));
+ }
+
+ @Test
+ public void testMultipleResultsWithClasspathAndLibrary() throws Exception {
+ List<Class<?>> classPath = new ArrayList<>(libraryClasses);
+ classPath.add(C.class);
+ testMultipleResolutionsMatchesFoundClasses(
+ readClasses(Collections.emptyList(), classPath, libraryClasses),
+ fieldResult -> assertTrue(fieldResult.hasClasspathResult()));
+ }
+
+ @Test
+ public void testProgramOverClasspath() throws Exception {
+ List<Class<?>> programAndClasspathClasses = new ArrayList<>(libraryClasses);
+ programAndClasspathClasses.add(C.class);
+ testMultipleResolutionsMatchesFoundClasses(
+ readClasses(programAndClasspathClasses, programAndClasspathClasses, libraryClasses),
+ fieldResult -> assertTrue(fieldResult.hasProgramResult()));
+ }
+
+ private void testMultipleResolutionsMatchesFoundClasses(
+ AndroidApp androidApp, Consumer<FieldResolutionResult> resultConsumer) throws Exception {
+ AppInfoWithClassHierarchy appInfoWithClassHierarchy =
+ computeAppInfoWithClassHierarchy(androidApp);
+ DexItemFactory factory = appInfoWithClassHierarchy.dexItemFactory();
+ DexField field =
+ factory.createField(
+ Reference.field(
+ Reference.classFromClass(C.class), "foo", Reference.primitiveFromDescriptor("I")));
+ FieldResolutionResult fieldResolutionResult = appInfoWithClassHierarchy.resolveField(field);
+ assertTrue(fieldResolutionResult.isMultiFieldResolutionResult());
+ resultConsumer.accept(fieldResolutionResult);
+ assertTrue(fieldResolutionResult.hasProgramOrClasspathResult());
+ assertFalse(fieldResolutionResult.isPossiblyFailedOrUnknownResolution());
+ Set<DexClass> resolvedHolders = new HashSet<>();
+ fieldResolutionResult.forEachFieldResolutionResult(
+ resolutionResult -> {
+ assertTrue(resolutionResult.isSingleFieldResolutionResult());
+ boolean existing =
+ resolvedHolders.add(
+ resolutionResult.asSingleFieldResolutionResult().getResolvedHolder());
+ assertTrue(existing);
+ });
+ assertEquals(2, resolvedHolders.size());
+ ClassResolutionResult classResolutionResult =
+ appInfoWithClassHierarchy.contextIndependentDefinitionForWithResolutionResult(
+ factory.createType(Reference.classFromClass(A.class)));
+ assertTrue(classResolutionResult.hasClassResolutionResult());
+ Set<DexClass> foundClasses = new HashSet<>();
+ classResolutionResult.forEachClassResolutionResult(foundClasses::add);
+ assertEquals(foundClasses, resolvedHolders);
+ }
+
+ public static class A {
+
+ public int foo;
+ }
+
+ public static class B extends A {}
+
+ public static class C extends B {}
+}
diff --git a/src/test/java/com/android/tools/r8/retrace/InlineWithoutNullCheckTest.java b/src/test/java/com/android/tools/r8/retrace/InlineWithoutNullCheckTest.java
index 6973f6b..820be96 100644
--- a/src/test/java/com/android/tools/r8/retrace/InlineWithoutNullCheckTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/InlineWithoutNullCheckTest.java
@@ -17,7 +17,6 @@
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.naming.retrace.StackTrace;
-import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -111,25 +110,15 @@
.addKeepMainRule(TestClassForInlineMethod.class)
.enableAlwaysInliningAnnotations()
.enableInliningAnnotations()
- .addKeepAttributes(ProguardKeepAttributes.SOURCE_FILE)
+ .addKeepAttributeSourceFile()
+ .addKeepAttributeLineNumberTable()
.setMinApi(parameters.getApiLevel())
.compile()
.inspect(this::checkSomething)
.run(parameters.getRuntime(), TestClassForInlineMethod.class)
.assertFailure()
- // TODO(b/143607166): The stack trace has one more frame on the top than expected.
.inspectStackTrace(
- stackTrace -> assertThat(expectedStackTraceForInlineMethod, not(isSame(stackTrace))))
- .inspectStackTrace(
- stackTrace ->
- assertThat(
- stackTrace,
- isSameExceptForFileNameAndLineNumber(
- createStackTraceBuilder()
- .addWithoutFileNameAndLineNumber(
- A.class, "inlineMethodWhichAccessInstanceMethod")
- .addWithoutFileNameAndLineNumber(TestClassForInlineMethod.class, "main")
- .build())));
+ stackTrace -> assertThat(expectedStackTraceForInlineMethod, isSame(stackTrace)));
}
@Test
@@ -139,25 +128,15 @@
.addKeepMainRule(TestClassForInlineField.class)
.enableAlwaysInliningAnnotations()
.enableInliningAnnotations()
- .addKeepAttributes(ProguardKeepAttributes.SOURCE_FILE)
+ .addKeepAttributeSourceFile()
+ .addKeepAttributeLineNumberTable()
.setMinApi(parameters.getApiLevel())
.compile()
.inspect(this::checkSomething)
.run(parameters.getRuntime(), TestClassForInlineField.class)
.assertFailure()
- // TODO(b/143607166): The stack trace has one more frame on the top than expected.
.inspectStackTrace(
- stackTrace -> assertThat(expectedStackTraceForInlineField, not(isSame(stackTrace))))
- .inspectStackTrace(
- stackTrace ->
- assertThat(
- stackTrace,
- isSameExceptForFileNameAndLineNumber(
- createStackTraceBuilder()
- .addWithoutFileNameAndLineNumber(
- A.class, "inlineMethodWhichAccessInstanceField")
- .addWithoutFileNameAndLineNumber(TestClassForInlineField.class, "main")
- .build())));
+ stackTrace -> assertThat(expectedStackTraceForInlineField, isSame(stackTrace)));
}
@Test
@@ -168,27 +147,15 @@
.addKeepMainRule(TestClassForInlineStaticField.class)
.enableAlwaysInliningAnnotations()
.enableInliningAnnotations()
- .addKeepAttributes(ProguardKeepAttributes.SOURCE_FILE)
+ .addKeepAttributeSourceFile()
+ .addKeepAttributeLineNumberTable()
.setMinApi(parameters.getApiLevel())
.compile()
.inspect(this::checkSomething)
.run(parameters.getRuntime(), TestClassForInlineStaticField.class)
.assertFailure()
- // TODO(b/143607166): The stack trace has one more frame on the top than expected.
.inspectStackTrace(
- stackTrace ->
- assertThat(expectedStackTraceForInlineStaticField, not(isSame(stackTrace))))
- .inspectStackTrace(
- stackTrace ->
- assertThat(
- stackTrace,
- isSameExceptForFileNameAndLineNumber(
- createStackTraceBuilder()
- .addWithoutFileNameAndLineNumber(
- A.class, "inlineMethodWhichAccessStaticField")
- .addWithoutFileNameAndLineNumber(
- TestClassForInlineStaticField.class, "main")
- .build())));
+ stackTrace -> assertThat(expectedStackTraceForInlineStaticField, isSame(stackTrace)));
}
private StackTrace.Builder createStackTraceBuilder() {
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerAssertionInClinitOnlyTest.java b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerAssertionInClinitOnlyTest.java
index 314d180..f2de8f4 100644
--- a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerAssertionInClinitOnlyTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerAssertionInClinitOnlyTest.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.rewrite.assertions;
+import com.android.tools.r8.R8TestBuilder;
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.rewrite.assertions.assertionhandler.AssertionHandlers;
@@ -35,4 +36,9 @@
List<Class<?>> getTestClasses() {
return ImmutableList.of(AssertionsInClinit.class);
}
+
+ @Override
+ protected void configure(R8TestBuilder<?> builder) {
+ builder.allowUnusedProguardConfigurationRules();
+ }
}
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerMissingClassTest.java b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerMissingClassTest.java
new file mode 100644
index 0000000..72057c3
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerMissingClassTest.java
@@ -0,0 +1,97 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.rewrite.assertions;
+
+import static org.junit.Assert.fail;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.rewrite.assertions.assertionhandler.AssertionHandlers;
+import com.android.tools.r8.rewrite.assertions.assertionhandler.AssertionsSimple;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.ZipUtils.ZipBuilder;
+import java.nio.file.Path;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class AssertionConfigurationAssertionHandlerMissingClassTest extends TestBase {
+
+ private static final String EXPECTED_OUTPUT =
+ StringUtils.lines(
+ "assertionHandler: simpleAssertion",
+ "assertionHandler: multipleAssertions",
+ "assertionHandler: multipleAssertions");
+ private static Class<?> MAIN_CLASS = AssertionsSimple.class;
+
+ @Parameter() public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build());
+ }
+
+ private MethodReference getAssertionHandler() {
+ try {
+ return Reference.methodFromMethod(
+ AssertionHandlers.class.getMethod("assertionHandler", Throwable.class));
+ } catch (NoSuchMethodException e) {
+ }
+ fail();
+ return null;
+ }
+
+ private Path jarWithAssertionHandler() throws Exception {
+ Path jar = temp.newFolder().toPath().resolve("assertion_handler.jar");
+ if (parameters.isDexRuntime()) {
+ testForD8()
+ .addProgramClasses(AssertionHandlers.class)
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .writeToZip(jar);
+ return jar;
+ } else {
+ return ZipBuilder.builder(jar)
+ .addFilesRelative(
+ ToolHelper.getClassPathForTests(),
+ ToolHelper.getClassFileForTestClass(AssertionHandlers.class))
+ .build();
+ }
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(MAIN_CLASS)
+ .addKeepMainRule(MAIN_CLASS)
+ .addKeepAnnotation()
+ .addKeepRules("-keepclassmembers class * { @com.android.tools.r8.Keep *; }")
+ .setMinApi(parameters.getApiLevel())
+ .addIgnoreWarnings()
+ .addAssertionsConfiguration(
+ builder -> builder.setAssertionHandler(getAssertionHandler()).setScopeAll().build())
+ .allowDiagnosticMessages()
+ .compileWithExpectedDiagnostics(
+ diagnostics ->
+ diagnostics
+ .assertOnlyWarnings()
+ .inspectWarnings(
+ diagnostic ->
+ diagnostic
+ .assertIsMissingDefinitionsDiagnostic()
+ .assertIsAllMissingClasses(AssertionHandlers.class)))
+ .addRunClasspathFiles(jarWithAssertionHandler())
+ .run(parameters.getRuntime(), MAIN_CLASS)
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerNoAssertionsAfterOptimizingTest.java b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerNoAssertionsAfterOptimizingTest.java
new file mode 100644
index 0000000..36f01a8
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerNoAssertionsAfterOptimizingTest.java
@@ -0,0 +1,49 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.rewrite.assertions;
+
+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.references.MethodReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.rewrite.assertions.assertionhandler.AssertionHandlers;
+import com.android.tools.r8.rewrite.assertions.assertionhandler.NoAssertionsAfterOptimization;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class AssertionConfigurationAssertionHandlerNoAssertionsAfterOptimizingTest
+ extends AssertionConfigurationAssertionHandlerTestBase {
+
+ private static final String EXPECTED_OUTPUT = StringUtils.lines("Hello, world!");
+
+ @Override
+ String getExpectedOutput() {
+ return EXPECTED_OUTPUT;
+ }
+
+ @Override
+ MethodReference getAssertionHandler() throws Exception {
+ return Reference.methodFromMethod(
+ AssertionHandlers.class.getMethod("assertionHandler", Throwable.class));
+ }
+
+ @Override
+ protected void inspect(CodeInspector inspector) {
+ assert getAssertionHandlerClasses().size() == 1;
+ assertThat(inspector.clazz(getAssertionHandlerClasses().get(0)), not(isPresent()));
+ }
+
+ @Override
+ List<Class<?>> getTestClasses() {
+ return ImmutableList.of(NoAssertionsAfterOptimization.class);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerTestBase.java b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerTestBase.java
index fa4de84..0583b32 100644
--- a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerTestBase.java
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerTestBase.java
@@ -6,10 +6,13 @@
import static org.junit.Assume.assumeTrue;
+import com.android.tools.r8.R8TestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.rewrite.assertions.assertionhandler.AssertionHandlers;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableList;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,6 +37,14 @@
abstract List<Class<?>> getTestClasses();
+ protected List<Class<?>> getAssertionHandlerClasses() {
+ return ImmutableList.of(AssertionHandlers.class);
+ }
+
+ protected void configure(R8TestBuilder<?> builder) {}
+
+ protected void inspect(CodeInspector inspector) {}
+
private MethodReference getAssertionHandlerIgnoreException() {
try {
return getAssertionHandler();
@@ -46,7 +57,7 @@
public void testD8() throws Exception {
assumeTrue(parameters.isDexRuntime());
testForD8(parameters.getBackend())
- .addProgramClasses(AssertionHandlers.class)
+ .addProgramClasses(getAssertionHandlerClasses())
.addProgramClasses(getTestClasses())
.setMinApi(parameters.getApiLevel())
.addOptionsModification(o -> o.testing.forceIRForCfToCfDesugar = true)
@@ -63,11 +74,11 @@
@Test
public void testR8() throws Exception {
testForR8(parameters.getBackend())
- .addProgramClasses(AssertionHandlers.class)
+ .addProgramClasses(getAssertionHandlerClasses())
.addProgramClasses(getTestClasses())
.addKeepMainRule(getTestClasses().get(0))
.addKeepAnnotation()
- .addKeepRules("-keep class * { @com.android.tools.r8.Keep *; }")
+ .addKeepRules("-keepclassmembers class * { @com.android.tools.r8.Keep *; }")
.setMinApi(parameters.getApiLevel())
.addAssertionsConfiguration(
builder ->
@@ -75,7 +86,9 @@
.setAssertionHandler(getAssertionHandlerIgnoreException())
.setScopeAll()
.build())
+ .apply(this::configure)
.run(parameters.getRuntime(), getTestClasses().get(0))
+ .inspect(this::inspect)
.assertSuccessWithOutput(getExpectedOutput());
}
}
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/assertionhandler/NoAssertionsAfterOptimization.java b/src/test/java/com/android/tools/r8/rewrite/assertions/assertionhandler/NoAssertionsAfterOptimization.java
new file mode 100644
index 0000000..994c83a
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/assertionhandler/NoAssertionsAfterOptimization.java
@@ -0,0 +1,27 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.rewrite.assertions.assertionhandler;
+
+import com.android.tools.r8.Keep;
+
+public class NoAssertionsAfterOptimization {
+
+ private static boolean alwaysFalse() {
+ return false;
+ }
+
+ @Keep
+ private static void assertionUnderAlwaysFalseCondition() {
+ if (alwaysFalse()) {
+ assert false : "Fifth assertion";
+ }
+ }
+
+ public static void main(String[] args) {
+ System.out.print("Hello, ");
+ assertionUnderAlwaysFalseCondition();
+ System.out.println("world!");
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java b/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java
index e110f57..f22ae69 100644
--- a/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java
@@ -78,6 +78,7 @@
return StringUtils.joinLines("Hello!", "Goodbye!", "");
case V7_0_0:
+ case V13_MASTER:
return StringUtils.joinLines(
"Hello!",
"Unexpected outcome of checkcast",
diff --git a/src/test/java/com/android/tools/r8/shaking/clinit/ClassInitInlineForStaticGetterInSuperTypeTest.java b/src/test/java/com/android/tools/r8/shaking/clinit/ClassInitInlineForStaticGetterInSuperTypeTest.java
index 7a4c15e..ae433d9 100644
--- a/src/test/java/com/android/tools/r8/shaking/clinit/ClassInitInlineForStaticGetterInSuperTypeTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/clinit/ClassInitInlineForStaticGetterInSuperTypeTest.java
@@ -18,7 +18,6 @@
public class ClassInitInlineForStaticGetterInSuperTypeTest extends TestBase {
private static final String EXPECTED = "Hello World";
- private static final String R8_EXPECTED = "Goodbye World";
@Parameter() public TestParameters parameters;
@@ -44,8 +43,7 @@
.addKeepRules("-keep class " + typeName(B.class) + " { <fields>; }")
.enableInliningAnnotations()
.run(parameters.getRuntime(), Main.class)
- // TODO(b/215477768): Should be Hello World
- .assertSuccessWithOutputLines(R8_EXPECTED);
+ .assertSuccessWithOutputLines(EXPECTED);
}
public static class A {
diff --git a/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java b/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
index 8cc71c8..804c5f8 100644
--- a/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
+++ b/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
@@ -76,7 +76,8 @@
public static boolean isExternalSynthetic(ClassReference reference) {
for (SyntheticKind kind : SyntheticKind.values()) {
if (kind == SyntheticKind.RECORD_TAG
- || kind == SyntheticKind.EMULATED_INTERFACE_MARKER_CLASS) {
+ || kind == SyntheticKind.EMULATED_INTERFACE_MARKER_CLASS
+ || kind == SyntheticKind.RETARGET_STUB) {
continue;
}
if (kind.isFixedSuffixSynthetic) {
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java
index 4ffcdb4..9be6468 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java
@@ -77,6 +77,16 @@
}
@Override
+ public TypeSubject getParameter(int index) {
+ throw new Unreachable("Cannot get the parameter for an absent method");
+ }
+
+ @Override
+ public List<TypeSubject> getParameters() {
+ throw new Unreachable("Cannot get the parameters for an absent method");
+ }
+
+ @Override
public ProgramMethod getProgramMethod() {
return null;
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
index 04f0d52..30b3fb0 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
@@ -171,6 +171,10 @@
return null;
}
+ public TypeSubject asTypeSubject() {
+ return null;
+ }
+
@Override
public abstract ClassAccessFlags getAccessFlags();
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
index 0d62343..cdc420e 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
@@ -289,6 +289,11 @@
}
@Override
+ public TypeSubject asTypeSubject() {
+ return new TypeSubject(codeInspector, dexClass.getType());
+ }
+
+ @Override
public boolean isAbstract() {
return dexClass.accessFlags.isAbstract();
}
@@ -504,10 +509,6 @@
return dexClass.toSourceString();
}
- public TypeSubject asTypeSubject() {
- return new TypeSubject(codeInspector, getDexProgramClass().type);
- }
-
@Override
public KmClassSubject getKmClass() {
AnnotationSubject annotationSubject = annotation(METADATA_TYPE);
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
index a41ab17..b99b090 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
@@ -124,6 +124,18 @@
}
@Override
+ public TypeSubject getParameter(int index) {
+ return new TypeSubject(codeInspector, getMethod().getParameter(index));
+ }
+
+ @Override
+ public List<TypeSubject> getParameters() {
+ return getMethod().getParameters().stream()
+ .map(parameter -> new TypeSubject(codeInspector, parameter))
+ .collect(Collectors.toList());
+ }
+
+ @Override
public ProgramMethod getProgramMethod() {
return new ProgramMethod(clazz.getDexProgramClass(), getMethod());
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/MethodMatchers.java b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodMatchers.java
new file mode 100644
index 0000000..8d7e78b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodMatchers.java
@@ -0,0 +1,54 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.utils.codeinspector;
+
+import static junit.framework.TestCase.assertEquals;
+
+import com.android.tools.r8.utils.StringUtils;
+import java.util.Arrays;
+import java.util.List;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+
+public class MethodMatchers {
+
+ public static Matcher<MethodSubject> hasParameters(TypeSubject... expectedParameters) {
+ return hasParameters(Arrays.asList(expectedParameters));
+ }
+
+ public static Matcher<MethodSubject> hasParameters(List<TypeSubject> expectedParameters) {
+ return new TypeSafeMatcher<MethodSubject>() {
+ @Override
+ protected boolean matchesSafely(MethodSubject methodSubject) {
+ if (!methodSubject.isPresent()) {
+ return false;
+ }
+ if (methodSubject.getParameters().size() != expectedParameters.size()) {
+ return false;
+ }
+ for (int i = 0; i < expectedParameters.size(); i++) {
+ TypeSubject actualParameter = methodSubject.getParameter(i);
+ TypeSubject expectedParameter = expectedParameters.get(i);
+ assertEquals(expectedParameter, actualParameter);
+ }
+ return true;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText(
+ "has parameters ("
+ + StringUtils.join(", ", expectedParameters, TypeSubject::getTypeName)
+ + ")");
+ }
+
+ @Override
+ public void describeMismatchSafely(final MethodSubject subject, Description description) {
+ description.appendText("method did not");
+ }
+ };
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
index 594b17a..3b7fe05 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.google.common.collect.Streams;
import java.util.Iterator;
+import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Stream;
@@ -51,6 +52,10 @@
public abstract DexEncodedMethod getMethod();
+ public abstract TypeSubject getParameter(int index);
+
+ public abstract List<TypeSubject> getParameters();
+
public abstract ProgramMethod getProgramMethod();
public Iterator<InstructionSubject> iterateInstructions() {
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/TypeSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/TypeSubject.java
index 357c777..5761b99 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/TypeSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/TypeSubject.java
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
@@ -17,6 +17,10 @@
this.dexType = dexType;
}
+ public String getTypeName() {
+ return dexType.getTypeName();
+ }
+
@Override
public boolean isPresent() {
return true;
diff --git a/third_party/android_jar/lib-v33.tar.gz.sha1 b/third_party/android_jar/lib-v33.tar.gz.sha1
new file mode 100644
index 0000000..2e88eb6
--- /dev/null
+++ b/third_party/android_jar/lib-v33.tar.gz.sha1
@@ -0,0 +1 @@
+ecd236f896f9a19eeb7d46eb983cbaf94fd31d76
\ No newline at end of file
diff --git a/third_party/openjdk/jdk-18/linux.tar.gz.sha1 b/third_party/openjdk/jdk-18/linux.tar.gz.sha1
new file mode 100644
index 0000000..3c8efd9
--- /dev/null
+++ b/third_party/openjdk/jdk-18/linux.tar.gz.sha1
@@ -0,0 +1 @@
+b545df5778c9025fe105dddcd8b3830d8731137b
\ No newline at end of file
diff --git a/third_party/openjdk/jdk-18/osx.tar.gz.sha1 b/third_party/openjdk/jdk-18/osx.tar.gz.sha1
new file mode 100644
index 0000000..9699f89
--- /dev/null
+++ b/third_party/openjdk/jdk-18/osx.tar.gz.sha1
@@ -0,0 +1 @@
+527883f93a157ae249f83f461b0368d87c8fe6a1
\ No newline at end of file
diff --git a/third_party/openjdk/jdk-18/windows.tar.gz.sha1 b/third_party/openjdk/jdk-18/windows.tar.gz.sha1
new file mode 100644
index 0000000..854167c
--- /dev/null
+++ b/third_party/openjdk/jdk-18/windows.tar.gz.sha1
@@ -0,0 +1 @@
+b1e3cb3be67dd78423a0a96c0214ac97b5edd112
\ No newline at end of file
diff --git a/tools/linux/README.art-versions b/tools/linux/README.art-versions
index ff57695..fee679c 100644
--- a/tools/linux/README.art-versions
+++ b/tools/linux/README.art-versions
@@ -42,6 +42,28 @@
<continue with repo sync as above>
+art-13-master (Android T)
+-------------------------
+Build from master commit e208b04cc2efaf707390d7acbe8f978142701d72.
+
+repo sync -cq -j24
+source build/envsetup.sh
+lunch aosp_redfin-userdebug
+m -j48
+m -j48 build-art
+m -j48 test-art-host
+
+Collected into tools/linux/host/art-13-master. The "host" path element is checked
+by the script for running Art.
+
+ cd <r8 checkout>
+ scripts/update-host-art.sh \
+ --android-checkout <...>/android/master \
+ --art-dir host/art-13-master \
+ --android-product redfin
+
+(cd tools/linux/host; upload_to_google_storage.py -a --bucket r8-deps art-13-master)
+
art-12.0.0 (Android S)
---------------------
Build from branch sc-beta4-release.
diff --git a/tools/linux/host/art-13-master.tar.gz.sha1 b/tools/linux/host/art-13-master.tar.gz.sha1
new file mode 100644
index 0000000..8b16edd
--- /dev/null
+++ b/tools/linux/host/art-13-master.tar.gz.sha1
@@ -0,0 +1 @@
+a2cf2b34b8712adb5c25a18bc6135946cfb1a047
\ No newline at end of file
diff --git a/tools/test.py b/tools/test.py
index 9d5e99f..e822efe 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -24,6 +24,7 @@
ALL_ART_VMS = [
"default",
+ "13.0.0",
"12.0.0",
"10.0.0",
"9.0.0",