Merge commit 'fb2abd1e8fe4b3e8730ecdba55608123671587dc' into dev-release
diff --git a/build.gradle b/build.gradle
index e83113a..ce0bc7f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -136,15 +136,6 @@
srcDirs = ['src/test/examplesJava17']
}
}
- jdk11TimeTests {
- java {
- srcDirs = [
- 'third_party/openjdk/jdk-11-test/java/time/tck',
- 'third_party/openjdk/jdk-11-test/java/time/test'
- ]
- exclude '**/TestZoneTextPrinterParser.java'
- }
- }
examplesTestNGRunner {
java {
srcDirs = ['src/test/testngrunner']
@@ -249,7 +240,6 @@
implementation group: 'org.ow2.asm', name: 'asm-analysis', version: asmVersion
implementation group: 'org.ow2.asm', name: 'asm-util', version: asmVersion
implementation files('third_party/android_jar/api-database/api-database.jar')
- jdk11TimeTestsCompile group: 'org.testng', name: 'testng', version: testngVersion
examplesTestNGRunnerCompile group: 'org.testng', name: 'testng', version: testngVersion
testCompile sourceSets.examples.output
testCompile "junit:junit:$junitVersion"
@@ -599,11 +589,6 @@
JavaVersion.VERSION_1_9,
false)
setJdkCompilationWithCompatibility(
- sourceSets.examplesJava11.compileJavaTaskName,
- 'jdk-11',
- JavaVersion.VERSION_11,
- false)
-setJdkCompilationWithCompatibility(
sourceSets.examplesJava10.compileJavaTaskName,
'jdk-11',
JavaVersion.VERSION_1_10,
@@ -619,11 +604,6 @@
JavaVersion.VERSION_11,
false)
setJdkCompilationWithCompatibility(
- sourceSets.jdk11TimeTests.compileJavaTaskName,
- 'jdk-11',
- JavaVersion.VERSION_11,
- false)
-setJdkCompilationWithCompatibility(
sourceSets.examplesJava17.compileJavaTaskName,
'jdk-17',
JavaVersion.VERSION_17,
@@ -648,6 +628,19 @@
classpath = sourceSets.main.compileClasspath
}
+task provideJdk11TestsDependencies(type: org.gradle.api.tasks.Copy) {
+ from sourceSets.examplesTestNGRunner.compileClasspath
+ include "**/**.jar"
+ into file("$buildDir/test/jdk11Tests")
+}
+
+task compileTestNGRunner (type: JavaCompile) {
+ dependsOn provideJdk11TestsDependencies
+ destinationDir = file("$buildDir/classes/java/examplesTestNGRunner")
+ source = sourceSets.examplesTestNGRunner.allSource
+ classpath = sourceSets.examplesTestNGRunner.compileClasspath
+}
+
if (!project.hasProperty('without_error_prone') &&
// Don't enable error prone on Java 8 as the plugin setup does not support it.
!org.gradle.internal.jvm.Jvm.current().javaVersion.java8) {
@@ -1634,28 +1627,6 @@
})
}
-task provideJdk11TestsDependencies(type: org.gradle.api.tasks.Copy) {
- from sourceSets.jdk11TimeTests.compileClasspath
- include "**/**.jar"
- into file("build/test/jdk11Tests")
-}
-
-task buildJdk11TimeTestsJar {
- def exampleOutputDir = file("build/test/jdk11Tests");
- def jarName = "jdk11TimeTests.jar"
- dependsOn "jar_jdk11TimeTests"
- dependsOn provideJdk11TestsDependencies
- task "jar_jdk11TimeTests"(type: Jar) {
- archiveName = jarName
- destinationDir = exampleOutputDir
- from sourceSets.examplesTestNGRunner.output
- include "**.class"
- from sourceSets.jdk11TimeTests.output
- include "**.class"
- include "**/**.class"
- }
-}
-
task buildKotlinR8TestResources {
def examplesDir = file("src/test/kotlinR8TestResources")
examplesDir.eachDir { dir ->
@@ -1793,6 +1764,10 @@
} else {
// On normal work machines this seems to give the best test execution time (without freezing)
maxParallelForks = processors.intdiv(3) ?: 1
+ // On low cpu count machines (bots) we under subscribe, so increase the count.
+ if (processors == 8) {
+ maxParallelForks = 4
+ }
}
println("NOTE: Max parallel forks " + maxParallelForks)
@@ -1900,10 +1875,6 @@
def err = new StringBuffer()
def command = "python tools/retrace.py --quiet"
def header = "RETRACED STACKTRACE";
- if (System.getenv('BUILDBOT_BUILDERNAME') != null
- && !System.getenv('BUILDBOT_BUILDERNAME').endsWith("_release")) {
- header += ": (${command} --commit_hash ${System.getenv('BUILDBOT_REVISION')})";
- }
out.append("\n--------------------------------------\n")
out.append("${header}\n")
out.append("--------------------------------------\n")
@@ -2411,7 +2382,7 @@
dependsOn buildDebugInfoExamplesDex
dependsOn buildPreNJdwpTestsJar
dependsOn buildPreNJdwpTestsDex
- dependsOn buildJdk11TimeTestsJar
+ dependsOn compileTestNGRunner
dependsOn provideArtFrameworksDependencies
} else {
logger.lifecycle("WARNING: Testing in not supported on your platform. Testing is only fully supported on " +
diff --git a/infra/config/global/cr-buildbucket.cfg b/infra/config/global/cr-buildbucket.cfg
deleted file mode 100644
index ae6487f..0000000
--- a/infra/config/global/cr-buildbucket.cfg
+++ /dev/null
@@ -1,525 +0,0 @@
-# Defines buckets on cr-buildbucket.appspot.com, used by to schedule builds
-# on buildbot. In particular, CQ uses some of these buckets to schedule tryjobs.
-#
-# See http://luci-config.appspot.com/schemas/projects:buildbucket.cfg for
-# schema of this file and documentation.
-#
-# Please keep this list sorted by bucket name.
-
-builder_mixins {
- name: "linux"
- dimensions: "os:Ubuntu-16.04"
-}
-
-builder_mixins {
- name: "win"
- dimensions: "os:Windows-10"
-}
-
-builder_mixins {
- name: "normal"
- dimensions: "normal:true"
-}
-
-builder_mixins {
- name: "jctf"
- dimensions: "jctf:true"
-}
-
-builder_mixins {
- name: "internal"
- dimensions: "internal:true"
- dimensions: "cores:2"
-}
-
-builder_mixins {
- name: "mac"
- dimensions: "os:Mac-10.13"
- dimensions: "cores:" # Macs can be 4 or 8 cores.
-}
-
-builder_mixins {
- name: "build_limited_scripts_slave recipe"
- recipe {
- cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
- cipd_version: "refs/heads/master"
- }
-}
-
-builder_mixins {
- name: "fast_bot"
- execution_timeout_secs: 5400 # 1.5 hours
-}
-
-acl_sets {
- name: "ci"
- acls {
- role: READER
- group: "all"
- }
- acls {
- role: SCHEDULER
- identity: "luci-scheduler@appspot.gserviceaccount.com"
- }
- acls {
- role: SCHEDULER
- group: "project-r8-committers"
- }
-}
-
-acl_sets {
- name: "try"
- acls {
- role: READER
- group: "project-r8-readers"
- }
- acls {
- role: WRITER
- group: "project-r8-admins"
- }
- acls {
- role: SCHEDULER
- group: "service-account-cq"
- }
- acls {
- role: SCHEDULER
- group: "project-r8-tryjob-access"
- }
-}
-
-buckets {
- name: "luci.r8.ci"
- acl_sets: "ci"
- swarming {
- hostname: "chrome-swarming.appspot.com"
- builder_defaults {
- dimensions: "cores:8"
- dimensions: "cpu:x86-64"
- dimensions: "pool:luci.r8.ci"
- service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
- execution_timeout_secs: 21600 # 6h
- expiration_secs: 126000 # 35h, execution_timeout_secs + expiration_secs must be <=47h
- swarming_tags: "vpython:native-python-wrapper"
- build_numbers: YES
- recipe {
- properties: "builder_group:internal.client.r8"
- name: "rex"
- }
- mixins: "build_limited_scripts_slave recipe"
- }
-
- builders {
- name: "archive"
- priority: 25
- mixins: "linux"
- execution_timeout_secs: 1800 # 1/2h
- recipe {
- properties: "archive:True"
- }
- }
- builders {
- name: "archive_release"
- priority: 25
- mixins: "linux"
- execution_timeout_secs: 1800 # 1/2h
- recipe {
- properties: "archive:True"
- }
-
- }
- # This builder is only triggered manually to build and archive maven
- # artifacts for the desugared library.
- builders {
- name: "archive_lib_desugar"
- priority: 25
- mixins: "linux"
- execution_timeout_secs: 3600 # 1h
- recipe {
- properties: "archive:True"
- properties: "sdk_desugar:True"
- }
- }
- builders {
- name: "desugared_library_head"
- execution_timeout_secs: 43200 # 12h
- mixins: "linux"
- mixins: "normal"
- priority: 26
- recipe {
- properties_j: "test_options:[\"--no_internal\", \"--desugared-library\", \"HEAD\"]"
- }
- }
- builders {
- name: "desugared_library_jdk11_head"
- mixins: "linux"
- mixins: "normal"
- priority: 26
- recipe {
- properties_j: "test_options:[\"--no_internal\", \"--desugared-library\", \"HEAD\", \"--desugared-library-configuration\", \"jdk11\"]"
- }
- }
- builders {
- name: "linux-dex-default"
- mixins: "linux"
- mixins: "normal"
- priority: 26
- recipe {
- properties_j: "test_options:[\"--runtimes=dex-default\", \"--tool=r8\", \"--no_internal\", \"--all_tests\", \"--one_line_per_test\", \"--archive_failures\"]"
- }
- }
- builders {
- name: "linux-none"
- mixins: "linux"
- mixins: "normal"
- priority: 26
- recipe {
- properties_j: "test_options:[\"--runtimes=none\", \"--no_internal\", \"--one_line_per_test\", \"--archive_failures\"]"
- }
- }
- builders {
- name: "linux-jdk8"
- mixins: "linux"
- mixins: "normal"
- priority: 26
- recipe {
- properties_j: "test_options:[\"--runtimes=jdk8\", \"--no_internal\", \"--one_line_per_test\", \"--archive_failures\"]"
- }
- }
- builders {
- name: "linux-jdk9"
- mixins: "linux"
- mixins: "normal"
- priority: 26
- recipe {
- properties_j: "test_options:[\"--runtimes=jdk9\", \"--no_internal\", \"--one_line_per_test\", \"--archive_failures\"]"
- }
- }
- builders {
- name: "linux-jdk11"
- mixins: "linux"
- mixins: "normal"
- priority: 26
- recipe {
- properties_j: "test_options:[\"--runtimes=jdk11\", \"--no_internal\", \"--one_line_per_test\", \"--archive_failures\"]"
- }
- }
- builders {
- name: "linux-dex-default_release"
- mixins: "normal"
- mixins: "linux"
- recipe {
- properties_j: "test_options:[\"--runtimes=dex-default\", \"--tool=r8\", \"--no_internal\", \"--all_tests\", \"--one_line_per_test\", \"--archive_failures\"]"
- }
- }
- builders {
- name: "linux-none_release"
- mixins: "normal"
- mixins: "linux"
- recipe {
- properties_j: "test_options:[\"--runtimes=none\", \"--no_internal\", \"--one_line_per_test\", \"--archive_failures\"]"
- }
- }
- builders {
- name: "linux-jdk8_release"
- mixins: "linux"
- mixins: "normal"
- priority: 26
- recipe {
- properties_j: "test_options:[\"--runtimes=jdk8\", \"--no_internal\", \"--one_line_per_test\", \"--archive_failures\"]"
- }
- }
- builders {
- name: "linux-jdk9_release"
- mixins: "linux"
- mixins: "normal"
- priority: 26
- recipe {
- properties_j: "test_options:[\"--runtimes=jdk9\", \"--no_internal\", \"--one_line_per_test\", \"--archive_failures\"]"
- }
- }
- builders {
- name: "linux-jdk11_release"
- mixins: "linux"
- mixins: "normal"
- priority: 26
- recipe {
- properties_j: "test_options:[\"--runtimes=jdk11\", \"--no_internal\", \"--one_line_per_test\", \"--archive_failures\"]"
- }
- }
- builders {
- name: "linux-android-4.0.4"
- mixins: "linux"
- mixins: "normal"
- recipe {
- properties: "tool:r8"
- properties: "dex_vm:4.0.4"
- }
- }
- builders {
- name: "linux-android-4.0.4_release"
- mixins: "linux"
- mixins: "normal"
- recipe {
- properties: "tool:r8"
- properties: "dex_vm:4.0.4"
- }
- }
- builders {
- name: "linux-android-4.4.4"
- mixins: "linux"
- mixins: "normal"
- recipe {
- properties: "tool:r8"
- properties: "dex_vm:4.4.4"
- }
- }
- builders {
- name: "linux-android-4.4.4_release"
- mixins: "linux"
- mixins: "normal"
- recipe {
- properties: "tool:r8"
- properties: "dex_vm:4.4.4"
- }
- }
- builders {
- name: "linux-android-5.1.1"
- mixins: "normal"
- mixins: "linux"
- recipe {
- properties: "tool:r8"
- properties: "dex_vm:5.1.1"
- }
- }
- builders {
- name: "linux-android-5.1.1_release"
- mixins: "linux"
- mixins: "normal"
- recipe {
- properties: "tool:r8"
- properties: "dex_vm:5.1.1"
- }
- }
- builders {
- name: "linux-android-6.0.1"
- mixins: "linux"
- mixins: "normal"
- recipe {
- properties: "tool:r8"
- properties: "dex_vm:6.0.1"
- }
- }
- builders {
- name: "linux-android-6.0.1_release"
- mixins: "linux"
- mixins: "normal"
- recipe {
- properties: "tool:r8"
- properties: "dex_vm:6.0.1"
- }
- }
- builders {
- name: "linux-android-7.0.0"
- mixins: "linux"
- mixins: "normal"
- recipe {
- properties: "tool:r8"
- properties: "dex_vm:7.0.0"
- }
- }
- builders {
- name: "linux-android-7.0.0_release"
- mixins: "linux"
- mixins: "normal"
- recipe {
- properties: "tool:r8"
- properties: "dex_vm:7.0.0"
- }
- }
- builders {
- name: "linux-android-8.1.0"
- mixins: "linux"
- mixins: "normal"
- recipe {
- properties: "tool:r8"
- properties: "dex_vm:8.1.0"
- }
- }
- builders {
- name: "linux-android-8.1.0_release"
- mixins: "linux"
- mixins: "normal"
- recipe {
- properties: "tool:r8"
- properties: "dex_vm:8.1.0"
- }
- }
- builders {
- name: "linux-android-9.0.0"
- mixins: "linux"
- mixins: "normal"
- recipe {
- properties: "tool:r8"
- properties: "dex_vm:9.0.0"
- }
- }
- builders {
- name: "linux-android-9.0.0_release"
- mixins: "linux"
- mixins: "normal"
- recipe {
- properties: "tool:r8"
- properties: "dex_vm:9.0.0"
- }
- }
- builders {
- name: "linux-android-10.0.0"
- mixins: "linux"
- mixins: "normal"
- recipe {
- properties: "tool:r8"
- properties: "dex_vm:10.0.0"
- }
- }
- builders {
- name: "linux-android-10.0.0_release"
- mixins: "linux"
- mixins: "normal"
- recipe {
- properties: "tool:r8"
- properties: "dex_vm:10.0.0"
- }
- }
- builders {
- name: "linux-android-12.0.0"
- mixins: "linux"
- mixins: "normal"
- recipe {
- properties: "tool:r8"
- properties: "dex_vm:12.0.0"
- }
- }
- builders {
- name: "linux-android-12.0.0_release"
- mixins: "linux"
- mixins: "normal"
- recipe {
- properties: "tool:r8"
- properties: "dex_vm:12.0.0"
- }
- }
- builders {
- name: "linux-internal"
- mixins: "linux"
- mixins: "internal"
- execution_timeout_secs: 43200 # 12h
- recipe {
- properties: "internal:True"
- }
- }
- builders {
- name: "linux-internal_release"
- mixins: "linux"
- mixins: "internal"
- execution_timeout_secs: 43200 # 12h
- recipe {
- properties: "internal:True"
- }
- }
- builders {
- name: "linux-run-on-app-dump"
- mixins: "linux"
- mixins: "normal"
- recipe {
- properties_j: "test_options:[\"--bot\"]"
- properties: "test_wrapper:tools/run_on_app_dump.py"
- }
- }
- builders {
- name: "linux-run-on-app-dump_release"
- mixins: "linux"
- mixins: "normal"
- recipe {
- properties_j: "test_options:[\"--bot\"]"
- properties: "test_wrapper:tools/run_on_app_dump.py"
- }
- }
- builders {
- name: "linux-jctf"
- mixins: "linux"
- mixins: "jctf"
- execution_timeout_secs: 43200 # 12h
- recipe {
- properties: "tool:d8"
- properties: "dex_vm:all"
- properties: "only_jctf:True"
- }
- }
- builders {
- name: "linux-jctf_release"
- mixins: "linux"
- mixins: "jctf"
- execution_timeout_secs: 43200 # 12h
- recipe {
- properties: "tool:d8"
- properties: "dex_vm:all"
- properties: "only_jctf:True"
- }
- }
- builders {
- name: "r8cf-linux-jctf"
- mixins: "linux"
- mixins: "jctf"
- execution_timeout_secs: 43200 # 12h
- recipe {
- properties: "tool:r8cf"
- properties: "dex_vm:all"
- properties: "only_jctf:True"
- }
- }
- builders {
- name: "r8cf-linux-jctf_release"
- mixins: "linux"
- mixins: "jctf"
- execution_timeout_secs: 43200 # 12h
- recipe {
- properties: "tool:r8cf"
- properties: "dex_vm:all"
- properties: "only_jctf:True"
- }
- }
- builders {
- name: "linux-kotlin-dev"
- mixins: "linux"
- mixins: "normal"
- recipe {
- properties_j: "test_options:[\"--no_internal\", \"--runtimes=dex-default:jdk11\", \"--kotlin-compiler-dev\", \"--one_line_per_test\", \"--archive_failures\", \"*kotlin*\"]"
- }
- }
- builders {
- name: "windows"
- mixins: "win"
- recipe {
- properties: "tool:r8"
- }
- }
- builders {
- name: "windows_release"
- mixins: "win"
- recipe {
- properties: "tool:r8"
- }
- }
- builders {
- name: "kotlin-builder"
- mixins: "linux"
- mixins: "normal"
- priority: 27
- recipe {
- properties_j: "test_options:[\"--not_used\"]"
- properties: "test_wrapper:google-scripts/build.py"
- properties: "kotlin_repo:True"
- }
- }
- }
-}
diff --git a/infra/config/global/generated/cr-buildbucket.cfg b/infra/config/global/generated/cr-buildbucket.cfg
index 3d645b7..6dd5ceb 100644
--- a/infra/config/global/generated/cr-buildbucket.cfg
+++ b/infra/config/global/generated/cr-buildbucket.cfg
@@ -30,36 +30,19 @@
name: "rex"
cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
cipd_version: "refs/heads/master"
- properties_j: "archive:\"true\""
properties_j: "builder_group:\"internal.client.r8\""
+ properties_j: "test_options:[\"not_used_but_evaluates_to_python_true\"]"
+ properties_j: "test_wrapper:\"tools/archive.py\""
}
priority: 25
execution_timeout_secs: 1800
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
- }
- builders {
- name: "archive_lib_desugar"
- swarming_host: "chrome-swarming.appspot.com"
- swarming_tags: "vpython:native-python-wrapper"
- dimensions: "cores:8"
- dimensions: "cpu:x86-64"
- dimensions: "os:Ubuntu-16.04"
- dimensions: "pool:luci.r8.ci"
- recipe {
- name: "rex"
- cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
- cipd_version: "refs/heads/master"
- properties_j: "archive:\"true\""
- properties_j: "builder_group:\"internal.client.r8\""
- properties_j: "sdk_desugar:\"true\""
+ experiments {
+ key: "luci.use_realms"
+ value: 100
}
- priority: 25
- execution_timeout_secs: 3600
- expiration_secs: 126000
- build_numbers: YES
- service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
}
builders {
name: "archive_release"
@@ -73,17 +56,22 @@
name: "rex"
cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
cipd_version: "refs/heads/master"
- properties_j: "archive:\"true\""
properties_j: "builder_group:\"internal.client.r8\""
+ properties_j: "test_options:[\"not_used_but_evaluates_to_python_true\"]"
+ properties_j: "test_wrapper:\"tools/archive.py\""
}
priority: 25
execution_timeout_secs: 1800
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
- name: "desugared_library_head"
+ name: "desugared_library-head"
swarming_host: "chrome-swarming.appspot.com"
swarming_tags: "vpython:native-python-wrapper"
dimensions: "cores:8"
@@ -102,9 +90,13 @@
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
- name: "desugared_library_jdk11_head"
+ name: "desugared_library-jdk11_head"
swarming_host: "chrome-swarming.appspot.com"
swarming_tags: "vpython:native-python-wrapper"
dimensions: "cores:8"
@@ -123,6 +115,140 @@
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
+ }
+ builders {
+ name: "lib_desugar-archive"
+ swarming_host: "chrome-swarming.appspot.com"
+ swarming_tags: "vpython:native-python-wrapper"
+ dimensions: "cores:8"
+ dimensions: "cpu:x86-64"
+ dimensions: "os:Ubuntu-16.04"
+ dimensions: "pool:luci.r8.ci"
+ recipe {
+ name: "rex"
+ cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
+ cipd_version: "refs/heads/master"
+ properties_j: "builder_group:\"internal.client.r8\""
+ properties_j: "test_options:[\"not_used_but_evaluates_to_python_true\"]"
+ properties_j: "test_wrapper:\"tools/archive_desugar_jdk_libs.py\""
+ }
+ priority: 25
+ execution_timeout_secs: 3600
+ expiration_secs: 126000
+ build_numbers: YES
+ service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
+ }
+ builders {
+ name: "linux-android-10.0.0"
+ swarming_host: "chrome-swarming.appspot.com"
+ swarming_tags: "vpython:native-python-wrapper"
+ dimensions: "cores:8"
+ dimensions: "cpu:x86-64"
+ dimensions: "normal:true"
+ dimensions: "os:Ubuntu-16.04"
+ dimensions: "pool:luci.r8.ci"
+ recipe {
+ name: "rex"
+ cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
+ cipd_version: "refs/heads/master"
+ properties_j: "builder_group:\"internal.client.r8\""
+ properties_j: "test_options:[\"--dex_vm=10.0.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+ }
+ priority: 26
+ execution_timeout_secs: 21600
+ expiration_secs: 126000
+ build_numbers: YES
+ service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
+ }
+ builders {
+ name: "linux-android-10.0.0_release"
+ swarming_host: "chrome-swarming.appspot.com"
+ swarming_tags: "vpython:native-python-wrapper"
+ dimensions: "cores:8"
+ dimensions: "cpu:x86-64"
+ dimensions: "normal:true"
+ dimensions: "os:Ubuntu-16.04"
+ dimensions: "pool:luci.r8.ci"
+ recipe {
+ name: "rex"
+ cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
+ cipd_version: "refs/heads/master"
+ properties_j: "builder_group:\"internal.client.r8\""
+ properties_j: "test_options:[\"--dex_vm=10.0.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+ }
+ priority: 26
+ execution_timeout_secs: 21600
+ expiration_secs: 126000
+ build_numbers: YES
+ service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
+ }
+ builders {
+ name: "linux-android-12.0.0"
+ swarming_host: "chrome-swarming.appspot.com"
+ swarming_tags: "vpython:native-python-wrapper"
+ dimensions: "cores:8"
+ dimensions: "cpu:x86-64"
+ dimensions: "normal:true"
+ dimensions: "os:Ubuntu-16.04"
+ dimensions: "pool:luci.r8.ci"
+ recipe {
+ name: "rex"
+ cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
+ cipd_version: "refs/heads/master"
+ properties_j: "builder_group:\"internal.client.r8\""
+ properties_j: "test_options:[\"--dex_vm=12.0.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+ }
+ priority: 26
+ execution_timeout_secs: 21600
+ expiration_secs: 126000
+ build_numbers: YES
+ service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
+ }
+ builders {
+ name: "linux-android-12.0.0_release"
+ swarming_host: "chrome-swarming.appspot.com"
+ swarming_tags: "vpython:native-python-wrapper"
+ dimensions: "cores:8"
+ dimensions: "cpu:x86-64"
+ dimensions: "normal:true"
+ dimensions: "os:Ubuntu-16.04"
+ dimensions: "pool:luci.r8.ci"
+ recipe {
+ name: "rex"
+ cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
+ cipd_version: "refs/heads/master"
+ properties_j: "builder_group:\"internal.client.r8\""
+ properties_j: "test_options:[\"--dex_vm=12.0.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+ }
+ priority: 26
+ execution_timeout_secs: 21600
+ expiration_secs: 126000
+ build_numbers: YES
+ service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
name: "linux-android-4.0.4"
@@ -145,6 +271,10 @@
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
name: "linux-android-4.0.4_release"
@@ -167,6 +297,10 @@
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
name: "linux-android-4.4.4"
@@ -189,6 +323,10 @@
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
name: "linux-android-4.4.4_release"
@@ -211,6 +349,10 @@
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
name: "linux-android-5.1.1"
@@ -233,6 +375,10 @@
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
name: "linux-android-5.1.1_release"
@@ -255,6 +401,10 @@
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
name: "linux-android-6.0.1"
@@ -277,6 +427,10 @@
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
name: "linux-android-6.0.1_release"
@@ -299,6 +453,10 @@
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
name: "linux-android-7.0.0"
@@ -321,6 +479,10 @@
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
name: "linux-android-7.0.0_release"
@@ -343,97 +505,13 @@
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
- }
- builders {
- name: "linux-android=10.0.0"
- swarming_host: "chrome-swarming.appspot.com"
- swarming_tags: "vpython:native-python-wrapper"
- dimensions: "cores:8"
- dimensions: "cpu:x86-64"
- dimensions: "normal:true"
- dimensions: "os:Ubuntu-16.04"
- dimensions: "pool:luci.r8.ci"
- recipe {
- name: "rex"
- cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
- cipd_version: "refs/heads/master"
- properties_j: "builder_group:\"internal.client.r8\""
- properties_j: "test_options:[\"--dex_vm=10.0.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
}
- priority: 26
- execution_timeout_secs: 21600
- expiration_secs: 126000
- build_numbers: YES
- service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
}
builders {
- name: "linux-android=10.0.0_release"
- swarming_host: "chrome-swarming.appspot.com"
- swarming_tags: "vpython:native-python-wrapper"
- dimensions: "cores:8"
- dimensions: "cpu:x86-64"
- dimensions: "normal:true"
- dimensions: "os:Ubuntu-16.04"
- dimensions: "pool:luci.r8.ci"
- recipe {
- name: "rex"
- cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
- cipd_version: "refs/heads/master"
- properties_j: "builder_group:\"internal.client.r8\""
- properties_j: "test_options:[\"--dex_vm=10.0.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
- }
- priority: 26
- execution_timeout_secs: 21600
- expiration_secs: 126000
- build_numbers: YES
- service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
- }
- builders {
- name: "linux-android=12.0.0"
- swarming_host: "chrome-swarming.appspot.com"
- swarming_tags: "vpython:native-python-wrapper"
- dimensions: "cores:8"
- dimensions: "cpu:x86-64"
- dimensions: "normal:true"
- dimensions: "os:Ubuntu-16.04"
- dimensions: "pool:luci.r8.ci"
- recipe {
- name: "rex"
- cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
- cipd_version: "refs/heads/master"
- properties_j: "builder_group:\"internal.client.r8\""
- properties_j: "test_options:[\"--dex_vm=12.0.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
- }
- priority: 26
- execution_timeout_secs: 21600
- expiration_secs: 126000
- build_numbers: YES
- service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
- }
- builders {
- name: "linux-android=12.0.0_release"
- swarming_host: "chrome-swarming.appspot.com"
- swarming_tags: "vpython:native-python-wrapper"
- dimensions: "cores:8"
- dimensions: "cpu:x86-64"
- dimensions: "normal:true"
- dimensions: "os:Ubuntu-16.04"
- dimensions: "pool:luci.r8.ci"
- recipe {
- name: "rex"
- cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
- cipd_version: "refs/heads/master"
- properties_j: "builder_group:\"internal.client.r8\""
- properties_j: "test_options:[\"--dex_vm=12.0.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
- }
- priority: 26
- execution_timeout_secs: 21600
- expiration_secs: 126000
- build_numbers: YES
- service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
- }
- builders {
- name: "linux-android=8.1.0"
+ name: "linux-android-8.1.0"
swarming_host: "chrome-swarming.appspot.com"
swarming_tags: "vpython:native-python-wrapper"
dimensions: "cores:8"
@@ -453,9 +531,13 @@
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
- name: "linux-android=8.1.0_release"
+ name: "linux-android-8.1.0_release"
swarming_host: "chrome-swarming.appspot.com"
swarming_tags: "vpython:native-python-wrapper"
dimensions: "cores:8"
@@ -475,9 +557,13 @@
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
- name: "linux-android=9.0.0"
+ name: "linux-android-9.0.0"
swarming_host: "chrome-swarming.appspot.com"
swarming_tags: "vpython:native-python-wrapper"
dimensions: "cores:8"
@@ -497,9 +583,13 @@
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
- name: "linux-android=9.0.0_release"
+ name: "linux-android-9.0.0_release"
swarming_host: "chrome-swarming.appspot.com"
swarming_tags: "vpython:native-python-wrapper"
dimensions: "cores:8"
@@ -519,6 +609,10 @@
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
name: "linux-d8_jctf"
@@ -534,15 +628,17 @@
cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
cipd_version: "refs/heads/master"
properties_j: "builder_group:\"internal.client.r8\""
- properties_j: "dex_vm:\"all\""
- properties_j: "only_jctf:\"true\""
- properties_j: "tool:\"d8\""
+ properties_j: "test_options:[\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\",\"--dex_vm=all\",\"--tool=d8\",\"--only_jctf\"]"
}
priority: 26
execution_timeout_secs: 43200
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
name: "linux-d8_jctf_release"
@@ -558,15 +654,17 @@
cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
cipd_version: "refs/heads/master"
properties_j: "builder_group:\"internal.client.r8\""
- properties_j: "dex_vm:\"all\""
- properties_j: "only_jctf:\"true\""
- properties_j: "tool:\"d8\""
+ properties_j: "test_options:[\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\",\"--dex_vm=all\",\"--tool=d8\",\"--only_jctf\"]"
}
priority: 26
execution_timeout_secs: 43200
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
name: "linux-dex_default"
@@ -589,6 +687,10 @@
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
name: "linux-dex_default_release"
@@ -611,6 +713,10 @@
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
name: "linux-internal"
@@ -626,13 +732,18 @@
cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
cipd_version: "refs/heads/master"
properties_j: "builder_group:\"internal.client.r8\""
- properties_j: "internal:\"true\""
+ properties_j: "test_options:[\"--bot\"]"
+ properties_j: "test_wrapper:\"tools/internal_test.py\""
}
priority: 25
execution_timeout_secs: 43200
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
name: "linux-internal_release"
@@ -648,13 +759,18 @@
cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
cipd_version: "refs/heads/master"
properties_j: "builder_group:\"internal.client.r8\""
- properties_j: "internal:\"true\""
+ properties_j: "test_options:[\"--bot\"]"
+ properties_j: "test_wrapper:\"tools/internal_test.py\""
}
priority: 25
execution_timeout_secs: 43200
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
name: "linux-jdk11"
@@ -677,6 +793,10 @@
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
name: "linux-jdk11_release"
@@ -699,6 +819,10 @@
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
name: "linux-jdk8"
@@ -721,6 +845,10 @@
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
name: "linux-jdk8_release"
@@ -743,6 +871,10 @@
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
name: "linux-jdk9"
@@ -765,6 +897,10 @@
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
name: "linux-jdk9_release"
@@ -787,9 +923,13 @@
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
- name: "linux-kotlin-dev"
+ name: "linux-kotlin_dev"
swarming_host: "chrome-swarming.appspot.com"
swarming_tags: "vpython:native-python-wrapper"
dimensions: "cores:8"
@@ -808,6 +948,10 @@
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
name: "linux-none"
@@ -830,6 +974,10 @@
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
name: "linux-none_release"
@@ -852,6 +1000,10 @@
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
name: "linux-r8cf_jctf"
@@ -867,15 +1019,17 @@
cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
cipd_version: "refs/heads/master"
properties_j: "builder_group:\"internal.client.r8\""
- properties_j: "dex_vm:\"all\""
- properties_j: "only_jctf:\"true\""
- properties_j: "tool:\"r8cf\""
+ properties_j: "test_options:[\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\",\"--dex_vm=all\",\"--tool=r8cf\",\"--only_jctf\"]"
}
priority: 26
execution_timeout_secs: 43200
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
name: "linux-r8cf_jctf_release"
@@ -891,15 +1045,17 @@
cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
cipd_version: "refs/heads/master"
properties_j: "builder_group:\"internal.client.r8\""
- properties_j: "dex_vm:\"all\""
- properties_j: "only_jctf:\"true\""
- properties_j: "tool:\"r8cf\""
+ properties_j: "test_options:[\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\",\"--dex_vm=all\",\"--tool=r8cf\",\"--only_jctf\"]"
}
priority: 26
execution_timeout_secs: 43200
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
name: "linux-run-on-app-dump"
@@ -922,6 +1078,10 @@
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
name: "linux-run-on-app-dump_release"
@@ -944,6 +1104,10 @@
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
name: "windows"
@@ -951,7 +1115,7 @@
swarming_tags: "vpython:native-python-wrapper"
dimensions: "cores:8"
dimensions: "cpu:x86-64"
- dimensions: "os:windows-10"
+ dimensions: "os:Windows-10"
dimensions: "pool:luci.r8.ci"
recipe {
name: "rex"
@@ -965,6 +1129,10 @@
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
builders {
name: "windows_release"
@@ -972,7 +1140,7 @@
swarming_tags: "vpython:native-python-wrapper"
dimensions: "cores:8"
dimensions: "cpu:x86-64"
- dimensions: "os:windows-10"
+ dimensions: "os:Windows-10"
dimensions: "pool:luci.r8.ci"
recipe {
name: "rex"
@@ -986,6 +1154,10 @@
expiration_secs: 126000
build_numbers: YES
service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.use_realms"
+ value: 100
+ }
}
}
}
diff --git a/infra/config/global/generated/luci-logdog.cfg b/infra/config/global/generated/luci-logdog.cfg
new file mode 100644
index 0000000..57dada0
--- /dev/null
+++ b/infra/config/global/generated/luci-logdog.cfg
@@ -0,0 +1,9 @@
+# Auto-generated by lucicfg.
+# Do not modify manually.
+#
+# For the schema of this file, see ProjectConfig message:
+# https://luci-config.appspot.com/schemas/projects:luci-logdog.cfg
+
+reader_auth_groups: "all"
+writer_auth_groups: "luci-logdog-r8-writers"
+archive_gs_bucket: "logdog-r8-archive"
diff --git a/infra/config/global/generated/luci-milo.cfg b/infra/config/global/generated/luci-milo.cfg
index 736c8cc..a48c9aa 100644
--- a/infra/config/global/generated/luci-milo.cfg
+++ b/infra/config/global/generated/luci-milo.cfg
@@ -8,212 +8,82 @@
id: "main"
name: "R8 Main Console"
repo_url: "https://r8.googlesource.com/r8"
- refs: "regexp:regexp:refs/heads/.*"
+ refs: "regexp:refs/heads/.*"
manifest_name: "REVISION"
builders {
- name: "buildbucket/luci.r8.ci/linux-d8_jctf"
- category: "R8"
- short_name: "d8_jctf"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-r8cf_jctf"
- category: "R8"
- short_name: "r8cf_jctf"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-d8_jctf_release"
- category: "R8 release"
- short_name: "d8_jctf_release"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-r8cf_jctf_release"
- category: "R8 release"
- short_name: "r8cf_jctf_release"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-run-on-app-dump"
- category: "R8"
- short_name: "dump"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-run-on-app-dump_release"
- category: "R8 release"
- short_name: "dump_release"
- }
- builders {
- name: "buildbucket/luci.r8.ci/desugared_library_head"
- category: "R8"
- short_name: "desugared_library_head"
- }
- builders {
- name: "buildbucket/luci.r8.ci/desugared_library_jdk11_head"
- category: "R8"
- short_name: "desugared_library_jdk11_head"
- }
- builders {
name: "buildbucket/luci.r8.ci/archive"
- category: "R8"
+ category: "archive"
short_name: "archive"
}
builders {
- name: "buildbucket/luci.r8.ci/archive_release"
- category: "R8 release"
- short_name: "archive_release"
- }
- builders {
- name: "buildbucket/luci.r8.ci/archive_lib_desugar"
- category: "R8"
- short_name: "archive_lib_desugar"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-internal"
- category: "R8"
- short_name: "internal"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-internal_release"
- category: "R8 release"
- short_name: "internal_release"
- }
- builders {
name: "buildbucket/luci.r8.ci/linux-dex_default"
category: "R8"
short_name: "dex_default"
}
builders {
- name: "buildbucket/luci.r8.ci/linux-dex_default_release"
- category: "R8 release"
- short_name: "dex_default_release"
- }
- builders {
name: "buildbucket/luci.r8.ci/linux-none"
category: "R8"
short_name: "none"
}
builders {
- name: "buildbucket/luci.r8.ci/linux-none_release"
- category: "R8 release"
- short_name: "none_release"
- }
- builders {
name: "buildbucket/luci.r8.ci/linux-jdk8"
category: "R8"
short_name: "jdk8"
}
builders {
- name: "buildbucket/luci.r8.ci/linux-jdk8_release"
- category: "R8 release"
- short_name: "jdk8_release"
- }
- builders {
name: "buildbucket/luci.r8.ci/linux-jdk9"
category: "R8"
short_name: "jdk9"
}
builders {
- name: "buildbucket/luci.r8.ci/linux-jdk9_release"
- category: "R8 release"
- short_name: "jdk9_release"
- }
- builders {
name: "buildbucket/luci.r8.ci/linux-jdk11"
category: "R8"
short_name: "jdk11"
}
builders {
- name: "buildbucket/luci.r8.ci/linux-jdk11_release"
- category: "R8 release"
- short_name: "jdk11_release"
- }
- builders {
name: "buildbucket/luci.r8.ci/linux-android-4.0.4"
category: "R8"
short_name: "4.0.4"
}
builders {
- name: "buildbucket/luci.r8.ci/linux-android-4.0.4_release"
- category: "R8 release"
- short_name: "4.0.4_release"
- }
- builders {
name: "buildbucket/luci.r8.ci/linux-android-4.4.4"
category: "R8"
short_name: "4.4.4"
}
builders {
- name: "buildbucket/luci.r8.ci/linux-android-4.4.4_release"
- category: "R8 release"
- short_name: "4.4.4_release"
- }
- builders {
name: "buildbucket/luci.r8.ci/linux-android-5.1.1"
category: "R8"
short_name: "5.1.1"
}
builders {
- name: "buildbucket/luci.r8.ci/linux-android-5.1.1_release"
- category: "R8 release"
- short_name: "5.1.1_release"
- }
- builders {
name: "buildbucket/luci.r8.ci/linux-android-6.0.1"
category: "R8"
short_name: "6.0.1"
}
builders {
- name: "buildbucket/luci.r8.ci/linux-android-6.0.1_release"
- category: "R8 release"
- short_name: "6.0.1_release"
- }
- builders {
name: "buildbucket/luci.r8.ci/linux-android-7.0.0"
category: "R8"
short_name: "7.0.0"
}
builders {
- name: "buildbucket/luci.r8.ci/linux-android-7.0.0_release"
- category: "R8 release"
- short_name: "7.0.0_release"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-android=8.1.0"
+ name: "buildbucket/luci.r8.ci/linux-android-8.1.0"
category: "R8"
- short_name: "android=8.1.0"
+ short_name: "8.1.0"
}
builders {
- name: "buildbucket/luci.r8.ci/linux-android=8.1.0_release"
- category: "R8 release"
- short_name: "android=8.1.0_release"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-android=9.0.0"
+ name: "buildbucket/luci.r8.ci/linux-android-9.0.0"
category: "R8"
- short_name: "android=9.0.0"
+ short_name: "9.0.0"
}
builders {
- name: "buildbucket/luci.r8.ci/linux-android=9.0.0_release"
- category: "R8 release"
- short_name: "android=9.0.0_release"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-android=10.0.0"
+ name: "buildbucket/luci.r8.ci/linux-android-10.0.0"
category: "R8"
- short_name: "android=10.0.0"
+ short_name: "10.0.0"
}
builders {
- name: "buildbucket/luci.r8.ci/linux-android=10.0.0_release"
- category: "R8 release"
- short_name: "android=10.0.0_release"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-android=12.0.0"
+ name: "buildbucket/luci.r8.ci/linux-android-12.0.0"
category: "R8"
- short_name: "android=12.0.0"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-android=12.0.0_release"
- category: "R8 release"
- short_name: "android=12.0.0_release"
+ short_name: "12.0.0"
}
builders {
name: "buildbucket/luci.r8.ci/windows"
@@ -221,13 +91,143 @@
short_name: "windows"
}
builders {
- name: "buildbucket/luci.r8.ci/windows_release"
- category: "R8 release"
- short_name: "windows_release"
+ name: "buildbucket/luci.r8.ci/linux-internal"
+ category: "R8"
+ short_name: "internal"
}
builders {
- name: "buildbucket/luci.r8.ci/linux-kotlin-dev"
+ name: "buildbucket/luci.r8.ci/linux-run-on-app-dump"
category: "R8"
- short_name: "dev"
+ short_name: "dump"
+ }
+ builders {
+ name: "buildbucket/luci.r8.ci/linux-kotlin_dev"
+ category: "R8"
+ short_name: "kotlin_dev"
+ }
+ builders {
+ name: "buildbucket/luci.r8.ci/linux-d8_jctf"
+ category: "jctf"
+ short_name: "d8_jctf"
+ }
+ builders {
+ name: "buildbucket/luci.r8.ci/linux-r8cf_jctf"
+ category: "jctf"
+ short_name: "r8cf_jctf"
+ }
+ builders {
+ name: "buildbucket/luci.r8.ci/lib_desugar-archive"
+ category: "library_desugar"
+ short_name: "archive"
+ }
+ builders {
+ name: "buildbucket/luci.r8.ci/desugared_library-head"
+ category: "library_desugar"
+ short_name: "head"
+ }
+ builders {
+ name: "buildbucket/luci.r8.ci/desugared_library-jdk11_head"
+ category: "library_desugar"
+ short_name: "jdk11_head"
+ }
+ builders {
+ name: "buildbucket/luci.r8.ci/archive_release"
+ category: "Release|archive"
+ short_name: "archive"
+ }
+ builders {
+ name: "buildbucket/luci.r8.ci/linux-dex_default_release"
+ category: "Release|R8"
+ short_name: "dex_default"
+ }
+ builders {
+ name: "buildbucket/luci.r8.ci/linux-none_release"
+ category: "Release|R8"
+ short_name: "none"
+ }
+ builders {
+ name: "buildbucket/luci.r8.ci/linux-jdk8_release"
+ category: "Release|R8"
+ short_name: "jdk8"
+ }
+ builders {
+ name: "buildbucket/luci.r8.ci/linux-jdk9_release"
+ category: "Release|R8"
+ short_name: "jdk9"
+ }
+ builders {
+ name: "buildbucket/luci.r8.ci/linux-jdk11_release"
+ category: "Release|R8"
+ short_name: "jdk11"
+ }
+ builders {
+ name: "buildbucket/luci.r8.ci/linux-android-4.0.4_release"
+ category: "Release|R8"
+ short_name: "4.0.4"
+ }
+ builders {
+ name: "buildbucket/luci.r8.ci/linux-android-4.4.4_release"
+ category: "Release|R8"
+ short_name: "4.4.4"
+ }
+ builders {
+ name: "buildbucket/luci.r8.ci/linux-android-5.1.1_release"
+ category: "Release|R8"
+ short_name: "5.1.1"
+ }
+ builders {
+ name: "buildbucket/luci.r8.ci/linux-android-6.0.1_release"
+ category: "Release|R8"
+ short_name: "6.0.1"
+ }
+ builders {
+ name: "buildbucket/luci.r8.ci/linux-android-7.0.0_release"
+ category: "Release|R8"
+ short_name: "7.0.0"
+ }
+ builders {
+ name: "buildbucket/luci.r8.ci/linux-android-8.1.0_release"
+ category: "Release|R8"
+ short_name: "8.1.0"
+ }
+ builders {
+ name: "buildbucket/luci.r8.ci/linux-android-9.0.0_release"
+ category: "Release|R8"
+ short_name: "9.0.0"
+ }
+ builders {
+ name: "buildbucket/luci.r8.ci/linux-android-10.0.0_release"
+ category: "Release|R8"
+ short_name: "10.0.0"
+ }
+ builders {
+ name: "buildbucket/luci.r8.ci/linux-android-12.0.0_release"
+ category: "Release|R8"
+ short_name: "12.0.0"
+ }
+ builders {
+ name: "buildbucket/luci.r8.ci/windows_release"
+ category: "Release|R8"
+ short_name: "windows"
+ }
+ builders {
+ name: "buildbucket/luci.r8.ci/linux-internal_release"
+ category: "Release|R8"
+ short_name: "internal"
+ }
+ builders {
+ name: "buildbucket/luci.r8.ci/linux-run-on-app-dump_release"
+ category: "Release|R8"
+ short_name: "dump"
+ }
+ builders {
+ name: "buildbucket/luci.r8.ci/linux-d8_jctf_release"
+ category: "Release|jctf"
+ short_name: "d8_jctf"
+ }
+ builders {
+ name: "buildbucket/luci.r8.ci/linux-r8cf_jctf_release"
+ category: "Release|jctf"
+ short_name: "r8cf_jctf"
}
}
diff --git a/infra/config/global/generated/luci-notify.cfg b/infra/config/global/generated/luci-notify.cfg
index 8228f3e..c6af3c9 100644
--- a/infra/config/global/generated/luci-notify.cfg
+++ b/infra/config/global/generated/luci-notify.cfg
@@ -36,7 +36,7 @@
}
builders {
bucket: "ci"
- name: "desugared_library_head"
+ name: "desugared_library-head"
repository: "https://r8.googlesource.com/r8"
}
}
@@ -48,7 +48,55 @@
}
builders {
bucket: "ci"
- name: "desugared_library_jdk11_head"
+ name: "desugared_library-jdk11_head"
+ repository: "https://r8.googlesource.com/r8"
+ }
+}
+notifiers {
+ notifications {
+ on_failure: true
+ on_new_failure: true
+ notify_blamelist {}
+ }
+ builders {
+ bucket: "ci"
+ name: "linux-android-10.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-10.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-12.0.0"
+ repository: "https://r8.googlesource.com/r8"
+ }
+}
+notifiers {
+ notifications {
+ on_failure: true
+ on_new_failure: true
+ notify_blamelist {}
+ }
+ builders {
+ bucket: "ci"
+ name: "linux-android-12.0.0_release"
repository: "https://r8.googlesource.com/r8"
}
}
@@ -180,7 +228,7 @@
}
builders {
bucket: "ci"
- name: "linux-android=10.0.0"
+ name: "linux-android-8.1.0"
repository: "https://r8.googlesource.com/r8"
}
}
@@ -192,7 +240,7 @@
}
builders {
bucket: "ci"
- name: "linux-android=10.0.0_release"
+ name: "linux-android-8.1.0_release"
repository: "https://r8.googlesource.com/r8"
}
}
@@ -204,7 +252,7 @@
}
builders {
bucket: "ci"
- name: "linux-android=12.0.0"
+ name: "linux-android-9.0.0"
repository: "https://r8.googlesource.com/r8"
}
}
@@ -216,55 +264,7 @@
}
builders {
bucket: "ci"
- name: "linux-android=12.0.0_release"
- repository: "https://r8.googlesource.com/r8"
- }
-}
-notifiers {
- notifications {
- on_failure: true
- on_new_failure: true
- notify_blamelist {}
- }
- builders {
- bucket: "ci"
- name: "linux-android=8.1.0"
- repository: "https://r8.googlesource.com/r8"
- }
-}
-notifiers {
- notifications {
- on_failure: true
- on_new_failure: true
- notify_blamelist {}
- }
- builders {
- bucket: "ci"
- name: "linux-android=8.1.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=9.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=9.0.0_release"
+ name: "linux-android-9.0.0_release"
repository: "https://r8.googlesource.com/r8"
}
}
@@ -420,7 +420,7 @@
}
builders {
bucket: "ci"
- name: "linux-kotlin-dev"
+ name: "linux-kotlin_dev"
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 46abc44..e9b307f 100644
--- a/infra/config/global/generated/luci-scheduler.cfg
+++ b/infra/config/global/generated/luci-scheduler.cfg
@@ -6,6 +6,7 @@
job {
id: "archive"
+ realm: "ci"
acl_sets: "ci"
triggering_policy {
kind: GREEDY_BATCHING
@@ -19,21 +20,8 @@
}
}
job {
- id: "archive_lib_desugar"
- acl_sets: "ci"
- triggering_policy {
- kind: GREEDY_BATCHING
- max_concurrent_invocations: 3
- max_batch_size: 1
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "archive_lib_desugar"
- }
-}
-job {
id: "archive_release"
+ realm: "ci"
acl_sets: "ci"
triggering_policy {
kind: GREEDY_BATCHING
@@ -47,26 +35,112 @@
}
}
job {
- id: "desugared_library_head"
+ id: "desugared_library-head"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
- builder: "desugared_library_head"
+ builder: "desugared_library-head"
}
}
job {
- id: "desugared_library_jdk11_head"
+ id: "desugared_library-jdk11_head"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
- builder: "desugared_library_jdk11_head"
+ builder: "desugared_library-jdk11_head"
+ }
+}
+job {
+ id: "lib_desugar-archive"
+ realm: "ci"
+ acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 3
+ max_batch_size: 1
+ }
+ buildbucket {
+ server: "cr-buildbucket.appspot.com"
+ bucket: "luci.r8.ci"
+ builder: "lib_desugar-archive"
+ }
+}
+job {
+ id: "linux-android-10.0.0"
+ realm: "ci"
+ acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
+ buildbucket {
+ server: "cr-buildbucket.appspot.com"
+ bucket: "luci.r8.ci"
+ builder: "linux-android-10.0.0"
+ }
+}
+job {
+ id: "linux-android-10.0.0_release"
+ realm: "ci"
+ acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
+ buildbucket {
+ server: "cr-buildbucket.appspot.com"
+ bucket: "luci.r8.ci"
+ builder: "linux-android-10.0.0_release"
+ }
+}
+job {
+ id: "linux-android-12.0.0"
+ realm: "ci"
+ acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
+ buildbucket {
+ server: "cr-buildbucket.appspot.com"
+ bucket: "luci.r8.ci"
+ builder: "linux-android-12.0.0"
+ }
+}
+job {
+ id: "linux-android-12.0.0_release"
+ realm: "ci"
+ acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
+ buildbucket {
+ server: "cr-buildbucket.appspot.com"
+ bucket: "luci.r8.ci"
+ builder: "linux-android-12.0.0_release"
}
}
job {
id: "linux-android-4.0.4"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
@@ -75,7 +149,12 @@
}
job {
id: "linux-android-4.0.4_release"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
@@ -84,7 +163,12 @@
}
job {
id: "linux-android-4.4.4"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
@@ -93,7 +177,12 @@
}
job {
id: "linux-android-4.4.4_release"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
@@ -102,7 +191,12 @@
}
job {
id: "linux-android-5.1.1"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
@@ -111,7 +205,12 @@
}
job {
id: "linux-android-5.1.1_release"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
@@ -120,7 +219,12 @@
}
job {
id: "linux-android-6.0.1"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
@@ -129,7 +233,12 @@
}
job {
id: "linux-android-6.0.1_release"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
@@ -138,7 +247,12 @@
}
job {
id: "linux-android-7.0.0"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
@@ -147,7 +261,12 @@
}
job {
id: "linux-android-7.0.0_release"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
@@ -155,80 +274,69 @@
}
}
job {
- id: "linux-android=10.0.0"
+ id: "linux-android-8.1.0"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
- builder: "linux-android=10.0.0"
+ builder: "linux-android-8.1.0"
}
}
job {
- id: "linux-android=10.0.0_release"
+ id: "linux-android-8.1.0_release"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
- builder: "linux-android=10.0.0_release"
+ builder: "linux-android-8.1.0_release"
}
}
job {
- id: "linux-android=12.0.0"
+ id: "linux-android-9.0.0"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
- builder: "linux-android=12.0.0"
+ builder: "linux-android-9.0.0"
}
}
job {
- id: "linux-android=12.0.0_release"
+ id: "linux-android-9.0.0_release"
+ realm: "ci"
acl_sets: "ci"
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-android=12.0.0_release"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
}
-}
-job {
- id: "linux-android=8.1.0"
- acl_sets: "ci"
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
- builder: "linux-android=8.1.0"
- }
-}
-job {
- id: "linux-android=8.1.0_release"
- acl_sets: "ci"
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-android=8.1.0_release"
- }
-}
-job {
- id: "linux-android=9.0.0"
- acl_sets: "ci"
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-android=9.0.0"
- }
-}
-job {
- id: "linux-android=9.0.0_release"
- acl_sets: "ci"
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-android=9.0.0_release"
+ builder: "linux-android-9.0.0_release"
}
}
job {
id: "linux-d8_jctf"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
@@ -237,7 +345,12 @@
}
job {
id: "linux-d8_jctf_release"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
@@ -246,7 +359,12 @@
}
job {
id: "linux-dex_default"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
@@ -255,7 +373,12 @@
}
job {
id: "linux-dex_default_release"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
@@ -264,11 +387,11 @@
}
job {
id: "linux-internal"
+ realm: "ci"
acl_sets: "ci"
triggering_policy {
kind: GREEDY_BATCHING
max_concurrent_invocations: 1
- max_batch_size: 1
}
buildbucket {
server: "cr-buildbucket.appspot.com"
@@ -278,11 +401,11 @@
}
job {
id: "linux-internal_release"
+ realm: "ci"
acl_sets: "ci"
triggering_policy {
kind: GREEDY_BATCHING
max_concurrent_invocations: 1
- max_batch_size: 1
}
buildbucket {
server: "cr-buildbucket.appspot.com"
@@ -292,7 +415,12 @@
}
job {
id: "linux-jdk11"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
@@ -301,7 +429,12 @@
}
job {
id: "linux-jdk11_release"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
@@ -310,7 +443,12 @@
}
job {
id: "linux-jdk8"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
@@ -319,7 +457,12 @@
}
job {
id: "linux-jdk8_release"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
@@ -328,7 +471,12 @@
}
job {
id: "linux-jdk9"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
@@ -337,7 +485,12 @@
}
job {
id: "linux-jdk9_release"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
@@ -345,17 +498,27 @@
}
}
job {
- id: "linux-kotlin-dev"
+ id: "linux-kotlin_dev"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
- builder: "linux-kotlin-dev"
+ builder: "linux-kotlin_dev"
}
}
job {
id: "linux-none"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
@@ -364,7 +527,12 @@
}
job {
id: "linux-none_release"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
@@ -373,7 +541,12 @@
}
job {
id: "linux-r8cf_jctf"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
@@ -382,7 +555,12 @@
}
job {
id: "linux-r8cf_jctf_release"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
@@ -391,7 +569,12 @@
}
job {
id: "linux-run-on-app-dump"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
@@ -400,7 +583,12 @@
}
job {
id: "linux-run-on-app-dump_release"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
@@ -409,7 +597,12 @@
}
job {
id: "windows"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
@@ -418,7 +611,12 @@
}
job {
id: "windows_release"
+ realm: "ci"
acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
@@ -427,17 +625,18 @@
}
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"
triggers: "linux-android-6.0.1_release"
triggers: "linux-android-7.0.0_release"
- triggers: "linux-android=10.0.0_release"
- triggers: "linux-android=12.0.0_release"
- triggers: "linux-android=8.1.0_release"
- triggers: "linux-android=9.0.0_release"
+ triggers: "linux-android-8.1.0_release"
+ triggers: "linux-android-9.0.0_release"
triggers: "linux-d8_jctf_release"
triggers: "linux-dex_default_release"
triggers: "linux-internal_release"
@@ -450,32 +649,33 @@
triggers: "windows_release"
gitiles {
repo: "https://r8.googlesource.com/r8"
- refs: "regexp:regexp:refs/heads/(?:d8-)?[0-9]+\\.[0-9]+(\\.[0-9]+)?"
+ refs: "regexp:refs/heads/(?:d8-)?[0-9]+\\.[0-9]+(\\.[0-9]+)?"
path_regexps: "src/main/java/com/android/tools/r8/Version.java"
}
}
trigger {
id: "main-gitiles-trigger"
+ realm: "ci"
acl_sets: "ci"
triggers: "archive"
- triggers: "desugared_library_head"
- triggers: "desugared_library_jdk11_head"
+ triggers: "desugared_library-head"
+ triggers: "desugared_library-jdk11_head"
+ triggers: "linux-android-10.0.0"
+ triggers: "linux-android-12.0.0"
triggers: "linux-android-4.0.4"
triggers: "linux-android-4.4.4"
triggers: "linux-android-5.1.1"
triggers: "linux-android-6.0.1"
triggers: "linux-android-7.0.0"
- triggers: "linux-android=10.0.0"
- triggers: "linux-android=12.0.0"
- triggers: "linux-android=8.1.0"
- triggers: "linux-android=9.0.0"
+ triggers: "linux-android-8.1.0"
+ triggers: "linux-android-9.0.0"
triggers: "linux-d8_jctf"
triggers: "linux-dex_default"
triggers: "linux-internal"
triggers: "linux-jdk11"
triggers: "linux-jdk8"
triggers: "linux-jdk9"
- triggers: "linux-kotlin-dev"
+ triggers: "linux-kotlin_dev"
triggers: "linux-none"
triggers: "linux-r8cf_jctf"
triggers: "linux-run-on-app-dump"
@@ -488,6 +688,14 @@
acl_sets {
name: "ci"
acls {
+ role: OWNER
+ granted_to: "luci-scheduler@appspot.gserviceaccount.com"
+ }
+ acls {
+ role: OWNER
+ granted_to: "group:project-r8-committers"
+ }
+ acls {
granted_to: "group:all"
}
}
diff --git a/infra/config/global/generated/realms.cfg b/infra/config/global/generated/realms.cfg
new file mode 100644
index 0000000..de02ce6
--- /dev/null
+++ b/infra/config/global/generated/realms.cfg
@@ -0,0 +1,67 @@
+# Auto-generated by lucicfg.
+# Do not modify manually.
+#
+# For the schema of this file, see RealmsCfg message:
+# https://luci-config.appspot.com/schemas/projects:realms.cfg
+
+realms {
+ name: "@root"
+ bindings {
+ role: "role/buildbucket.reader"
+ principals: "group:all"
+ }
+ bindings {
+ role: "role/buildbucket.triggerer"
+ principals: "group:project-r8-committers"
+ principals: "user:luci-scheduler@appspot.gserviceaccount.com"
+ }
+ bindings {
+ role: "role/configs.reader"
+ principals: "group:all"
+ }
+ bindings {
+ role: "role/logdog.reader"
+ principals: "group:all"
+ }
+ bindings {
+ role: "role/logdog.writer"
+ principals: "group:luci-logdog-r8-writers"
+ }
+ bindings {
+ role: "role/scheduler.owner"
+ principals: "group:project-r8-committers"
+ principals: "user:luci-scheduler@appspot.gserviceaccount.com"
+ }
+ bindings {
+ role: "role/scheduler.reader"
+ principals: "group:all"
+ }
+ bindings {
+ role: "role/swarming.poolOwner"
+ principals: "group:mdb/r8-team"
+ }
+ bindings {
+ role: "role/swarming.poolViewer"
+ principals: "group:googlers"
+ }
+}
+realms {
+ name: "ci"
+ bindings {
+ role: "role/buildbucket.builderServiceAccount"
+ principals: "user:r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ }
+ bindings {
+ role: "role/swarming.taskTriggerer"
+ principals: "group:mdb/chrome-troopers"
+ principals: "group:mdb/r8-team"
+ }
+}
+realms {
+ name: "pools/ci"
+ bindings {
+ role: "role/swarming.poolUser"
+ principals: "group:mdb/chrome-troopers"
+ principals: "group:mdb/r8-team"
+ }
+}
diff --git a/infra/config/global/luci-logdog.cfg b/infra/config/global/luci-logdog.cfg
deleted file mode 100644
index 985ab91..0000000
--- a/infra/config/global/luci-logdog.cfg
+++ /dev/null
@@ -1,14 +0,0 @@
-# For the schema of this file and documentation, see ProjectConfig message in
-# https://luci-config.appspot.com/schemas/services/luci-logdog:logdog.cfg
-# This is for the pdfium project, but we're going to piggyback
-# off of the chromium settings.
-
-# Auth groups who can read log streams.
-reader_auth_groups: "project-r8-readers"
-# Auth groups who can register and emit new log streams.
-writer_auth_groups: "luci-logdog-r8-writers"
-# The base Google Storage archival path for this project.
-#
-# Archived LogDog logs will be written to this bucket/path.
-archive_gs_bucket: "logdog-r8-archive"
-
diff --git a/infra/config/global/luci-milo.cfg b/infra/config/global/luci-milo.cfg
deleted file mode 100644
index 2dd3fcb..0000000
--- a/infra/config/global/luci-milo.cfg
+++ /dev/null
@@ -1,241 +0,0 @@
-consoles {
- id: "main_all"
- name: "R8 all"
- repo_url: "https://r8.googlesource.com/r8"
- refs: "regexp:refs/heads/.*"
- manifest_name: "REVISION"
-
- builders {
- name: "buildbucket/luci.r8.ci/archive"
- category: "archive"
- short_name: "archive"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-dex-default"
- category: "R8"
- short_name: "dex-default"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-none"
- category: "R8"
- short_name: "none"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-jdk8"
- category: "R8"
- short_name: "jdk8"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-jdk9"
- category: "R8"
- short_name: "jdk9"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-jdk11"
- category: "R8"
- short_name: "jdk11"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-android-4.0.4"
- category: "R8"
- short_name: "4.0.4"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-android-4.4.4"
- category: "R8"
- short_name: "4.4.4"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-android-5.1.1"
- category: "R8"
- short_name: "5.1.1"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-android-6.0.1"
- category: "R8"
- short_name: "6.0.1"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-android-7.0.0"
- category: "R8"
- short_name: "7.0.0"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-android-8.1.0"
- category: "R8"
- short_name: "8.1.0"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-android-9.0.0"
- category: "R8"
- short_name: "9.0.0"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-android-10.0.0"
- category: "R8"
- short_name: "10.0.0"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-android-12.0.0"
- category: "R8"
- short_name: "12.0.0"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-internal"
- category: "R8"
- short_name: "internal"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-run-on-app-dump"
- category: "R8"
- short_name: "apps-dump"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-jctf"
- category: "R8"
- short_name: "jctf"
- }
- builders {
- name: "buildbucket/luci.r8.ci/r8cf-linux-jctf"
- category: "R8"
- short_name: "cf-jctf"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-kotlin-dev"
- category: "R8"
- short_name: "kotlin-dev"
- }
- builders {
- name: "buildbucket/luci.r8.ci/windows"
- category: "win"
- short_name: "win"
- }
- builders {
- name: "buildbucket/luci.r8.ci/archive_lib_desugar"
- category: "library_desugar"
- short_name: "release"
- }
- builders {
- name: "buildbucket/luci.r8.ci/desugared_library_head"
- category: "library_desugar"
- short_name: "head"
- }
- builders {
- name: "buildbucket/luci.r8.ci/desugared_library_jdk11_head"
- category: "library_desugar"
- short_name: "head_jdk11"
- }
- builders {
- name: "buildbucket/luci.r8.ci/archive_release"
- category: "release archive"
- short_name: "archive"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-dex-default_release"
- category: "R8 release"
- short_name: "dex-default"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-none_release"
- category: "R8 release"
- short_name: "none"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-jdk8_release"
- category: "R8 release"
- short_name: "jdk8"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-jdk9_release"
- category: "R8 release"
- short_name: "jdk9"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-jdk11_release"
- category: "R8 release"
- short_name: "jdk11"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-android-4.0.4_release"
- category: "R8 release"
- short_name: "4.0.4"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-android-4.4.4_release"
- category: "R8 release"
- short_name: "4.4.4"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-android-5.1.1_release"
- category: "R8 release"
- short_name: "5.1.1"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-android-6.0.1_release"
- category: "R8 release"
- short_name: "6.0.1"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-android-7.0.0_release"
- category: "R8 release"
- short_name: "7.0.0"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-android-8.1.0_release"
- category: "R8 release"
- short_name: "8.1.0"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-android-9.0.0_release"
- category: "R8 release"
- short_name: "9.0.0"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-android-10.0.0_release"
- category: "R8 release"
- short_name: "10.0.0"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-android-12.0.0_release"
- category: "R8 release"
- short_name: "12.0.0"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-internal_release"
- category: "R8 release"
- short_name: "internal"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-run-on-app-dump_release"
- category: "R8 release"
- short_name: "apps-dump"
- }
- builders {
- name: "buildbucket/luci.r8.ci/r8cf-linux-jctf_release"
- category: "R8 release"
- short_name: "cf-jctf"
- }
- builders {
- name: "buildbucket/luci.r8.ci/linux-jctf_release"
- category: "R8 release"
- short_name: "jctf"
- }
- builders {
- name: "buildbucket/luci.r8.ci/windows_release"
- category: "win release"
- short_name: "win"
- }
-
-}
-consoles {
- id: "kotlin"
- name: "Kotlin"
- repo_url: "https://github.com/google/kotlin"
- refs: "regexp:refs/heads/.*"
- manifest_name: "REVISION"
- builders {
- name: "buildbucket/luci.r8.ci/kotlin-builder"
- category: "kotlin"
- short_name: "kotlin_builder"
- }
-}
diff --git a/infra/config/global/luci-notify.cfg b/infra/config/global/luci-notify.cfg
deleted file mode 100644
index 2ed0fc7..0000000
--- a/infra/config/global/luci-notify.cfg
+++ /dev/null
@@ -1,191 +0,0 @@
-# Defines email notifications for builders.
-# See schema at
-# https://chromium.googlesource.com/infra/luci/luci-go/+/master/luci_notify/api/config/notify.proto
-#
-
-notifiers {
- name: "r8-failures"
- notifications {
- on_change: false
- on_success: false
- on_failure: true
- on_new_failure: true
- # This means send to all people on the blamelist!
- notify_blamelist {}
- }
- builders {
- name: "archive"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "archive_release"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "linux"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "linux-jdk8"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "linux-jdk9"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "linux_release"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "linux-android-4.0.4"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "linux-android-4.0.4_release"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "linux-android-4.4.4"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "linux-android-4.4.4_release"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "linux-android-5.1.1"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "linux-android-5.1.1_release"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "linux-android-6.0.1"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "linux-android-6.0.1_release"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "linux-android-7.0.0"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "linux-android-7.0.0_release"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "linux-android-8.1.0"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "linux-android-8.1.0_release"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "linux-android-9.0.0"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "linux-android-9.0.0_release"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "linux-android-10.0.0"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "linux-android-10.0.0_release"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "linux-android-12.0.0"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "linux-android-12.0.0_release"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "linux-internal"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "linux-internal_release"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "linux-run-on-app-dump"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "linux-run-on-app-dump_release"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "linux-jctf"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "linux-jctf_release"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "r8cf-linux-jctf"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "r8cf-linux-jctf_release"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "linux-kotlin-dev"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "windows"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
- builders {
- name: "windows_release"
- bucket: "ci"
- repository: "https://r8.googlesource.com/r8"
- }
-}
diff --git a/infra/config/global/luci-scheduler.cfg b/infra/config/global/luci-scheduler.cfg
deleted file mode 100644
index 6af1a32..0000000
--- a/infra/config/global/luci-scheduler.cfg
+++ /dev/null
@@ -1,730 +0,0 @@
-# Defines jobs on luci-scheduler.appspot.com.
-#
-# For schema of this file and documentation see ProjectConfig message in
-#
-# https://chromium.googlesource.com/infra/luci/luci-go/+/master/scheduler/appengine/messages/config.proto
-
-acl_sets {
- name: "default"
- acls {
- role: READER
- granted_to: "group:project-r8-readers"
- }
- acls {
- role: OWNER
- granted_to: "group:project-r8-admins"
- }
-}
-
-# The format of this file is important, we have a hackish parsing to trigger
-# builds in tools/trigger.py
-trigger {
- id: "main-gitiles-trigger"
- acl_sets: "default"
- gitiles: {
- repo: "https://r8.googlesource.com/r8"
- refs: "refs/heads/main"
- }
- triggers: "archive"
- triggers: "linux-dex-default"
- triggers: "linux-none"
- triggers: "linux-jdk8"
- triggers: "linux-jdk9"
- triggers: "linux-jdk11"
- triggers: "linux-android-4.0.4"
- triggers: "linux-android-4.4.4"
- triggers: "linux-android-5.1.1"
- triggers: "linux-android-6.0.1"
- triggers: "linux-android-7.0.0"
- triggers: "linux-android-8.1.0"
- triggers: "linux-android-9.0.0"
- triggers: "linux-android-10.0.0"
- triggers: "linux-android-12.0.0"
- triggers: "linux-run-on-app-dump"
- triggers: "linux-internal"
- triggers: "linux-jctf"
- triggers: "r8cf-linux-jctf"
- triggers: "linux-kotlin-dev"
- triggers: "windows"
- triggers: "desugared_library_head"
- triggers: "desugared_library_jdk11_head"
-}
-
-trigger {
- id: "desugar_library_trigger"
- acl_sets: "default"
- gitiles: {
- repo: "https://github.googlesource.com/google/desugar_jdk_libs"
- refs: "refs/heads/master"
- }
- triggers: "archive_lib_desugar"
-}
-
-trigger {
- id: "kotlin_trigger"
- acl_sets: "default"
- gitiles: {
- repo: "https://github.googlesource.com/google/kotlin"
- refs: "refs/heads/google-ir"
- }
- triggers: "kotlin-builder"
-}
-
-trigger {
- id: "branch-gitiles-trigger"
- acl_sets: "default"
- gitiles: {
- 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: "regexp:refs/heads/(?:d8-)?[0-9]+\\.[0-9]+(\\.[0-9]+)?"
- path_regexps: "src/main/java/com/android/tools/r8/Version.java"
- }
- triggers: "archive_release"
- triggers: "linux-dex-default_release"
- triggers: "linux-none_release"
- triggers: "linux-jdk8_release"
- triggers: "linux-jdk9_release"
- triggers: "linux-jdk11_release"
- triggers: "linux-android-4.0.4_release"
- triggers: "linux-android-4.4.4_release"
- triggers: "linux-android-5.1.1_release"
- triggers: "linux-android-6.0.1_release"
- triggers: "linux-android-7.0.0_release"
- triggers: "linux-android-8.1.0_release"
- triggers: "linux-android-9.0.0_release"
- triggers: "linux-android-10.0.0_release"
- triggers: "linux-android-12.0.0_release"
- triggers: "linux-internal_release"
- triggers: "linux-jctf_release"
- triggers: "r8cf-linux-jctf_release"
- triggers: "windows_release"
-}
-
-trigger {
- id: "app-dump-gitiles-trigger"
- acl_sets: "default"
- gitiles: {
- repo: "https://r8.googlesource.com/r8"
- # Only trigger apps from 3.0 (this works until we reach version 10)
- refs: "regexp:refs/heads/[3-9]+\\.[0-9]+(\\.[0-9]+)?"
- path_regexps: "src/main/java/com/android/tools/r8/Version.java"
- }
- triggers: "linux-run-on-app-dump_release"
-}
-
-
-job {
- id: "archive"
- acl_sets: "default"
- triggering_policy: {
- max_concurrent_invocations: 3
- max_batch_size: 1
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "archive"
- }
-}
-
-job {
- id: "archive_release"
- acl_sets: "default"
- triggering_policy: {
- max_batch_size: 1
- max_concurrent_invocations: 3
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "archive_release"
- }
-}
-
-job {
- id: "archive_lib_desugar"
- acl_sets: "default"
- triggering_policy: {
- max_concurrent_invocations: 1
- max_batch_size: 1
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "archive_lib_desugar"
- }
-}
-
-job {
- id: "desugared_library_head"
- acl_sets: "default"
- triggering_policy: {
- max_concurrent_invocations: 1
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "desugared_library_head"
- }
-}
-
-job {
- id: "desugared_library_jdk11_head"
- acl_sets: "default"
- triggering_policy: {
- max_concurrent_invocations: 1
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "desugared_library_jdk11_head"
- }
-}
-
-job {
- id: "kotlin-builder"
- acl_sets: "default"
- triggering_policy: {
- max_concurrent_invocations: 1
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "kotlin-builder"
- }
-}
-
-job {
- id: "linux-dex-default"
- acl_sets: "default"
- triggering_policy: {
- kind: GREEDY_BATCHING
- max_concurrent_invocations: 6
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-dex-default"
- }
-}
-
-job {
- id: "linux-none"
- acl_sets: "default"
- triggering_policy: {
- kind: GREEDY_BATCHING
- max_concurrent_invocations: 6
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-none"
- }
-}
-
-job {
- id: "linux-jdk8"
- acl_sets: "default"
- triggering_policy: {
- kind: GREEDY_BATCHING
- max_concurrent_invocations: 2
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-jdk8"
- }
-}
-
-job {
- id: "linux-jdk8_release"
- acl_sets: "default"
- triggering_policy: {
- kind: GREEDY_BATCHING
- max_concurrent_invocations: 2
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-jdk8_release"
- }
-}
-
-job {
- id: "linux-jdk9"
- acl_sets: "default"
- triggering_policy: {
- kind: GREEDY_BATCHING
- max_concurrent_invocations: 2
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-jdk9"
- }
-}
-
-job {
- id: "linux-jdk9_release"
- acl_sets: "default"
- triggering_policy: {
- kind: GREEDY_BATCHING
- max_concurrent_invocations: 2
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-jdk9_release"
- }
-}
-
-job {
- id: "linux-jdk11"
- acl_sets: "default"
- triggering_policy: {
- kind: GREEDY_BATCHING
- max_concurrent_invocations: 2
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-jdk11"
- }
-}
-
-job {
- id: "linux-jdk11_release"
- acl_sets: "default"
- triggering_policy: {
- kind: GREEDY_BATCHING
- max_concurrent_invocations: 2
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-jdk11_release"
- }
-}
-
-job {
- id: "linux-android-4.0.4"
- acl_sets: "default"
- triggering_policy: {
- kind: GREEDY_BATCHING
- max_concurrent_invocations: 6
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-android-4.0.4"
- }
-}
-
-job {
- id: "linux-android-4.0.4_release"
- acl_sets: "default"
- triggering_policy: {
- max_batch_size: 1
- max_concurrent_invocations: 3
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-android-4.0.4_release"
- }
-}
-
-job {
- id: "linux-android-4.4.4"
- acl_sets: "default"
- triggering_policy: {
- kind: GREEDY_BATCHING
- max_concurrent_invocations: 6
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-android-4.4.4"
- }
-}
-
-job {
- id: "linux-android-4.4.4_release"
- acl_sets: "default"
- triggering_policy: {
- max_batch_size: 1
- max_concurrent_invocations: 3
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-android-4.4.4_release"
- }
-}
-
-job {
- id: "linux-android-5.1.1"
- acl_sets: "default"
- triggering_policy: {
- kind: GREEDY_BATCHING
- max_concurrent_invocations: 6
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-android-5.1.1"
- }
-}
-
-job {
- id: "linux-android-5.1.1_release"
- acl_sets: "default"
- triggering_policy: {
- max_batch_size: 1
- max_concurrent_invocations: 3
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-android-5.1.1_release"
- }
-}
-
-job {
- id: "linux-android-6.0.1"
- acl_sets: "default"
- triggering_policy: {
- kind: GREEDY_BATCHING
- max_concurrent_invocations: 6
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-android-6.0.1"
- }
-}
-
-job {
- id: "linux-android-6.0.1_release"
- acl_sets: "default"
- triggering_policy: {
- max_batch_size: 1
- max_concurrent_invocations: 3
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-android-6.0.1_release"
- }
-}
-
-job {
- id: "linux-android-7.0.0"
- acl_sets: "default"
- triggering_policy: {
- kind: GREEDY_BATCHING
- max_concurrent_invocations: 6
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-android-7.0.0"
- }
-}
-
-job {
- id: "linux-android-7.0.0_release"
- acl_sets: "default"
- triggering_policy: {
- max_batch_size: 1
- max_concurrent_invocations: 3
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-android-7.0.0_release"
- }
-}
-
-job {
- id: "linux-android-8.1.0"
- acl_sets: "default"
- triggering_policy: {
- kind: GREEDY_BATCHING
- max_concurrent_invocations: 6
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-android-8.1.0"
- }
-}
-
-job {
- id: "linux-android-8.1.0_release"
- acl_sets: "default"
- triggering_policy: {
- max_batch_size: 1
- max_concurrent_invocations: 3
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-android-8.1.0_release"
- }
-}
-
-
-job {
- id: "linux-android-9.0.0"
- acl_sets: "default"
- triggering_policy: {
- kind: GREEDY_BATCHING
- max_concurrent_invocations: 6
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-android-9.0.0"
- }
-}
-
-job {
- id: "linux-android-9.0.0_release"
- acl_sets: "default"
- triggering_policy: {
- max_batch_size: 1
- max_concurrent_invocations: 3
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-android-9.0.0_release"
- }
-}
-
-job {
- id: "linux-android-10.0.0"
- acl_sets: "default"
- triggering_policy: {
- kind: GREEDY_BATCHING
- max_concurrent_invocations: 6
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-android-10.0.0"
- }
-}
-
-job {
- id: "linux-android-10.0.0_release"
- acl_sets: "default"
- triggering_policy: {
- max_batch_size: 1
- max_concurrent_invocations: 3
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-android-10.0.0_release"
- }
-}
-
-job {
- id: "linux-android-12.0.0"
- acl_sets: "default"
- triggering_policy: {
- kind: GREEDY_BATCHING
- max_concurrent_invocations: 6
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-android-12.0.0"
- }
-}
-
-job {
- id: "linux-android-12.0.0_release"
- acl_sets: "default"
- triggering_policy: {
- max_batch_size: 1
- max_concurrent_invocations: 3
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-android-12.0.0_release"
- }
-}
-
-job {
- id: "linux-internal"
- acl_sets: "default"
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-internal"
- }
-}
-
-job {
- id: "linux-internal_release"
- acl_sets: "default"
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-internal_release"
- }
-}
-
-job {
- id: "linux-run-on-app-dump"
- acl_sets: "default"
- triggering_policy: {
- kind: GREEDY_BATCHING
- max_concurrent_invocations: 3
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-run-on-app-dump"
- }
-}
-
-job {
- id: "linux-run-on-app-dump_release"
- acl_sets: "default"
- triggering_policy: {
- max_batch_size: 1
- max_concurrent_invocations: 3
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-run-on-app-dump_release"
- }
-}
-
-job {
- id: "linux-jctf"
- acl_sets: "default"
- triggering_policy: {
- kind: GREEDY_BATCHING
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-jctf"
- }
-}
-
-job {
- id: "linux-jctf_release"
- acl_sets: "default"
- triggering_policy: {
- max_batch_size: 1
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-jctf_release"
- }
-}
-
-job {
- id: "linux-dex-default_release"
- acl_sets: "default"
- triggering_policy: {
- max_batch_size: 1
- max_concurrent_invocations: 3
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-dex-default_release"
- }
-}
-
-job {
- id: "linux-none_release"
- acl_sets: "default"
- triggering_policy: {
- max_batch_size: 1
- max_concurrent_invocations: 3
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-none_release"
- }
-}
-
-job {
- id: "r8cf-linux-jctf"
- acl_sets: "default"
- triggering_policy: {
- kind: GREEDY_BATCHING
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "r8cf-linux-jctf"
- }
-}
-
-job {
- id: "r8cf-linux-jctf_release"
- acl_sets: "default"
- triggering_policy: {
- max_batch_size: 1
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "r8cf-linux-jctf_release"
- }
-}
-
-job {
- id: "linux-kotlin-dev"
- acl_sets: "default"
- triggering_policy: {
- kind: GREEDY_BATCHING
- max_concurrent_invocations: 2
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "linux-kotlin-dev"
- }
-}
-
-job {
- id: "windows"
- triggering_policy: {
- kind: GREEDY_BATCHING
- max_concurrent_invocations: 3
- }
- acl_sets: "default"
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "windows"
- }
-}
-
-job {
- id: "windows_release"
- acl_sets: "default"
- triggering_policy: {
- max_batch_size: 1
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "luci.r8.ci"
- builder: "windows_release"
- }
-}
-
diff --git a/infra/config/global/main.star b/infra/config/global/main.star
index 5e790b5..0d94768 100755
--- a/infra/config/global/main.star
+++ b/infra/config/global/main.star
@@ -1,5 +1,14 @@
#!/usr/bin/env lucicfg
+lucicfg.check_version("1.28.0", "Please use newer `lucicfg` binary")
+
+# Enable LUCI Realms support.
+lucicfg.enable_experiment("crbug.com/1085650")
+
+# Launch 0% of Builds in "realms-aware mode"
+luci.builder.defaults.experiments.set({"luci.use_realms": 100})
+
+
luci.project(
name = "r8",
buildbucket = "cr-buildbucket.appspot.com",
@@ -21,6 +30,8 @@
acl.entry(
[
acl.BUILDBUCKET_TRIGGERER,
+ acl.SCHEDULER_OWNER,
+
],
groups = [
"project-r8-committers"
@@ -29,8 +40,54 @@
"luci-scheduler@appspot.gserviceaccount.com"
]
),
+ acl.entry(
+ [
+ acl.LOGDOG_WRITER,
+ ],
+ groups = [
+ "luci-logdog-r8-writers"
+ ],
+ ),
+ ],
+ bindings = [
+ luci.binding(
+ roles = "role/swarming.poolOwner",
+ groups = "mdb/r8-team",
+ ),
+ luci.binding(
+ roles = "role/swarming.poolViewer",
+ groups = "googlers",
+ ),
+ ],
+)
- ]
+luci.logdog(gs_bucket = "logdog-r8-archive")
+
+
+# Allow the given users to use LUCI `led` tool and "Debug" button
+# inside the given bucket & pool security realms.
+def led_users(*, pool_realm, builder_realm, groups):
+ luci.realm(
+ name = pool_realm,
+ bindings = [
+ luci.binding(
+ roles = "role/swarming.poolUser",
+ groups = groups,
+ ),
+ ],
+ )
+ luci.binding(
+ realm = builder_realm,
+ roles = "role/swarming.taskTriggerer",
+ groups = groups,
+ )
+led_users(
+ pool_realm="pools/ci",
+ builder_realm="ci",
+ groups=[
+ "mdb/r8-team",
+ "mdb/chrome-troopers",
+ ],
)
luci.bucket(name = "ci")
@@ -55,7 +112,7 @@
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 = ["regexp:refs/heads/(?:d8-)?[0-9]+\\.[0-9]+(\\.[0-9]+)?"],
+ refs = ["refs/heads/(?:d8-)?[0-9]+\\.[0-9]+(\\.[0-9]+)?"],
path_regexps = ["src/main/java/com/android/tools/r8/Version.java"]
)
@@ -63,16 +120,14 @@
name = "main",
title = "R8 Main Console",
repo = "https://r8.googlesource.com/r8",
- refs = ["regexp:refs/heads/.*"]
+ refs = ["refs/heads/.*"]
)
+
+view_builders = []
+
def builder_view(name, category, short_name):
- return luci.console_view_entry(
- console_view = "main",
- builder = name,
- category = category,
- short_name = short_name,
- )
+ view_builders.append((name, category, short_name))
luci.recipe(
name="rex",
@@ -96,7 +151,7 @@
"pool" : "luci.r8.ci"
}
if windows:
- dimensions["os"] = "windows-10"
+ dimensions["os"] = "Windows-10"
else:
dimensions["os"] = "Ubuntu-16.04"
if jctf:
@@ -107,10 +162,14 @@
dimensions["normal"] = "true"
return dimensions
-def r8_builder(name, priority=26, trigger=True, **kwargs):
+def r8_builder(name, priority=26, trigger=True, category=None,
+ triggering_policy=None, **kwargs):
release = name.endswith("release")
triggered = None if not trigger else ["branch-gitiles-trigger"] if release\
else ["main-gitiles-trigger"]
+ triggering_policy = triggering_policy or scheduler.policy(
+ kind = scheduler.GREEDY_BATCHING_KIND,
+ max_concurrent_invocations = 4)
luci.builder(
name = name,
@@ -122,21 +181,25 @@
notifies = ["r8-failures"] if trigger else None,
priority = priority,
triggered_by = triggered,
+ triggering_policy = triggering_policy,
executable = "rex",
**kwargs
)
- category = "R8 release" if release else "R8"
- builder_view(name, category, name.split("-")[-1])
+ category = category if category else "R8"
+ category = "Release|" + category if release else category
+ builder_view(name, category, name.split("-")[-1].replace("_release", ""))
def r8_tester(name,
test_options,
dimensions = None,
execution_timeout = time.hour * 6,
- expiration_timeout = time.hour * 35):
+ expiration_timeout = time.hour * 35,
+ category=None):
dimensions = dimensions if dimensions else get_dimensions(normal=True)
for name in [name, name + "_release"]:
r8_builder(
name = name,
+ category = category,
execution_timeout = execution_timeout,
expiration_timeout = expiration_timeout,
dimensions = dimensions,
@@ -146,28 +209,81 @@
}
)
-def r8_tester_with_default(name, test_options, dimensions=None):
- r8_tester(name, test_options + common_test_options, dimensions)
+def r8_tester_with_default(name, test_options, dimensions=None, category=None):
+ r8_tester(name, test_options + common_test_options,
+ dimensions = dimensions, category = category)
-def jctf():
- for release in ["", "_release"]:
- for tool in ["d8", "r8cf"]:
- properties = {
- "tool": tool,
- "builder_group" : "internal.client.r8",
- "dex_vm" : "all",
- "only_jctf" : "true",
- }
- name = "linux-" + tool + "_jctf"
- name = name + release
- r8_builder(
- name,
- dimensions = get_dimensions(jctf=True),
- execution_timeout = time.hour * 12,
- expiration_timeout = time.hour * 35,
- properties = properties,
- )
-jctf()
+def archivers():
+ for name in ["archive", "archive_release", "lib_desugar-archive"]:
+ desugar = "desugar" in name
+ properties = {
+ "test_wrapper" : "tools/archive_desugar_jdk_libs.py" if desugar else "tools/archive.py",
+ "builder_group" : "internal.client.r8"
+ }
+ r8_builder(
+ name,
+ category = "library_desugar" if desugar else "archive",
+ dimensions = get_dimensions(),
+ triggering_policy = scheduler.policy(
+ kind = scheduler.GREEDY_BATCHING_KIND,
+ max_batch_size = 1,
+ max_concurrent_invocations = 3
+ ),
+ priority = 25,
+ trigger = not desugar,
+ properties = properties,
+ execution_timeout = time.hour * 1 if desugar else time.minute * 30 ,
+ expiration_timeout = time.hour * 35,
+ )
+archivers()
+
+r8_tester_with_default("linux-dex_default", ["--runtimes=dex-default"])
+r8_tester_with_default("linux-none", ["--runtimes=none"])
+r8_tester_with_default("linux-jdk8", ["--runtimes=jdk8"])
+r8_tester_with_default("linux-jdk9", ["--runtimes=jdk9"])
+r8_tester_with_default("linux-jdk11", ["--runtimes=jdk11"])
+
+r8_tester_with_default("linux-android-4.0.4",
+ ["--dex_vm=4.0.4", "--all_tests"])
+r8_tester_with_default("linux-android-4.4.4",
+ ["--dex_vm=4.4.4", "--all_tests"])
+r8_tester_with_default("linux-android-5.1.1",
+ ["--dex_vm=5.1.1", "--all_tests"])
+r8_tester_with_default("linux-android-6.0.1",
+ ["--dex_vm=6.0.1", "--all_tests"])
+r8_tester_with_default("linux-android-7.0.0",
+ ["--dex_vm=7.0.0", "--all_tests"])
+r8_tester_with_default("linux-android-8.1.0",
+ ["--dex_vm=8.1.0", "--all_tests"])
+r8_tester_with_default("linux-android-9.0.0",
+ ["--dex_vm=9.0.0", "--all_tests"])
+r8_tester_with_default("linux-android-10.0.0",
+ ["--dex_vm=10.0.0", "--all_tests"])
+r8_tester_with_default("linux-android-12.0.0",
+ ["--dex_vm=12.0.0", "--all_tests"])
+
+r8_tester_with_default("windows", ["--all_tests"],
+ dimensions=get_dimensions(windows=True))
+
+def internal():
+ for name in ["linux-internal", "linux-internal_release"]:
+ r8_builder(
+ name,
+ dimensions = get_dimensions(internal=True),
+ triggering_policy = scheduler.policy(
+ kind = scheduler.GREEDY_BATCHING_KIND,
+ max_concurrent_invocations = 1
+ ),
+ priority = 25,
+ properties = {
+ "test_options" : ["--bot"],
+ "test_wrapper" : "tools/internal_test.py",
+ "builder_group" : "internal.client.r8"
+ },
+ execution_timeout = time.hour * 12,
+ expiration_timeout = time.hour * 35,
+ )
+internal()
def app_dump():
for release in ["", "_release"]:
@@ -195,9 +311,10 @@
"builder_group" : "internal.client.r8",
"test_options" : test_options,
}
- name = "desugared_library_" + name
+ name = "desugared_library-" + name
r8_builder(
name,
+ category = "library_desugar",
dimensions = get_dimensions(),
execution_timeout = time.hour * 12,
expiration_timeout = time.hour * 35,
@@ -205,81 +322,8 @@
)
desugared_library()
-def archivers():
- for name in ["archive", "archive_release", "archive_lib_desugar"]:
- desugar = "desugar" in name
- properties = {
- "archive": "true",
- "builder_group" : "internal.client.r8"
- }
- if desugar:
- properties["sdk_desugar"] = "true"
- r8_builder(
- name,
- dimensions = get_dimensions(),
- triggering_policy = scheduler.policy(
- kind = scheduler.GREEDY_BATCHING_KIND,
- max_batch_size = 1,
- max_concurrent_invocations = 3
- ),
- priority = 25,
- trigger = not desugar,
- properties = properties,
- execution_timeout = time.hour * 1 if desugar else time.minute * 30 ,
- expiration_timeout = time.hour * 35,
- )
-archivers()
-
-def internal():
- for name in ["linux-internal", "linux-internal_release"]:
- r8_builder(
- name,
- dimensions = get_dimensions(internal=True),
- triggering_policy = scheduler.policy(
- kind = scheduler.GREEDY_BATCHING_KIND,
- max_batch_size = 1,
- max_concurrent_invocations = 1
- ),
- priority = 25,
- properties = {
- "internal": "true",
- "builder_group" : "internal.client.r8"
- },
- execution_timeout = time.hour * 12,
- expiration_timeout = time.hour * 35,
- )
-internal()
-
-r8_tester_with_default("linux-dex_default", ["--runtimes=dex-default"])
-r8_tester_with_default("linux-none", ["--runtimes=none"])
-r8_tester_with_default("linux-jdk8", ["--runtimes=jdk8"])
-r8_tester_with_default("linux-jdk9", ["--runtimes=jdk9"])
-r8_tester_with_default("linux-jdk11", ["--runtimes=jdk11"])
-
-r8_tester_with_default("linux-android-4.0.4",
- ["--dex_vm=4.0.4", "--all_tests"])
-r8_tester_with_default("linux-android-4.4.4",
- ["--dex_vm=4.4.4", "--all_tests"])
-r8_tester_with_default("linux-android-5.1.1",
- ["--dex_vm=5.1.1", "--all_tests"])
-r8_tester_with_default("linux-android-6.0.1",
- ["--dex_vm=6.0.1", "--all_tests"])
-r8_tester_with_default("linux-android-7.0.0",
- ["--dex_vm=7.0.0", "--all_tests"])
-r8_tester_with_default("linux-android=8.1.0",
- ["--dex_vm=8.1.0", "--all_tests"])
-r8_tester_with_default("linux-android=9.0.0",
- ["--dex_vm=9.0.0", "--all_tests"])
-r8_tester_with_default("linux-android=10.0.0",
- ["--dex_vm=10.0.0", "--all_tests"])
-r8_tester_with_default("linux-android=12.0.0",
- ["--dex_vm=12.0.0", "--all_tests"])
-
-r8_tester_with_default("windows", ["--all_tests"],
- dimensions=get_dimensions(windows=True))
-
r8_builder(
- "linux-kotlin-dev",
+ "linux-kotlin_dev",
dimensions = get_dimensions(),
execution_timeout = time.hour * 12,
expiration_timeout = time.hour * 35,
@@ -288,3 +332,52 @@
"test_options" : ["--runtimes=dex-default:jdk11", "--kotlin-compiler-dev", "--one_line_per_test", "--archive_failures", "--no-internal", "*kotlin*"]
}
)
+
+def jctf():
+ for release in ["", "_release"]:
+ for tool in ["d8", "r8cf"]:
+ properties = {
+ "test_options" : [
+ "--no_internal",
+ "--one_line_per_test",
+ "--archive_failures",
+ "--dex_vm=all",
+ "--tool=" + tool,
+ "--only_jctf"],
+ "builder_group" : "internal.client.r8",
+ }
+ name = "linux-" + tool + "_jctf" + release
+ r8_builder(
+ name,
+ category = "jctf",
+ dimensions = get_dimensions(jctf=True),
+ execution_timeout = time.hour * 12,
+ expiration_timeout = time.hour * 35,
+ properties = properties,
+ )
+jctf()
+
+order_of_categories = [
+ "archive",
+ "R8",
+ "jctf",
+ "library_desugar",
+ "Release|archive",
+ "Release|R8",
+ "Release|jctf"
+]
+
+def add_view_entries():
+ # Ensure that all categories are ordered
+ for v in view_builders:
+ if not v[1] in order_of_categories:
+ fail()
+ for category in order_of_categories:
+ for v in [x for x in view_builders if x[1] == category]:
+ luci.console_view_entry(
+ console_view = "main",
+ builder = v[0],
+ category = v[1],
+ short_name = v[2]
+ )
+add_view_entries()
\ No newline at end of file
diff --git a/infra/config/global/project.cfg b/infra/config/global/project.cfg
deleted file mode 100644
index 4ae5cd5..0000000
--- a/infra/config/global/project.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-# For the schema of this file and documentation, see ProjectCfg message in
-# https://luci-config.appspot.com/schemas/projects:project.cfg
-name: "r8"
-access: "group:all" # public
-
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 65a9a2f..22dd97f 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -26,7 +26,6 @@
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexCode;
import com.android.tools.r8.graph.DexDebugEvent;
-import com.android.tools.r8.graph.DexDefinition;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
@@ -37,6 +36,7 @@
import com.android.tools.r8.graph.GenericSignatureCorrectnessHelper;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
+import com.android.tools.r8.graph.ProgramDefinition;
import com.android.tools.r8.graph.PrunedItems;
import com.android.tools.r8.graph.SubtypingInfo;
import com.android.tools.r8.graph.analysis.ClassInitializerAssertionEnablingAnalysis;
@@ -50,13 +50,10 @@
import com.android.tools.r8.ir.desugar.CfClassSynthesizerDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterLibraryTypeSynthesizer;
import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
-import com.android.tools.r8.ir.desugar.records.RecordRewriter;
+import com.android.tools.r8.ir.desugar.records.RecordDesugaring;
import com.android.tools.r8.ir.optimize.AssertionsRewriter;
-import com.android.tools.r8.ir.optimize.MethodPoolCollection;
import com.android.tools.r8.ir.optimize.NestReducer;
import com.android.tools.r8.ir.optimize.SwitchMapCollector;
-import com.android.tools.r8.ir.optimize.UninstantiatedTypeOptimization;
-import com.android.tools.r8.ir.optimize.UninstantiatedTypeOptimization.UninstantiatedTypeOptimizationGraphLens;
import com.android.tools.r8.ir.optimize.enums.EnumUnboxingCfMethods;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
import com.android.tools.r8.ir.optimize.templates.CfUtilityMethodsForCodeOptimizations;
@@ -318,7 +315,7 @@
EnumUnboxingCfMethods.registerSynthesizedCodeReferences(appView.dexItemFactory());
}
if (options.shouldDesugarRecords()) {
- RecordRewriter.registerSynthesizedCodeReferences(appView.dexItemFactory());
+ RecordDesugaring.registerSynthesizedCodeReferences(appView.dexItemFactory());
}
CfUtilityMethodsForCodeOptimizations.registerSynthesizedCodeReferences(
appView.dexItemFactory());
@@ -510,17 +507,6 @@
}
assert appView.verticallyMergedClasses() != null;
- if (options.enableUninstantiatedTypeOptimization) {
- timing.begin("UninstantiatedTypeOptimization");
- UninstantiatedTypeOptimizationGraphLens lens =
- new UninstantiatedTypeOptimization(appViewWithLiveness)
- .strenghtenOptimizationInfo()
- .run(new MethodPoolCollection(appViewWithLiveness), executorService, timing);
- assert lens == null || getDirectApp(appView).verifyNothingToRewrite(appView, lens);
- appView.rewriteWithLens(lens);
- timing.end();
- }
-
HorizontalClassMerger.createForInitialClassMerging(appViewWithLiveness)
.runIfNecessary(runtimeTypeCheckInfo, executorService, timing);
}
@@ -1060,11 +1046,12 @@
enqueuer.getGraphReporter().getGraphNode(reference), System.out);
}
}
- if (rootSet.checkDiscarded.isEmpty()
- || appView.options().testing.dontReportFailingCheckDiscarded) {
+ if (appView.options().testing.dontReportFailingCheckDiscarded) {
return;
}
- List<DexDefinition> failed = new DiscardedChecker(rootSet, classes.get()).run();
+ DiscardedChecker discardedChecker =
+ forMainDex ? DiscardedChecker.createForMainDex(appView) : DiscardedChecker.create(appView);
+ List<ProgramDefinition> failed = discardedChecker.run(classes.get(), executorService);
if (failed.isEmpty()) {
return;
}
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
index 08e18ca4..e469f0a 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
@@ -18,6 +18,7 @@
import com.android.tools.r8.StringResource;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.UnsupportedMainDexListUsageDiagnostic;
+import com.android.tools.r8.graph.ApplicationReaderMap;
import com.android.tools.r8.graph.ClassKind;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexApplicationReadFlags;
@@ -366,11 +367,13 @@
}
// Read the DexCode items and DexProgramClass items in parallel.
if (!options.skipReadingDexCode) {
+ ApplicationReaderMap applicationReaderMap = ApplicationReaderMap.getInstance(options);
for (DexParser<DexProgramClass> dexParser : dexParsers) {
futures.add(
executorService.submit(
() -> {
- dexParser.addClassDefsTo(classes::add); // Depends on Methods, Code items etc.
+ dexParser.addClassDefsTo(
+ classes::add, applicationReaderMap); // Depends on Methods, Code items etc.
}));
}
}
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
index 3b2c1df..6c02456 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -218,12 +218,12 @@
Collection<DexProgramClass> classes = appView.appInfo().classes();
Reference2LongMap<DexString> inputChecksums = new Reference2LongOpenHashMap<>(classes.size());
for (DexProgramClass clazz : classes) {
- inputChecksums.put(clazz.getType().descriptor, clazz.getChecksum());
+ inputChecksums.put(namingLens.lookupDescriptor(clazz.getType()), clazz.getChecksum());
}
for (VirtualFile file : files) {
ClassesChecksum toWrite = new ClassesChecksum();
for (DexProgramClass clazz : file.classes()) {
- DexString desc = clazz.type.descriptor;
+ DexString desc = namingLens.lookupDescriptor(clazz.type);
toWrite.addChecksum(desc.toString(), inputChecksums.getLong(desc));
}
file.injectString(appView.dexItemFactory().createString(toWrite.toJsonString()));
@@ -243,7 +243,7 @@
if (markers != null && !markers.isEmpty()) {
if (proguardMapId != null) {
- markers.get(0).setPgMapId(proguardMapId.get());
+ markers.get(0).setPgMapId(proguardMapId.getId());
}
markerStrings = new ArrayList<>(markers.size());
for (Marker marker : markers) {
diff --git a/src/main/java/com/android/tools/r8/dex/DexParser.java b/src/main/java/com/android/tools/r8/dex/DexParser.java
index 03c50c0..03e0e31 100644
--- a/src/main/java/com/android/tools/r8/dex/DexParser.java
+++ b/src/main/java/com/android/tools/r8/dex/DexParser.java
@@ -80,7 +80,6 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
-import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Supplier;
@@ -715,7 +714,7 @@
return methods;
}
- void addClassDefsTo(Consumer<T> classCollection) {
+ void addClassDefsTo(Consumer<T> classCollection, ApplicationReaderMap applicationReaderMap) {
final DexSection dexSection = lookupSection(Constants.TYPE_CLASS_DEF_ITEM);
final int length = dexSection.length;
indexedItems.initializeClasses(length);
@@ -768,7 +767,8 @@
Long checksum = null;
if (checksums != null && !checksums.isEmpty()) {
- String desc = type.toDescriptorString();
+ DexType originalType = applicationReaderMap.getInvertedType(type);
+ String desc = originalType.toDescriptorString();
checksum = checksums.getOrDefault(desc, null);
if (!options.dexClassChecksumFilter.test(desc, checksum)) {
continue;
@@ -1003,11 +1003,11 @@
private void populateTypes() {
DexSection dexSection = lookupSection(Constants.TYPE_TYPE_ID_ITEM);
assert verifyOrderOfTypeIds(dexSection);
- Map<DexType, DexType> typeMap = ApplicationReaderMap.getTypeMap(options);
+ ApplicationReaderMap applicationReaderMap = ApplicationReaderMap.getInstance(options);
indexedItems.initializeTypes(dexSection.length);
for (int i = 0; i < dexSection.length; i++) {
DexType type = typeAt(i);
- DexType actualType = typeMap.getOrDefault(type, type);
+ DexType actualType = applicationReaderMap.getType(type);
indexedItems.setType(i, actualType);
}
}
diff --git a/src/main/java/com/android/tools/r8/errors/CheckDiscardDiagnostic.java b/src/main/java/com/android/tools/r8/errors/CheckDiscardDiagnostic.java
index 67e74bf..ce54533 100644
--- a/src/main/java/com/android/tools/r8/errors/CheckDiscardDiagnostic.java
+++ b/src/main/java/com/android/tools/r8/errors/CheckDiscardDiagnostic.java
@@ -5,7 +5,7 @@
import com.android.tools.r8.Diagnostic;
import com.android.tools.r8.Keep;
-import com.android.tools.r8.graph.DexDefinition;
+import com.android.tools.r8.graph.ProgramDefinition;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.position.Position;
import com.android.tools.r8.shaking.GraphReporter;
@@ -24,15 +24,18 @@
private ImmutableList.Builder<String> messagesBuilder = ImmutableList.builder();
public Builder addFailedItems(
- List<DexDefinition> failed,
+ List<ProgramDefinition> failed,
GraphReporter graphReporter,
WhyAreYouKeepingConsumer whyAreYouKeepingConsumer) {
- for (DexDefinition definition : failed) {
+ for (ProgramDefinition definition : failed) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
whyAreYouKeepingConsumer.printWhyAreYouKeeping(
graphReporter.getGraphNode(definition.getReference()), new PrintStream(baos));
messagesBuilder.add(
- "Item " + definition.toSourceString() + " was not discarded.\n" + baos.toString());
+ "Item "
+ + definition.getReference().toSourceString()
+ + " was not discarded.\n"
+ + baos.toString());
}
return this;
}
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 0225c1d..99b9cb7 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -561,6 +561,10 @@
}
}
+ public boolean hasVerticallyMergedClasses() {
+ return verticallyMergedClasses != null;
+ }
+
/**
* Get the result of vertical class merging. Returns null if vertical class merging has not been
* run.
diff --git a/src/main/java/com/android/tools/r8/graph/ApplicationReaderMap.java b/src/main/java/com/android/tools/r8/graph/ApplicationReaderMap.java
index 5ce8224..496066b3 100644
--- a/src/main/java/com/android/tools/r8/graph/ApplicationReaderMap.java
+++ b/src/main/java/com/android/tools/r8/graph/ApplicationReaderMap.java
@@ -5,27 +5,65 @@
package com.android.tools.r8.graph;
import com.android.tools.r8.utils.InternalOptions;
-import com.google.common.collect.ImmutableMap;
-import java.util.Map;
-public class ApplicationReaderMap {
+public abstract class ApplicationReaderMap {
- public static Map<String, String> getDescriptorMap(InternalOptions options) {
- ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
+ public static ApplicationReaderMap INSTANCE;
+
+ public abstract String getDescriptor(String descriptor);
+
+ public abstract DexType getType(DexType type);
+
+ public abstract DexType getInvertedType(DexType type);
+
+ public static ApplicationReaderMap getInstance(InternalOptions options) {
if (options.shouldDesugarRecords() && !options.testing.disableRecordApplicationReaderMap) {
- builder.put(DexItemFactory.recordTagDescriptorString, DexItemFactory.recordDescriptorString);
+ return new RecordMap(options.dexItemFactory());
}
- return builder.build();
+ return new EmptyMap();
}
- public static Map<DexType, DexType> getTypeMap(InternalOptions options) {
- DexItemFactory factory = options.dexItemFactory();
- ImmutableMap.Builder<DexType, DexType> builder = ImmutableMap.builder();
- getDescriptorMap(options)
- .forEach(
- (k, v) -> {
- builder.put(factory.createType(k), factory.createType(v));
- });
- return builder.build();
+ public static class EmptyMap extends ApplicationReaderMap {
+
+ @Override
+ public String getDescriptor(String descriptor) {
+ return descriptor;
+ }
+
+ @Override
+ public DexType getType(DexType type) {
+ return type;
+ }
+
+ @Override
+ public DexType getInvertedType(DexType type) {
+ return type;
+ }
+ }
+
+ public static class RecordMap extends ApplicationReaderMap {
+
+ private final DexItemFactory factory;
+
+ public RecordMap(DexItemFactory factory) {
+ this.factory = factory;
+ }
+
+ @Override
+ public String getDescriptor(String descriptor) {
+ return descriptor.equals(DexItemFactory.recordTagDescriptorString)
+ ? DexItemFactory.recordDescriptorString
+ : descriptor;
+ }
+
+ @Override
+ public DexType getType(DexType type) {
+ return type == factory.recordTagType ? factory.recordType : type;
+ }
+
+ @Override
+ public DexType getInvertedType(DexType type) {
+ return type == factory.recordType ? factory.recordTagType : type;
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 82f09f8..450bc51 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -217,7 +217,7 @@
}
public int getNumberOfArguments() {
- return getReference().getArity() + BooleanUtils.intValue(isInstance());
+ return getReference().getNumberOfArguments(isStatic());
}
public CompilationState getCompilationState() {
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 82fa005..d31d8b7 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -2131,6 +2131,11 @@
return sb.toString();
}
+ public <T> T createFreshMember(
+ Function<DexString, Optional<T>> tryString, String baseName, DexType holder) {
+ return createFreshMember(tryString, baseName, holder, 0);
+ }
+
/**
* Find a fresh method name that is not used by any other method. The method name takes the form
* "basename$holdername" or "basename$holdername$index".
@@ -2138,15 +2143,16 @@
* @param tryString callback to check if the method name is in use.
*/
public <T> T createFreshMember(
- Function<DexString, Optional<T>> tryString, String baseName, DexType holder) {
- int index = 0;
+ Function<DexString, Optional<T>> tryString, String baseName, DexType holder, int index) {
+ int offset = 0;
while (true) {
- assert index < 1000;
- DexString name = createString(createMemberString(baseName, holder, index++));
+ assert offset < 1000;
+ DexString name = createString(createMemberString(baseName, holder, index + offset));
Optional<T> result = tryString.apply(name);
if (result.isPresent()) {
return result.get();
}
+ offset++;
}
}
@@ -2216,14 +2222,28 @@
return internalCreateFreshMethodNameWithHolder(baseName, holder, proto, target, isFresh);
}
+ public DexMethod createFreshMethodNameWithoutHolder(
+ String baseName, DexProto proto, DexType target, Predicate<DexMethod> isFresh) {
+ return createFreshMethodNameWithoutHolder(baseName, proto, target, isFresh, 0);
+ }
+
/**
* Tries to find a method name for insertion into the class {@code target} of the form baseName$n,
* where {@code baseName} is supplied by the user, and {@code n} is picked to be the first number
- * so that {@code isFresh.apply(method)} returns {@code true}.
+ * starting from {@param index} so that {@code isFresh.apply(method)} returns {@code true}.
*/
public DexMethod createFreshMethodNameWithoutHolder(
- String baseName, DexProto proto, DexType target, Predicate<DexMethod> isFresh) {
- return internalCreateFreshMethodNameWithHolder(baseName, null, proto, target, isFresh);
+ String baseName, DexProto proto, DexType target, Predicate<DexMethod> isFresh, int index) {
+ return internalCreateFreshMethodNameWithHolder(baseName, null, proto, target, isFresh, index);
+ }
+
+ private DexMethod internalCreateFreshMethodNameWithHolder(
+ String baseName,
+ DexType holder,
+ DexProto proto,
+ DexType target,
+ Predicate<DexMethod> isFresh) {
+ return internalCreateFreshMethodNameWithHolder(baseName, holder, proto, target, isFresh, 0);
}
/**
@@ -2235,7 +2255,8 @@
DexType holder,
DexProto proto,
DexType target,
- Predicate<DexMethod> isFresh) {
+ Predicate<DexMethod> isFresh,
+ int index) {
return createFreshMember(
name -> {
DexMethod tryMethod = createMethod(target, proto, name);
@@ -2246,7 +2267,8 @@
}
},
baseName,
- holder);
+ holder,
+ index);
}
/**
diff --git a/src/main/java/com/android/tools/r8/graph/DexMethod.java b/src/main/java/com/android/tools/r8/graph/DexMethod.java
index c2eeffa..d7f282f 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMethod.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.references.TypeReference;
+import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.StructuralMapping;
import com.android.tools.r8.utils.structural.StructuralSpecification;
@@ -69,6 +70,10 @@
return getParameter(argumentIndex - 1);
}
+ public int getNumberOfArguments(boolean isStatic) {
+ return getArity() + BooleanUtils.intValue(!isStatic);
+ }
+
public DexType getParameter(int index) {
return proto.getParameter(index);
}
diff --git a/src/main/java/com/android/tools/r8/graph/JarApplicationReader.java b/src/main/java/com/android/tools/r8/graph/JarApplicationReader.java
index 047be58..ca751d0 100644
--- a/src/main/java/com/android/tools/r8/graph/JarApplicationReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarApplicationReader.java
@@ -4,11 +4,10 @@
package com.android.tools.r8.graph;
import com.android.tools.r8.graph.DexMethodHandle.MethodHandleType;
-import com.android.tools.r8.ir.desugar.records.RecordRewriter;
+import com.android.tools.r8.ir.desugar.records.RecordDesugaring;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.InternalOptions;
import java.util.List;
-import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.objectweb.asm.Type;
@@ -25,13 +24,13 @@
private final ConcurrentHashMap<String, Type> asmObjectTypeCache = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, Type> asmTypeCache = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, DexString> stringCache = new ConcurrentHashMap<>();
- private final Map<String, String> typeDescriptorMap;
+ private final ApplicationReaderMap applicationReaderMap;
private boolean hasReadRecordReferenceFromProgramClass = false;
public JarApplicationReader(InternalOptions options) {
this.options = options;
- typeDescriptorMap = ApplicationReaderMap.getDescriptorMap(options);
+ applicationReaderMap = ApplicationReaderMap.getInstance(options);
}
public Type getAsmObjectType(String name) {
@@ -61,7 +60,7 @@
public DexType getTypeFromDescriptor(String desc) {
assert isValidDescriptor(desc);
- String actualDesc = typeDescriptorMap.getOrDefault(desc, desc);
+ String actualDesc = applicationReaderMap.getDescriptor(desc);
return options.itemFactory.createType(getString(actualDesc));
}
@@ -162,13 +161,14 @@
}
public void checkFieldForRecord(DexField dexField) {
- if (options.shouldDesugarRecords() && RecordRewriter.refersToRecord(dexField, getFactory())) {
+ if (options.shouldDesugarRecords() && RecordDesugaring.refersToRecord(dexField, getFactory())) {
setHasReadRecordReferenceFromProgramClass();
}
}
public void checkMethodForRecord(DexMethod dexMethod) {
- if (options.shouldDesugarRecords() && RecordRewriter.refersToRecord(dexMethod, getFactory())) {
+ if (options.shouldDesugarRecords()
+ && RecordDesugaring.refersToRecord(dexMethod, getFactory())) {
setHasReadRecordReferenceFromProgramClass();
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/NestedGraphLens.java b/src/main/java/com/android/tools/r8/graph/NestedGraphLens.java
index 1b49b31..00bd8bb 100644
--- a/src/main/java/com/android/tools/r8/graph/NestedGraphLens.java
+++ b/src/main/java/com/android/tools/r8/graph/NestedGraphLens.java
@@ -211,14 +211,19 @@
// unreachable.
DexMethod newMethod = methodMap.apply(previous.getReference());
if (newMethod == null) {
+ newMethod = previous.getReference();
+ }
+ RewrittenPrototypeDescription newPrototypeChanges =
+ internalDescribePrototypeChanges(previous.getPrototypeChanges(), newMethod);
+ if (newMethod == previous.getReference()
+ && newPrototypeChanges == previous.getPrototypeChanges()) {
return previous;
}
// TODO(sgjesse): Should we always do interface to virtual mapping? Is it a performance win
// that only subclasses which are known to need it actually do it?
return MethodLookupResult.builder(this)
.setReference(newMethod)
- .setPrototypeChanges(
- internalDescribePrototypeChanges(previous.getPrototypeChanges(), newMethod))
+ .setPrototypeChanges(newPrototypeChanges)
.setType(mapInvocationType(newMethod, previous.getReference(), previous.getType()))
.build();
}
diff --git a/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
index a4a886f..5328885 100644
--- a/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
+++ b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
@@ -4,11 +4,12 @@
package com.android.tools.r8.graph;
-import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.ir.analysis.value.SingleValue;
import com.android.tools.r8.ir.code.ConstInstruction;
import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.Position;
+import com.android.tools.r8.ir.code.TypeAndLocalInfoSupplier;
import com.android.tools.r8.ir.conversion.ExtraParameter;
import com.android.tools.r8.ir.conversion.ExtraUnusedNullParameter;
import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfoFixer;
@@ -183,26 +184,29 @@
private final DexType oldType;
private final DexType newType;
+ private final SingleValue singleValue;
- static RewrittenTypeInfo toVoid(DexType oldReturnType, DexItemFactory dexItemFactory) {
- return new RewrittenTypeInfo(oldReturnType, dexItemFactory.voidType);
+ public static RewrittenTypeInfo toVoid(
+ DexType oldReturnType, DexItemFactory dexItemFactory, SingleValue singleValue) {
+ assert singleValue != null;
+ return new RewrittenTypeInfo(oldReturnType, dexItemFactory.voidType, singleValue);
}
public RewrittenTypeInfo(DexType oldType, DexType newType) {
+ this(oldType, newType, null);
+ }
+
+ public RewrittenTypeInfo(DexType oldType, DexType newType, SingleValue singleValue) {
this.oldType = oldType;
this.newType = newType;
+ this.singleValue = singleValue;
+ assert !newType.isVoidType() || singleValue != null;
}
public RewrittenTypeInfo combine(RewrittenPrototypeDescription other) {
return other.hasRewrittenReturnInfo() ? combine(other.getRewrittenReturnInfo()) : this;
}
- public RewrittenTypeInfo combine(RewrittenTypeInfo other) {
- assert !getNewType().isVoidType();
- assert getNewType() == other.getOldType();
- return new RewrittenTypeInfo(getOldType(), other.getNewType());
- }
-
public DexType getNewType() {
return newType;
}
@@ -211,8 +215,16 @@
return oldType;
}
- boolean hasBeenChangedToReturnVoid(DexItemFactory dexItemFactory) {
- return newType == dexItemFactory.voidType;
+ public SingleValue getSingleValue() {
+ return singleValue;
+ }
+
+ boolean hasBeenChangedToReturnVoid() {
+ return newType.isVoidType();
+ }
+
+ public boolean hasSingleValue() {
+ return singleValue != null;
}
@Override
@@ -231,9 +243,13 @@
return info;
}
assert info.isRewrittenTypeInfo();
- RewrittenTypeInfo rewrittenTypeInfo = info.asRewrittenTypeInfo();
- assert newType == rewrittenTypeInfo.oldType;
- return new RewrittenTypeInfo(oldType, rewrittenTypeInfo.newType);
+ return combine(info.asRewrittenTypeInfo());
+ }
+
+ public RewrittenTypeInfo combine(RewrittenTypeInfo other) {
+ assert !getNewType().isVoidType();
+ assert getNewType() == other.getOldType();
+ return new RewrittenTypeInfo(getOldType(), other.getNewType(), other.getSingleValue());
}
@Override
@@ -242,12 +258,14 @@
return false;
}
RewrittenTypeInfo other = (RewrittenTypeInfo) obj;
- return oldType == other.oldType && newType == other.newType;
+ return oldType == other.oldType
+ && newType == other.newType
+ && Objects.equals(singleValue, other.singleValue);
}
@Override
public int hashCode() {
- return Objects.hash(oldType, newType);
+ return Objects.hash(oldType, newType, singleValue);
}
public boolean verifyIsDueToUnboxing(DexItemFactory dexItemFactory) {
@@ -549,18 +567,6 @@
: new RewrittenPrototypeDescription(extraParameters, rewrittenReturnInfo, argumentsInfo);
}
- public static RewrittenPrototypeDescription createForUninstantiatedTypes(
- DexMethod method,
- AppView<AppInfoWithLiveness> appView,
- ArgumentInfoCollection removedArgumentsInfo) {
- DexType returnType = method.proto.returnType;
- RewrittenTypeInfo returnInfo =
- returnType.isAlwaysNull(appView)
- ? RewrittenTypeInfo.toVoid(returnType, appView.dexItemFactory())
- : null;
- return create(Collections.emptyList(), returnInfo, removedArgumentsInfo);
- }
-
public static RewrittenPrototypeDescription createForRewrittenTypes(
RewrittenTypeInfo returnInfo, ArgumentInfoCollection rewrittenArgumentsInfo) {
return create(Collections.emptyList(), returnInfo, rewrittenArgumentsInfo);
@@ -622,9 +628,8 @@
return extraParameters.size();
}
- public boolean hasBeenChangedToReturnVoid(DexItemFactory dexItemFactory) {
- return rewrittenReturnInfo != null
- && rewrittenReturnInfo.hasBeenChangedToReturnVoid(dexItemFactory);
+ public boolean hasBeenChangedToReturnVoid() {
+ return rewrittenReturnInfo != null && rewrittenReturnInfo.hasBeenChangedToReturnVoid();
}
public ArgumentInfoCollection getArgumentInfoCollection() {
@@ -654,12 +659,29 @@
*
* <p>Note that the current implementation always returns null at this point.
*/
- public ConstInstruction getConstantReturn(IRCode code, Position position) {
- ConstInstruction instruction = code.createConstNull();
+ public Instruction getConstantReturn(
+ AppView<AppInfoWithLiveness> appView,
+ IRCode code,
+ ProgramMethod method,
+ Position position,
+ TypeAndLocalInfoSupplier info) {
+ assert rewrittenReturnInfo != null;
+ assert rewrittenReturnInfo.hasSingleValue();
+ assert rewrittenReturnInfo.getSingleValue().isMaterializableInContext(appView, method);
+ Instruction instruction =
+ rewrittenReturnInfo.getSingleValue().createMaterializingInstruction(appView, code, info);
instruction.setPosition(position);
return instruction;
}
+ public DexMethod rewriteMethod(ProgramMethod method, DexItemFactory dexItemFactory) {
+ if (isEmpty()) {
+ return method.getReference();
+ }
+ DexProto rewrittenProto = rewriteProto(method.getDefinition(), dexItemFactory);
+ return method.getReference().withProto(rewrittenProto, dexItemFactory);
+ }
+
public DexProto rewriteProto(DexEncodedMethod encodedMethod, DexItemFactory dexItemFactory) {
if (isEmpty()) {
return encodedMethod.getReference().proto;
@@ -672,39 +694,13 @@
return dexItemFactory.createProto(newReturnType, newParameters);
}
- public RewrittenPrototypeDescription withConstantReturn(
- DexType oldReturnType, DexItemFactory dexItemFactory) {
- assert rewrittenReturnInfo == null;
- return !hasBeenChangedToReturnVoid(dexItemFactory)
- ? new RewrittenPrototypeDescription(
- extraParameters,
- RewrittenTypeInfo.toVoid(oldReturnType, dexItemFactory),
- argumentInfoCollection)
- : this;
- }
-
- public RewrittenPrototypeDescription withRemovedArguments(ArgumentInfoCollection other) {
- if (other.isEmpty()) {
+ public RewrittenPrototypeDescription withRewrittenReturnInfo(
+ RewrittenTypeInfo newRewrittenReturnInfo) {
+ if (Objects.equals(rewrittenReturnInfo, newRewrittenReturnInfo)) {
return this;
}
return new RewrittenPrototypeDescription(
- extraParameters, rewrittenReturnInfo, argumentInfoCollection.combine(other));
- }
-
- public RewrittenPrototypeDescription withRewrittenReturnInfo(
- RewrittenTypeInfo rewrittenReturnInfo) {
- if (rewrittenReturnInfo == null) {
- return this;
- }
- if (!hasRewrittenReturnInfo()) {
- return new RewrittenPrototypeDescription(
- extraParameters, rewrittenReturnInfo, argumentInfoCollection);
- }
- throw new Unreachable();
- }
-
- public RewrittenPrototypeDescription withExtraUnusedNullParameter() {
- return withExtraUnusedNullParameters(1);
+ extraParameters, newRewrittenReturnInfo, argumentInfoCollection);
}
public RewrittenPrototypeDescription withExtraUnusedNullParameters(
@@ -714,10 +710,6 @@
return withExtraParameters(parameters);
}
- public RewrittenPrototypeDescription withExtraParameter(ExtraParameter parameter) {
- return withExtraParameters(Collections.singletonList(parameter));
- }
-
public RewrittenPrototypeDescription withExtraParameters(List<ExtraParameter> parameters) {
if (parameters.isEmpty()) {
return this;
diff --git a/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescriptionMethodOptimizationInfoFixer.java b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescriptionMethodOptimizationInfoFixer.java
index 4c869ef..e25d391 100644
--- a/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescriptionMethodOptimizationInfoFixer.java
+++ b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescriptionMethodOptimizationInfoFixer.java
@@ -162,7 +162,7 @@
return bitSet;
}
int n = bitSet.length();
- BitSet rewrittenNonNullParamOnNormalExits = new BitSet(n);
+ BitSet rewrittenBitSet = new BitSet(n);
for (int argumentIndex = 0; argumentIndex < n; argumentIndex++) {
if (!bitSet.get(argumentIndex)) {
continue;
@@ -171,9 +171,8 @@
if (argumentInfo.isRemovedArgumentInfo() || argumentInfo.isRewrittenTypeInfo()) {
continue;
}
- rewrittenNonNullParamOnNormalExits.set(
- getArgumentInfoCollection().getNewArgumentIndex(argumentIndex));
+ rewrittenBitSet.set(getArgumentInfoCollection().getNewArgumentIndex(argumentIndex));
}
- return rewrittenNonNullParamOnNormalExits.isEmpty() ? null : rewrittenNonNullParamOnNormalExits;
+ return rewrittenBitSet.isEmpty() ? null : rewrittenBitSet;
}
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
index eea0202..162ad98 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.horizontalclassmerging.policies.LimitClassGroups;
import com.android.tools.r8.horizontalclassmerging.policies.MinimizeInstanceFieldCasts;
import com.android.tools.r8.horizontalclassmerging.policies.NoAnnotationClasses;
+import com.android.tools.r8.horizontalclassmerging.policies.NoCheckDiscard;
import com.android.tools.r8.horizontalclassmerging.policies.NoClassAnnotationCollisions;
import com.android.tools.r8.horizontalclassmerging.policies.NoClassInitializerWithObservableSideEffects;
import com.android.tools.r8.horizontalclassmerging.policies.NoConstructorCollisions;
@@ -103,6 +104,7 @@
ImmutableList.Builder<SingleClassPolicy> builder) {
builder.add(
new CheckSyntheticClasses(appView),
+ new NoCheckDiscard(appView),
new NoKeepRules(appView),
new NoClassInitializerWithObservableSideEffects());
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java
index 3251db1..b3d27a5 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java
@@ -20,7 +20,7 @@
import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.RewrittenPrototypeDescription;
import com.android.tools.r8.graph.UseRegistry;
@@ -258,7 +258,7 @@
classInitializer.getOrigin(),
RewrittenPrototypeDescription.none());
- DexType downcast = null;
+ DexProgramClass downcast = null;
instructionIterator.previous();
instructionIterator.inlineInvoke(
appView, code, inliningIR, blockIterator, blocksToRemove, downcast);
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoCheckDiscard.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoCheckDiscard.java
new file mode 100644
index 0000000..1266e1d
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoCheckDiscard.java
@@ -0,0 +1,33 @@
+// 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.horizontalclassmerging.policies;
+
+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.horizontalclassmerging.SingleClassPolicy;
+import com.android.tools.r8.shaking.KeepInfoCollection;
+import com.android.tools.r8.utils.InternalOptions;
+
+public class NoCheckDiscard extends SingleClassPolicy {
+
+ private final KeepInfoCollection keepInfo;
+ private final InternalOptions options;
+
+ public NoCheckDiscard(AppView<? extends AppInfoWithClassHierarchy> appView) {
+ this.keepInfo = appView.getKeepInfo();
+ this.options = appView.options();
+ }
+
+ @Override
+ public boolean canMerge(DexProgramClass clazz) {
+ return !keepInfo.getClassInfo(clazz).isCheckDiscardedEnabled(options);
+ }
+
+ @Override
+ public String getName() {
+ return "NoCheckDiscard";
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java
index c9bcee0..911bddb 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java
@@ -7,6 +7,7 @@
import static com.android.tools.r8.ir.analysis.type.Nullability.definitelyNotNull;
import static com.android.tools.r8.ir.analysis.type.TypeElement.classClassType;
+import com.android.tools.r8.features.ClassToFeatureSplitMap;
import com.android.tools.r8.graph.AccessControl;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
@@ -24,6 +25,7 @@
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfo;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.synthesis.SyntheticItems;
public class SingleConstClassValue extends SingleConstValue {
@@ -104,7 +106,16 @@
DexType baseType = type.toBaseType(appView.dexItemFactory());
if (baseType.isClassType()) {
DexClass clazz = appView.definitionFor(type);
- return clazz != null && clazz.isPublic() && clazz.isResolvable(appView);
+ if (clazz == null || !clazz.isPublic() || !clazz.isResolvable(appView)) {
+ return false;
+ }
+ ClassToFeatureSplitMap classToFeatureSplitMap = appView.appInfo().getClassToFeatureSplitMap();
+ SyntheticItems syntheticItems = appView.getSyntheticItems();
+ if (clazz.isProgramClass()
+ && classToFeatureSplitMap.isInFeature(clazz.asProgramClass(), syntheticItems)) {
+ return false;
+ }
+ return true;
}
assert baseType.isPrimitiveType();
return true;
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 530bfc4..a5d76c3 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
@@ -6,6 +6,7 @@
import static com.android.tools.r8.ir.analysis.type.Nullability.maybeNull;
+import com.android.tools.r8.features.ClassToFeatureSplitMap;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
@@ -27,6 +28,7 @@
import com.android.tools.r8.ir.optimize.enums.EnumDataMap;
import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfo;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.synthesis.SyntheticItems;
public abstract class SingleFieldValue extends SingleValue {
@@ -109,7 +111,16 @@
assert false;
return false;
}
- return holder.isPublic();
+ if (!holder.isPublic()) {
+ return false;
+ }
+ ClassToFeatureSplitMap classToFeatureSplitMap = appView.appInfo().getClassToFeatureSplitMap();
+ SyntheticItems syntheticItems = appView.getSyntheticItems();
+ if (holder.isProgramClass()
+ && classToFeatureSplitMap.isInFeature(holder.asProgramClass(), syntheticItems)) {
+ return false;
+ }
+ return true;
}
@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 2448b0c..62cbb04 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
@@ -743,7 +743,7 @@
IRCode inlinee,
ListIterator<BasicBlock> blocksIterator,
Set<BasicBlock> blocksToRemove,
- DexType downcast) {
+ DexProgramClass downcast) {
assert blocksToRemove != null;
ProgramMethod callerContext = code.context();
ProgramMethod calleeContext = inlinee.context();
@@ -787,9 +787,9 @@
// instruction if the program still type checks without the cast.
Value receiver = invoke.inValues().get(0);
TypeElement castTypeLattice =
- TypeElement.fromDexType(downcast, receiver.getType().nullability(), appView);
+ TypeElement.fromDexType(downcast.getType(), receiver.getType().nullability(), appView);
SafeCheckCast castInstruction =
- new SafeCheckCast(code.createValue(castTypeLattice), receiver, downcast);
+ new SafeCheckCast(code.createValue(castTypeLattice), receiver, downcast.getType());
castInstruction.setPosition(invoke.getPosition());
// Splice in the check cast operation.
diff --git a/src/main/java/com/android/tools/r8/ir/code/FieldPut.java b/src/main/java/com/android/tools/r8/ir/code/FieldPut.java
new file mode 100644
index 0000000..b45feb0
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/code/FieldPut.java
@@ -0,0 +1,26 @@
+// 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.code;
+
+import com.android.tools.r8.graph.DexField;
+
+public interface FieldPut {
+
+ DexField getField();
+
+ int getValueIndex();
+
+ Value value();
+
+ FieldInstruction asFieldInstruction();
+
+ boolean isInstancePut();
+
+ InstancePut asInstancePut();
+
+ boolean isStaticPut();
+
+ StaticPut asStaticPut();
+}
diff --git a/src/main/java/com/android/tools/r8/ir/code/IRCodeInstructionListIterator.java b/src/main/java/com/android/tools/r8/ir/code/IRCodeInstructionListIterator.java
index 4e223924..f9bbcc8 100644
--- a/src/main/java/com/android/tools/r8/ir/code/IRCodeInstructionListIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/IRCodeInstructionListIterator.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DebugLocalInfo;
import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
@@ -129,7 +130,7 @@
IRCode inlinee,
ListIterator<BasicBlock> blockIterator,
Set<BasicBlock> blocksToRemove,
- DexType downcast) {
+ DexProgramClass downcast) {
throw new Unimplemented();
}
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 20377f3..3dff277 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
@@ -32,7 +32,7 @@
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import java.util.Arrays;
-public class InstancePut extends FieldInstruction implements InstanceFieldInstruction {
+public class InstancePut extends FieldInstruction implements FieldPut, InstanceFieldInstruction {
public InstancePut(DexField field, Value object, Value value) {
this(field, object, value, false);
@@ -65,13 +65,18 @@
}
@Override
+ public int getValueIndex() {
+ return 1;
+ }
+
+ @Override
public Value object() {
return inValues.get(0);
}
@Override
public Value value() {
- return inValues.get(1);
+ return inValues.get(getValueIndex());
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/Instruction.java b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
index 0332c6e..85ac375 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
@@ -221,6 +221,7 @@
newValue.addUser(this);
}
}
+ oldValue.removeUser(this);
}
public void replaceValue(int index, Value newValue) {
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java b/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java
index 14a7d45..d08413d 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DebugLocalInfo;
import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
@@ -254,9 +255,9 @@
IRCode inlinee,
ListIterator<BasicBlock> blockIterator,
Set<BasicBlock> blocksToRemove,
- DexType downcast);
+ DexProgramClass downcast);
- /** See {@link #inlineInvoke(AppView, IRCode, IRCode, ListIterator, Set, DexType)}. */
+ /** See {@link #inlineInvoke(AppView, IRCode, IRCode, ListIterator, Set, DexProgramClass)}. */
default BasicBlock inlineInvoke(AppView<?> appView, IRCode code, IRCode inlinee) {
Set<BasicBlock> blocksToRemove = Sets.newIdentityHashSet();
BasicBlock result = inlineInvoke(appView, code, inlinee, null, blocksToRemove, null);
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java b/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
index 6c22403..92998f3 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.cf.LoadStoreHelper;
import com.android.tools.r8.cf.TypeVerificationHelper;
+import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -46,6 +47,29 @@
this.method = target;
}
+ public static InvokeMethod create(
+ Type type, DexMethod target, Value result, List<Value> arguments, boolean itf) {
+ switch (type) {
+ case DIRECT:
+ return new InvokeDirect(target, result, arguments, itf);
+ case INTERFACE:
+ return new InvokeInterface(target, result, arguments);
+ case STATIC:
+ return new InvokeStatic(target, result, arguments, itf);
+ case SUPER:
+ return new InvokeSuper(target, result, arguments, itf);
+ case VIRTUAL:
+ assert !itf;
+ return new InvokeVirtual(target, result, arguments);
+ case CUSTOM:
+ case MULTI_NEW_ARRAY:
+ case NEW_ARRAY:
+ case POLYMORPHIC:
+ default:
+ throw new Unreachable("Unexpected invoke type: " + type);
+ }
+ }
+
public abstract boolean getInterfaceBit();
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/LinearFlowInstructionListIterator.java b/src/main/java/com/android/tools/r8/ir/code/LinearFlowInstructionListIterator.java
index 3e61866..b5aa980 100644
--- a/src/main/java/com/android/tools/r8/ir/code/LinearFlowInstructionListIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/LinearFlowInstructionListIterator.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DebugLocalInfo;
import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
@@ -146,7 +147,7 @@
IRCode inlinee,
ListIterator<BasicBlock> blockIterator,
Set<BasicBlock> blocksToRemove,
- DexType downcast) {
+ DexProgramClass downcast) {
return currentBlockIterator.inlineInvoke(
appView, code, inlinee, blockIterator, blocksToRemove, downcast);
}
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 9b68a81..92eea52 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
@@ -30,7 +30,7 @@
import com.android.tools.r8.ir.regalloc.RegisterAllocator;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
-public class StaticPut extends FieldInstruction implements StaticFieldInstruction {
+public class StaticPut extends FieldInstruction implements FieldPut, StaticFieldInstruction {
public StaticPut(Value source, DexField field) {
super(field, null, source);
@@ -47,9 +47,14 @@
}
@Override
+ public int getValueIndex() {
+ return 0;
+ }
+
+ @Override
public Value value() {
assert inValues.size() == 1;
- return inValues.get(0);
+ return inValues.get(getValueIndex());
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/D8MethodProcessor.java b/src/main/java/com/android/tools/r8/ir/conversion/D8MethodProcessor.java
index 9bcee66..22b279b 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/D8MethodProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/D8MethodProcessor.java
@@ -83,7 +83,7 @@
nonTerminalFutures.add(
ThreadUtils.processAsynchronously(
() ->
- converter.rewriteCode(
+ converter.rewriteNonDesugaredCode(
method,
eventConsumer,
OptimizationFeedbackIgnore.getInstance(),
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index 0b2d838..d265b7b 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -1856,7 +1856,7 @@
public void addReturn(int value) {
DexType returnType = method.getDefinition().returnType();
if (returnType.isVoidType()) {
- assert prototypeChanges.hasBeenChangedToReturnVoid(appView.dexItemFactory());
+ assert prototypeChanges.hasBeenChangedToReturnVoid();
addReturn();
} else {
ValueTypeConstraint returnTypeConstraint =
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 ee74491..4f92d5b 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
@@ -547,7 +547,7 @@
if (options.isGeneratingClassFiles()
|| !(options.passthroughDexCode && definition.getCode().isDexCode())) {
// We do not process in call graph order, so anything could be a leaf.
- rewriteCode(
+ rewriteNonDesugaredCode(
method,
desugaringEventConsumer,
simpleOptimizationFeedback,
@@ -1033,7 +1033,7 @@
}
}
- Timing rewriteCode(
+ Timing rewriteNonDesugaredCode(
ProgramMethod method,
CfInstructionDesugaringEventConsumer desugaringEventConsumer,
OptimizationFeedback feedback,
@@ -1043,7 +1043,7 @@
method.getOrigin(),
new MethodPosition(method.getReference().asMethodReference()),
() ->
- rewriteCodeInternal(
+ rewriteNonDesugaredCodeInternal(
method,
desugaringEventConsumer,
feedback,
@@ -1056,20 +1056,36 @@
OptimizationFeedback feedback,
MethodProcessor methodProcessor,
MethodProcessingContext methodProcessingContext) {
- return rewriteCode(
- method,
- CfInstructionDesugaringEventConsumer.createForDesugaredCode(),
- feedback,
- methodProcessor,
- methodProcessingContext);
+ return ExceptionUtils.withOriginAndPositionAttachmentHandler(
+ method.getOrigin(),
+ new MethodPosition(method.getReference().asMethodReference()),
+ () ->
+ rewriteDesugaredCodeInternal(
+ method, feedback, methodProcessor, methodProcessingContext));
}
- private Timing rewriteCodeInternal(
+ private Timing rewriteNonDesugaredCodeInternal(
ProgramMethod method,
CfInstructionDesugaringEventConsumer desugaringEventConsumer,
OptimizationFeedback feedback,
MethodProcessor methodProcessor,
MethodProcessingContext methodProcessingContext) {
+ boolean didDesugar = desugar(method, desugaringEventConsumer, methodProcessingContext);
+ if (Log.ENABLED && didDesugar) {
+ Log.debug(
+ getClass(),
+ "Desugared code for %s:\n%s",
+ method.toSourceString(),
+ logCode(options, method.getDefinition()));
+ }
+ return rewriteDesugaredCodeInternal(method, feedback, methodProcessor, methodProcessingContext);
+ }
+
+ private Timing rewriteDesugaredCodeInternal(
+ ProgramMethod method,
+ OptimizationFeedback feedback,
+ MethodProcessor methodProcessor,
+ MethodProcessingContext methodProcessingContext) {
if (options.verbose) {
options.reporter.info(
new StringDiagnostic("Processing: " + method.toSourceString()));
@@ -1081,14 +1097,6 @@
method.toSourceString(),
logCode(options, method.getDefinition()));
}
- boolean didDesugar = desugar(method, desugaringEventConsumer, methodProcessingContext);
- if (Log.ENABLED && didDesugar) {
- Log.debug(
- getClass(),
- "Desugared code for %s:\n%s",
- method.toSourceString(),
- logCode(options, method.getDefinition()));
- }
if (options.testing.hookInIrConversion != null) {
options.testing.hookInIrConversion.run();
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
index 0356381..d012cd6 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
@@ -37,6 +37,7 @@
import com.android.tools.r8.graph.AccessControl;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DebugLocalInfo;
import com.android.tools.r8.graph.DexCallSite;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexClassAndField;
@@ -61,10 +62,10 @@
import com.android.tools.r8.ir.analysis.value.SingleNumberValue;
import com.android.tools.r8.ir.code.Assume;
import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
import com.android.tools.r8.ir.code.CatchHandlers;
import com.android.tools.r8.ir.code.CheckCast;
import com.android.tools.r8.ir.code.ConstClass;
-import com.android.tools.r8.ir.code.ConstInstruction;
import com.android.tools.r8.ir.code.ConstMethodHandle;
import com.android.tools.r8.ir.code.FieldInstruction;
import com.android.tools.r8.ir.code.IRCode;
@@ -97,12 +98,12 @@
import com.android.tools.r8.logging.Log;
import com.android.tools.r8.optimize.MemberRebindingAnalysis;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.verticalclassmerging.InterfaceTypeToClassTypeLensCodeRewriterHelper;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
-import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.function.BiFunction;
@@ -122,7 +123,7 @@
}
private Value makeOutValue(Instruction insn, IRCode code) {
- if (insn.outValue() != null) {
+ if (insn.hasOutValue()) {
TypeElement oldType = insn.getOutType();
TypeElement newType = oldType.rewrittenWithLens(appView, appView.graphLens());
return code.createValue(newType, insn.getLocalInfo());
@@ -149,7 +150,9 @@
DexItemFactory factory = appView.dexItemFactory();
// Rewriting types that affects phi can cause us to compute TOP for cyclic phi's. To solve this
// we track all phi's that needs to be re-computed.
- ListIterator<BasicBlock> blocks = code.listIterator();
+ BasicBlockIterator blocks = code.listIterator();
+ InterfaceTypeToClassTypeLensCodeRewriterHelper interfaceTypeToClassTypeRewriterHelper =
+ InterfaceTypeToClassTypeLensCodeRewriterHelper.create(appView, code, methodProcessor);
boolean mayHaveUnreachableBlocks = false;
while (blocks.hasNext()) {
BasicBlock block = blocks.next();
@@ -250,7 +253,11 @@
ArgumentInfoCollection argumentInfoCollection =
prototypeChanges.getArgumentInfoCollection();
if (argumentInfoCollection.isEmpty()) {
- newInValues = invoke.inValues();
+ if (prototypeChanges.hasExtraParameters()) {
+ newInValues = new ArrayList<>(invoke.inValues());
+ } else {
+ newInValues = invoke.inValues();
+ }
} else {
if (argumentInfoCollection.hasRemovedArguments()) {
if (Log.ENABLED) {
@@ -282,11 +289,29 @@
}
}
- ConstInstruction constantReturnMaterializingInstruction = null;
- if (prototypeChanges.hasBeenChangedToReturnVoid(appView.dexItemFactory())
- && invoke.outValue() != null) {
+ Instruction constantReturnMaterializingInstruction = null;
+ if (prototypeChanges.hasBeenChangedToReturnVoid() && invoke.hasOutValue()) {
+ TypeAndLocalInfoSupplier typeAndLocalInfo =
+ new TypeAndLocalInfoSupplier() {
+ @Override
+ public DebugLocalInfo getLocalInfo() {
+ return invoke.getLocalInfo();
+ }
+
+ @Override
+ public TypeElement getOutType() {
+ return graphLens
+ .lookupType(invokedMethod.getReturnType())
+ .toTypeElement(appView);
+ }
+ };
constantReturnMaterializingInstruction =
- prototypeChanges.getConstantReturn(code, invoke.getPosition());
+ prototypeChanges.getConstantReturn(
+ appView.withLiveness(),
+ code,
+ method,
+ invoke.getPosition(),
+ typeAndLocalInfo);
if (invoke.outValue().hasLocalInfo()) {
constantReturnMaterializingInstruction
.outValue()
@@ -300,7 +325,7 @@
}
Value newOutValue =
- prototypeChanges.hasBeenChangedToReturnVoid(appView.dexItemFactory())
+ prototypeChanges.hasBeenChangedToReturnVoid()
? null
: makeOutValue(invoke, code);
@@ -352,15 +377,17 @@
boolean isInterface =
getBooleanOrElse(
appView.definitionFor(actualTarget.holder), DexClass::isInterface, false);
- Invoke newInvoke =
- Invoke.create(
- actualInvokeType,
- actualTarget,
- null,
- newOutValue,
- newInValues,
- isInterface);
+ InvokeMethod newInvoke =
+ InvokeMethod.create(
+ actualInvokeType, actualTarget, newOutValue, newInValues, isInterface);
+
iterator.replaceCurrentInstruction(newInvoke);
+
+ // Insert casts for the program to type check if interfaces has been vertically
+ // merged into their unique (non-interface) subclass. See also b/199561570.
+ interfaceTypeToClassTypeRewriterHelper.insertCastsForOperandsIfNeeded(
+ invoke, newInvoke, lensLookup, blocks, block, iterator);
+
if (newOutValue != null && newOutValue.getType() != current.getOutType()) {
affectedPhis.addAll(newOutValue.uniquePhiUsers());
}
@@ -379,7 +406,7 @@
DexType actualReturnType = actualTarget.proto.returnType;
DexType expectedReturnType = graphLens.lookupType(invokedMethod.proto.returnType);
- if (newInvoke.outValue() != null && actualReturnType != expectedReturnType) {
+ if (newInvoke.hasOutValue() && actualReturnType != expectedReturnType) {
throw new Unreachable(
"Unexpected need to insert a cast. Possibly related to resolving"
+ " b/79143143.\n"
@@ -444,8 +471,11 @@
DexMethod replacementMethod =
graphLens.lookupPutFieldForMethod(rewrittenField, method.getReference());
if (replacementMethod != null) {
- iterator.replaceCurrentInstruction(
- new InvokeStatic(replacementMethod, null, instancePut.inValues()));
+ InvokeStatic replacement =
+ new InvokeStatic(replacementMethod, null, instancePut.inValues());
+ iterator.replaceCurrentInstruction(replacement);
+ interfaceTypeToClassTypeRewriterHelper.insertCastsForOperandsIfNeeded(
+ instancePut, replacement, blocks, block, iterator);
} else if (rewrittenField != field) {
Value rewrittenValue =
rewriteValueIfDefault(
@@ -454,6 +484,8 @@
InstancePut.createPotentiallyInvalid(
rewrittenField, instancePut.object(), rewrittenValue);
iterator.replaceCurrentInstruction(newInstancePut);
+ interfaceTypeToClassTypeRewriterHelper.insertCastsForOperandsIfNeeded(
+ instancePut, newInstancePut, blocks, block, iterator);
}
}
break;
@@ -507,15 +539,21 @@
DexField actualField = rewriteFieldReference(lookup, method);
DexMethod replacementMethod =
graphLens.lookupPutFieldForMethod(actualField, method.getReference());
+
if (replacementMethod != null) {
- iterator.replaceCurrentInstruction(
- new InvokeStatic(
- replacementMethod, staticPut.outValue(), staticPut.inValues()));
+ InvokeStatic replacement =
+ new InvokeStatic(replacementMethod, staticPut.outValue(), staticPut.inValues());
+ iterator.replaceCurrentInstruction(replacement);
+ interfaceTypeToClassTypeRewriterHelper.insertCastsForOperandsIfNeeded(
+ staticPut, replacement, blocks, block, iterator);
} else if (actualField != field) {
Value rewrittenValue =
rewriteValueIfDefault(
code, iterator, field.type, actualField.type, staticPut.value());
- iterator.replaceCurrentInstruction(new StaticPut(rewrittenValue, actualField));
+ StaticPut replacement = new StaticPut(rewrittenValue, actualField);
+ iterator.replaceCurrentInstruction(replacement);
+ interfaceTypeToClassTypeRewriterHelper.insertCastsForOperandsIfNeeded(
+ staticPut, replacement, blocks, block, iterator);
}
}
break;
@@ -602,7 +640,7 @@
if (ret.isReturnVoid()) {
break;
}
- DexType returnType = code.method().getReference().proto.returnType;
+ DexType returnType = code.context().getReturnType();
Value retValue = ret.returnValue();
DexType initialType =
retValue.getType().isPrimitiveType()
@@ -610,10 +648,18 @@
: factory.objectType; // Place holder, any reference type will do.
Value rewrittenValue =
rewriteValueIfDefault(code, iterator, initialType, returnType, retValue);
+ Return rewrittenReturn;
if (retValue != rewrittenValue) {
- Return newReturn = new Return(rewrittenValue);
- iterator.replaceCurrentInstruction(newReturn);
+ rewrittenReturn = new Return(rewrittenValue);
+ iterator.replaceCurrentInstruction(rewrittenReturn);
+ } else {
+ rewrittenReturn = ret;
}
+
+ // Insert casts for the program to type check if interfaces has been vertically
+ // merged into their unique (non-interface) subclass. See also b/199561570.
+ interfaceTypeToClassTypeRewriterHelper.insertCastsForOperandsIfNeeded(
+ rewrittenReturn, blocks, block, iterator);
}
break;
@@ -680,6 +726,10 @@
if (!affectedPhis.isEmpty()) {
new DestructivePhiTypeUpdater(appView).recomputeAndPropagateTypes(code, affectedPhis);
}
+
+ // Finalize cast insertion.
+ interfaceTypeToClassTypeRewriterHelper.processWorklist();
+
assert code.isConsistentSSABeforeTypesAreCorrect();
assert code.hasNoMergedClasses(appView);
}
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 b0ea9ef..dbd3de8 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
@@ -8,7 +8,7 @@
import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizer;
import com.android.tools.r8.ir.desugar.desugaredlibrary.RetargetingInfo;
import com.android.tools.r8.ir.desugar.itf.ProgramEmulatedInterfaceSynthesizer;
-import com.android.tools.r8.ir.desugar.records.RecordRewriter;
+import com.android.tools.r8.ir.desugar.records.RecordDesugaring;
import com.android.tools.r8.utils.ThreadUtils;
import java.util.ArrayList;
import java.util.Collection;
@@ -33,7 +33,7 @@
}
synthesizers.add(new DesugaredLibraryWrapperSynthesizer(appView));
}
- RecordRewriter recordRewriter = RecordRewriter.create(appView);
+ RecordDesugaring recordRewriter = RecordDesugaring.create(appView);
if (recordRewriter != null) {
synthesizers.add(recordRewriter);
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
index 929b5a8..28334b1 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
@@ -77,107 +77,6 @@
companionMethodConsumer);
}
- // TODO(b/183998768): Remove this event consumer. It should be unneeded for R8 and for D8 the
- // desugaring of interface methods should be able to happen up front too avoiding the companion
- // callback on nest accessors.
- public static CfInstructionDesugaringEventConsumer createForDesugaredCode() {
- return new CfInstructionDesugaringEventConsumer() {
-
- @Override
- public void acceptCompanionMethod(ProgramMethod method, ProgramMethod companionMethod) {
- // A synthesized nest based accessor may itself be defined on an interface, in which case
- // desugaring the accessor will result in a rewrite to the companion method.
- }
-
- @Override
- public void acceptClasspathEmulatedInterface(DexClasspathClass clazz) {
- assert false;
- }
-
- @Override
- public void acceptWrapperClasspathClass(DexClasspathClass clazz) {
- assert false;
- }
-
- @Override
- public void acceptAPIConversion(ProgramMethod method) {
- assert false;
- }
-
- @Override
- public void acceptDesugaredLibraryRetargeterDispatchClasspathClass(DexClasspathClass clazz) {
- assert false;
- }
-
- @Override
- public void acceptThrowMethod(ProgramMethod method, ProgramMethod context) {
- assert false;
- }
-
- @Override
- public void acceptInvokeStaticInterfaceOutliningMethod(
- ProgramMethod method, ProgramMethod context) {
- assert false;
- }
-
- @Override
- public void acceptRecordClass(DexProgramClass recordClass) {
- assert false;
- }
-
- @Override
- public void acceptRecordMethod(ProgramMethod method) {
- assert false;
- }
-
- @Override
- public void acceptBackportedMethod(ProgramMethod backportedMethod, ProgramMethod context) {
- assert false;
- }
-
- @Override
- public void acceptInvokeSpecialBridgeInfo(InvokeSpecialBridgeInfo info) {
- assert false;
- }
-
- @Override
- public void acceptLambdaClass(LambdaClass lambdaClass, ProgramMethod context) {
- assert false;
- }
-
- @Override
- public void acceptConstantDynamicClass(
- ConstantDynamicClass constantDynamicClass, ProgramMethod context) {
- assert false;
- }
-
- @Override
- public void acceptNestFieldGetBridge(ProgramField target, ProgramMethod bridge) {
- assert false;
- }
-
- @Override
- public void acceptNestFieldPutBridge(ProgramField target, ProgramMethod bridge) {
- assert false;
- }
-
- @Override
- public void acceptNestMethodBridge(ProgramMethod target, ProgramMethod bridge) {
- assert false;
- }
-
- @Override
- public void acceptTwrCloseResourceMethod(ProgramMethod closeMethod, ProgramMethod context) {
- assert false;
- }
-
- @Override
- public void acceptCompanionClassClinit(ProgramMethod method) {
- assert false;
- }
- };
- }
-
public static class D8CfInstructionDesugaringEventConsumer
extends CfInstructionDesugaringEventConsumer {
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 1e393aa..064e82d 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
@@ -10,7 +10,7 @@
import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterPostProcessor;
import com.android.tools.r8.ir.desugar.desugaredlibrary.RetargetingInfo;
import com.android.tools.r8.ir.desugar.itf.InterfaceMethodProcessorFacade;
-import com.android.tools.r8.ir.desugar.records.RecordRewriter;
+import com.android.tools.r8.ir.desugar.records.RecordDesugaring;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -73,7 +73,7 @@
if (apiCallbackSynthesizor != null) {
desugarings.add(apiCallbackSynthesizor);
}
- RecordRewriter recordRewriter = RecordRewriter.create(appView);
+ RecordDesugaring recordRewriter = RecordDesugaring.create(appView);
if (recordRewriter != null) {
desugarings.add(recordRewriter);
}
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 62b65d4..66d3a56 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
@@ -25,7 +25,7 @@
import com.android.tools.r8.ir.desugar.lambda.LambdaInstructionDesugaring;
import com.android.tools.r8.ir.desugar.nest.D8NestBasedAccessDesugaring;
import com.android.tools.r8.ir.desugar.nest.NestBasedAccessDesugaring;
-import com.android.tools.r8.ir.desugar.records.RecordRewriter;
+import com.android.tools.r8.ir.desugar.records.RecordDesugaring;
import com.android.tools.r8.ir.desugar.stringconcat.StringConcatInstructionDesugaring;
import com.android.tools.r8.ir.desugar.twr.TwrInstructionDesugaring;
import com.android.tools.r8.utils.IntBox;
@@ -48,7 +48,7 @@
private final List<CfInstructionDesugaring> desugarings = new ArrayList<>();
private final NestBasedAccessDesugaring nestBasedAccessDesugaring;
- private final RecordRewriter recordRewriter;
+ private final RecordDesugaring recordRewriter;
private final DesugaredLibraryRetargeter desugaredLibraryRetargeter;
private final InterfaceMethodRewriter interfaceMethodRewriter;
private final DesugaredLibraryAPIConverter desugaredLibraryAPIConverter;
@@ -125,7 +125,7 @@
if (nestBasedAccessDesugaring != null) {
desugarings.add(nestBasedAccessDesugaring);
}
- this.recordRewriter = RecordRewriter.create(appView);
+ this.recordRewriter = RecordDesugaring.create(appView);
if (recordRewriter != null) {
desugarings.add(recordRewriter);
}
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 1c99088..6b76836 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
@@ -220,13 +220,7 @@
method.getHolder().asClasspathOrLibraryClass(),
appView,
classBuilder -> {},
- clazz -> {
- // TODO(b/183998768): When interface method desugaring is cf to cf in R8, the
- // eventConsumer should always be non null.
- if (eventConsumer != null) {
- eventConsumer.acceptClasspathEmulatedInterface(clazz);
- }
- },
+ eventConsumer::acceptClasspathEmulatedInterface,
methodBuilder ->
methodBuilder
.setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic())
@@ -303,7 +297,7 @@
.setAnnotations(definition.annotations())
// Will be traced by the enqueuer.
.disableAndroidApiLevelCheck()
- // TODO(b/183998768): Should this not also be updating with a fake 'this'
+ // TODO(b/200938394): Should this not also be updating with a fake 'this'
.setParameterAnnotationsList(definition.getParameterAnnotations())
.setCode(ignored -> InvalidCode.getInstance());
},
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodProcessorFacade.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodProcessorFacade.java
index 41668bd..434238a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodProcessorFacade.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodProcessorFacade.java
@@ -47,8 +47,6 @@
InterfaceProcessingDesugaringEventConsumer eventConsumer,
ExecutorService executorService)
throws ExecutionException {
- // TODO(b/183998768): Would be nice to use the ClassProcessing for the processing of classes,
- // and do here only the finalization.
ThreadUtils.processItems(
Iterables.filter(programClasses, (DexProgramClass clazz) -> shouldProcess(clazz, flavour)),
clazz -> classProcessor.process(clazz, eventConsumer),
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 6ab7f62..2152ef0 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
@@ -365,7 +365,7 @@
.addScanEffect(() -> leavingStaticInvokeToInterface(context))
.build();
}
- // TODO(b/183998768): This should not be needed. Targeted synthetics should be in place.
+ // TODO(b/199135051): This should not be needed. Targeted synthetics should be in place.
if (appView.getSyntheticItems().isPendingSynthetic(invoke.getMethod().getHolderType())) {
// We did not create this code yet, but it will not require rewriting.
return DesugarDescription.nothing();
@@ -551,7 +551,7 @@
directTarget.asProgramMethod());
companionMethod = companionMethodDefinition.getReference();
} else {
- // TODO(b/183998768): Why does this not create a stub on the class path?
+ // TODO(b/200938617): Why does this not create a stub on the class path?
companionMethod = helper.privateAsMethodOfCompanionClass(directTarget);
}
} else {
@@ -716,11 +716,9 @@
methodProcessingContext,
dexItemFactory) -> {
DexClassAndMethod method = resolutionResult.getResolutionPair();
- // TODO(b/183998768): Why do this amend routine. We have done resolution, so would
- // that
- // not be the correct target!? I think this is just legacy from before resolution
- // was
- // implemented in full.
+ // TODO(b/199135051): Why do this amend routine. We have done resolution, so would
+ // that not be the correct target!? I think this is just legacy from before
+ // resolution was implemented in full.
DexMethod amendedMethod =
amendDefaultMethod(context12.getHolder(), invokedMethod);
assert method.getReference() == amendedMethod;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordDesugaring.java
similarity index 98%
rename from src/main/java/com/android/tools/r8/ir/desugar/records/RecordRewriter.java
rename to src/main/java/com/android/tools/r8/ir/desugar/records/RecordDesugaring.java
index f508ca6..09319b6 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordDesugaring.java
@@ -64,7 +64,7 @@
import java.util.function.BiFunction;
import org.objectweb.asm.Opcodes;
-public class RecordRewriter
+public class RecordDesugaring
implements CfInstructionDesugaring, CfClassSynthesizerDesugaring, CfPostProcessingDesugaring {
private final AppView<?> appView;
@@ -75,8 +75,8 @@
public static final String GET_FIELDS_AS_OBJECTS_METHOD_NAME = "$record$getFieldsAsObjects";
public static final String EQUALS_RECORD_METHOD_NAME = "$record$equals";
- public static RecordRewriter create(AppView<?> appView) {
- return appView.options().shouldDesugarRecords() ? new RecordRewriter(appView) : null;
+ public static RecordDesugaring create(AppView<?> appView) {
+ return appView.options().shouldDesugarRecords() ? new RecordDesugaring(appView) : null;
}
public static void registerSynthesizedCodeReferences(DexItemFactory factory) {
@@ -85,7 +85,7 @@
RecordEqualsCfCodeProvider.registerSynthesizedCodeReferences(factory);
}
- private RecordRewriter(AppView<?> appView) {
+ private RecordDesugaring(AppView<?> appView) {
this.appView = appView;
factory = appView.dexItemFactory();
recordToStringHelperProto =
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java b/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
index c6bb8a7..04ba47d 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
@@ -223,7 +223,7 @@
// We can exploit that a catch handler must be dead if its guard is never instantiated
// directly or indirectly.
- if (appInfoWithLiveness != null && appView.options().enableUninstantiatedTypeOptimization) {
+ if (appInfoWithLiveness != null) {
DexProgramClass clazz = asProgramClassOrNull(appView.definitionFor(guard));
if (clazz != null && !appInfoWithLiveness.isInstantiatedDirectlyOrIndirectly(clazz)) {
builder.add(new CatchHandler<>(guard, target));
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 0a42896..0332cce 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
@@ -20,6 +20,7 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
import com.android.tools.r8.ir.analysis.inlining.SimpleInliningConstraint;
+import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.InstancePut;
@@ -703,7 +704,8 @@
}
@Override
- public DexType getReceiverTypeIfKnown(InvokeMethod invoke) {
- return null; // Maybe improve later.
+ public ClassTypeElement getReceiverTypeOrDefault(
+ InvokeMethod invoke, ClassTypeElement defaultValue) {
+ return defaultValue;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ForcedInliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/ForcedInliningOracle.java
index 7534cba..41b6fe6 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ForcedInliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ForcedInliningOracle.java
@@ -5,10 +5,10 @@
package com.android.tools.r8.ir.optimize;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
+import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.InvokeDirect;
@@ -135,10 +135,14 @@
public void markInlined(InlineeWithReason inlinee) {}
@Override
- public DexType getReceiverTypeIfKnown(InvokeMethod invoke) {
+ public ClassTypeElement getReceiverTypeOrDefault(
+ InvokeMethod invoke, ClassTypeElement defaultValue) {
assert invoke.isInvokeMethodWithReceiver();
Inliner.InliningInfo info = invokesToInline.get(invoke.asInvokeMethodWithReceiver());
assert info != null;
- return info.receiverType;
+ if (info.receiverClass != null) {
+ return info.receiverClass.getType().toTypeElement(appView).asClassType();
+ }
+ return defaultValue;
}
}
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 d36206d..7591f78 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
@@ -24,6 +24,7 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
import com.android.tools.r8.ir.analysis.proto.ProtoInliningReasonStrategy;
+import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
import com.android.tools.r8.ir.analysis.type.Nullability;
import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
import com.android.tools.r8.ir.analysis.type.TypeElement;
@@ -847,11 +848,11 @@
public static class InliningInfo {
public final ProgramMethod target;
- public final DexType receiverType; // null, if unknown
+ public final DexProgramClass receiverClass; // null, if unknown
- public InliningInfo(ProgramMethod target, DexType receiverType) {
+ public InliningInfo(ProgramMethod target, DexProgramClass receiverClass) {
this.target = target;
- this.receiverType = receiverType;
+ this.receiverClass = receiverClass;
}
}
@@ -1016,14 +1017,11 @@
continue;
}
- DexType downcastTypeOrNull = getDowncastTypeIfNeeded(strategy, invoke, singleTarget);
- if (downcastTypeOrNull != null) {
- DexClass downcastClass = appView.definitionFor(downcastTypeOrNull, context);
- if (downcastClass == null
- || AccessControl.isClassAccessible(downcastClass, context, appView)
- .isPossiblyFalse()) {
- continue;
- }
+ DexProgramClass downcastClass = getDowncastTypeIfNeeded(strategy, invoke, singleTarget);
+ if (downcastClass != null
+ && AccessControl.isClassAccessible(downcastClass, context, appView)
+ .isPossiblyFalse()) {
+ continue;
}
if (!inlineeStack.isEmpty()
@@ -1073,7 +1071,7 @@
iterator.previous();
strategy.markInlined(inlinee);
iterator.inlineInvoke(
- appView, code, inlinee.code, blockIterator, blocksToRemove, downcastTypeOrNull);
+ appView, code, inlinee.code, blockIterator, blocksToRemove, downcastClass);
if (inlinee.reason == Reason.SINGLE_CALLER) {
feedback.markInlinedIntoSingleCallSite(singleTargetMethod);
@@ -1160,19 +1158,22 @@
return false;
}
- private DexType getDowncastTypeIfNeeded(
+ private DexProgramClass getDowncastTypeIfNeeded(
InliningStrategy strategy, InvokeMethod invoke, ProgramMethod target) {
if (invoke.isInvokeMethodWithReceiver()) {
- // If the invoke has a receiver but the actual type of the receiver is different
- // from the computed target holder, inlining requires a downcast of the receiver.
- DexType receiverType = strategy.getReceiverTypeIfKnown(invoke);
- if (receiverType == null) {
- // In case we don't know exact type of the receiver we use declared
- // method holder as a fallback.
- receiverType = invoke.getInvokedMethod().holder;
+ // If the invoke has a receiver but the actual type of the receiver is different from the
+ // computed target holder, inlining requires a downcast of the receiver. In case we don't know
+ // the exact type of the receiver we use the static type of the receiver.
+ Value receiver = invoke.asInvokeMethodWithReceiver().getReceiver();
+ if (!receiver.getType().isClassType()) {
+ return target.getHolder();
}
- if (!appView.appInfo().isSubtype(receiverType, target.getHolderType())) {
- return target.getHolderType();
+
+ ClassTypeElement receiverType =
+ strategy.getReceiverTypeOrDefault(invoke, receiver.getType().asClassType());
+ ClassTypeElement targetType = target.getHolderType().toTypeElement(appView).asClassType();
+ if (!receiverType.lessThanOrEqualUpToNullability(targetType, appView)) {
+ return target.getHolder();
}
}
return null;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InliningStrategy.java b/src/main/java/com/android/tools/r8/ir/optimize/InliningStrategy.java
index 1dc076f..b6d33ea 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/InliningStrategy.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/InliningStrategy.java
@@ -4,8 +4,8 @@
package com.android.tools.r8.ir.optimize;
-import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.InvokeDirect;
@@ -49,5 +49,5 @@
void ensureMethodProcessed(ProgramMethod target, IRCode inlinee, OptimizationFeedback feedback);
- DexType getReceiverTypeIfKnown(InvokeMethod invoke);
+ ClassTypeElement getReceiverTypeOrDefault(InvokeMethod invoke, ClassTypeElement defaultValue);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MethodPoolCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/MethodPoolCollection.java
index 2b439a6..652c185 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MethodPoolCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MethodPoolCollection.java
@@ -34,10 +34,6 @@
private final Predicate<DexEncodedMethod> methodTester;
- public MethodPoolCollection(AppView<AppInfoWithLiveness> appView) {
- this(appView, appView.appInfo().computeSubtypingInfo());
- }
-
public MethodPoolCollection(AppView<AppInfoWithLiveness> appView, SubtypingInfo subtypingInfo) {
this(appView, subtypingInfo, Predicates.alwaysTrue());
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java b/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
deleted file mode 100644
index df7eeb3..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
+++ /dev/null
@@ -1,331 +0,0 @@
-// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.ir.optimize;
-
-import static com.android.tools.r8.ir.optimize.UninstantiatedTypeOptimization.Strategy.ALLOW_ARGUMENT_REMOVAL;
-import static com.android.tools.r8.ir.optimize.UninstantiatedTypeOptimization.Strategy.DISALLOW_ARGUMENT_REMOVAL;
-
-import com.android.tools.r8.graph.AppView;
-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.DexProgramClass;
-import com.android.tools.r8.graph.DexProto;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.NestedGraphLens;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
-import com.android.tools.r8.graph.TopDownClassHierarchyTraversal;
-import com.android.tools.r8.ir.analysis.value.AbstractValue;
-import com.android.tools.r8.ir.optimize.MemberPoolCollection.MemberPool;
-import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
-import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.MethodSignatureEquivalence;
-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.MutableBidirectionalOneToOneMap;
-import com.google.common.base.Equivalence.Wrapper;
-import com.google.common.collect.BiMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.IdentityHashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ExecutorService;
-
-public class UninstantiatedTypeOptimization {
-
- enum Strategy {
- ALLOW_ARGUMENT_REMOVAL,
- DISALLOW_ARGUMENT_REMOVAL
- }
-
- public static class UninstantiatedTypeOptimizationGraphLens extends NestedGraphLens {
-
- private final Map<DexMethod, ArgumentInfoCollection> removedArgumentsInfoPerMethod;
-
- UninstantiatedTypeOptimizationGraphLens(
- BidirectionalOneToOneMap<DexMethod, DexMethod> methodMap,
- Map<DexMethod, ArgumentInfoCollection> removedArgumentsInfoPerMethod,
- AppView<?> appView) {
- super(appView, EMPTY_FIELD_MAP, methodMap, EMPTY_TYPE_MAP);
- this.removedArgumentsInfoPerMethod = removedArgumentsInfoPerMethod;
- }
-
- @Override
- protected RewrittenPrototypeDescription internalDescribePrototypeChanges(
- RewrittenPrototypeDescription prototypeChanges, DexMethod method) {
- DexMethod previous = internalGetPreviousMethodSignature(method);
- if (previous == method) {
- assert !removedArgumentsInfoPerMethod.containsKey(method);
- return prototypeChanges;
- }
- if (method.getReturnType().isVoidType() && !previous.getReturnType().isVoidType()) {
- prototypeChanges =
- prototypeChanges.withConstantReturn(previous.getReturnType(), dexItemFactory());
- }
- return prototypeChanges.withRemovedArguments(
- removedArgumentsInfoPerMethod.getOrDefault(method, ArgumentInfoCollection.empty()));
- }
- }
-
- private static final MethodSignatureEquivalence equivalence = MethodSignatureEquivalence.get();
-
- private final AppView<AppInfoWithLiveness> appView;
-
- public UninstantiatedTypeOptimization(AppView<AppInfoWithLiveness> appView) {
- this.appView = appView;
- }
-
- public UninstantiatedTypeOptimization strenghtenOptimizationInfo() {
- OptimizationFeedback feedback = OptimizationFeedbackSimple.getInstance();
- AbstractValue nullValue = appView.abstractValueFactory().createSingleNumberValue(0);
- for (DexProgramClass clazz : appView.appInfo().classes()) {
- clazz.forEachField(
- field -> {
- if (field.type().isAlwaysNull(appView)) {
- feedback.recordFieldHasAbstractValue(field, appView, nullValue);
- }
- });
- clazz.forEachMethod(
- method -> {
- if (method.returnType().isAlwaysNull(appView)) {
- feedback.methodReturnsAbstractValue(method, appView, nullValue);
- }
- });
- }
- return this;
- }
-
- public UninstantiatedTypeOptimizationGraphLens run(
- MethodPoolCollection methodPoolCollection, ExecutorService executorService, Timing timing) {
- try {
- methodPoolCollection.buildAll(executorService, timing);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
-
- Map<Wrapper<DexMethod>, Set<DexType>> changedVirtualMethods = new HashMap<>();
- MutableBidirectionalOneToOneMap<DexMethod, DexMethod> methodMapping =
- new BidirectionalOneToOneHashMap<>();
- Map<DexMethod, ArgumentInfoCollection> removedArgumentsInfoPerMethod = new IdentityHashMap<>();
-
- TopDownClassHierarchyTraversal.forProgramClasses(appView)
- .visit(
- appView.appInfo().classes(),
- clazz ->
- processClass(
- clazz,
- changedVirtualMethods,
- methodMapping.getForwardMap(),
- methodPoolCollection,
- removedArgumentsInfoPerMethod));
-
- if (!methodMapping.isEmpty()) {
- return new UninstantiatedTypeOptimizationGraphLens(
- methodMapping, removedArgumentsInfoPerMethod, appView);
- }
- return null;
- }
-
- private void processClass(
- DexProgramClass clazz,
- Map<Wrapper<DexMethod>, Set<DexType>> changedVirtualMethods,
- BiMap<DexMethod, DexMethod> methodMapping,
- MethodPoolCollection methodPoolCollection,
- Map<DexMethod, ArgumentInfoCollection> removedArgumentsInfoPerMethod) {
- MemberPool<DexMethod> methodPool = methodPoolCollection.get(clazz);
-
- if (clazz.isInterface()) {
- // Do not allow changing the prototype of methods that override an interface method.
- // This achieved by faking that there is already a method with the given signature.
- for (DexEncodedMethod virtualMethod : clazz.virtualMethods()) {
- RewrittenPrototypeDescription prototypeChanges =
- RewrittenPrototypeDescription.createForUninstantiatedTypes(
- virtualMethod.getReference(),
- appView,
- getRemovedArgumentsInfo(virtualMethod, ALLOW_ARGUMENT_REMOVAL));
- if (!prototypeChanges.isEmpty()) {
- DexMethod newMethod = getNewMethodSignature(virtualMethod, prototypeChanges);
- Wrapper<DexMethod> wrapper = equivalence.wrap(newMethod);
- if (!methodPool.hasSeenDirectly(wrapper)) {
- methodPool.seen(wrapper);
- }
- }
- }
- return;
- }
-
- Map<DexEncodedMethod, RewrittenPrototypeDescription> prototypeChangesPerMethod =
- new IdentityHashMap<>();
- for (DexEncodedMethod directMethod : clazz.directMethods()) {
- RewrittenPrototypeDescription prototypeChanges =
- getPrototypeChanges(directMethod, ALLOW_ARGUMENT_REMOVAL);
- if (!prototypeChanges.isEmpty()) {
- prototypeChangesPerMethod.put(directMethod, prototypeChanges);
- }
- }
-
- // Reserve all signatures which are known to not be touched below.
- Set<Wrapper<DexMethod>> usedSignatures = new HashSet<>();
- for (DexEncodedMethod method : clazz.methods()) {
- if (!prototypeChangesPerMethod.containsKey(method)) {
- usedSignatures.add(equivalence.wrap(method.getReference()));
- }
- }
-
- // Change the return type of direct methods that return an uninstantiated type to void.
- clazz
- .getMethodCollection()
- .replaceDirectMethods(
- encodedMethod -> {
- DexMethod method = encodedMethod.getReference();
- RewrittenPrototypeDescription prototypeChanges =
- prototypeChangesPerMethod.getOrDefault(
- encodedMethod, RewrittenPrototypeDescription.none());
- ArgumentInfoCollection removedArgumentsInfo =
- prototypeChanges.getArgumentInfoCollection();
- DexMethod newMethod = getNewMethodSignature(encodedMethod, prototypeChanges);
- if (newMethod != method) {
- Wrapper<DexMethod> wrapper = equivalence.wrap(newMethod);
-
- // TODO(b/110806787): Can be extended to handle collisions by renaming the given
- // method.
- if (usedSignatures.add(wrapper)) {
- methodMapping.put(method, newMethod);
- if (removedArgumentsInfo.hasRemovedArguments()) {
- removedArgumentsInfoPerMethod.put(newMethod, removedArgumentsInfo);
- }
- return encodedMethod.toTypeSubstitutedMethod(
- newMethod,
- removedArgumentsInfo.createParameterAnnotationsRemover(encodedMethod));
- }
- }
- return encodedMethod;
- });
-
- // Change the return type of virtual methods that return an uninstantiated type to void.
- // This is done in two steps. First we change the return type of all methods that override
- // a method whose return type has already been changed to void previously. Note that
- // all supertypes of the current class are always visited prior to the current class.
- // This is important to ensure that a method that used to override a method in its super
- // class will continue to do so after this optimization.
- clazz
- .getMethodCollection()
- .replaceVirtualMethods(
- encodedMethod -> {
- DexMethod method = encodedMethod.getReference();
- RewrittenPrototypeDescription prototypeChanges =
- getPrototypeChanges(encodedMethod, DISALLOW_ARGUMENT_REMOVAL);
- ArgumentInfoCollection removedArgumentsInfo =
- prototypeChanges.getArgumentInfoCollection();
- DexMethod newMethod = getNewMethodSignature(encodedMethod, prototypeChanges);
- if (newMethod != method) {
- Wrapper<DexMethod> wrapper = equivalence.wrap(newMethod);
-
- boolean isOverrideOfPreviouslyChangedMethodInSuperClass =
- changedVirtualMethods
- .getOrDefault(equivalence.wrap(method), ImmutableSet.of())
- .stream()
- .anyMatch(other -> appView.appInfo().isSubtype(clazz.type, other));
- if (isOverrideOfPreviouslyChangedMethodInSuperClass) {
- assert methodPool.hasSeen(wrapper);
-
- boolean signatureIsAvailable = usedSignatures.add(wrapper);
- assert signatureIsAvailable;
-
- methodMapping.put(method, newMethod);
- return encodedMethod.toTypeSubstitutedMethod(
- newMethod,
- removedArgumentsInfo.createParameterAnnotationsRemover(encodedMethod));
- }
- }
- return encodedMethod;
- });
- clazz
- .getMethodCollection()
- .replaceVirtualMethods(
- encodedMethod -> {
- DexMethod method = encodedMethod.getReference();
- RewrittenPrototypeDescription prototypeChanges =
- getPrototypeChanges(encodedMethod, DISALLOW_ARGUMENT_REMOVAL);
- ArgumentInfoCollection removedArgumentsInfo =
- prototypeChanges.getArgumentInfoCollection();
- DexMethod newMethod = getNewMethodSignature(encodedMethod, prototypeChanges);
- if (newMethod != method) {
- Wrapper<DexMethod> wrapper = equivalence.wrap(newMethod);
-
- // TODO(b/110806787): Can be extended to handle collisions by renaming the given
- // method. Note that this also requires renaming all of the methods that override
- // this
- // method, though.
- if (!methodPool.hasSeen(wrapper) && usedSignatures.add(wrapper)) {
- methodPool.seen(wrapper);
-
- methodMapping.put(method, newMethod);
-
- boolean added =
- changedVirtualMethods
- .computeIfAbsent(
- equivalence.wrap(method), key -> Sets.newIdentityHashSet())
- .add(clazz.type);
- assert added;
-
- return encodedMethod.toTypeSubstitutedMethod(
- newMethod,
- removedArgumentsInfo.createParameterAnnotationsRemover(encodedMethod));
- }
- }
- return encodedMethod;
- });
- }
-
- private RewrittenPrototypeDescription getPrototypeChanges(
- DexEncodedMethod encodedMethod, Strategy strategy) {
- if (ArgumentRemovalUtils.isPinned(encodedMethod, appView)
- || appView.appInfo().isKeepConstantArgumentsMethod(encodedMethod.getReference())) {
- return RewrittenPrototypeDescription.none();
- }
- return RewrittenPrototypeDescription.createForUninstantiatedTypes(
- encodedMethod.getReference(), appView, getRemovedArgumentsInfo(encodedMethod, strategy));
- }
-
- private ArgumentInfoCollection getRemovedArgumentsInfo(
- DexEncodedMethod encodedMethod, Strategy strategy) {
- if (strategy == DISALLOW_ARGUMENT_REMOVAL) {
- return ArgumentInfoCollection.empty();
- }
-
- ArgumentInfoCollection.Builder argInfosBuilder = ArgumentInfoCollection.builder();
- DexProto proto = encodedMethod.getReference().proto;
- int offset = encodedMethod.getFirstNonReceiverArgumentIndex();
- for (int i = 0; i < proto.parameters.size(); ++i) {
- DexType type = proto.parameters.values[i];
- if (type.isAlwaysNull(appView)) {
- RemovedArgumentInfo removedArg =
- RemovedArgumentInfo.builder()
- .setSingleValue(appView.abstractValueFactory().createNullValue())
- .setType(type)
- .build();
- argInfosBuilder.addArgumentInfo(i + offset, removedArg);
- }
- }
- return argInfosBuilder.build();
- }
-
- private DexMethod getNewMethodSignature(
- DexEncodedMethod encodedMethod, RewrittenPrototypeDescription prototypeChanges) {
- DexItemFactory dexItemFactory = appView.dexItemFactory();
- DexMethod method = encodedMethod.getReference();
- DexProto newProto = prototypeChanges.rewriteProto(encodedMethod, dexItemFactory);
-
- return dexItemFactory.createMethod(method.holder, newProto, method.name);
- }
-}
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 1f4064f..5f05d8d 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
@@ -442,7 +442,7 @@
throw new IllegalClassInlinerStateException();
}
- directMethodCalls.put(invoke, new InliningInfo(singleTarget, eligibleClass.type));
+ directMethodCalls.put(invoke, new InliningInfo(singleTarget, eligibleClass));
break;
}
}
@@ -920,7 +920,7 @@
.getParent();
}
- return new InliningInfo(singleTarget, eligibleClass.type);
+ return new InliningInfo(singleTarget, eligibleClass);
}
// An invoke is eligible for inlining in the following cases:
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java
index da704c1..1fe7a27 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java
@@ -12,6 +12,10 @@
import com.android.tools.r8.graph.NestedGraphLens;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.RewrittenPrototypeDescription;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.RewrittenTypeInfo;
+import com.android.tools.r8.ir.analysis.value.AbstractValueFactory;
+import com.android.tools.r8.ir.analysis.value.SingleFieldValue;
+import com.android.tools.r8.ir.analysis.value.SingleValue;
import com.android.tools.r8.ir.code.Invoke;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.BooleanUtils;
@@ -28,7 +32,9 @@
class EnumUnboxingLens extends NestedGraphLens {
+ private final AbstractValueFactory abstractValueFactory;
private final Map<DexMethod, RewrittenPrototypeDescription> prototypeChangesPerMethod;
+ private final EnumDataMap unboxedEnums;
EnumUnboxingLens(
AppView<?> appView,
@@ -37,12 +43,36 @@
Map<DexType, DexType> typeMap,
Map<DexMethod, RewrittenPrototypeDescription> prototypeChangesPerMethod) {
super(appView, fieldMap, methodMap::getRepresentativeValue, typeMap, methodMap);
+ assert !appView.unboxedEnums().isEmpty();
+ this.abstractValueFactory = appView.abstractValueFactory();
this.prototypeChangesPerMethod = prototypeChangesPerMethod;
+ this.unboxedEnums = appView.unboxedEnums();
}
@Override
protected RewrittenPrototypeDescription internalDescribePrototypeChanges(
RewrittenPrototypeDescription prototypeChanges, DexMethod method) {
+ // Rewrite the single value of the given RewrittenPrototypeDescription if it is referring to an
+ // unboxed enum field.
+ if (prototypeChanges.hasRewrittenReturnInfo()) {
+ RewrittenTypeInfo rewrittenTypeInfo = prototypeChanges.getRewrittenReturnInfo();
+ if (rewrittenTypeInfo.hasSingleValue()) {
+ SingleValue singleValue = rewrittenTypeInfo.getSingleValue();
+ if (singleValue.isSingleFieldValue()) {
+ SingleFieldValue singleFieldValue = singleValue.asSingleFieldValue();
+ if (unboxedEnums.hasUnboxedValueFor(singleFieldValue.getField())) {
+ prototypeChanges =
+ prototypeChanges.withRewrittenReturnInfo(
+ new RewrittenTypeInfo(
+ rewrittenTypeInfo.getOldType(),
+ rewrittenTypeInfo.getNewType(),
+ abstractValueFactory.createSingleNumberValue(
+ unboxedEnums.getUnboxedValue(singleFieldValue.getField()))));
+ }
+ }
+ }
+ }
+
// During the second IR processing enum unboxing is the only optimization rewriting
// prototype description, if this does not hold, remove the assertion and merge
// the two prototype changes.
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/BooleanMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/BooleanMethodOptimizer.java
index 2c93f77..b0b64ee 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/BooleanMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/BooleanMethodOptimizer.java
@@ -10,6 +10,8 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
import com.android.tools.r8.ir.code.ConstString;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
@@ -37,10 +39,12 @@
@Override
public void optimize(
IRCode code,
+ BasicBlockIterator blockIterator,
InstructionListIterator instructionIterator,
InvokeMethod invoke,
DexClassAndMethod singleTarget,
- Set<Value> affectedValues) {
+ Set<Value> affectedValues,
+ Set<BasicBlock> blocksToRemove) {
if (singleTarget.getReference() == dexItemFactory.booleanMembers.booleanValue) {
optimizeBooleanValue(code, instructionIterator, invoke);
} else if (singleTarget.getReference() == dexItemFactory.booleanMembers.parseBoolean) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/ByteMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/ByteMethodOptimizer.java
index 5fb3d05..952d7cc 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/ByteMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/ByteMethodOptimizer.java
@@ -8,6 +8,8 @@
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionListIterator;
@@ -33,10 +35,12 @@
@Override
public void optimize(
IRCode code,
+ BasicBlockIterator blockIterator,
InstructionListIterator instructionIterator,
InvokeMethod invoke,
DexClassAndMethod singleTarget,
- Set<Value> affectedValues) {
+ Set<Value> affectedValues,
+ Set<BasicBlock> blocksToRemove) {
if (singleTarget.getReference() == dexItemFactory.byteMembers.byteValue) {
optimizeByteValue(instructionIterator, invoke);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/EnumMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/EnumMethodOptimizer.java
index 5ee7017..167a528 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/EnumMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/EnumMethodOptimizer.java
@@ -12,6 +12,8 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.Assume;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.InvokeMethod;
@@ -35,10 +37,12 @@
@Override
public void optimize(
IRCode code,
+ BasicBlockIterator blockIterator,
InstructionListIterator instructionIterator,
InvokeMethod invoke,
DexClassAndMethod singleTarget,
- Set<Value> affectedValues) {
+ Set<Value> affectedValues,
+ Set<BasicBlock> blocksToRemove) {
if (singleTarget.getReference() == appView.dexItemFactory().enumMembers.valueOf
&& invoke.inValues().get(0).isConstClass()) {
insertAssumeDynamicType(code, instructionIterator, invoke);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMemberOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMemberOptimizer.java
index 1ce2493..935e869 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMemberOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMemberOptimizer.java
@@ -12,6 +12,8 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionListIterator;
@@ -115,48 +117,62 @@
MethodProcessor methodProcessor,
MethodProcessingContext methodProcessingContext) {
Set<Value> affectedValues = Sets.newIdentityHashSet();
- InstructionListIterator instructionIterator = code.instructionListIterator();
- Map<LibraryMethodModelCollection<?>, LibraryMethodModelCollection.State> optimizationStates =
- new IdentityHashMap<>();
- while (instructionIterator.hasNext()) {
- Instruction instruction = instructionIterator.next();
- if (!instruction.isInvokeMethod()) {
+ BasicBlockIterator blockIterator = code.listIterator();
+ Set<BasicBlock> blocksToRemove = Sets.newIdentityHashSet();
+ while (blockIterator.hasNext()) {
+ BasicBlock block = blockIterator.next();
+ if (blocksToRemove.contains(block)) {
continue;
}
- InvokeMethod invoke = instruction.asInvokeMethod();
- DexClassAndMethod singleTarget = invoke.lookupSingleTarget(appView, code.context());
- if (singleTarget == null) {
- continue;
- }
+ InstructionListIterator instructionIterator = block.listIterator(code);
+ Map<LibraryMethodModelCollection<?>, LibraryMethodModelCollection.State> optimizationStates =
+ new IdentityHashMap<>();
+ while (instructionIterator.hasNext()) {
+ Instruction instruction = instructionIterator.next();
+ if (!instruction.isInvokeMethod()) {
+ continue;
+ }
- LibraryMethodModelCollection<?> optimizer =
- libraryMethodModelCollections.get(singleTarget.getHolderType());
- if (optimizer == null) {
- continue;
- }
+ InvokeMethod invoke = instruction.asInvokeMethod();
+ DexClassAndMethod singleTarget = invoke.lookupSingleTarget(appView, code.context());
+ if (singleTarget == null) {
+ continue;
+ }
- if (invoke.hasUnusedOutValue()
- && !singleTarget.getDefinition().isInstanceInitializer()
- && !invoke.instructionMayHaveSideEffects(appView, code.context())) {
- instructionIterator.removeOrReplaceByDebugLocalRead();
- continue;
- }
+ LibraryMethodModelCollection<?> optimizer =
+ libraryMethodModelCollections.get(singleTarget.getHolderType());
+ if (optimizer == null) {
+ continue;
+ }
- LibraryMethodModelCollection.State optimizationState =
- optimizationStates.computeIfAbsent(
- optimizer,
- libraryMethodModelCollection ->
- libraryMethodModelCollection.createInitialState(methodProcessor));
- optimizer.optimize(
- code,
- instructionIterator,
- invoke,
- singleTarget,
- affectedValues,
- optimizationState,
- methodProcessingContext);
+ if (invoke.hasUnusedOutValue()
+ && !singleTarget.getDefinition().isInstanceInitializer()
+ && !invoke.instructionMayHaveSideEffects(appView, code.context())) {
+ instructionIterator.removeOrReplaceByDebugLocalRead();
+ continue;
+ }
+
+ LibraryMethodModelCollection.State optimizationState =
+ optimizationStates.computeIfAbsent(
+ optimizer,
+ libraryMethodModelCollection ->
+ libraryMethodModelCollection.createInitialState(methodProcessor));
+ optimizer.optimize(
+ code,
+ blockIterator,
+ instructionIterator,
+ invoke,
+ singleTarget,
+ affectedValues,
+ blocksToRemove,
+ optimizationState,
+ methodProcessingContext);
+ }
}
+
+ code.removeBlocks(blocksToRemove);
+
if (!affectedValues.isEmpty()) {
new TypeAnalysis(appView).narrowing(affectedValues);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMethodModelCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMethodModelCollection.java
index da38111..dbc5b0b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMethodModelCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMethodModelCollection.java
@@ -7,6 +7,8 @@
import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.InvokeMethod;
@@ -34,28 +36,34 @@
*/
void optimize(
IRCode code,
+ BasicBlockIterator blockIterator,
InstructionListIterator instructionIterator,
InvokeMethod invoke,
DexClassAndMethod singleTarget,
Set<Value> affectedValues,
+ Set<BasicBlock> blocksToRemove,
T state,
MethodProcessingContext methodProcessingContext);
@SuppressWarnings("unchecked")
default void optimize(
IRCode code,
+ BasicBlockIterator blockIterator,
InstructionListIterator instructionIterator,
InvokeMethod invoke,
DexClassAndMethod singleTarget,
Set<Value> affectedValues,
+ Set<BasicBlock> blocksToRemove,
Object state,
MethodProcessingContext methodProcessingContext) {
optimize(
code,
+ blockIterator,
instructionIterator,
invoke,
singleTarget,
affectedValues,
+ blocksToRemove,
(T) state,
methodProcessingContext);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/LogMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/LogMethodOptimizer.java
index aa93f3c..37ca53d 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/LogMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/LogMethodOptimizer.java
@@ -9,6 +9,8 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionListIterator;
@@ -102,10 +104,12 @@
@Override
public void optimize(
IRCode code,
+ BasicBlockIterator blockIterator,
InstructionListIterator instructionIterator,
InvokeMethod invoke,
DexClassAndMethod singleTarget,
- Set<Value> affectedValues) {
+ Set<Value> affectedValues,
+ Set<BasicBlock> blocksToRemove) {
int maxRemovedAndroidLogLevel =
appView.options().getProguardConfiguration().getMaxRemovedAndroidLogLevel();
if (singleTarget.getReference() == isLoggableMethod) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/NopLibraryMethodModelCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/library/NopLibraryMethodModelCollection.java
index 2eeb165..e545164 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/NopLibraryMethodModelCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/NopLibraryMethodModelCollection.java
@@ -7,6 +7,8 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.InvokeMethod;
@@ -32,8 +34,10 @@
@Override
public void optimize(
IRCode code,
+ BasicBlockIterator blockIterator,
InstructionListIterator instructionIterator,
InvokeMethod invoke,
DexClassAndMethod singleTarget,
- Set<Value> affectedValues) {}
+ Set<Value> affectedValues,
+ Set<BasicBlock> blocksToRemove) {}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectMethodOptimizer.java
index c325500..98e0014 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectMethodOptimizer.java
@@ -8,6 +8,8 @@
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.InvokeMethod;
@@ -30,10 +32,12 @@
@Override
public void optimize(
IRCode code,
+ BasicBlockIterator blockIterator,
InstructionListIterator instructionIterator,
InvokeMethod invoke,
DexClassAndMethod singleTarget,
- Set<Value> affectedValues) {
+ Set<Value> affectedValues,
+ Set<BasicBlock> blocksToRemove) {
if (singleTarget.getReference() == dexItemFactory.objectMembers.getClass) {
optimizeGetClass(instructionIterator, invoke);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectsMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectsMethodOptimizer.java
index 1e518d6..7e55ce3 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectsMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectsMethodOptimizer.java
@@ -11,6 +11,8 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.InvokeMethod;
@@ -44,10 +46,12 @@
@Override
public void optimize(
IRCode code,
+ BasicBlockIterator blockIterator,
InstructionListIterator instructionIterator,
InvokeMethod invoke,
DexClassAndMethod singleTarget,
- Set<Value> affectedValues) {
+ Set<Value> affectedValues,
+ Set<BasicBlock> blocksToRemove) {
DexMethod singleTargetReference = singleTarget.getReference();
switch (singleTargetReference.getName().byteAt(0)) {
case 'e':
@@ -72,7 +76,14 @@
break;
case 'r':
if (objectsMethods.isRequireNonNullMethod(singleTargetReference)) {
- optimizeRequireNonNull(instructionIterator, invoke, affectedValues, singleTarget);
+ optimizeRequireNonNull(
+ code,
+ blockIterator,
+ instructionIterator,
+ invoke,
+ affectedValues,
+ blocksToRemove,
+ singleTarget);
}
break;
case 't':
@@ -159,9 +170,12 @@
}
private void optimizeRequireNonNull(
+ IRCode code,
+ BasicBlockIterator blockIterator,
InstructionListIterator instructionIterator,
InvokeMethod invoke,
Set<Value> affectedValues,
+ Set<BasicBlock> blocksToRemove,
DexClassAndMethod singleTarget) {
if (invoke.hasOutValue() && invoke.outValue().hasLocalInfo()) {
// Replacing the out-value with an in-value would change debug info.
@@ -176,7 +190,13 @@
}
instructionIterator.removeOrReplaceByDebugLocalRead();
} else if (inValue.isAlwaysNull(appView)) {
- if (singleTarget.getReference() == objectsMethods.requireNonNullElse) {
+ if (singleTarget.getReference() == objectsMethods.requireNonNull) {
+ // Optimize Objects.requireNonNull(null) into throw null.
+ if (appView.hasClassHierarchy()) {
+ instructionIterator.replaceCurrentInstructionWithThrowNull(
+ appView.withClassHierarchy(), code, blockIterator, blocksToRemove, affectedValues);
+ }
+ } else if (singleTarget.getReference() == objectsMethods.requireNonNullElse) {
// Optimize Objects.requireNonNullElse(null, defaultObj) into defaultObj if defaultObj
// is never null.
if (invoke.getLastArgument().isNeverNull()) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/StatelessLibraryMethodModelCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/library/StatelessLibraryMethodModelCollection.java
index df15197..520c27a 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/StatelessLibraryMethodModelCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/StatelessLibraryMethodModelCollection.java
@@ -6,6 +6,8 @@
import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.InvokeMethod;
@@ -24,22 +26,33 @@
public abstract void optimize(
IRCode code,
- InstructionListIterator instructionIterator,
- InvokeMethod invoke,
- DexClassAndMethod singleTarget,
- Set<Value> affectedValues);
-
- @Override
- public final void optimize(
- IRCode code,
+ BasicBlockIterator blockIterator,
InstructionListIterator instructionIterator,
InvokeMethod invoke,
DexClassAndMethod singleTarget,
Set<Value> affectedValues,
+ Set<BasicBlock> blocksToRemove);
+
+ @Override
+ public final void optimize(
+ IRCode code,
+ BasicBlockIterator blockIterator,
+ InstructionListIterator instructionIterator,
+ InvokeMethod invoke,
+ DexClassAndMethod singleTarget,
+ Set<Value> affectedValues,
+ Set<BasicBlock> blocksToRemove,
State state,
MethodProcessingContext methodProcessingContext) {
assert state == null;
- optimize(code, instructionIterator, invoke, singleTarget, affectedValues);
+ optimize(
+ code,
+ blockIterator,
+ instructionIterator,
+ invoke,
+ singleTarget,
+ affectedValues,
+ blocksToRemove);
}
static class State implements LibraryMethodModelCollection.State {}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/StringBuilderMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/StringBuilderMethodOptimizer.java
index 07ab344..8e03c61 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/StringBuilderMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/StringBuilderMethodOptimizer.java
@@ -18,6 +18,8 @@
import com.android.tools.r8.graph.DexItemFactory.StringBuildingMethods;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionListIterator;
@@ -67,10 +69,12 @@
@Override
public void optimize(
IRCode code,
+ BasicBlockIterator blockIterator,
InstructionListIterator instructionIterator,
InvokeMethod invoke,
DexClassAndMethod singleTarget,
Set<Value> affectedValues,
+ Set<BasicBlock> blocksToRemove,
State state,
MethodProcessingContext methodProcessingContext) {
if (invoke.isInvokeMethodWithReceiver()) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/StringMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/StringMethodOptimizer.java
index 8c62340..e5483db 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/StringMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/StringMethodOptimizer.java
@@ -12,6 +12,8 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
import com.android.tools.r8.ir.code.DexItemBasedConstString;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
@@ -40,10 +42,12 @@
@Override
public void optimize(
IRCode code,
+ BasicBlockIterator blockIterator,
InstructionListIterator instructionIterator,
InvokeMethod invoke,
DexClassAndMethod singleTarget,
- Set<Value> affectedValues) {
+ Set<Value> affectedValues,
+ Set<BasicBlock> blocksToRemove) {
DexMethod singleTargetReference = singleTarget.getReference();
if (singleTargetReference == dexItemFactory.stringMembers.equals) {
optimizeEquals(code, instructionIterator, invoke.asInvokeVirtual());
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
index 537d9af..827f316 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
@@ -1033,7 +1033,8 @@
RegisterPositions freePositions, int registerConstraint) {
int n = Math.min(maxRegisterNumber, registerConstraint);
for (int register = 0; register <= n; ++register) {
- if (freePositions.get(register) > 0) {
+ if (!freePositions.isBlocked(register)) {
+ assert freePositions.get(register) > 0;
// If this register is free according to freePositions, then it should also be free
// according to freeRegisters.
boolean isMoveExceptionRegister =
@@ -1639,7 +1640,7 @@
}
// Set all free positions for possible registers to max integer.
- RegisterPositions freePositions = new RegisterPositions(registerConstraint + 1);
+ RegisterPositions freePositions = new RegisterPositionsImpl(registerConstraint + 1);
if ((options().debug || code.method().getOptimizationInfo().isReachabilitySensitive())
&& !code.method().accessFlags.isStatic()) {
@@ -1648,7 +1649,7 @@
// the input register.
assert numberOfArgumentRegisters > 0;
assert firstArgumentValue != null && firstArgumentValue.requiredRegisters() == 1;
- freePositions.set(0, 0);
+ freePositions.setBlocked(0);
}
if (mode == ArgumentReuseMode.ALLOW_ARGUMENT_REUSE_U8BIT
@@ -1656,7 +1657,7 @@
// Argument reuse is not allowed and we block all the argument registers so that
// arguments are never free.
for (int i = 0; i < numberOfArgumentRegisters && i <= registerConstraint; i++) {
- freePositions.set(i, 0);
+ freePositions.setBlocked(i);
}
}
@@ -1667,7 +1668,7 @@
if (overlapsMoveExceptionInterval(unhandledInterval)) {
int moveExceptionRegister = getMoveExceptionRegister();
if (moveExceptionRegister <= registerConstraint) {
- freePositions.set(moveExceptionRegister, 0);
+ freePositions.setBlocked(moveExceptionRegister);
}
}
@@ -1677,7 +1678,7 @@
if (activeRegister <= registerConstraint) {
for (int i = 0; i < intervals.requiredRegisters(); i++) {
if (activeRegister + i <= registerConstraint) {
- freePositions.set(activeRegister + i, 0);
+ freePositions.setBlocked(activeRegister + i);
}
}
}
@@ -1691,13 +1692,13 @@
int nextOverlap = unhandledInterval.nextOverlap(intervals);
for (int i = 0; i < intervals.requiredRegisters(); i++) {
int register = inactiveRegister + i;
- if (register <= registerConstraint) {
+ if (register <= registerConstraint && !freePositions.isBlocked(register)) {
int unhandledStart = toInstructionPosition(unhandledInterval.getStart());
if (nextOverlap == unhandledStart) {
// Don't use the register for an inactive interval that is only free until the next
// instruction. We can get into this situation when unhandledInterval starts at a
// gap position.
- freePositions.set(register, 0);
+ freePositions.setBlocked(register);
} else {
if (nextOverlap < freePositions.get(register)) {
freePositions.set(register, nextOverlap, intervals);
@@ -1717,8 +1718,9 @@
// Get the register (pair) that is free the longest. That is the register with the largest
// free position.
- int candidate = getLargestValidCandidate(
- unhandledInterval, registerConstraint, needsRegisterPair, freePositions, Type.ANY);
+ int candidate =
+ getLargestValidCandidate(
+ unhandledInterval, registerConstraint, needsRegisterPair, freePositions, Type.ANY);
// It is not always possible to find a largest valid candidate. If none of the usable register
// are free we typically get the last candidate. However, if that candidate has to be
@@ -1742,7 +1744,7 @@
}
// If the first use for these intervals is unconstrained, just spill this interval instead
// of finding another candidate to spill via allocateBlockedRegister.
- if (!unhandledInterval.getUses().first().hasConstraint()) {
+ if (!unhandledInterval.hasUses() || !unhandledInterval.getUses().first().hasConstraint()) {
int nextConstrainedPosition = unhandledInterval.firstUseWithConstraint().getPosition();
int register = getSpillRegister(unhandledInterval, null);
LiveIntervals split = unhandledInterval.splitBefore(nextConstrainedPosition);
@@ -1835,6 +1837,9 @@
return false;
}
if (register + (needsRegisterPair ? 1 : 0) <= registerConstraint) {
+ if (freePositions.isBlocked(register, needsRegisterPair)) {
+ return false;
+ }
int freePosition = freePositions.get(register);
if (needsRegisterPair) {
freePosition = Math.min(freePosition, freePositions.get(register + 1));
@@ -1907,6 +1912,7 @@
}
private int getLargestCandidate(
+ LiveIntervals unhandledInterval,
int registerConstraint,
RegisterPositions freePositions,
boolean needsRegisterPair,
@@ -1915,10 +1921,10 @@
int largest = -1;
for (int i = 0; i <= registerConstraint; i++) {
- if (!freePositions.hasType(i, type)) {
+ if (freePositions.isBlocked(i, needsRegisterPair) || !freePositions.hasType(i, type)) {
continue;
}
- int freePosition = freePositions.get(i);
+ int usePosition = freePositions.get(i);
if (needsRegisterPair) {
if (i == numberOfArgumentRegisters - 1) {
// The last register of the method is |i|, so we cannot use the pair (|i|, |i+1|).
@@ -1927,11 +1933,16 @@
if (i >= registerConstraint) {
break;
}
- freePosition = Math.min(freePosition, freePositions.get(i + 1));
+ usePosition = Math.min(usePosition, freePositions.get(i + 1));
}
- if (freePosition > largest) {
+ if (unhandledInterval.hasUses() && usePosition == unhandledInterval.getFirstUse()) {
+ // This register has a use at the same instruction as the value we are allocation a register
+ // for. Find another register.
+ continue;
+ }
+ if (usePosition > largest) {
candidate = i;
- largest = freePosition;
+ largest = usePosition;
if (largest == Integer.MAX_VALUE) {
break;
}
@@ -1943,44 +1954,87 @@
private int handleWorkaround(
Predicate<LiveIntervals> workaroundNeeded,
BiPredicate<LiveIntervals, Integer> workaroundNeededForCandidate,
- int candidate, LiveIntervals unhandledInterval, int registerConstraint,
- boolean needsRegisterPair, RegisterPositions freePositions, RegisterPositions.Type type) {
+ int candidate,
+ LiveIntervals unhandledInterval,
+ int registerConstraint,
+ boolean needsRegisterPair,
+ RegisterPositionsWithExtraBlockedRegisters freePositions,
+ RegisterPositions.Type type) {
if (workaroundNeeded.test(unhandledInterval)) {
int lastCandidate = candidate;
while (workaroundNeededForCandidate.test(unhandledInterval, candidate)) {
// Make the unusable register unavailable for allocation and try again.
- freePositions.set(candidate, 0);
- candidate = getLargestCandidate(registerConstraint, freePositions, needsRegisterPair, type);
+ freePositions.setBlockedTemporarily(candidate);
+ candidate =
+ getLargestCandidate(
+ unhandledInterval, registerConstraint, freePositions, needsRegisterPair, type);
// If there are only invalid candidates of the give type we will end up with the same
// candidate returned again once we have tried them all. In that case we didn't find a
// valid register candidate and we need to broaden the search to other types.
if (lastCandidate == candidate) {
+ assert false
+ : "Unexpected attempt to take blocked register "
+ + candidate
+ + " in "
+ + code.context().toSourceString();
return REGISTER_CANDIDATE_NOT_FOUND;
}
+ // If we did not find a valid register, then give up, and broaden the search to other types.
+ if (candidate == REGISTER_CANDIDATE_NOT_FOUND) {
+ return candidate;
+ }
lastCandidate = candidate;
}
}
return candidate;
}
- private int getLargestValidCandidate(LiveIntervals unhandledInterval, int registerConstraint,
- boolean needsRegisterPair, RegisterPositions freePositions, RegisterPositions.Type type) {
- int candidate = getLargestCandidate(registerConstraint, freePositions, needsRegisterPair, type);
+ private int getLargestValidCandidate(
+ LiveIntervals unhandledInterval,
+ int registerConstraint,
+ boolean needsRegisterPair,
+ RegisterPositions usePositions,
+ RegisterPositions.Type type) {
+ int candidate =
+ getLargestCandidate(
+ unhandledInterval, registerConstraint, usePositions, needsRegisterPair, type);
if (candidate == REGISTER_CANDIDATE_NOT_FOUND) {
return candidate;
}
- candidate = handleWorkaround(
- this::needsLongResultOverlappingLongOperandsWorkaround,
- this::isLongResultOverlappingLongOperands,
- candidate, unhandledInterval, registerConstraint, needsRegisterPair, freePositions, type);
- candidate = handleWorkaround(
- this::needsSingleResultOverlappingLongOperandsWorkaround,
- this::isSingleResultOverlappingLongOperands,
- candidate, unhandledInterval, registerConstraint, needsRegisterPair, freePositions, type);
- candidate = handleWorkaround(
- this::needsArrayGetWideWorkaround,
- this::isArrayGetArrayRegister,
- candidate, unhandledInterval, registerConstraint, needsRegisterPair, freePositions, type);
+ // Wrap the use positions such that registers blocked by the workarounds are only blocked until
+ // the end of this method.
+ RegisterPositionsWithExtraBlockedRegisters usePositionsWrapper =
+ new RegisterPositionsWithExtraBlockedRegisters(usePositions);
+ candidate =
+ handleWorkaround(
+ this::needsLongResultOverlappingLongOperandsWorkaround,
+ this::isLongResultOverlappingLongOperands,
+ candidate,
+ unhandledInterval,
+ registerConstraint,
+ needsRegisterPair,
+ usePositionsWrapper,
+ type);
+ candidate =
+ handleWorkaround(
+ this::needsSingleResultOverlappingLongOperandsWorkaround,
+ this::isSingleResultOverlappingLongOperands,
+ candidate,
+ unhandledInterval,
+ registerConstraint,
+ needsRegisterPair,
+ usePositionsWrapper,
+ type);
+ candidate =
+ handleWorkaround(
+ this::needsArrayGetWideWorkaround,
+ this::isArrayGetArrayRegister,
+ candidate,
+ unhandledInterval,
+ registerConstraint,
+ needsRegisterPair,
+ usePositionsWrapper,
+ type);
return candidate;
}
@@ -1992,8 +2046,8 @@
}
// Initialize all candidate registers to Integer.MAX_VALUE.
- RegisterPositions usePositions = new RegisterPositions(registerConstraint + 1);
- RegisterPositions blockedPositions = new RegisterPositions(registerConstraint + 1);
+ RegisterPositions usePositions = new RegisterPositionsImpl(registerConstraint + 1);
+ RegisterPositions blockedPositions = new RegisterPositionsImpl(registerConstraint + 1);
// Compute next use location for all currently active registers.
for (LiveIntervals intervals : active) {
@@ -2027,12 +2081,12 @@
// Disallow the reuse of argument registers by always treating them as being used
// at instruction number 0.
for (int i = 0; i < numberOfArgumentRegisters; i++) {
- usePositions.set(i, 0);
+ usePositions.setBlocked(i);
}
// Disallow reuse of the move exception register if we have reserved one.
if (overlapsMoveExceptionInterval(unhandledInterval)) {
- usePositions.set(getMoveExceptionRegister(), 0);
+ usePositions.setBlocked(getMoveExceptionRegister());
}
// Treat active and inactive linked argument intervals as pinned. They cannot be given another
@@ -2046,12 +2100,18 @@
boolean needsRegisterPair = unhandledInterval.getType().isWide();
// First look for a candidate that can be rematerialized.
- int candidate = getLargestValidCandidate(unhandledInterval, registerConstraint,
- needsRegisterPair, usePositions, Type.CONST_NUMBER);
+ int candidate =
+ getLargestValidCandidate(
+ unhandledInterval,
+ registerConstraint,
+ needsRegisterPair,
+ usePositions,
+ Type.CONST_NUMBER);
if (candidate != Integer.MAX_VALUE) {
// Look for a non-const, non-monitor candidate.
- int otherCandidate = getLargestValidCandidate(
- unhandledInterval, registerConstraint, needsRegisterPair, usePositions, Type.OTHER);
+ int otherCandidate =
+ getLargestValidCandidate(
+ unhandledInterval, registerConstraint, needsRegisterPair, usePositions, Type.OTHER);
if (otherCandidate == Integer.MAX_VALUE || candidate == REGISTER_CANDIDATE_NOT_FOUND) {
candidate = otherCandidate;
} else {
@@ -2063,6 +2123,7 @@
candidate = otherCandidate;
}
}
+
// If looking at constants and non-monitor registers did not find a valid spill candidate
// we allow ourselves to look at monitor spill candidates as well. Registers holding objects
// used as monitors should not be spilled if we can avoid it. Spilling them can lead
@@ -2343,7 +2404,8 @@
blockedPositions.set(register + i, firstUse, other);
// If we start blocking registers other than linked arguments, we might need to
// explicitly update the use positions as well as blocked positions.
- assert usePositions.get(register + i) <= blockedPositions.get(register + i);
+ assert usePositions.isBlocked(register + i)
+ || usePositions.get(register + i) <= blockedPositions.get(register + i);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java b/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java
index 0c5705c..8b81c83 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java
@@ -389,6 +389,10 @@
return Integer.MAX_VALUE;
}
+ public boolean hasUses() {
+ return !uses.isEmpty();
+ }
+
public int getFirstUse() {
return uses.first().getPosition();
}
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/RegisterPositions.java b/src/main/java/com/android/tools/r8/ir/regalloc/RegisterPositions.java
index eff8bea..caafb2e 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/RegisterPositions.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/RegisterPositions.java
@@ -3,99 +3,37 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.regalloc;
-import com.android.tools.r8.errors.Unreachable;
-import java.util.Arrays;
-import java.util.BitSet;
-
/**
* Simple mapping from a register to an int value.
- * <p>
- * The backing for the mapping grows as needed up to a given limit. If no mapping exists for
- * a register number the value is assumed to be Integer.MAX_VALUE.
+ *
+ * <p>The backing for the mapping grows as needed up to a given limit. If no mapping exists for a
+ * register number the value is assumed to be Integer.MAX_VALUE.
*/
+public abstract class RegisterPositions {
-public class RegisterPositions {
+ enum Type {
+ MONITOR,
+ CONST_NUMBER,
+ OTHER,
+ ANY
+ }
- enum Type { MONITOR, CONST_NUMBER, OTHER, ANY }
+ public abstract boolean hasType(int index, Type type);
- private static final int INITIAL_SIZE = 16;
- private final int limit;
- private int[] backing;
- private final BitSet registerHoldsConstant;
- private final BitSet registerHoldsMonitor;
- private final BitSet registerHoldsNewStringInstanceDisallowingSpilling;
+ public abstract void set(int index, int value, LiveIntervals intervals);
- public RegisterPositions(int limit) {
- this.limit = limit;
- backing = new int[INITIAL_SIZE];
- for (int i = 0; i < INITIAL_SIZE; i++) {
- backing[i] = Integer.MAX_VALUE;
+ public abstract int get(int index);
+
+ public abstract int getLimit();
+
+ public abstract void setBlocked(int index);
+
+ public abstract boolean isBlocked(int index);
+
+ public final boolean isBlocked(int index, boolean isWide) {
+ if (isBlocked(index)) {
+ return true;
}
- registerHoldsConstant = new BitSet(limit);
- registerHoldsMonitor = new BitSet(limit);
- registerHoldsNewStringInstanceDisallowingSpilling = new BitSet(limit);
- }
-
- public boolean hasType(int index, Type type) {
- switch (type) {
- case MONITOR:
- return holdsMonitor(index);
- case CONST_NUMBER:
- return holdsConstant(index);
- case OTHER:
- return !holdsMonitor(index)
- && !holdsConstant(index)
- && !holdsNewStringInstanceDisallowingSpilling(index);
- case ANY:
- return true;
- default:
- throw new Unreachable("Unexpected register position type: " + type);
- }
- }
-
- private boolean holdsConstant(int index) {
- return registerHoldsConstant.get(index);
- }
-
- private boolean holdsMonitor(int index) { return registerHoldsMonitor.get(index); }
-
- private boolean holdsNewStringInstanceDisallowingSpilling(int index) {
- return registerHoldsNewStringInstanceDisallowingSpilling.get(index);
- }
-
- public void set(int index, int value) {
- if (index >= backing.length) {
- grow(index + 1);
- }
- backing[index] = value;
- }
-
- public void set(int index, int value, LiveIntervals intervals) {
- set(index, value);
- registerHoldsConstant.set(index, intervals.isConstantNumberInterval());
- registerHoldsMonitor.set(index, intervals.usedInMonitorOperation());
- registerHoldsNewStringInstanceDisallowingSpilling.set(
- index, intervals.isNewStringInstanceDisallowingSpilling());
- }
-
- public int get(int index) {
- if (index < backing.length) {
- return backing[index];
- }
- assert index < limit;
- return Integer.MAX_VALUE;
- }
-
- public void grow(int minSize) {
- int size = backing.length;
- while (size < minSize) {
- size *= 2;
- }
- size = Math.min(size, limit);
- int oldSize = backing.length;
- backing = Arrays.copyOf(backing, size);
- for (int i = oldSize; i < size; i++) {
- backing[i] = Integer.MAX_VALUE;
- }
+ return isWide && isBlocked(index + 1);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/RegisterPositionsImpl.java b/src/main/java/com/android/tools/r8/ir/regalloc/RegisterPositionsImpl.java
new file mode 100644
index 0000000..0f11ebf
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/RegisterPositionsImpl.java
@@ -0,0 +1,117 @@
+// 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.regalloc;
+
+import com.android.tools.r8.errors.Unreachable;
+import java.util.Arrays;
+import java.util.BitSet;
+
+public class RegisterPositionsImpl extends RegisterPositions {
+
+ private static final int INITIAL_SIZE = 16;
+ private final int limit;
+ private int[] backing;
+ private final BitSet registerHoldsConstant;
+ private final BitSet registerHoldsMonitor;
+ private final BitSet registerHoldsNewStringInstanceDisallowingSpilling;
+ private final BitSet blockedRegisters;
+
+ public RegisterPositionsImpl(int limit) {
+ this.limit = limit;
+ backing = new int[INITIAL_SIZE];
+ for (int i = 0; i < INITIAL_SIZE; i++) {
+ backing[i] = Integer.MAX_VALUE;
+ }
+ registerHoldsConstant = new BitSet(limit);
+ registerHoldsMonitor = new BitSet(limit);
+ registerHoldsNewStringInstanceDisallowingSpilling = new BitSet(limit);
+ blockedRegisters = new BitSet(limit);
+ }
+
+ @Override
+ public boolean hasType(int index, Type type) {
+ assert !isBlocked(index);
+ switch (type) {
+ case MONITOR:
+ return holdsMonitor(index);
+ case CONST_NUMBER:
+ return holdsConstant(index);
+ case OTHER:
+ return !holdsMonitor(index)
+ && !holdsConstant(index)
+ && !holdsNewStringInstanceDisallowingSpilling(index);
+ case ANY:
+ return true;
+ default:
+ throw new Unreachable("Unexpected register position type: " + type);
+ }
+ }
+
+ private boolean holdsConstant(int index) {
+ return registerHoldsConstant.get(index);
+ }
+
+ private boolean holdsMonitor(int index) {
+ return registerHoldsMonitor.get(index);
+ }
+
+ private boolean holdsNewStringInstanceDisallowingSpilling(int index) {
+ return registerHoldsNewStringInstanceDisallowingSpilling.get(index);
+ }
+
+ private void set(int index, int value) {
+ if (index >= backing.length) {
+ grow(index + 1);
+ }
+ backing[index] = value;
+ }
+
+ @Override
+ public void set(int index, int value, LiveIntervals intervals) {
+ set(index, value);
+ registerHoldsConstant.set(index, intervals.isConstantNumberInterval());
+ registerHoldsMonitor.set(index, intervals.usedInMonitorOperation());
+ registerHoldsNewStringInstanceDisallowingSpilling.set(
+ index, intervals.isNewStringInstanceDisallowingSpilling());
+ }
+
+ @Override
+ public int get(int index) {
+ assert !isBlocked(index);
+ if (index < backing.length) {
+ return backing[index];
+ }
+ assert index < limit;
+ return Integer.MAX_VALUE;
+ }
+
+ @Override
+ public int getLimit() {
+ return limit;
+ }
+
+ @Override
+ public void setBlocked(int index) {
+ blockedRegisters.set(index);
+ }
+
+ @Override
+ public boolean isBlocked(int index) {
+ return blockedRegisters.get(index);
+ }
+
+ private void grow(int minSize) {
+ int size = backing.length;
+ while (size < minSize) {
+ size *= 2;
+ }
+ size = Math.min(size, limit);
+ int oldSize = backing.length;
+ backing = Arrays.copyOf(backing, size);
+ for (int i = oldSize; i < size; i++) {
+ backing[i] = Integer.MAX_VALUE;
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/RegisterPositionsWithExtraBlockedRegisters.java b/src/main/java/com/android/tools/r8/ir/regalloc/RegisterPositionsWithExtraBlockedRegisters.java
new file mode 100644
index 0000000..16c7bb4
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/RegisterPositionsWithExtraBlockedRegisters.java
@@ -0,0 +1,58 @@
+// 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.regalloc;
+
+import java.util.BitSet;
+
+public class RegisterPositionsWithExtraBlockedRegisters extends RegisterPositions {
+
+ private final RegisterPositions positions;
+ private final BitSet extraBlockedRegisters;
+
+ public RegisterPositionsWithExtraBlockedRegisters(RegisterPositions positions) {
+ this.positions = positions;
+ this.extraBlockedRegisters = new BitSet(positions.getLimit());
+ }
+
+ @Override
+ public boolean hasType(int index, Type type) {
+ assert !isBlockedTemporarily(index);
+ return positions.hasType(index, type);
+ }
+
+ @Override
+ public void set(int index, int value, LiveIntervals intervals) {
+ positions.set(index, value, intervals);
+ }
+
+ @Override
+ public int get(int index) {
+ assert !isBlockedTemporarily(index);
+ return positions.get(index);
+ }
+
+ @Override
+ public int getLimit() {
+ return positions.getLimit();
+ }
+
+ @Override
+ public void setBlocked(int index) {
+ positions.setBlocked(index);
+ }
+
+ public void setBlockedTemporarily(int index) {
+ extraBlockedRegisters.set(index);
+ }
+
+ @Override
+ public boolean isBlocked(int index) {
+ return positions.isBlocked(index) || isBlockedTemporarily(index);
+ }
+
+ public boolean isBlockedTemporarily(int index) {
+ return extraBlockedRegisters.get(index);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
index dcf4d30..c3677ba 100644
--- a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
@@ -132,7 +132,7 @@
private void writeApplication(ClassFileConsumer consumer) {
if (proguardMapSupplier != null && options.proguardMapConsumer != null) {
- marker.setPgMapId(proguardMapSupplier.writeProguardMap().get());
+ marker.setPgMapId(proguardMapSupplier.writeProguardMap().getId());
}
Optional<String> markerString =
includeMarker(marker) ? Optional.of(marker.toString()) : Optional.empty();
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java b/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java
index 2d36290..7e7cff8 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.Version;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.naming.mappinginformation.MapVersionMappingInformation;
-import com.android.tools.r8.utils.Box;
import com.android.tools.r8.utils.ChainableStringConsumer;
import com.android.tools.r8.utils.ExceptionUtils;
import com.android.tools.r8.utils.InternalOptions;
@@ -17,6 +16,7 @@
import com.google.common.hash.Hasher;
import com.google.common.hash.Hashing;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
public class ProguardMapSupplier {
@@ -26,16 +26,29 @@
public static final String MARKER_KEY_COMPILER_HASH = "compiler_hash";
public static final String MARKER_KEY_MIN_API = "min_api";
public static final String MARKER_KEY_PG_MAP_ID = "pg_map_id";
+ public static final String MARKER_KEY_PG_MAP_HASH = "pg_map_hash";
+ public static final String SHA_256_KEY = "SHA-256";
public static int PG_MAP_ID_LENGTH = 7;
- // Truncated murmur hash of the non-whitespace codepoints of the Proguard map (excluding the
- // marker).
- public static class ProguardMapId extends Box<String> {
+ // Hash of the Proguard map (excluding the header up to and including the hash marker).
+ public static class ProguardMapId {
+ private final String hash;
+
private ProguardMapId(String id) {
- super(id);
assert id != null;
- assert id.length() == PG_MAP_ID_LENGTH;
+ this.hash = id;
+ }
+
+ /** Truncated prefix of the content hash. */
+ // TODO(b/201269335): Update this to be a full "source-file marker".
+ public String getId() {
+ return hash.substring(0, PG_MAP_ID_LENGTH);
+ }
+
+ /** The actual content hash. */
+ public String getHash() {
+ return hash;
}
}
@@ -99,7 +112,6 @@
builder.append(
"# " + MARKER_KEY_COMPILER_HASH + ": " + VersionProperties.INSTANCE.getSha() + "\n");
}
- builder.append("# " + MARKER_KEY_PG_MAP_ID + ": " + id.get() + "\n");
// Turn off linting of the mapping file in some build systems.
builder.append("# common_typos_disable" + "\n");
// Emit the R8 specific map-file version.
@@ -110,26 +122,31 @@
.append(new MapVersionMappingInformation(mapVersion).serialize())
.append("\n");
}
+ builder.append("# " + MARKER_KEY_PG_MAP_ID + ": " + id.getId() + "\n");
+ // Place the map hash as the last header item. Everything past this line is the hashed content.
+ builder
+ .append("# ")
+ .append(MARKER_KEY_PG_MAP_HASH)
+ .append(": ")
+ .append(SHA_256_KEY)
+ .append(" ")
+ .append(id.getHash())
+ .append("\n");
consumer.accept(builder.toString(), reporter);
}
static class ProguardMapIdBuilder implements ChainableStringConsumer {
- private final Hasher hasher = Hashing.murmur3_32().newHasher();
+ private final Hasher hasher = Hashing.sha256().newHasher();
@Override
public ProguardMapIdBuilder accept(String string) {
- for (int i = 0; i < string.length(); i++) {
- char c = string.charAt(i);
- if (!Character.isWhitespace(c)) {
- hasher.putInt(c);
- }
- }
+ hasher.putString(string, StandardCharsets.UTF_8);
return this;
}
public ProguardMapId build() {
- return new ProguardMapId(hasher.hash().toString().substring(0, PG_MAP_ID_LENGTH));
+ return new ProguardMapId(hasher.hash().toString());
}
}
@@ -142,7 +159,7 @@
}
}
- static class ProguardMapChecker implements StringConsumer {
+ public static class ProguardMapChecker implements StringConsumer {
private final StringConsumer inner;
private final StringBuilder contents = new StringBuilder();
@@ -164,7 +181,9 @@
@Override
public void finished(DiagnosticsHandler handler) {
inner.finished(handler);
- assert validateProguardMapParses(contents.toString());
+ String stringContent = contents.toString();
+ assert validateProguardMapParses(stringContent);
+ assert validateProguardMapHash(stringContent).isOk();
}
private static boolean validateProguardMapParses(String content) {
@@ -176,5 +195,78 @@
}
return true;
}
+
+ public static class VerifyMappingFileHashResult {
+ private final boolean error;
+ private final String message;
+
+ public static VerifyMappingFileHashResult createOk() {
+ return new VerifyMappingFileHashResult(false, null);
+ }
+
+ public static VerifyMappingFileHashResult createInfo(String message) {
+ return new VerifyMappingFileHashResult(false, message);
+ }
+
+ public static VerifyMappingFileHashResult createError(String message) {
+ return new VerifyMappingFileHashResult(true, message);
+ }
+
+ private VerifyMappingFileHashResult(boolean error, String message) {
+ this.error = error;
+ this.message = message;
+ }
+
+ public boolean isOk() {
+ return !error && message == null;
+ }
+
+ public boolean isError() {
+ return error;
+ }
+
+ public String getMessage() {
+ assert message != null;
+ return message;
+ }
+ }
+
+ public static VerifyMappingFileHashResult validateProguardMapHash(String content) {
+ int lineEnd = -1;
+ while (true) {
+ int lineStart = lineEnd + 1;
+ lineEnd = content.indexOf('\n', lineStart);
+ if (lineEnd < 0) {
+ return VerifyMappingFileHashResult.createInfo("Failure to find map hash");
+ }
+ String line = content.substring(lineStart, lineEnd).trim();
+ if (line.isEmpty()) {
+ // Ignore empty lines in the header.
+ continue;
+ }
+ if (line.charAt(0) != '#') {
+ // At the first non-empty non-comment line we assume that the file has no hash marker.
+ return VerifyMappingFileHashResult.createInfo("Failure to find map hash in header");
+ }
+ String headerLine = line.substring(1).trim();
+ if (headerLine.startsWith(MARKER_KEY_PG_MAP_HASH)) {
+ int shaIndex = headerLine.indexOf(SHA_256_KEY + " ", MARKER_KEY_PG_MAP_HASH.length());
+ if (shaIndex < 0) {
+ return VerifyMappingFileHashResult.createError(
+ "Unknown map hash function: '" + headerLine + "'");
+ }
+ String headerHash = headerLine.substring(shaIndex + SHA_256_KEY.length()).trim();
+ // We are on the hash line. Everything past this line is the hashed content.
+ Hasher hasher = Hashing.sha256().newHasher();
+ String hashedContent = content.substring(lineEnd + 1);
+ hasher.putString(hashedContent, StandardCharsets.UTF_8);
+ String computedHash = hasher.hash().toString();
+ return headerHash.equals(computedHash)
+ ? VerifyMappingFileHashResult.createOk()
+ : VerifyMappingFileHashResult.createError(
+ "Mismatching map hash: '" + headerHash + "' != '" + computedHash + "'");
+ }
+ }
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/RewriteFrameMappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/RewriteFrameMappingInformation.java
index 8dccf93..cc8c795 100644
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/RewriteFrameMappingInformation.java
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/RewriteFrameMappingInformation.java
@@ -159,8 +159,8 @@
@Override
public boolean evaluate(RetraceStackTraceContextImpl context) {
- return context.getSeenException() != null
- && context.getSeenException().getDescriptor().equals(descriptor);
+ return context.getThrownException() != null
+ && context.getThrownException().getDescriptor().equals(descriptor);
}
public static ThrowsCondition deserialize(String conditionString) {
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorGraphLens.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorGraphLens.java
index c3fe41b..a0f67e0 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorGraphLens.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorGraphLens.java
@@ -44,7 +44,12 @@
assert !this.prototypeChanges.containsKey(method);
return prototypeChanges;
}
- return prototypeChanges.combine(getPrototypeChanges(method));
+ RewrittenPrototypeDescription newPrototypeChanges =
+ prototypeChanges.combine(getPrototypeChanges(method));
+ assert previous.getReturnType().isVoidType()
+ || !method.getReturnType().isVoidType()
+ || newPrototypeChanges.hasRewrittenReturnInfo();
+ return newPrototypeChanges;
}
@Override
@@ -87,6 +92,9 @@
if (!prototypeChangesForMethod.isEmpty()) {
prototypeChanges.put(to, prototypeChangesForMethod);
}
+ assert from.getReturnType().isVoidType()
+ || !to.getReturnType().isVoidType()
+ || prototypeChangesForMethod.hasRewrittenReturnInfo();
return this;
}
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 68c7d12..eff9893 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
@@ -105,10 +105,15 @@
clazz.forEachProgramMethodMatching(
DexEncodedMethod::hasCode,
method -> {
- AffectedMethodUseRegistry registry =
- new AffectedMethodUseRegistry(appView, graphLens);
- if (method.registerCodeReferencesWithResult(registry)) {
+ if (graphLens.internalGetNextMethodSignature(method.getReference())
+ != method.getReference()) {
methodsToReprocessInClass.add(method);
+ } else {
+ AffectedMethodUseRegistry registry =
+ new AffectedMethodUseRegistry(appView, graphLens);
+ if (method.registerCodeReferencesWithResult(registry)) {
+ methodsToReprocessInClass.add(method);
+ }
}
});
return methodsToReprocessInClass;
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java
index ae2a8aa..7118043 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java
@@ -14,6 +14,8 @@
import com.android.tools.r8.ir.analysis.type.DynamicType;
import com.android.tools.r8.ir.analysis.type.Nullability;
import com.android.tools.r8.ir.optimize.info.ConcreteCallSiteOptimizationInfo;
+import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo;
+import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcreteArrayTypeParameterState;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcreteClassTypeParameterState;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcreteMethodState;
@@ -80,9 +82,6 @@
// instructions, build a flow graph where nodes are parameters and there is an edge from a
// parameter p1 to p2 if the value of p2 is at least the value of p1. Then propagate the
// collected argument information throughout the flow graph.
- // TODO(b/190154391): If we learn that parameter p1 is constant, and that the enclosing method
- // returns p1 according to the optimization info, then update the optimization info to describe
- // that the method returns the constant.
timing.begin("Propagate argument information for virtual methods");
ThreadUtils.processItems(
stronglyConnectedProgramComponents,
@@ -165,6 +164,7 @@
methodState = MethodState.unknown();
}
+ methodState = getMethodStateAfterUninstantiatedParameterRemoval(method, methodState);
methodState = getMethodStateAfterUnusedParameterRemoval(method, methodState);
if (methodState.isUnknown()) {
@@ -220,11 +220,54 @@
return;
}
+ ConcreteMonomorphicMethodState finalMethodState = widenedMethodState.asMonomorphic();
method
.getDefinition()
.setCallSiteOptimizationInfo(
- ConcreteCallSiteOptimizationInfo.fromMethodState(
- appView, method, widenedMethodState.asMonomorphic()));
+ ConcreteCallSiteOptimizationInfo.fromMethodState(appView, method, finalMethodState));
+
+ // Strengthen the return value of the method if the method is known to return one of the
+ // arguments.
+ MethodOptimizationInfo optimizationInfo = method.getOptimizationInfo();
+ if (optimizationInfo.returnsArgument()) {
+ ParameterState returnedArgumentState =
+ finalMethodState.getParameterState(optimizationInfo.getReturnedArgument());
+ OptimizationFeedback.getSimple()
+ .methodReturnsAbstractValue(
+ method.getDefinition(), appView, returnedArgumentState.getAbstractValue(appView));
+ }
+ }
+
+ private MethodState getMethodStateAfterUninstantiatedParameterRemoval(
+ ProgramMethod method, MethodState methodState) {
+ assert methodState.isMonomorphic() || methodState.isUnknown();
+ if (appView.appInfo().isKeepConstantArgumentsMethod(method)) {
+ return methodState;
+ }
+
+ int numberOfArguments = method.getDefinition().getNumberOfArguments();
+ List<ParameterState> parameterStates =
+ methodState.isMonomorphic()
+ ? methodState.asMonomorphic().getParameterStates()
+ : ListUtils.newInitializedArrayList(numberOfArguments, ParameterState.unknown());
+ List<ParameterState> narrowedParameterStates =
+ ListUtils.mapOrElse(
+ parameterStates,
+ (argumentIndex, parameterState) -> {
+ if (!method.getDefinition().isStatic() && argumentIndex == 0) {
+ return parameterState;
+ }
+ DexType argumentType = method.getArgumentType(argumentIndex);
+ if (!argumentType.isAlwaysNull(appView)) {
+ return parameterState;
+ }
+ return new ConcreteClassTypeParameterState(
+ appView.abstractValueFactory().createNullValue(), DynamicType.definitelyNull());
+ },
+ null);
+ return narrowedParameterStates != null
+ ? new ConcreteMonomorphicMethodState(narrowedParameterStates)
+ : methodState;
}
private MethodState getMethodStateAfterUnusedParameterRemoval(
@@ -263,12 +306,16 @@
private ParameterState getUnusedParameterState(DexType argumentType) {
if (argumentType.isArrayType()) {
+ // Ensure argument removal by simulating that this unused parameter is the constant null.
return new ConcreteArrayTypeParameterState(Nullability.definitelyNull());
} else if (argumentType.isClassType()) {
+ // Ensure argument removal by simulating that this unused parameter is the constant null.
return new ConcreteClassTypeParameterState(
appView.abstractValueFactory().createNullValue(), DynamicType.definitelyNull());
} else {
assert argumentType.isPrimitiveType();
+ // Ensure argument removal by simulating that this unused parameter is the constant zero.
+ // Note that the same zero value is used for all primitive types.
return new ConcretePrimitiveTypeParameterState(
appView.abstractValueFactory().createZeroValue());
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java
index 055013f..57611a3 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java
@@ -19,17 +19,22 @@
import com.android.tools.r8.graph.RewrittenPrototypeDescription;
import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.RewrittenTypeInfo;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.analysis.value.SingleValue;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.ir.optimize.info.ConcreteCallSiteOptimizationInfo;
import com.android.tools.r8.optimize.argumentpropagation.ArgumentPropagatorGraphLens.Builder;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.BooleanBox;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.IntBox;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Pair;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
import com.android.tools.r8.utils.collections.DexMethodSignatureSet;
+import com.android.tools.r8.utils.collections.ProgramMethodMap;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
@@ -52,6 +57,47 @@
public class ArgumentPropagatorProgramOptimizer {
+ static class AllowedPrototypeChanges {
+
+ private static final AllowedPrototypeChanges EMPTY =
+ new AllowedPrototypeChanges(false, IntSets.EMPTY_SET);
+
+ boolean canRewriteToVoid;
+ IntSet removableParameterIndices;
+
+ AllowedPrototypeChanges(boolean canRewriteToVoid, IntSet removableParameterIndices) {
+ this.canRewriteToVoid = canRewriteToVoid;
+ this.removableParameterIndices = removableParameterIndices;
+ }
+
+ public static AllowedPrototypeChanges create(RewrittenPrototypeDescription prototypeChanges) {
+ return prototypeChanges.isEmpty()
+ ? empty()
+ : new AllowedPrototypeChanges(
+ prototypeChanges.hasBeenChangedToReturnVoid(),
+ prototypeChanges.getArgumentInfoCollection().getKeys());
+ }
+
+ public static AllowedPrototypeChanges empty() {
+ return EMPTY;
+ }
+
+ @Override
+ public int hashCode() {
+ return BooleanUtils.intValue(canRewriteToVoid) | (removableParameterIndices.hashCode() << 1);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ AllowedPrototypeChanges other = (AllowedPrototypeChanges) obj;
+ return canRewriteToVoid == other.canRewriteToVoid
+ && removableParameterIndices.equals(other.removableParameterIndices);
+ }
+ }
+
private final AppView<AppInfoWithLiveness> appView;
private final ImmediateProgramSubtypingInfo immediateSubtypingInfo;
@@ -117,17 +163,24 @@
private final DexItemFactory dexItemFactory;
private final InternalOptions options;
- private final Map<DexMethodSignature, IntSet> removableVirtualMethodParameters =
- new HashMap<>();
+ private final Map<DexMethodSignature, AllowedPrototypeChanges>
+ allowedPrototypeChangesForVirtualMethods = new HashMap<>();
- // Reserved names, i.e., mappings from pairs (old method signature, number of removed arguments)
- // to the new method signature for that method.
- private final Map<DexMethodSignature, Map<IntSet, DexMethodSignature>> newMethodSignatures =
- new HashMap<>();
+ private final ProgramMethodMap<SingleValue> returnValuesForVirtualMethods =
+ ProgramMethodMap.create();
+
+ // Reserved names, i.e., mappings from pairs (old method signature, prototype changes) to the
+ // new method signature for that method.
+ private final Map<DexMethodSignature, Map<AllowedPrototypeChanges, DexMethodSignature>>
+ newMethodSignatures = new HashMap<>();
+
+ // The method name suffix to start from when searching for a fresh method signature. Used to
+ // avoid searching from index 0 to a large number when searching for a fresh method signature.
+ private final Map<DexMethodSignature, IntBox> newMethodSignatureSuffixes = new HashMap<>();
// Occupied method signatures (inverse of reserved names). Used to effectively check if a given
// method signature is already reserved.
- private final Map<DexMethodSignature, Pair<IntSet, DexMethodSignature>>
+ private final Map<DexMethodSignature, Pair<AllowedPrototypeChanges, DexMethodSignature>>
occupiedMethodSignatures = new HashMap<>();
public StronglyConnectedComponentOptimizer() {
@@ -160,7 +213,7 @@
// To ensure that we preserve the overriding relationships between methods, we only remove a
// constant or unused parameter from a virtual method when it can be removed from all other
// virtual methods in the component with the same method signature.
- computeRemovableVirtualMethodParameters(stronglyConnectedProgramClasses);
+ computePrototypeChangesForVirtualMethods(stronglyConnectedProgramClasses);
// Build a graph lens while visiting the classes in the component.
// TODO(b/190154391): Consider visiting the interfaces first, and then processing the
@@ -201,36 +254,37 @@
pinnedMethodSignatures.addAll(getOrComputeLibraryVirtualMethods(superclass)));
}
pinnedMethodSignatures.forEach(
- signature -> reserveMethodSignature(signature, signature, IntSets.EMPTY_SET));
+ signature ->
+ reserveMethodSignature(signature, signature, AllowedPrototypeChanges.empty()));
}
private void reserveMethodSignature(
DexMethodSignature newMethodSignature,
DexMethodSignature originalMethodSignature,
- IntSet removedParameterIndices) {
+ AllowedPrototypeChanges allowedPrototypeChanges) {
// Record that methods with the given signature and removed parameters should be mapped to the
// new signature.
newMethodSignatures
.computeIfAbsent(originalMethodSignature, ignoreKey(HashMap::new))
- .put(removedParameterIndices, newMethodSignature);
+ .put(allowedPrototypeChanges, newMethodSignature);
// Record that the new method signature is used, by a method with the old signature that had
// the
// given removed parameters.
occupiedMethodSignatures.put(
- newMethodSignature, new Pair<>(removedParameterIndices, originalMethodSignature));
+ newMethodSignature, new Pair<>(allowedPrototypeChanges, originalMethodSignature));
}
- private void computeRemovableVirtualMethodParameters(
+ private void computePrototypeChangesForVirtualMethods(
Set<DexProgramClass> stronglyConnectedProgramClasses) {
// Group the virtual methods in the component by their signatures.
Map<DexMethodSignature, ProgramMethodSet> virtualMethodsBySignature =
computeVirtualMethodsBySignature(stronglyConnectedProgramClasses);
virtualMethodsBySignature.forEach(
(signature, methods) -> {
- // Check that there are no keep rules that prohibit parameter removal from any of the
+ // Check that there are no keep rules that prohibit prototype changes from any of the
// methods.
- if (Iterables.any(methods, method -> !isParameterRemovalAllowed(method))) {
+ if (Iterables.any(methods, method -> !isPrototypeChangesAllowed(method))) {
return;
}
@@ -244,10 +298,30 @@
}
}
- // If any parameters could be removed, record it.
- if (!removableVirtualMethodParametersInAllMethods.isEmpty()) {
- removableVirtualMethodParameters.put(
- signature, removableVirtualMethodParametersInAllMethods);
+ // If any prototype changes can be made, record it.
+ SingleValue returnValueForVirtualMethods =
+ getReturnValueForVirtualMethods(signature, methods);
+ boolean canRewriteVirtualMethodsToVoid = returnValueForVirtualMethods != null;
+ if (canRewriteVirtualMethodsToVoid
+ || !removableVirtualMethodParametersInAllMethods.isEmpty()) {
+ allowedPrototypeChangesForVirtualMethods.put(
+ signature,
+ new AllowedPrototypeChanges(
+ canRewriteVirtualMethodsToVoid,
+ removableVirtualMethodParametersInAllMethods));
+ }
+
+ // Also record the found return value for abstract virtual methods.
+ if (canRewriteVirtualMethodsToVoid) {
+ for (ProgramMethod method : methods) {
+ if (method.getAccessFlags().isAbstract()) {
+ returnValuesForVirtualMethods.put(method, returnValueForVirtualMethods);
+ } else {
+ AbstractValue returnValueForVirtualMethod =
+ method.getOptimizationInfo().getAbstractReturnValue();
+ assert returnValueForVirtualMethod.equals(returnValueForVirtualMethods);
+ }
+ }
}
});
}
@@ -266,13 +340,47 @@
return virtualMethodsBySignature;
}
- private boolean isParameterRemovalAllowed(ProgramMethod method) {
+ private boolean isPrototypeChangesAllowed(ProgramMethod method) {
return appView.getKeepInfo(method).isParameterRemovalAllowed(options)
&& !method.getDefinition().isLibraryMethodOverride().isPossiblyTrue()
&& !appView.appInfo().isBootstrapMethod(method)
&& !appView.appInfo().isMethodTargetedByInvokeDynamic(method);
}
+ private SingleValue getReturnValueForVirtualMethods(
+ DexMethodSignature signature, ProgramMethodSet methods) {
+ if (signature.getReturnType().isVoidType()) {
+ return null;
+ }
+
+ SingleValue returnValue = null;
+ for (ProgramMethod method : methods) {
+ if (method.getDefinition().isAbstract()) {
+ DexProgramClass holder = method.getHolder();
+ if (holder.isInterface()) {
+ ObjectAllocationInfoCollection objectAllocationInfoCollection =
+ appView.appInfo().getObjectAllocationInfoCollection();
+ if (objectAllocationInfoCollection.isImmediateInterfaceOfInstantiatedLambda(holder)) {
+ return null;
+ }
+ }
+ // OK, this can be rewritten to have void return type.
+ continue;
+ }
+ if (!appView.appInfo().mayPropagateValueFor(method)) {
+ return null;
+ }
+ AbstractValue returnValueForMethod = method.getOptimizationInfo().getAbstractReturnValue();
+ if (!returnValueForMethod.isSingleValue()
+ || !returnValueForMethod.asSingleValue().isMaterializableInAllContexts(appView)
+ || (returnValue != null && !returnValueForMethod.equals(returnValue))) {
+ return null;
+ }
+ returnValue = returnValueForMethod.asSingleValue();
+ }
+ return returnValue;
+ }
+
private boolean canRemoveParameterFromVirtualMethods(
int parameterIndex, ProgramMethodSet methods) {
for (ProgramMethod method : methods) {
@@ -316,9 +424,8 @@
method -> {
RewrittenPrototypeDescription prototypeChanges =
method.getDefinition().belongsToDirectPool()
- ? computeRemovableParametersFromDirectMethod(
- method, instanceInitializerSignatures)
- : computeRemovableParametersFromVirtualMethod(method);
+ ? computePrototypeChangesForDirectMethod(method, instanceInitializerSignatures)
+ : computePrototypeChangesForVirtualMethod(method);
DexMethod newMethodSignature = getNewMethodSignature(method, prototypeChanges);
if (newMethodSignature != method.getReference()) {
partialGraphLensBuilder.recordMove(
@@ -332,19 +439,20 @@
private DexMethod getNewMethodSignature(
ProgramMethod method, RewrittenPrototypeDescription prototypeChanges) {
DexMethodSignature methodSignatureWithoutPrototypeChanges = method.getMethodSignature();
- IntSet removableParameterIndices = prototypeChanges.getArgumentInfoCollection().getKeys();
+ AllowedPrototypeChanges allowedPrototypeChanges =
+ AllowedPrototypeChanges.create(prototypeChanges);
// Check if there is a reserved signature for this already.
DexMethodSignature reservedSignature =
newMethodSignatures
.getOrDefault(methodSignatureWithoutPrototypeChanges, Collections.emptyMap())
- .get(removableParameterIndices);
+ .get(allowedPrototypeChanges);
if (reservedSignature != null) {
return reservedSignature.withHolder(method.getHolderType(), dexItemFactory);
}
DexMethod methodReferenceWithParametersRemoved =
- prototypeChanges.getArgumentInfoCollection().rewriteMethod(method, dexItemFactory);
+ prototypeChanges.rewriteMethod(method, dexItemFactory);
DexMethodSignature methodSignatureWithParametersRemoved =
methodReferenceWithParametersRemoved.getSignature();
@@ -354,50 +462,65 @@
reserveMethodSignature(
methodSignatureWithParametersRemoved,
methodSignatureWithoutPrototypeChanges,
- removableParameterIndices);
+ allowedPrototypeChanges);
}
return methodReferenceWithParametersRemoved;
}
- Pair<IntSet, DexMethodSignature> occupant =
+ Pair<AllowedPrototypeChanges, DexMethodSignature> occupant =
occupiedMethodSignatures.get(methodSignatureWithParametersRemoved);
// In this case we should have found a reserved method signature above.
- assert !(occupant.getFirst().equals(removableParameterIndices)
+ assert !(occupant.getFirst().equals(allowedPrototypeChanges)
&& occupant.getSecond().equals(methodSignatureWithoutPrototypeChanges));
// We need to find a new name for this method, since the signature is already occupied.
// TODO(b/190154391): Instead of generating a new name, we could also try permuting the order
// of parameters.
+ IntBox suffix =
+ newMethodSignatureSuffixes.computeIfAbsent(
+ methodSignatureWithParametersRemoved, ignoreKey(IntBox::new));
DexMethod newMethod =
dexItemFactory.createFreshMethodNameWithoutHolder(
method.getName().toString(),
methodReferenceWithParametersRemoved.getProto(),
method.getHolderType(),
candidate -> {
- Pair<IntSet, DexMethodSignature> candidateOccupant =
- occupiedMethodSignatures.get(candidate.getSignature());
- if (candidateOccupant == null) {
- return true;
- }
- return candidateOccupant.getFirst().equals(removableParameterIndices)
- && candidateOccupant.getSecond().equals(methodSignatureWithoutPrototypeChanges);
- });
+ suffix.increment();
+ return isMethodSignatureFresh(
+ candidate.getSignature(),
+ methodSignatureWithoutPrototypeChanges,
+ allowedPrototypeChanges);
+ },
+ suffix.get());
// Reserve the newly generated method signature.
if (!method.getDefinition().isInstanceInitializer()) {
reserveMethodSignature(
newMethod.getSignature(),
methodSignatureWithoutPrototypeChanges,
- removableParameterIndices);
+ allowedPrototypeChanges);
}
return newMethod;
}
- private RewrittenPrototypeDescription computeRemovableParametersFromDirectMethod(
+ private boolean isMethodSignatureFresh(
+ DexMethodSignature signature,
+ DexMethodSignature previous,
+ AllowedPrototypeChanges allowedPrototypeChanges) {
+ Pair<AllowedPrototypeChanges, DexMethodSignature> candidateOccupant =
+ occupiedMethodSignatures.get(signature);
+ if (candidateOccupant == null) {
+ return true;
+ }
+ return candidateOccupant.getFirst().equals(allowedPrototypeChanges)
+ && candidateOccupant.getSecond().equals(previous);
+ }
+
+ private RewrittenPrototypeDescription computePrototypeChangesForDirectMethod(
ProgramMethod method, DexMethodSignatureSet instanceInitializerSignatures) {
assert method.getDefinition().belongsToDirectPool();
- if (!isParameterRemovalAllowed(method)) {
+ if (!isPrototypeChangesAllowed(method)) {
return RewrittenPrototypeDescription.none();
}
// TODO(b/199864962): Allow parameter removal from check-not-null classified methods.
@@ -422,15 +545,16 @@
return prototypeChanges;
}
- private RewrittenPrototypeDescription computeRemovableParametersFromVirtualMethod(
+ private RewrittenPrototypeDescription computePrototypeChangesForVirtualMethod(
ProgramMethod method) {
- IntSet removableParameterIndices =
- removableVirtualMethodParameters.getOrDefault(
- method.getMethodSignature(), IntSets.EMPTY_SET);
- if (removableParameterIndices.isEmpty()) {
+ AllowedPrototypeChanges allowedPrototypeChanges =
+ allowedPrototypeChangesForVirtualMethods.get(method.getMethodSignature());
+ if (allowedPrototypeChanges == null) {
return RewrittenPrototypeDescription.none();
}
+ IntSet removableParameterIndices = allowedPrototypeChanges.removableParameterIndices;
+
if (method.getAccessFlags().isAbstract()) {
// Treat the parameters as unused.
ArgumentInfoCollection.Builder removableParametersBuilder =
@@ -443,26 +567,41 @@
.build());
}
return RewrittenPrototypeDescription.create(
- Collections.emptyList(), null, removableParametersBuilder.build());
+ Collections.emptyList(),
+ computeReturnChangesForMethod(method, allowedPrototypeChanges.canRewriteToVoid),
+ removableParametersBuilder.build());
}
RewrittenPrototypeDescription prototypeChanges =
- computePrototypeChangesForMethod(method, removableParameterIndices::contains);
+ computePrototypeChangesForMethod(
+ method,
+ allowedPrototypeChanges.canRewriteToVoid,
+ removableParameterIndices::contains);
assert prototypeChanges.getArgumentInfoCollection().size()
== removableParameterIndices.size();
return prototypeChanges;
}
private RewrittenPrototypeDescription computePrototypeChangesForMethod(ProgramMethod method) {
- return computePrototypeChangesForMethod(method, parameterIndex -> true);
+ return computePrototypeChangesForMethod(method, true, parameterIndex -> true);
}
private RewrittenPrototypeDescription computePrototypeChangesForMethod(
+ ProgramMethod method,
+ boolean allowToVoidRewriting,
+ IntPredicate removableParameterIndices) {
+ return RewrittenPrototypeDescription.create(
+ Collections.emptyList(),
+ computeReturnChangesForMethod(method, allowToVoidRewriting),
+ computeParameterChangesForMethod(method, removableParameterIndices));
+ }
+
+ private ArgumentInfoCollection computeParameterChangesForMethod(
ProgramMethod method, IntPredicate removableParameterIndices) {
ConcreteCallSiteOptimizationInfo optimizationInfo =
method.getDefinition().getCallSiteOptimizationInfo().asConcreteCallSiteOptimizationInfo();
if (optimizationInfo == null) {
- return RewrittenPrototypeDescription.none();
+ return ArgumentInfoCollection.empty();
}
ArgumentInfoCollection.Builder removableParametersBuilder = ArgumentInfoCollection.builder();
@@ -483,8 +622,34 @@
.build());
}
}
- return RewrittenPrototypeDescription.create(
- Collections.emptyList(), null, removableParametersBuilder.build());
+ return removableParametersBuilder.build();
+ }
+
+ private RewrittenTypeInfo computeReturnChangesForMethod(
+ ProgramMethod method, boolean allowToVoidRewriting) {
+ if (!allowToVoidRewriting) {
+ assert !returnValuesForVirtualMethods.containsKey(method);
+ return null;
+ }
+
+ AbstractValue returnValue;
+ if (method.getReturnType().isAlwaysNull(appView)) {
+ returnValue = appView.abstractValueFactory().createNullValue();
+ } else if (method.getDefinition().belongsToVirtualPool()
+ && returnValuesForVirtualMethods.containsKey(method)) {
+ assert method.getAccessFlags().isAbstract();
+ returnValue = returnValuesForVirtualMethods.get(method);
+ } else {
+ returnValue = method.getOptimizationInfo().getAbstractReturnValue();
+ }
+
+ if (!returnValue.isSingleValue()
+ || !returnValue.asSingleValue().isMaterializableInAllContexts(appView)) {
+ return null;
+ }
+
+ SingleValue singleValue = returnValue.asSingleValue();
+ return RewrittenTypeInfo.toVoid(method.getReturnType(), dexItemFactory, singleValue);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/retrace/Retrace.java b/src/main/java/com/android/tools/r8/retrace/Retrace.java
index 11dcc13..c474a8a 100644
--- a/src/main/java/com/android/tools/r8/retrace/Retrace.java
+++ b/src/main/java/com/android/tools/r8/retrace/Retrace.java
@@ -10,6 +10,8 @@
import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.Keep;
import com.android.tools.r8.Version;
+import com.android.tools.r8.naming.ProguardMapSupplier.ProguardMapChecker;
+import com.android.tools.r8.naming.ProguardMapSupplier.ProguardMapChecker.VerifyMappingFileHashResult;
import com.android.tools.r8.retrace.RetraceCommand.Builder;
import com.android.tools.r8.retrace.internal.RetraceAbortException;
import com.android.tools.r8.retrace.internal.RetracerImpl;
@@ -18,25 +20,37 @@
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.OptionsParsing;
import com.android.tools.r8.utils.OptionsParsing.ParseContext;
-import com.android.tools.r8.utils.Pair;
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.Timing;
import com.google.common.base.Charsets;
+import com.google.common.base.Equivalence;
+import com.google.common.base.Equivalence.Wrapper;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterators;
+import com.google.common.io.CharStreams;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
+import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.function.Function;
import java.util.stream.Collectors;
/**
@@ -51,7 +65,7 @@
public static final String USAGE_MESSAGE =
StringUtils.lines(
"Usage: retrace <proguard-map> [stack-trace-file] "
- + "[--regex <regexp>, --verbose, --info, --quiet]",
+ + "[--regex <regexp>, --verbose, --info, --quiet, --verify-mapping-file-hash]",
" where <proguard-map> is an r8 generated mapping file.");
private static Builder parseArguments(String[] args, DiagnosticsHandler diagnosticsHandler) {
@@ -89,6 +103,12 @@
builder.setRegularExpression(regex);
continue;
}
+ Boolean verify = OptionsParsing.tryParseBoolean(context, "--verify-mapping-file-hash");
+ if (verify != null) {
+ builder.setVerifyMappingFileHash(true);
+ hasSetStackTrace = true;
+ continue;
+ }
if (!hasSetProguardMap) {
builder.setProguardMapProducer(getMappingSupplier(context.head(), diagnosticsHandler));
context.next();
@@ -158,7 +178,7 @@
* @param stackTrace the stack trace to be retrace
* @return list of potentially ambiguous stack traces.
*/
- public List<List<T>> retraceStackTrace(List<T> stackTrace) {
+ public List<Iterator<T>> retraceStackTrace(List<T> stackTrace) {
ListUtils.forEachWithIndex(
stackTrace,
(line, lineNumber) -> {
@@ -168,57 +188,38 @@
throw new RetraceAbortException();
}
});
- List<Pair<List<T>, RetraceStackTraceContext>> retracedStackTraces = new ArrayList<>();
- retracedStackTraces.add(
- new Pair<>(new ArrayList<>(), RetraceStackTraceContext.getInitialContext()));
- retracedStackTraces =
+ RetraceStackTraceElementProxyEquivalence<T, ST> equivalence =
+ new RetraceStackTraceElementProxyEquivalence<>(isVerbose);
+ RetracedNodeState<T, ST> root = RetracedNodeState.initial(equivalence);
+ List<RetracedNodeState<T, ST>> allLeaves =
ListUtils.fold(
stackTrace,
- retracedStackTraces,
+ (List<RetracedNodeState<T, ST>>) ImmutableList.of(root),
(acc, stackTraceLine) -> {
ST parsedLine = stackTraceLineParser.parse(stackTraceLine);
- List<Pair<List<T>, RetraceStackTraceContext>> newRetracedStackTraces =
- new ArrayList<>();
- for (Pair<List<T>, RetraceStackTraceContext> retracedStackTrace : acc) {
- Map<
- RetraceStackTraceElementProxy<T, ST>,
- List<RetraceStackTraceElementProxy<T, ST>>>
- ambiguousBlocks = new HashMap<>();
- List<RetraceStackTraceElementProxy<T, ST>> ambiguousKeys = new ArrayList<>();
+ List<RetracedNodeState<T, ST>> newLeaves = new ArrayList<>();
+ for (RetracedNodeState<T, ST> previousNode : acc) {
proxyRetracer
- .retrace(parsedLine, retracedStackTrace.getSecond())
+ .retrace(parsedLine, previousNode.context)
.forEach(
retracedElement -> {
if (retracedElement.isTopFrame() || !retracedElement.hasRetracedClass()) {
- ambiguousKeys.add(retracedElement);
- ambiguousBlocks.put(retracedElement, new ArrayList<>());
+ previousNode.addChild(retracedElement, retracedElement.getContext());
}
- ambiguousBlocks.get(ListUtils.last(ambiguousKeys)).add(retracedElement);
+ previousNode.addFrameToCurrentChild(
+ parsedLine.toRetracedItem(retracedElement, isVerbose));
});
- if (ambiguousKeys.isEmpty()) {
- // This happens when there is nothing to report.
- newRetracedStackTraces.add(
- new Pair<>(
- retracedStackTrace.getFirst(),
- RetraceStackTraceContext.getInitialContext()));
- continue;
+ if (!previousNode.hasChildren()) {
+ // This happens when there is nothing to retrace. Add the node to newLeaves to
+ // ensure we keep retracing this path.
+ previousNode.addChild(null, RetraceStackTraceContext.empty());
}
- Collections.sort(ambiguousKeys);
- ambiguousKeys.forEach(
- key -> {
- List<T> resultList = new ArrayList<>();
- resultList.addAll(retracedStackTrace.getFirst());
- resultList.addAll(
- ListUtils.map(
- ambiguousBlocks.get(key),
- retracedElement ->
- parsedLine.toRetracedItem(retracedElement, isVerbose)));
- newRetracedStackTraces.add(new Pair<>(resultList, key.getContext()));
- });
+ newLeaves.addAll(previousNode.getChildren());
}
- return newRetracedStackTraces;
+ return newLeaves;
});
- return ListUtils.map(retracedStackTraces, Pair::getFirst);
+ assert !allLeaves.isEmpty();
+ return ListUtils.map(allLeaves, RetracedNodeState::iterator);
}
/**
@@ -232,7 +233,7 @@
List<RetraceStackTraceElementProxy<T, ST>> ambiguousKeys = new ArrayList<>();
ST parsedLine = stackTraceLineParser.parse(stackTraceFrame);
proxyRetracer
- .retrace(parsedLine, RetraceStackTraceContext.getInitialContext())
+ .retrace(parsedLine, RetraceStackTraceContext.empty())
.forEach(
retracedElement -> {
if (retracedElement.isTopFrame() || !retracedElement.hasRetracedClass()) {
@@ -259,7 +260,7 @@
public List<T> retraceLine(T stackTraceLine) {
ST parsedLine = stackTraceLineParser.parse(stackTraceLine);
return proxyRetracer
- .retrace(parsedLine, RetraceStackTraceContext.getInitialContext())
+ .retrace(parsedLine, RetraceStackTraceContext.empty())
.map(
retraceFrame -> {
retraceFrame.getOriginalItem().toRetracedItem(retraceFrame, isVerbose);
@@ -282,8 +283,31 @@
static void runForTesting(RetraceCommand command, boolean allowExperimentalMapping) {
try {
Timing timing = Timing.create("R8 retrace", command.printMemory());
- timing.begin("Read proguard map");
RetraceOptions options = command.getOptions();
+ if (command.getOptions().isVerifyMappingFileHash()) {
+ try (Reader reader = options.getProguardMapProducer().get()) {
+ VerifyMappingFileHashResult checkResult =
+ ProguardMapChecker.validateProguardMapHash(CharStreams.toString(reader));
+ if (checkResult.isError()) {
+ command
+ .getOptions()
+ .getDiagnosticsHandler()
+ .error(new StringDiagnostic(checkResult.getMessage()));
+ throw new RuntimeException(checkResult.getMessage());
+ }
+ if (!checkResult.isOk()) {
+ command
+ .getOptions()
+ .getDiagnosticsHandler()
+ .warning(new StringDiagnostic(checkResult.getMessage()));
+ }
+ } catch (IOException e) {
+ command.getOptions().getDiagnosticsHandler().error(new ExceptionDiagnostic(e));
+ throw new RuntimeException(e);
+ }
+ return;
+ }
+ timing.begin("Read proguard map");
DiagnosticsHandler diagnosticsHandler = options.getDiagnosticsHandler();
// The setup of a retracer should likely also follow a builder pattern instead of having
// static create methods. That would avoid the need to method overload the construction here
@@ -433,4 +457,200 @@
}
}
}
+
+ private static class RetraceStackTraceElementProxyEquivalence<
+ T, ST extends StackTraceElementProxy<T, ST>>
+ extends Equivalence<RetraceStackTraceElementProxy<T, ST>> {
+
+ private final boolean isVerbose;
+
+ public RetraceStackTraceElementProxyEquivalence(boolean isVerbose) {
+ this.isVerbose = isVerbose;
+ }
+
+ @Override
+ protected boolean doEquivalent(
+ RetraceStackTraceElementProxy<T, ST> one, RetraceStackTraceElementProxy<T, ST> other) {
+ if (one == other) {
+ return true;
+ }
+ if (testNotEqualProperty(
+ one,
+ other,
+ RetraceStackTraceElementProxy::hasRetracedClass,
+ r -> r.getRetracedClass().getTypeName())
+ || testNotEqualProperty(
+ one,
+ other,
+ RetraceStackTraceElementProxy::hasSourceFile,
+ RetraceStackTraceElementProxy::getSourceFile)
+ // TODO(b/201042571): This will have to change.
+ || testNotEqualProperty(
+ one,
+ other,
+ RetraceStackTraceElementProxy::hasLineNumber,
+ RetraceStackTraceElementProxy::getLineNumber)) {
+ return false;
+ }
+ if (one.hasRetracedMethod() != other.hasRetracedMethod()) {
+ return false;
+ }
+ if (one.hasRetracedMethod()) {
+ RetracedMethodReference oneMethod = one.getRetracedMethod();
+ RetracedMethodReference otherMethod = other.getRetracedMethod();
+ if (oneMethod.isKnown() != otherMethod.isKnown()) {
+ return false;
+ }
+ // In verbose mode we check the signature, otherwise we only check the name
+ if (!oneMethod.getMethodName().equals(otherMethod.getMethodName())) {
+ return false;
+ }
+ if (isVerbose
+ && ((oneMethod.isKnown()
+ && !oneMethod
+ .asKnown()
+ .getMethodReference()
+ .toString()
+ .equals(otherMethod.asKnown().getMethodReference().toString()))
+ || (!oneMethod.isKnown()
+ && !oneMethod.getMethodName().equals(otherMethod.getMethodName())))) {
+ return false;
+ }
+ }
+ if (one.hasRetracedField() != other.hasRetracedField()) {
+ return false;
+ }
+ if (one.hasRetracedField()) {
+ RetracedFieldReference oneField = one.getRetracedField();
+ RetracedFieldReference otherField = other.getRetracedField();
+ if (oneField.isKnown() != otherField.isKnown()) {
+ return false;
+ }
+ if (!oneField.getFieldName().equals(otherField.getFieldName())) {
+ return false;
+ }
+ if (isVerbose
+ && ((oneField.isKnown()
+ && !oneField
+ .asKnown()
+ .getFieldReference()
+ .toString()
+ .equals(otherField.asKnown().getFieldReference().toString()))
+ || (oneField.isUnknown()
+ && !oneField.getFieldName().equals(otherField.getFieldName())))) {
+ return false;
+ }
+ }
+ if (one.hasRetracedFieldOrReturnType() != other.hasRetracedFieldOrReturnType()) {
+ return false;
+ }
+ if (one.hasRetracedFieldOrReturnType()) {
+ RetracedTypeReference oneFieldOrReturn = one.getRetracedFieldOrReturnType();
+ RetracedTypeReference otherFieldOrReturn = other.getRetracedFieldOrReturnType();
+ if (!compareRetracedTypeReference(oneFieldOrReturn, otherFieldOrReturn)) {
+ return false;
+ }
+ }
+ if (one.hasRetracedMethodArguments() != other.hasRetracedMethodArguments()) {
+ return false;
+ }
+ if (one.hasRetracedMethodArguments()) {
+ List<RetracedTypeReference> oneMethodArguments = one.getRetracedMethodArguments();
+ List<RetracedTypeReference> otherMethodArguments = other.getRetracedMethodArguments();
+ if (oneMethodArguments.size() != otherMethodArguments.size()) {
+ return false;
+ }
+ for (int i = 0; i < oneMethodArguments.size(); i++) {
+ if (compareRetracedTypeReference(
+ oneMethodArguments.get(i), otherMethodArguments.get(i))) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ private boolean compareRetracedTypeReference(
+ RetracedTypeReference one, RetracedTypeReference other) {
+ return one.isVoid() == other.isVoid()
+ && (one.isVoid() || one.getTypeName().equals(other.getTypeName()));
+ }
+
+ @Override
+ protected int doHash(RetraceStackTraceElementProxy<T, ST> proxy) {
+ return 0;
+ }
+
+ private <V extends Comparable<V>> boolean testNotEqualProperty(
+ RetraceStackTraceElementProxy<T, ST> one,
+ RetraceStackTraceElementProxy<T, ST> other,
+ Function<RetraceStackTraceElementProxy<T, ST>, Boolean> predicate,
+ Function<RetraceStackTraceElementProxy<T, ST>, V> getter) {
+ return Comparator.comparing(predicate).thenComparing(getter).compare(one, other) != 0;
+ }
+
+ public static <T, ST extends StackTraceElementProxy<T, ST>>
+ RetraceStackTraceElementProxyEquivalence<T, ST> getInstance(boolean isVerbose) {
+ return new RetraceStackTraceElementProxyEquivalence<>(isVerbose);
+ }
+ }
+
+ private static class RetracedNodeState<T, ST extends StackTraceElementProxy<T, ST>>
+ implements Iterable<T> {
+
+ private final RetracedNodeState<T, ST> parent;
+ private final Set<Wrapper<RetraceStackTraceElementProxy<T, ST>>> seenSet = new HashSet<>();
+ private final Map<RetraceStackTraceElementProxy<T, ST>, RetracedNodeState<T, ST>> children =
+ new TreeMap<>(Comparator.nullsFirst(Comparator.naturalOrder()));
+ private RetracedNodeState<T, ST> currentChild;
+ private final RetraceStackTraceContext context;
+ private final List<T> frames = new ArrayList<>();
+ private final RetraceStackTraceElementProxyEquivalence<T, ST> equivalence;
+
+ private RetracedNodeState(
+ RetracedNodeState<T, ST> parent,
+ RetraceStackTraceContext context,
+ RetraceStackTraceElementProxyEquivalence<T, ST> equivalence) {
+ this.parent = parent;
+ this.context = context;
+ this.equivalence = equivalence;
+ }
+
+ private void addFrameToCurrentChild(T frame) {
+ if (currentChild != null) {
+ currentChild.frames.add(frame);
+ }
+ }
+
+ private void addChild(
+ RetraceStackTraceElementProxy<T, ST> element, RetraceStackTraceContext context) {
+ if (seenSet.add(equivalence.wrap(element))) {
+ RetracedNodeState<T, ST> newChild = new RetracedNodeState<>(this, context, equivalence);
+ this.currentChild = newChild;
+ children.put(element, newChild);
+ } else {
+ this.currentChild = null;
+ }
+ }
+
+ private static <T, ST extends StackTraceElementProxy<T, ST>> RetracedNodeState<T, ST> initial(
+ RetraceStackTraceElementProxyEquivalence<T, ST> equivalence) {
+ return new RetracedNodeState<>(null, RetraceStackTraceContext.empty(), equivalence);
+ }
+
+ @Override
+ public Iterator<T> iterator() {
+ return parent != null
+ ? Iterators.concat(parent.iterator(), frames.iterator())
+ : frames.iterator();
+ }
+
+ public boolean hasChildren() {
+ return !children.isEmpty();
+ }
+
+ public Collection<? extends RetracedNodeState<T, ST>> getChildren() {
+ return children.values();
+ }
+ }
}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceClassElement.java b/src/main/java/com/android/tools/r8/retrace/RetraceClassElement.java
index 6e61118..f7830c3 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceClassElement.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceClassElement.java
@@ -7,7 +7,7 @@
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.TypeReference;
import java.util.List;
-import java.util.Optional;
+import java.util.OptionalInt;
@Keep
public interface RetraceClassElement extends RetraceElement<RetraceClassResult> {
@@ -20,17 +20,18 @@
RetraceMethodResult lookupMethod(String methodName);
- RetraceFrameResult lookupFrame(Optional<Integer> position, String methodName);
+ RetraceFrameResult lookupFrame(
+ RetraceStackTraceContext context, OptionalInt position, String methodName);
RetraceFrameResult lookupFrame(
- Optional<Integer> position,
+ RetraceStackTraceContext context,
+ OptionalInt position,
String methodName,
List<TypeReference> formalTypes,
TypeReference returnType);
- RetraceFrameResult lookupFrame(Optional<Integer> position, MethodReference methodReference);
+ RetraceFrameResult lookupFrame(
+ RetraceStackTraceContext context, OptionalInt position, MethodReference methodReference);
RetraceUnknownJsonMappingInformationResult getUnknownJsonMappingInformation();
-
- RetraceStackTraceContext getContextWhereClassWasThrown();
}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceClassResult.java b/src/main/java/com/android/tools/r8/retrace/RetraceClassResult.java
index e2b59fa..9f5bc71 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceClassResult.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceClassResult.java
@@ -7,7 +7,7 @@
import com.android.tools.r8.Keep;
import com.android.tools.r8.references.TypeReference;
import java.util.List;
-import java.util.Optional;
+import java.util.OptionalInt;
@Keep
public interface RetraceClassResult extends RetraceResult<RetraceClassElement> {
@@ -24,12 +24,14 @@
String methodName, List<TypeReference> formalTypes, TypeReference returnType);
RetraceFrameResult lookupFrame(
- RetraceStackTraceContext context, Optional<Integer> position, String methodName);
+ RetraceStackTraceContext context, OptionalInt position, String methodName);
RetraceFrameResult lookupFrame(
RetraceStackTraceContext context,
- Optional<Integer> position,
+ OptionalInt position,
String methodName,
List<TypeReference> formalTypes,
TypeReference returnType);
+
+ RetraceThrownExceptionResult lookupThrownException(RetraceStackTraceContext context);
}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceCommand.java b/src/main/java/com/android/tools/r8/retrace/RetraceCommand.java
index 76d6b77..c627248 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceCommand.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceCommand.java
@@ -24,7 +24,8 @@
ProguardMapProducer proguardMapProducer,
List<String> stackTrace,
Consumer<List<String>> retracedStackTraceConsumer,
- boolean isVerbose) {
+ boolean isVerbose,
+ boolean verifyMappingFileHash) {
this.stackTrace = stackTrace;
this.retracedStackTraceConsumer = retracedStackTraceConsumer;
this.options =
@@ -32,9 +33,10 @@
.setRegularExpression(regularExpression)
.setProguardMapProducer(proguardMapProducer)
.setVerbose(isVerbose)
+ .setVerifyMappingFileHash(verifyMappingFileHash)
.build();
- assert this.stackTrace != null;
+ assert this.stackTrace != null || verifyMappingFileHash;
assert this.retracedStackTraceConsumer != null;
}
@@ -81,6 +83,7 @@
private String regularExpression = StackTraceRegularExpressionParser.DEFAULT_REGULAR_EXPRESSION;
private List<String> stackTrace;
private Consumer<List<String>> retracedStackTraceConsumer;
+ private boolean verifyMappingFileHash = false;
private Builder(DiagnosticsHandler diagnosticsHandler) {
this.diagnosticsHandler = diagnosticsHandler;
@@ -125,6 +128,12 @@
return this;
}
+ /** Set if the mapping-file hash should be checked if present. */
+ public Builder setVerifyMappingFileHash(boolean verifyMappingFileHash) {
+ this.verifyMappingFileHash = verifyMappingFileHash;
+ return this;
+ }
+
/**
* Set a consumer for receiving the retraced stack trace.
*
@@ -142,7 +151,7 @@
if (this.proguardMapProducer == null) {
throw new RuntimeException("ProguardMapSupplier not specified");
}
- if (this.stackTrace == null) {
+ if (this.stackTrace == null && !verifyMappingFileHash) {
throw new RuntimeException("StackTrace not specified");
}
if (this.retracedStackTraceConsumer == null) {
@@ -154,7 +163,8 @@
proguardMapProducer,
stackTrace,
retracedStackTraceConsumer,
- isVerbose);
+ isVerbose,
+ verifyMappingFileHash);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceFrameElement.java b/src/main/java/com/android/tools/r8/retrace/RetraceFrameElement.java
index f2ad4e7..419f6b3 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceFrameElement.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceFrameElement.java
@@ -5,7 +5,8 @@
import com.android.tools.r8.Keep;
import java.util.List;
-import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
@Keep
public interface RetraceFrameElement extends RetraceElement<RetraceFrameResult> {
@@ -16,10 +17,13 @@
RetraceClassElement getClassElement();
- void visitAllFrames(BiConsumer<RetracedMethodReference, Integer> consumer);
+ void forEach(Consumer<RetracedSingleFrame> consumer);
- void visitRewrittenFrames(
- RetraceStackTraceContext context, BiConsumer<RetracedMethodReference, Integer> consumer);
+ Stream<RetracedSingleFrame> stream();
+
+ void forEachRewritten(RetraceStackTraceContext context, Consumer<RetracedSingleFrame> consumer);
+
+ Stream<RetracedSingleFrame> streamRewritten(RetraceStackTraceContext context);
RetracedSourceFile getSourceFile(RetracedClassMemberReference frame);
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceMethodResult.java b/src/main/java/com/android/tools/r8/retrace/RetraceMethodResult.java
index 9abb027..805443c 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceMethodResult.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceMethodResult.java
@@ -9,6 +9,5 @@
@Keep
public interface RetraceMethodResult extends RetraceResult<RetraceMethodElement> {
- RetraceFrameResult narrowByPosition(int position);
-
+ RetraceFrameResult narrowByPosition(RetraceStackTraceContext context, int position);
}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceOptions.java b/src/main/java/com/android/tools/r8/retrace/RetraceOptions.java
index 47d8c74..2543f35 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceOptions.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceOptions.java
@@ -17,6 +17,7 @@
public class RetraceOptions {
private final boolean isVerbose;
+ private final boolean verifyMappingFileHash;
private final String regularExpression;
private final DiagnosticsHandler diagnosticsHandler;
private final ProguardMapProducer proguardMapProducer;
@@ -25,11 +26,13 @@
String regularExpression,
DiagnosticsHandler diagnosticsHandler,
ProguardMapProducer proguardMapProducer,
- boolean isVerbose) {
+ boolean isVerbose,
+ boolean verifyMappingFileHash) {
this.regularExpression = regularExpression;
this.diagnosticsHandler = diagnosticsHandler;
this.proguardMapProducer = proguardMapProducer;
this.isVerbose = isVerbose;
+ this.verifyMappingFileHash = verifyMappingFileHash;
assert diagnosticsHandler != null;
assert proguardMapProducer != null;
@@ -39,6 +42,10 @@
return isVerbose;
}
+ public boolean isVerifyMappingFileHash() {
+ return verifyMappingFileHash;
+ }
+
public String getRegularExpression() {
return regularExpression;
}
@@ -69,6 +76,7 @@
public static class Builder {
private boolean isVerbose;
+ private boolean verifyMappingFileHash;
private final DiagnosticsHandler diagnosticsHandler;
private ProguardMapProducer proguardMapProducer;
private String regularExpression = defaultRegularExpression();
@@ -83,6 +91,12 @@
return this;
}
+ /** Set if the mapping-file hash should be checked if present. */
+ public Builder setVerifyMappingFileHash(boolean verifyMappingFileHash) {
+ this.verifyMappingFileHash = verifyMappingFileHash;
+ return this;
+ }
+
/**
* Set a producer for the proguard mapping contents.
*
@@ -116,7 +130,11 @@
throw new RuntimeException("Regular expression not specified");
}
return new RetraceOptions(
- regularExpression, diagnosticsHandler, proguardMapProducer, isVerbose);
+ regularExpression,
+ diagnosticsHandler,
+ proguardMapProducer,
+ isVerbose,
+ verifyMappingFileHash);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceStackTraceContext.java b/src/main/java/com/android/tools/r8/retrace/RetraceStackTraceContext.java
index e87ff95..5af984a 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceStackTraceContext.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceStackTraceContext.java
@@ -10,7 +10,7 @@
@Keep
public interface RetraceStackTraceContext {
- static RetraceStackTraceContext getInitialContext() {
+ static RetraceStackTraceContext empty() {
return RetraceStackTraceContextImpl.builder().build();
}
}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceStackTraceElementProxy.java b/src/main/java/com/android/tools/r8/retrace/RetraceStackTraceElementProxy.java
index c148bc0..7f4747a 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceStackTraceElementProxy.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceStackTraceElementProxy.java
@@ -25,9 +25,9 @@
boolean hasLineNumber();
- boolean hasFieldOrReturnType();
+ boolean hasRetracedFieldOrReturnType();
- boolean hasMethodArguments();
+ boolean hasRetracedMethodArguments();
ST getOriginalItem();
@@ -39,7 +39,7 @@
RetracedTypeReference getRetracedFieldOrReturnType();
- List<RetracedTypeReference> getMethodArguments();
+ List<RetracedTypeReference> getRetracedMethodArguments();
String getSourceFile();
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceThrownExceptionElement.java b/src/main/java/com/android/tools/r8/retrace/RetraceThrownExceptionElement.java
new file mode 100644
index 0000000..1af093c
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceThrownExceptionElement.java
@@ -0,0 +1,18 @@
+// 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.retrace;
+
+import com.android.tools.r8.Keep;
+
+@Keep
+public interface RetraceThrownExceptionElement
+ extends RetraceElement<RetraceThrownExceptionResult> {
+
+ RetracedSourceFile getSourceFile();
+
+ RetracedClassReference getRetracedClass();
+
+ RetraceStackTraceContext getContext();
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceThrownExceptionResult.java b/src/main/java/com/android/tools/r8/retrace/RetraceThrownExceptionResult.java
new file mode 100644
index 0000000..b53ec9b
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceThrownExceptionResult.java
@@ -0,0 +1,11 @@
+// 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.retrace;
+
+import com.android.tools.r8.Keep;
+
+@Keep
+public interface RetraceThrownExceptionResult
+ extends RetraceResult<RetraceThrownExceptionElement> {}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetracedSingleFrame.java b/src/main/java/com/android/tools/r8/retrace/RetracedSingleFrame.java
new file mode 100644
index 0000000..6f14809
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/RetracedSingleFrame.java
@@ -0,0 +1,15 @@
+// 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.retrace;
+
+import com.android.tools.r8.Keep;
+
+@Keep
+public interface RetracedSingleFrame {
+
+ RetracedMethodReference getMethodReference();
+
+ int getIndex();
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/Retracer.java b/src/main/java/com/android/tools/r8/retrace/Retracer.java
index bd865a8..34d413b 100644
--- a/src/main/java/com/android/tools/r8/retrace/Retracer.java
+++ b/src/main/java/com/android/tools/r8/retrace/Retracer.java
@@ -29,6 +29,9 @@
RetraceTypeResult retraceType(TypeReference typeReference);
+ RetraceThrownExceptionResult retraceThrownException(
+ ClassReference exception, RetraceStackTraceContext context);
+
static Retracer createDefault(
ProguardMapProducer proguardMapProducer, DiagnosticsHandler diagnosticsHandler) {
return RetracerImpl.create(proguardMapProducer, diagnosticsHandler, false);
diff --git a/src/main/java/com/android/tools/r8/retrace/StringRetrace.java b/src/main/java/com/android/tools/r8/retrace/StringRetrace.java
index ff5b970..09a6931 100644
--- a/src/main/java/com/android/tools/r8/retrace/StringRetrace.java
+++ b/src/main/java/com/android/tools/r8/retrace/StringRetrace.java
@@ -9,10 +9,12 @@
import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.Keep;
import com.android.tools.r8.retrace.internal.StackTraceElementStringProxy;
+import com.android.tools.r8.utils.BooleanBox;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.StringUtils;
import java.util.ArrayList;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
@@ -77,48 +79,37 @@
*/
public List<String> retrace(List<String> stackTrace) {
List<String> retracedStrings = new ArrayList<>();
- List<List<String>> retracedStackTraces =
- removeDuplicateStackTraces(retraceStackTrace(stackTrace));
+ List<Iterator<String>> retracedStackTraces = retraceStackTrace(stackTrace);
if (retracedStackTraces.size() > 1 && isVerbose) {
retracedStrings.add("There are " + retracedStackTraces.size() + " ambiguous stack traces.");
}
for (int i = 0; i < retracedStackTraces.size(); i++) {
- List<String> result = retracedStackTraces.get(i);
- if (i > 0 && !result.isEmpty()) {
- // We are reporting an ambiguous frame. To support retracing tools that retrace line by line
- // we have to emit <OR> at the point of the first ' at ' if we can find it.
- String firstLine = result.get(0);
- int indexToInsertOr = firstLine.indexOf(" at ");
- boolean hasSpace = indexToInsertOr >= 0;
- if (indexToInsertOr < 0) {
- indexToInsertOr = Math.max(StringUtils.firstNonWhitespaceCharacter(firstLine), 0);
- }
- result.set(
- 0,
- firstLine.substring(0, indexToInsertOr)
- + (hasSpace ? "<OR>" : "<OR> ")
- + firstLine.substring(indexToInsertOr));
- }
- retracedStrings.addAll(result);
+ Iterator<String> result = retracedStackTraces.get(i);
+ BooleanBox insertOr = new BooleanBox(i > 0);
+ result.forEachRemaining(
+ stackTraceLine -> {
+ if (insertOr.get()) {
+ // We are reporting an ambiguous frame. To support retracing tools that retrace line
+ // by line we have to emit <OR> at the point of the first ' at ' if we can find it.
+ int indexToInsertOr = stackTraceLine.indexOf(" at ");
+ boolean hasSpace = indexToInsertOr >= 0;
+ if (indexToInsertOr < 0) {
+ indexToInsertOr =
+ Math.max(StringUtils.firstNonWhitespaceCharacter(stackTraceLine), 0);
+ }
+ retracedStrings.add(
+ stackTraceLine.substring(0, indexToInsertOr)
+ + (hasSpace ? "<OR>" : "<OR> ")
+ + stackTraceLine.substring(indexToInsertOr));
+ insertOr.set(false);
+ } else {
+ retracedStrings.add(stackTraceLine);
+ }
+ });
}
return retracedStrings;
}
- private List<List<String>> removeDuplicateStackTraces(List<List<String>> stackTraces) {
- if (stackTraces.size() == 1) {
- return stackTraces;
- }
- Set<List<String>> seenStackTraces = new HashSet<>();
- List<List<String>> nonDuplicateStackTraces = new ArrayList<>();
- stackTraces.forEach(
- stackTrace -> {
- if (seenStackTraces.add(stackTrace)) {
- nonDuplicateStackTraces.add(stackTrace);
- }
- });
- return nonDuplicateStackTraces;
- }
-
/**
* Retraces a single stack trace line and returns the potential list of original frames
*
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java
index 0f165cf..f94035b 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java
@@ -25,7 +25,7 @@
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.List;
-import java.util.Optional;
+import java.util.OptionalInt;
import java.util.function.BiFunction;
import java.util.stream.Stream;
@@ -47,10 +47,6 @@
return new RetraceClassResultImpl(obfuscatedReference, mapper, retracer);
}
- RetracerImpl getRetracerImpl() {
- return retracer;
- }
-
@Override
public RetraceFieldResultImpl lookupField(String fieldName) {
return lookupField(FieldDefinition.create(obfuscatedReference, fieldName));
@@ -124,25 +120,32 @@
@Override
public RetraceFrameResultImpl lookupFrame(
- RetraceStackTraceContext context, Optional<Integer> position, String methodName) {
- return lookupFrame(MethodDefinition.create(obfuscatedReference, methodName), position);
+ RetraceStackTraceContext context, OptionalInt position, String methodName) {
+ return lookupFrame(context, position, MethodDefinition.create(obfuscatedReference, methodName));
}
@Override
public RetraceFrameResultImpl lookupFrame(
RetraceStackTraceContext context,
- Optional<Integer> position,
+ OptionalInt position,
String methodName,
List<TypeReference> formalTypes,
TypeReference returnType) {
return lookupFrame(
+ context,
+ position,
MethodDefinition.create(
- Reference.method(obfuscatedReference, methodName, formalTypes, returnType)),
- position);
+ Reference.method(obfuscatedReference, methodName, formalTypes, returnType)));
+ }
+
+ @Override
+ public RetraceThrownExceptionResultImpl lookupThrownException(RetraceStackTraceContext context) {
+ return new RetraceThrownExceptionResultImpl(
+ (RetraceStackTraceContextImpl) context, obfuscatedReference, mapper);
}
private RetraceFrameResultImpl lookupFrame(
- MethodDefinition definition, Optional<Integer> position) {
+ RetraceStackTraceContext context, OptionalInt position, MethodDefinition definition) {
List<Pair<RetraceClassElementImpl, List<MappedRange>>> mappings = new ArrayList<>();
internalStream()
.forEach(
@@ -153,11 +156,12 @@
mappings.add(new Pair<>(element, mappedRanges));
});
});
- return new RetraceFrameResultImpl(this, mappings, definition, position, retracer);
+ return new RetraceFrameResultImpl(
+ this, mappings, definition, position, retracer, (RetraceStackTraceContextImpl) context);
}
private List<List<MappedRange>> getMappedRangesForFrame(
- RetraceClassElementImpl element, MethodDefinition definition, Optional<Integer> position) {
+ RetraceClassElementImpl element, MethodDefinition definition, OptionalInt position) {
List<List<MappedRange>> overloadedRanges = new ArrayList<>();
if (mapper == null) {
overloadedRanges.add(null);
@@ -170,8 +174,8 @@
return overloadedRanges;
}
List<MappedRange> mappedRangesForPosition = null;
- if (position.isPresent() && position.get() >= 0) {
- mappedRangesForPosition = mappedRanges.allRangesForLine(position.get(), false);
+ if (position.isPresent() && position.getAsInt() >= 0) {
+ mappedRangesForPosition = mappedRanges.allRangesForLine(position.getAsInt(), false);
}
if (mappedRangesForPosition == null || mappedRangesForPosition.isEmpty()) {
mappedRangesForPosition = mappedRanges.getMappedRanges();
@@ -228,7 +232,7 @@
private final RetracedClassReferenceImpl classReference;
private final ClassNamingForNameMapper mapper;
- public RetraceClassElementImpl(
+ private RetraceClassElementImpl(
RetraceClassResultImpl classResult,
RetracedClassReferenceImpl classReference,
ClassNamingForNameMapper mapper) {
@@ -244,8 +248,8 @@
@Override
public RetracedSourceFile getSourceFile() {
- if (classResult.mapper != null) {
- for (MappingInformation info : classResult.mapper.getAdditionalMappingInfo()) {
+ if (mapper != null) {
+ for (MappingInformation info : mapper.getAdditionalMappingInfo()) {
if (info.isFileNameInformation()) {
return new RetracedSourceFileImpl(info.asFileNameInformation().getFileName());
}
@@ -272,13 +276,6 @@
}
@Override
- public RetraceStackTraceContext getContextWhereClassWasThrown() {
- return RetraceStackTraceContextImpl.builder()
- .setSeenException(getRetracedClass().getClassReference())
- .build();
- }
-
- @Override
public RetraceFieldResultImpl lookupField(String fieldName) {
return lookupField(FieldDefinition.create(classReference.getClassReference(), fieldName));
}
@@ -332,18 +329,23 @@
}
@Override
- public RetraceFrameResultImpl lookupFrame(Optional<Integer> position, String methodName) {
+ public RetraceFrameResultImpl lookupFrame(
+ RetraceStackTraceContext context, OptionalInt position, String methodName) {
return lookupFrame(
- position, MethodDefinition.create(classReference.getClassReference(), methodName));
+ context,
+ position,
+ MethodDefinition.create(classReference.getClassReference(), methodName));
}
@Override
public RetraceFrameResult lookupFrame(
- Optional<Integer> position,
+ RetraceStackTraceContext context,
+ OptionalInt position,
String methodName,
List<TypeReference> formalTypes,
TypeReference returnType) {
return lookupFrame(
+ context,
position,
MethodDefinition.create(
Reference.method(
@@ -352,8 +354,8 @@
@Override
public RetraceFrameResult lookupFrame(
- Optional<Integer> position, MethodReference methodReference) {
- return lookupFrame(position, MethodDefinition.create(methodReference));
+ RetraceStackTraceContext context, OptionalInt position, MethodReference methodReference) {
+ return lookupFrame(context, position, MethodDefinition.create(methodReference));
}
@Override
@@ -363,7 +365,7 @@
}
private RetraceFrameResultImpl lookupFrame(
- Optional<Integer> position, MethodDefinition definition) {
+ RetraceStackTraceContext context, OptionalInt position, MethodDefinition definition) {
MethodDefinition methodDefinition =
MethodDefinition.create(classReference.getClassReference(), definition.getName());
ImmutableList.Builder<Pair<RetraceClassElementImpl, List<MappedRange>>> builder =
@@ -375,7 +377,12 @@
builder.add(new Pair<>(this, mappedRanges));
});
return new RetraceFrameResultImpl(
- classResult, builder.build(), methodDefinition, position, classResult.retracer);
+ classResult,
+ builder.build(),
+ methodDefinition,
+ position,
+ classResult.retracer,
+ (RetraceStackTraceContextImpl) context);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceFrameResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceFrameResultImpl.java
index 9bee685..a2936bf 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetraceFrameResultImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceFrameResultImpl.java
@@ -15,7 +15,7 @@
import com.android.tools.r8.retrace.RetraceInvalidRewriteFrameDiagnostics;
import com.android.tools.r8.retrace.RetraceStackTraceContext;
import com.android.tools.r8.retrace.RetracedClassMemberReference;
-import com.android.tools.r8.retrace.RetracedMethodReference;
+import com.android.tools.r8.retrace.RetracedSingleFrame;
import com.android.tools.r8.retrace.RetracedSourceFile;
import com.android.tools.r8.retrace.internal.RetraceClassResultImpl.RetraceClassElementImpl;
import com.android.tools.r8.utils.ListUtils;
@@ -26,17 +26,18 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import java.util.Optional;
-import java.util.function.BiConsumer;
+import java.util.OptionalInt;
+import java.util.function.Consumer;
import java.util.stream.Stream;
class RetraceFrameResultImpl implements RetraceFrameResult {
private final RetraceClassResultImpl classResult;
private final MethodDefinition methodDefinition;
- private final Optional<Integer> obfuscatedPosition;
+ private final OptionalInt obfuscatedPosition;
private final List<Pair<RetraceClassElementImpl, List<MappedRange>>> mappedRanges;
private final RetracerImpl retracer;
+ private final RetraceStackTraceContextImpl context;
private OptionalBool isAmbiguousCache = OptionalBool.UNKNOWN;
@@ -44,13 +45,15 @@
RetraceClassResultImpl classResult,
List<Pair<RetraceClassElementImpl, List<MappedRange>>> mappedRanges,
MethodDefinition methodDefinition,
- Optional<Integer> obfuscatedPosition,
- RetracerImpl retracer) {
+ OptionalInt obfuscatedPosition,
+ RetracerImpl retracer,
+ RetraceStackTraceContextImpl context) {
this.classResult = classResult;
this.methodDefinition = methodDefinition;
this.obfuscatedPosition = obfuscatedPosition;
this.mappedRanges = mappedRanges;
this.retracer = retracer;
+ this.context = context;
}
@Override
@@ -95,7 +98,8 @@
classElement.getRetracedClass().getClassReference())),
ImmutableList.of(),
obfuscatedPosition,
- retracer));
+ retracer,
+ context));
}
// Iterate over mapped ranges that may have different positions than specified.
List<ElementImpl> ambiguousFrames = new ArrayList<>();
@@ -128,13 +132,12 @@
getRetracedMethod(methodReference, topFrame, obfuscatedPosition),
mappedRangesForElement,
obfuscatedPosition,
- retracer);
+ retracer,
+ context);
}
private RetracedMethodReferenceImpl getRetracedMethod(
- MethodReference methodReference,
- MappedRange mappedRange,
- Optional<Integer> obfuscatedPosition) {
+ MethodReference methodReference, MappedRange mappedRange, OptionalInt obfuscatedPosition) {
if (mappedRange.minifiedRange == null
|| (obfuscatedPosition.orElse(-1) == -1 && !isAmbiguous())) {
int originalLineNumber = mappedRange.getFirstLineNumberOfOriginalRange();
@@ -145,11 +148,11 @@
}
}
if (!obfuscatedPosition.isPresent()
- || !mappedRange.minifiedRange.contains(obfuscatedPosition.get())) {
+ || !mappedRange.minifiedRange.contains(obfuscatedPosition.getAsInt())) {
return RetracedMethodReferenceImpl.create(methodReference);
}
return RetracedMethodReferenceImpl.create(
- methodReference, mappedRange.getOriginalLineNumber(obfuscatedPosition.get()));
+ methodReference, mappedRange.getOriginalLineNumber(obfuscatedPosition.getAsInt()));
}
public static class ElementImpl implements RetraceFrameElement {
@@ -158,22 +161,25 @@
private final RetraceFrameResultImpl retraceFrameResult;
private final RetraceClassElementImpl classElement;
private final List<MappedRange> mappedRanges;
- private final Optional<Integer> obfuscatedPosition;
+ private final OptionalInt obfuscatedPosition;
private final RetracerImpl retracer;
+ private final RetraceStackTraceContextImpl context;
ElementImpl(
RetraceFrameResultImpl retraceFrameResult,
RetraceClassElementImpl classElement,
RetracedMethodReferenceImpl methodReference,
List<MappedRange> mappedRanges,
- Optional<Integer> obfuscatedPosition,
- RetracerImpl retracer) {
+ OptionalInt obfuscatedPosition,
+ RetracerImpl retracer,
+ RetraceStackTraceContextImpl context) {
this.methodReference = methodReference;
this.retraceFrameResult = retraceFrameResult;
this.classElement = classElement;
this.mappedRanges = mappedRanges;
this.obfuscatedPosition = obfuscatedPosition;
this.retracer = retracer;
+ this.context = context;
}
private boolean isOuterMostFrameCompilerSynthesized() {
@@ -214,46 +220,67 @@
}
@Override
- public void visitAllFrames(BiConsumer<RetracedMethodReference, Integer> consumer) {
+ public void forEach(Consumer<RetracedSingleFrame> consumer) {
+ if (mappedRanges == null || mappedRanges.isEmpty()) {
+ consumer.accept(RetracedSingleFrameImpl.create(getTopFrame(), 0));
+ return;
+ }
int counter = 0;
- consumer.accept(getTopFrame(), counter++);
+ consumer.accept(RetracedSingleFrameImpl.create(getTopFrame(), counter++));
for (RetracedMethodReferenceImpl outerFrame : getOuterFrames()) {
- consumer.accept(outerFrame, counter++);
+ consumer.accept(RetracedSingleFrameImpl.create(outerFrame, counter++));
}
}
@Override
- public void visitRewrittenFrames(
- RetraceStackTraceContext context, BiConsumer<RetracedMethodReference, Integer> consumer) {
+ public Stream<RetracedSingleFrame> stream() {
+ Stream.Builder<RetracedSingleFrame> builder = Stream.builder();
+ forEach(builder::add);
+ return builder.build();
+ }
+
+ @Override
+ public void forEachRewritten(
+ RetraceStackTraceContext context, Consumer<RetracedSingleFrame> consumer) {
RetraceStackTraceContextImpl contextImpl = (RetraceStackTraceContextImpl) context;
RetraceStackTraceCurrentEvaluationInformation currentFrameInformation =
- contextImpl.computeRewritingInformation(mappedRanges);
+ context == null
+ ? RetraceStackTraceCurrentEvaluationInformation.empty()
+ : contextImpl.computeRewritingInformation(mappedRanges);
int index = 0;
int numberOfFramesToRemove = currentFrameInformation.getRemoveInnerFrames();
- RetracedMethodReferenceImpl prev = getTopFrame();
- List<RetracedMethodReferenceImpl> outerFrames = getOuterFrames();
- if (numberOfFramesToRemove > outerFrames.size() + 1) {
- assert prev.isKnown();
+ int totalNumberOfFrames =
+ (mappedRanges == null || mappedRanges.isEmpty()) ? 1 : mappedRanges.size();
+ if (numberOfFramesToRemove > totalNumberOfFrames) {
DiagnosticsHandler diagnosticsHandler = retracer.getDiagnosticsHandler();
diagnosticsHandler.warning(
RetraceInvalidRewriteFrameDiagnostics.create(
- numberOfFramesToRemove, prev.asKnown().toString()));
+ numberOfFramesToRemove, getTopFrame().asKnown().toString()));
numberOfFramesToRemove = 0;
}
+ RetracedMethodReferenceImpl prev = getTopFrame();
+ List<RetracedMethodReferenceImpl> outerFrames = getOuterFrames();
for (RetracedMethodReferenceImpl next : outerFrames) {
if (numberOfFramesToRemove-- <= 0) {
- consumer.accept(prev, index++);
+ consumer.accept(RetracedSingleFrameImpl.create(prev, index++));
}
prev = next;
}
// We expect only the last frame, i.e., the outer-most caller to potentially be synthesized.
// If not include it too.
if (numberOfFramesToRemove <= 0 && !isOuterMostFrameCompilerSynthesized()) {
- consumer.accept(prev, index);
+ consumer.accept(RetracedSingleFrameImpl.create(prev, index));
}
}
@Override
+ public Stream<RetracedSingleFrame> streamRewritten(RetraceStackTraceContext context) {
+ Stream.Builder<RetracedSingleFrame> builder = Stream.builder();
+ forEachRewritten(context, builder::add);
+ return builder.build();
+ }
+
+ @Override
public RetracedSourceFile getSourceFile(RetracedClassMemberReference frame) {
return RetraceUtils.getSourceFileOrLookup(
frame.getHolderClass(), classElement, retraceFrameResult.retracer);
@@ -266,20 +293,22 @@
}
List<RetracedMethodReferenceImpl> outerFrames = new ArrayList<>();
for (int i = 1; i < mappedRanges.size(); i++) {
- MappedRange mappedRange = mappedRanges.get(i);
- MethodReference methodReference =
- methodReferenceFromMappedRange(
- mappedRange, classElement.getRetracedClass().getClassReference());
- outerFrames.add(
- retraceFrameResult.getRetracedMethod(methodReference, mappedRange, obfuscatedPosition));
+ outerFrames.add(getMethodReferenceFromMappedRange(mappedRanges.get(i)));
}
return outerFrames;
}
+ private RetracedMethodReferenceImpl getMethodReferenceFromMappedRange(MappedRange mappedRange) {
+ MethodReference methodReference =
+ methodReferenceFromMappedRange(
+ mappedRange, classElement.getRetracedClass().getClassReference());
+ return retraceFrameResult.getRetracedMethod(methodReference, mappedRange, obfuscatedPosition);
+ }
+
@Override
public RetraceStackTraceContext getContext() {
// This will change when supporting outline frames.
- return RetraceStackTraceContext.getInitialContext();
+ return RetraceStackTraceContext.empty();
}
}
}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceMethodResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceMethodResultImpl.java
index 7d97ed2..978a933 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetraceMethodResultImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceMethodResultImpl.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.retrace.RetraceMethodElement;
import com.android.tools.r8.retrace.RetraceMethodResult;
+import com.android.tools.r8.retrace.RetraceStackTraceContext;
import com.android.tools.r8.retrace.RetracedMethodReference;
import com.android.tools.r8.retrace.RetracedSourceFile;
import com.android.tools.r8.retrace.internal.RetraceClassResultImpl.RetraceClassElementImpl;
@@ -17,7 +18,7 @@
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.List;
-import java.util.Optional;
+import java.util.OptionalInt;
import java.util.stream.Stream;
public class RetraceMethodResultImpl implements RetraceMethodResult {
@@ -61,7 +62,7 @@
}
@Override
- public RetraceFrameResultImpl narrowByPosition(int position) {
+ public RetraceFrameResultImpl narrowByPosition(RetraceStackTraceContext context, int position) {
List<Pair<RetraceClassElementImpl, List<MappedRange>>> narrowedRanges = new ArrayList<>();
List<Pair<RetraceClassElementImpl, List<MappedRange>>> noMappingRanges = new ArrayList<>();
for (Pair<RetraceClassElementImpl, List<MappedRange>> mappedRange : mappedRanges) {
@@ -92,8 +93,9 @@
classResult,
narrowedRanges.isEmpty() ? noMappingRanges : narrowedRanges,
methodDefinition,
- Optional.of(position),
- retracer);
+ OptionalInt.of(position),
+ retracer,
+ (RetraceStackTraceContextImpl) context);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceStackTraceContextImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceStackTraceContextImpl.java
index 7cc4a30..31533d4 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetraceStackTraceContextImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceStackTraceContextImpl.java
@@ -15,14 +15,14 @@
public class RetraceStackTraceContextImpl implements RetraceStackTraceContext {
- private final ClassReference seenException;
+ private final ClassReference thrownException;
- private RetraceStackTraceContextImpl(ClassReference seenException) {
- this.seenException = seenException;
+ private RetraceStackTraceContextImpl(ClassReference thrownException) {
+ this.thrownException = thrownException;
}
- public ClassReference getSeenException() {
- return seenException;
+ public ClassReference getThrownException() {
+ return thrownException;
}
RetraceStackTraceCurrentEvaluationInformation computeRewritingInformation(
@@ -54,22 +54,26 @@
}
public static Builder builder() {
- return new Builder();
+ return Builder.create();
}
public static class Builder {
- private ClassReference seenException;
+ private ClassReference thrownException;
private Builder() {}
- public Builder setSeenException(ClassReference seenException) {
- this.seenException = seenException;
+ public Builder setThrownException(ClassReference thrownException) {
+ this.thrownException = thrownException;
return this;
}
public RetraceStackTraceContextImpl build() {
- return new RetraceStackTraceContextImpl(seenException);
+ return new RetraceStackTraceContextImpl(thrownException);
+ }
+
+ public static Builder create() {
+ return new Builder();
}
}
}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceThrownExceptionResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceThrownExceptionResultImpl.java
new file mode 100644
index 0000000..aa2c1f0
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceThrownExceptionResultImpl.java
@@ -0,0 +1,98 @@
+// 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.retrace.internal;
+
+import com.android.tools.r8.naming.ClassNamingForNameMapper;
+import com.android.tools.r8.naming.mappinginformation.MappingInformation;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.retrace.RetraceStackTraceContext;
+import com.android.tools.r8.retrace.RetraceThrownExceptionElement;
+import com.android.tools.r8.retrace.RetraceThrownExceptionResult;
+import com.android.tools.r8.retrace.RetracedSourceFile;
+import java.util.stream.Stream;
+
+public class RetraceThrownExceptionResultImpl implements RetraceThrownExceptionResult {
+
+ private final RetraceStackTraceContextImpl context;
+ private final ClassReference obfuscatedReference;
+ private final ClassNamingForNameMapper mapper;
+
+ RetraceThrownExceptionResultImpl(
+ RetraceStackTraceContextImpl context,
+ ClassReference obfuscatedReference,
+ ClassNamingForNameMapper mapper) {
+ this.context = context;
+ this.obfuscatedReference = obfuscatedReference;
+ this.mapper = mapper;
+ }
+
+ @Override
+ public Stream<RetraceThrownExceptionElement> stream() {
+ return Stream.of(createElement());
+ }
+
+ private RetraceThrownExceptionElement createElement() {
+ return new RetraceThrownExceptionElementImpl(
+ this,
+ RetracedClassReferenceImpl.create(
+ mapper == null
+ ? obfuscatedReference
+ : Reference.classFromTypeName(mapper.originalName)),
+ mapper,
+ obfuscatedReference);
+ }
+
+ public static class RetraceThrownExceptionElementImpl implements RetraceThrownExceptionElement {
+
+ private final RetraceThrownExceptionResultImpl thrownExceptionResult;
+ private final RetracedClassReferenceImpl classReference;
+ private final ClassNamingForNameMapper mapper;
+ private final ClassReference thrownException;
+
+ private RetraceThrownExceptionElementImpl(
+ RetraceThrownExceptionResultImpl thrownExceptionResult,
+ RetracedClassReferenceImpl classReference,
+ ClassNamingForNameMapper mapper,
+ ClassReference thrownException) {
+ this.thrownExceptionResult = thrownExceptionResult;
+ this.classReference = classReference;
+ this.mapper = mapper;
+ this.thrownException = thrownException;
+ }
+
+ @Override
+ public RetracedClassReferenceImpl getRetracedClass() {
+ return classReference;
+ }
+
+ @Override
+ public RetraceThrownExceptionResult getRetraceResultContext() {
+ return thrownExceptionResult;
+ }
+
+ @Override
+ public RetracedSourceFile getSourceFile() {
+ if (mapper != null) {
+ for (MappingInformation info : mapper.getAdditionalMappingInfo()) {
+ if (info.isFileNameInformation()) {
+ return new RetracedSourceFileImpl(info.asFileNameInformation().getFileName());
+ }
+ }
+ }
+ return new RetracedSourceFileImpl(null);
+ }
+
+ @Override
+ public boolean isCompilerSynthesized() {
+ return false;
+ }
+
+ @Override
+ public RetraceStackTraceContext getContext() {
+ return RetraceStackTraceContextImpl.builder().setThrownException(thrownException).build();
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetracedMethodReferenceImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetracedMethodReferenceImpl.java
index 9ac65be..49061b2 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetracedMethodReferenceImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetracedMethodReferenceImpl.java
@@ -16,6 +16,23 @@
public abstract class RetracedMethodReferenceImpl implements RetracedMethodReference {
private static final int NO_POSITION = -1;
+ private static final Comparator<RetracedMethodReference> comparator =
+ Comparator.comparing(RetracedMethodReference::getMethodName)
+ .thenComparing(RetracedMethodReference::isKnown)
+ .thenComparing(
+ RetracedMethodReference::asKnown,
+ Comparator.nullsFirst(
+ Comparator.comparing(
+ (KnownRetracedMethodReference m) -> {
+ if (m == null) {
+ return null;
+ }
+ return m.isVoid() ? "void" : m.getReturnType().getTypeName();
+ }))
+ .thenComparing(
+ KnownRetracedMethodReference::getFormalTypes,
+ ComparatorUtils.listComparator(
+ Comparator.comparing(TypeReference::getTypeName))));
private RetracedMethodReferenceImpl() {}
@@ -36,23 +53,7 @@
@Override
public int compareTo(RetracedMethodReference other) {
- return Comparator.comparing(RetracedMethodReference::getMethodName)
- .thenComparing(RetracedMethodReference::isKnown)
- .thenComparing(
- RetracedMethodReference::asKnown,
- Comparator.nullsFirst(
- Comparator.comparing(
- (KnownRetracedMethodReference m) -> {
- if (m == null) {
- return null;
- }
- return m.isVoid() ? "void" : m.getReturnType().getTypeName();
- }))
- .thenComparing(
- KnownRetracedMethodReference::getFormalTypes,
- ComparatorUtils.listComparator(
- Comparator.comparing(TypeReference::getTypeName))))
- .compare(this, other);
+ return comparator.compare(this, other);
}
public static final class KnownRetracedMethodReferenceImpl extends RetracedMethodReferenceImpl
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetracedSingleFrameImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetracedSingleFrameImpl.java
new file mode 100644
index 0000000..c69b148
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetracedSingleFrameImpl.java
@@ -0,0 +1,33 @@
+// 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.retrace.internal;
+
+import com.android.tools.r8.retrace.RetracedMethodReference;
+import com.android.tools.r8.retrace.RetracedSingleFrame;
+
+public class RetracedSingleFrameImpl implements RetracedSingleFrame {
+
+ private final RetracedMethodReference methodReference;
+ private final int index;
+
+ private RetracedSingleFrameImpl(RetracedMethodReference methodReference, int index) {
+ this.methodReference = methodReference;
+ this.index = index;
+ }
+
+ @Override
+ public RetracedMethodReference getMethodReference() {
+ return methodReference;
+ }
+
+ @Override
+ public int getIndex() {
+ return index;
+ }
+
+ static RetracedSingleFrameImpl create(RetracedMethodReference methodReference, int index) {
+ return new RetracedSingleFrameImpl(methodReference, index);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetracerImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetracerImpl.java
index bad33d8..9aadbb3 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetracerImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetracerImpl.java
@@ -63,7 +63,7 @@
@Override
public RetraceFrameResult retraceFrame(MethodReference methodReference, int position) {
- return retraceFrame(methodReference, position, RetraceStackTraceContext.getInitialContext());
+ return retraceFrame(methodReference, position, RetraceStackTraceContext.empty());
}
@Override
@@ -71,7 +71,7 @@
MethodReference methodReference, int position, RetraceStackTraceContext context) {
return retraceClass(methodReference.getHolderClass())
.lookupMethod(methodReference.getMethodName())
- .narrowByPosition(position);
+ .narrowByPosition(context, position);
}
@Override
@@ -89,4 +89,10 @@
public RetraceTypeResultImpl retraceType(TypeReference typeReference) {
return RetraceTypeResultImpl.create(typeReference, this);
}
+
+ @Override
+ public RetraceThrownExceptionResultImpl retraceThrownException(
+ ClassReference exception, RetraceStackTraceContext context) {
+ return retraceClass(exception).lookupThrownException(context);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementProxyRetracerImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementProxyRetracerImpl.java
index 2e2c38f..8040744 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementProxyRetracerImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementProxyRetracerImpl.java
@@ -25,7 +25,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import java.util.Optional;
+import java.util.OptionalInt;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -70,26 +70,29 @@
RetraceClassResult classResult) {
return currentResults.flatMap(
proxy ->
- classResult.stream()
+ // We assume, since no method was defined for this stack trace element, that this was a
+ // thrown exception.
+ classResult.lookupThrownException(proxy.getContext()).stream()
.map(
- classElement ->
+ thrownExceptionElement ->
proxy
.builder()
- .setRetracedClass(classElement.getRetracedClass())
+ .setRetracedClass(thrownExceptionElement.getRetracedClass())
.joinAmbiguous(classResult.isAmbiguous())
.setTopFrame(true)
- // We assume, since no method was defined for this stack trace element,
- // that this was a thrown exception.
- .setContext(classElement.getContextWhereClassWasThrown())
+ .setContext(thrownExceptionElement.getContext())
.applyIf(
element.hasSourceFile(),
builder -> {
- RetracedSourceFile sourceFile = classElement.getSourceFile();
+ RetracedSourceFile sourceFile =
+ thrownExceptionElement.getSourceFile();
builder.setSourceFile(
sourceFile.hasRetraceResult()
? sourceFile.getSourceFile()
: RetraceUtils.inferSourceFile(
- classElement.getRetracedClass().getTypeName(),
+ thrownExceptionElement
+ .getRetracedClass()
+ .getTypeName(),
element.getSourceFile(),
classResult.hasRetraceResult()));
})
@@ -105,49 +108,48 @@
RetraceFrameResult frameResult =
classResult.lookupFrame(
proxy.context,
- element.hasLineNumber() ? Optional.of(element.getLineNumber()) : Optional.empty(),
+ element.hasLineNumber()
+ ? OptionalInt.of(element.getLineNumber())
+ : OptionalInt.empty(),
element.getMethodName());
return frameResult.stream()
.flatMap(
- frameElement -> {
- List<RetraceStackTraceElementProxyImpl<T, ST>> retracedProxies =
- new ArrayList<>();
- frameElement.visitRewrittenFrames(
- proxy.getContext(),
- (frame, index) -> {
- boolean isTopFrame = index == 0;
- retracedProxies.add(
- proxy
- .builder()
- .setRetracedClass(frame.getHolderClass())
- .setRetracedMethod(frame)
- .joinAmbiguous(frameResult.isAmbiguous() && isTopFrame)
- .setTopFrame(isTopFrame)
- .setContext(frameElement.getContext())
- .applyIf(
- element.hasLineNumber(),
- builder -> {
- builder.setLineNumber(
- frame.getOriginalPositionOrDefault(
- element.getLineNumber()));
- })
- .applyIf(
- element.hasSourceFile(),
- builder -> {
- RetracedSourceFile sourceFileResult =
- frameElement.getSourceFile(frame);
- builder.setSourceFile(
- sourceFileResult.hasRetraceResult()
- ? sourceFileResult.getSourceFile()
- : RetraceUtils.inferSourceFile(
- frame.getHolderClass().getTypeName(),
- element.getSourceFile(),
- classResult.hasRetraceResult()));
- })
- .build());
- });
- return retracedProxies.stream();
- });
+ frameElement ->
+ frameElement
+ .streamRewritten(proxy.getContext())
+ .map(
+ singleFrame -> {
+ boolean isTopFrame = singleFrame.getIndex() == 0;
+ RetracedMethodReference method = singleFrame.getMethodReference();
+ return proxy
+ .builder()
+ .setRetracedClass(method.getHolderClass())
+ .setRetracedMethod(method)
+ .joinAmbiguous(frameResult.isAmbiguous() && isTopFrame)
+ .setTopFrame(isTopFrame)
+ .setContext(frameElement.getContext())
+ .applyIf(
+ element.hasLineNumber(),
+ builder -> {
+ builder.setLineNumber(
+ method.getOriginalPositionOrDefault(
+ element.getLineNumber()));
+ })
+ .applyIf(
+ element.hasSourceFile(),
+ builder -> {
+ RetracedSourceFile sourceFileResult =
+ frameElement.getSourceFile(method);
+ builder.setSourceFile(
+ sourceFileResult.hasRetraceResult()
+ ? sourceFileResult.getSourceFile()
+ : RetraceUtils.inferSourceFile(
+ method.getHolderClass().getTypeName(),
+ element.getSourceFile(),
+ classResult.hasRetraceResult()));
+ })
+ .build();
+ }));
});
}
@@ -330,12 +332,12 @@
}
@Override
- public boolean hasFieldOrReturnType() {
+ public boolean hasRetracedFieldOrReturnType() {
return fieldOrReturnType != null;
}
@Override
- public boolean hasMethodArguments() {
+ public boolean hasRetracedMethodArguments() {
return methodArguments != null;
}
@@ -365,7 +367,7 @@
}
@Override
- public List<RetracedTypeReference> getMethodArguments() {
+ public List<RetracedTypeReference> getRetracedMethodArguments() {
return methodArguments;
}
@@ -408,6 +410,9 @@
@Override
public int compareTo(RetraceStackTraceElementProxy<T, ST> other) {
+ if (this == other) {
+ return 0;
+ }
int classCompare = Boolean.compare(hasRetracedClass(), other.hasRetracedClass());
if (classCompare != 0) {
return classCompare;
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementStringProxy.java b/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementStringProxy.java
index 7afc10b..fc195d0 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementStringProxy.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementStringProxy.java
@@ -273,7 +273,7 @@
startIndex,
endIndex,
(retraced, original, verbose) -> {
- if (!retraced.hasFieldOrReturnType()) {
+ if (!retraced.hasRetracedFieldOrReturnType()) {
return original.getFieldOrReturnType();
}
return retraced.getRetracedFieldOrReturnType().isVoid()
@@ -291,11 +291,11 @@
startIndex,
endIndex,
(retraced, original, verbose) -> {
- if (!retraced.hasMethodArguments()) {
+ if (!retraced.hasRetracedMethodArguments()) {
return original.getMethodArguments();
}
return StringUtils.join(
- ",", retraced.getMethodArguments(), RetracedTypeReference::getTypeName);
+ ",", retraced.getRetracedMethodArguments(), RetracedTypeReference::getTypeName);
});
orderedIndices.add(methodArguments);
return this;
diff --git a/src/main/java/com/android/tools/r8/shaking/DependentMinimumKeepInfoCollection.java b/src/main/java/com/android/tools/r8/shaking/DependentMinimumKeepInfoCollection.java
index aca76da..8e48dfe 100644
--- a/src/main/java/com/android/tools/r8/shaking/DependentMinimumKeepInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/shaking/DependentMinimumKeepInfoCollection.java
@@ -21,8 +21,8 @@
import com.android.tools.r8.shaking.KeepInfo.Joiner;
import com.android.tools.r8.utils.MapUtils;
import com.android.tools.r8.utils.TriConsumer;
-import java.util.HashMap;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
import java.util.function.Function;
@@ -31,12 +31,7 @@
private final Map<EnqueuerEvent, MinimumKeepInfoCollection> dependentMinimumKeepInfo;
public DependentMinimumKeepInfoCollection() {
- this(new HashMap<>());
- }
-
- private DependentMinimumKeepInfoCollection(
- Map<EnqueuerEvent, MinimumKeepInfoCollection> dependentMinimumKeepInfo) {
- this.dependentMinimumKeepInfo = dependentMinimumKeepInfo;
+ this.dependentMinimumKeepInfo = new ConcurrentHashMap<>();
}
public void forEach(BiConsumer<EnqueuerEvent, MinimumKeepInfoCollection> consumer) {
diff --git a/src/main/java/com/android/tools/r8/shaking/DiscardedChecker.java b/src/main/java/com/android/tools/r8/shaking/DiscardedChecker.java
index b04748c..dfc170e 100644
--- a/src/main/java/com/android/tools/r8/shaking/DiscardedChecker.java
+++ b/src/main/java/com/android/tools/r8/shaking/DiscardedChecker.java
@@ -3,40 +3,86 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
-import com.android.tools.r8.graph.DexDefinition;
+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.DexReference;
-import com.android.tools.r8.shaking.RootSetUtils.RootSet;
+import com.android.tools.r8.graph.ProgramDefinition;
+import com.android.tools.r8.shaking.KeepInfo.Joiner;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.ThreadUtils;
import java.util.ArrayList;
-import java.util.HashSet;
import java.util.List;
-import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
public class DiscardedChecker {
- private final Set<DexReference> checkDiscarded;
- private final Iterable<DexProgramClass> classes;
+ private final AppView<? extends AppInfoWithClassHierarchy> appView;
+ private final InternalOptions options;
- public DiscardedChecker(RootSet rootSet, Iterable<DexProgramClass> classes) {
- this.checkDiscarded = new HashSet<>(rootSet.checkDiscarded);
- this.classes = classes;
+ private final List<ProgramDefinition> failed = new ArrayList<>();
+
+ private DiscardedChecker(AppView<? extends AppInfoWithClassHierarchy> appView) {
+ this.appView = appView;
+ this.options = appView.options();
}
- public List<DexDefinition> run() {
- List<DexDefinition> failed = new ArrayList<>(checkDiscarded.size());
- // TODO(b/131668850): Lookup the definition based on the reference.
- for (DexProgramClass clazz : classes) {
- checkItem(clazz, failed);
- clazz.forEachMethod(method -> checkItem(method, failed));
- clazz.forEachField(field -> checkItem(field, failed));
- }
+ public static DiscardedChecker create(AppView<? extends AppInfoWithClassHierarchy> appView) {
+ return new DiscardedChecker(appView);
+ }
+
+ public static DiscardedChecker createForMainDex(
+ AppView<? extends AppInfoWithClassHierarchy> appView) {
+ MinimumKeepInfoCollection unconditionalKeepInfo =
+ appView
+ .getMainDexRootSet()
+ .getDependentMinimumKeepInfo()
+ .getOrCreateUnconditionalMinimumKeepInfo();
+ return new DiscardedChecker(appView) {
+
+ @Override
+ boolean isCheckDiscardedEnabled(ProgramDefinition definition) {
+ return unconditionalKeepInfo.hasMinimumKeepInfoThatMatches(
+ definition.getReference(), Joiner::isCheckDiscardedEnabled);
+ }
+ };
+ }
+
+ public List<ProgramDefinition> run(
+ Iterable<DexProgramClass> classes, ExecutorService executorService)
+ throws ExecutionException {
+ assert failed.isEmpty();
+
+ // TODO(b/131668850): Consider only iterating the items matched by a -checkdiscard rule.
+ ThreadUtils.processItems(classes, this::checkClassAndMembers, executorService);
+
+ // Sort the failures for determinism.
+ failed.sort((item, other) -> item.getReference().compareTo(other.getReference()));
+
return failed;
}
- private void checkItem(DexDefinition item, List<DexDefinition> failed) {
- DexReference reference = item.getReference();
- if (checkDiscarded.contains(reference)) {
- failed.add(item);
+ boolean isCheckDiscardedEnabled(ProgramDefinition definition) {
+ return appView.getKeepInfo().getInfo(definition).isCheckDiscardedEnabled(options);
+ }
+
+ private void checkClassAndMembers(DexProgramClass clazz) {
+ // Only look for -checkdiscard failures for members if the class itself did not fail a
+ // -checkdiscard check
+ if (check(clazz)) {
+ clazz.forEachProgramMember(this::check);
}
}
+
+ /** Returns true if the check succeeded (i.e., no -checkdiscard failure was found). */
+ private boolean check(ProgramDefinition item) {
+ if (isCheckDiscardedEnabled(item)) {
+ // We expect few check discarded failures thus locking here should be OK.
+ synchronized (failed) {
+ failed.add(item);
+ }
+ return false;
+ }
+ return true;
+ }
}
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 28c2602..b4fef63 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -4098,10 +4098,9 @@
// When generating interface bridges the method may be inserted into a live hierarchy.
// If so we need to also mark it as live as the reachable check above will not reprocess the
// hierarchy.
- // TODO(b/183998768): The check for isInterface here should be possible to remove now.
if (definition.isNonAbstractVirtualMethod()
- && (objectAllocationInfoCollection.isInstantiatedDirectlyOrHasInstantiatedSubtype(holder)
- || holder.isInterface())) {
+ && objectAllocationInfoCollection.isInstantiatedDirectlyOrHasInstantiatedSubtype(
+ holder)) {
// TODO(b/120959039): Codify the kept-graph expectations for these cases in tests.
markVirtualMethodAsLive(target, reason);
}
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepInfo.java b/src/main/java/com/android/tools/r8/shaking/KeepInfo.java
index f846462..12265aa 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepInfo.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepInfo.java
@@ -20,6 +20,7 @@
private final boolean allowMinification;
private final boolean allowOptimization;
private final boolean allowShrinking;
+ private final boolean checkDiscarded;
private final boolean requireAccessModificationForRepackaging;
private KeepInfo(
@@ -28,12 +29,14 @@
boolean allowMinification,
boolean allowOptimization,
boolean allowShrinking,
+ boolean checkDiscarded,
boolean requireAccessModificationForRepackaging) {
this.allowAccessModification = allowAccessModification;
this.allowAnnotationRemoval = allowAnnotationRemoval;
this.allowMinification = allowMinification;
this.allowOptimization = allowOptimization;
this.allowShrinking = allowShrinking;
+ this.checkDiscarded = checkDiscarded;
this.requireAccessModificationForRepackaging = requireAccessModificationForRepackaging;
}
@@ -44,6 +47,7 @@
builder.isMinificationAllowed(),
builder.isOptimizationAllowed(),
builder.isShrinkingAllowed(),
+ builder.isCheckDiscardedEnabled(),
builder.isAccessModificationRequiredForRepackaging());
}
@@ -70,8 +74,18 @@
return allowAnnotationRemoval;
}
+ public boolean isCheckDiscardedEnabled(GlobalKeepInfoConfiguration configuration) {
+ return internalIsCheckDiscardedEnabled();
+ }
+
+ boolean internalIsCheckDiscardedEnabled() {
+ return checkDiscarded;
+ }
+
public boolean isParameterRemovalAllowed(GlobalKeepInfoConfiguration configuration) {
- return isOptimizationAllowed(configuration) && isShrinkingAllowed(configuration);
+ return isOptimizationAllowed(configuration)
+ && isShrinkingAllowed(configuration)
+ && !isCheckDiscardedEnabled(configuration);
}
/**
@@ -208,7 +222,8 @@
&& (allowAnnotationRemoval || !other.internalIsAnnotationRemovalAllowed())
&& (allowMinification || !other.internalIsMinificationAllowed())
&& (allowOptimization || !other.internalIsOptimizationAllowed())
- && (allowShrinking || !other.internalIsShrinkingAllowed());
+ && (allowShrinking || !other.internalIsShrinkingAllowed())
+ && (!checkDiscarded || other.internalIsCheckDiscardedEnabled());
}
/** Builder to construct an arbitrary keep info object. */
@@ -230,6 +245,7 @@
private boolean allowMinification;
private boolean allowOptimization;
private boolean allowShrinking;
+ private boolean checkDiscarded;
private boolean requireAccessModificationForRepackaging;
Builder() {
@@ -243,6 +259,7 @@
allowMinification = original.internalIsMinificationAllowed();
allowOptimization = original.internalIsOptimizationAllowed();
allowShrinking = original.internalIsShrinkingAllowed();
+ checkDiscarded = original.internalIsCheckDiscardedEnabled();
requireAccessModificationForRepackaging =
original.internalIsAccessModificationRequiredForRepackaging();
}
@@ -253,6 +270,7 @@
disallowMinification();
disallowOptimization();
disallowShrinking();
+ unsetCheckDiscarded();
requireAccessModificationForRepackaging();
return self();
}
@@ -263,6 +281,7 @@
allowMinification();
allowOptimization();
allowShrinking();
+ unsetCheckDiscarded();
unsetRequireAccessModificationForRepackaging();
return self();
}
@@ -288,6 +307,7 @@
&& isMinificationAllowed() == other.internalIsMinificationAllowed()
&& isOptimizationAllowed() == other.internalIsOptimizationAllowed()
&& isShrinkingAllowed() == other.internalIsShrinkingAllowed()
+ && isCheckDiscardedEnabled() == other.internalIsCheckDiscardedEnabled()
&& isAccessModificationRequiredForRepackaging()
== other.internalIsAccessModificationRequiredForRepackaging();
}
@@ -304,6 +324,10 @@
return allowAnnotationRemoval;
}
+ public boolean isCheckDiscardedEnabled() {
+ return checkDiscarded;
+ }
+
public boolean isMinificationAllowed() {
return allowMinification;
}
@@ -355,6 +379,19 @@
return setAllowShrinking(false);
}
+ public B setCheckDiscarded(boolean checkDiscarded) {
+ this.checkDiscarded = checkDiscarded;
+ return self();
+ }
+
+ public B setCheckDiscarded() {
+ return setCheckDiscarded(true);
+ }
+
+ public B unsetCheckDiscarded() {
+ return setCheckDiscarded(false);
+ }
+
public B setRequireAccessModificationForRepackaging(
boolean requireAccessModificationForRepackaging) {
this.requireAccessModificationForRepackaging = requireAccessModificationForRepackaging;
@@ -440,6 +477,10 @@
return builder.isEqualTo(builder.getBottomInfo());
}
+ public boolean isCheckDiscardedEnabled() {
+ return builder.isCheckDiscardedEnabled();
+ }
+
public boolean isShrinkingAllowed() {
return builder.isShrinkingAllowed();
}
@@ -483,6 +524,11 @@
return self();
}
+ public J setCheckDiscarded() {
+ builder.setCheckDiscarded();
+ return self();
+ }
+
public J requireAccessModificationForRepackaging() {
builder.requireAccessModificationForRepackaging();
return self();
@@ -495,6 +541,7 @@
applyIf(!builder.isMinificationAllowed(), Joiner::disallowMinification);
applyIf(!builder.isOptimizationAllowed(), Joiner::disallowOptimization);
applyIf(!builder.isShrinkingAllowed(), Joiner::disallowShrinking);
+ applyIf(builder.isCheckDiscardedEnabled(), Joiner::setCheckDiscarded);
applyIf(
builder.isAccessModificationRequiredForRepackaging(),
Joiner::requireAccessModificationForRepackaging);
diff --git a/src/main/java/com/android/tools/r8/shaking/MinimumKeepInfoCollection.java b/src/main/java/com/android/tools/r8/shaking/MinimumKeepInfoCollection.java
index 9f97e63..ec1594a 100644
--- a/src/main/java/com/android/tools/r8/shaking/MinimumKeepInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/shaking/MinimumKeepInfoCollection.java
@@ -20,8 +20,8 @@
import com.android.tools.r8.shaking.KeepInfo.Joiner;
import com.android.tools.r8.utils.MapUtils;
import java.util.Collections;
-import java.util.IdentityHashMap;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
import java.util.function.BiPredicate;
import java.util.function.Predicate;
@@ -34,7 +34,7 @@
private final Map<DexReference, KeepInfo.Joiner<?, ?, ?>> minimumKeepInfo;
public MinimumKeepInfoCollection() {
- this(new IdentityHashMap<>());
+ this(new ConcurrentHashMap<>());
}
private MinimumKeepInfoCollection(Map<DexReference, KeepInfo.Joiner<?, ?, ?>> minimumKeepInfo) {
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardCheckDiscardRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardCheckDiscardRule.java
index 82b81a4..8ab748e 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardCheckDiscardRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardCheckDiscardRule.java
@@ -75,6 +75,16 @@
}
@Override
+ public boolean isProguardCheckDiscardRule() {
+ return true;
+ }
+
+ @Override
+ public ProguardCheckDiscardRule asProguardCheckDiscardRule() {
+ return this;
+ }
+
+ @Override
String typeString() {
return "checkdiscard";
}
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 fbedd8e..41181b1 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java
@@ -66,6 +66,14 @@
used = true;
}
+ public boolean isProguardCheckDiscardRule() {
+ return false;
+ }
+
+ public ProguardCheckDiscardRule asProguardCheckDiscardRule() {
+ return null;
+ }
+
public boolean isProguardKeepRule() {
return false;
}
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 c4ddd9f..3dc1bc5 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
@@ -5,6 +5,7 @@
import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import static com.android.tools.r8.utils.LensUtils.rewriteAndApplyIfNotPrimitiveType;
+import static com.google.common.base.Predicates.alwaysTrue;
import static java.util.Collections.emptyMap;
import com.android.tools.r8.dex.Constants;
@@ -38,6 +39,7 @@
import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
import com.android.tools.r8.graph.ProgramDefinition;
import com.android.tools.r8.graph.ProgramField;
+import com.android.tools.r8.graph.ProgramMember;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.PrunedItems;
import com.android.tools.r8.graph.SubtypingInfo;
@@ -53,6 +55,7 @@
import com.android.tools.r8.shaking.EnqueuerEvent.InstantiatedClassEnqueuerEvent;
import com.android.tools.r8.shaking.EnqueuerEvent.LiveClassEnqueuerEvent;
import com.android.tools.r8.shaking.EnqueuerEvent.UnconditionalKeepInfoEvent;
+import com.android.tools.r8.shaking.KeepInfo.Joiner;
import com.android.tools.r8.utils.ArrayUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.MethodSignatureEquivalence;
@@ -60,6 +63,7 @@
import com.android.tools.r8.utils.PredicateSet;
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.ThreadUtils;
+import com.android.tools.r8.utils.TraversalContinuation;
import com.android.tools.r8.utils.collections.ProgramMethodMap;
import com.google.common.base.Equivalence.Wrapper;
import com.google.common.collect.ImmutableList;
@@ -104,7 +108,6 @@
private final DependentMinimumKeepInfoCollection dependentMinimumKeepInfo =
new DependentMinimumKeepInfoCollection();
private final LinkedHashMap<DexReference, DexReference> reasonAsked = new LinkedHashMap<>();
- private final LinkedHashMap<DexReference, DexReference> checkDiscarded = new LinkedHashMap<>();
private final Set<DexMethod> alwaysInline = Sets.newIdentityHashSet();
private final Set<DexMethod> neverInline = Sets.newIdentityHashSet();
private final Set<DexMethod> neverInlineDueToSingleCaller = Sets.newIdentityHashSet();
@@ -136,6 +139,7 @@
private final Map<OriginWithPosition, Set<DexMethod>> assumeNoSideEffectsWarnings =
new LinkedHashMap<>();
+ private final Set<DexProgramClass> classesWithCheckDiscardedMembers = Sets.newIdentityHashSet();
private final OptimizationFeedbackSimple feedback = OptimizationFeedbackSimple.getInstance();
@@ -229,7 +233,7 @@
} else {
// Members mentioned at -keep should always be pinned as long as that -keep rule is
// not triggered conditionally.
- preconditionSupplier.put((definition -> true), null);
+ preconditionSupplier.put(alwaysTrue(), null);
}
markMatchingVisibleMethods(
clazz, memberKeepRules, rule, preconditionSupplier, false, ifRule);
@@ -245,22 +249,8 @@
assert ifRule == null;
if (rule instanceof ProguardIfRule) {
throw new Unreachable("-if rule will be evaluated separately, not here.");
- } else if (rule instanceof ProguardCheckDiscardRule) {
- if (!clazz.isProgramClass()) {
- appView
- .reporter()
- .warning(
- new StringDiagnostic(
- "The rule `" + rule + "` matches a class not in the program."));
- } else if (memberKeepRules.isEmpty()) {
- markClass(clazz, rule, ifRule);
- } else {
- preconditionSupplier = ImmutableMap.of((definition -> true), clazz.asProgramClass());
- markMatchingVisibleMethods(
- clazz, memberKeepRules, rule, preconditionSupplier, true, ifRule);
- markMatchingVisibleFields(
- clazz, memberKeepRules, rule, preconditionSupplier, true, ifRule);
- }
+ } else if (rule.isProguardCheckDiscardRule()) {
+ evaluateCheckDiscardRule(clazz, rule.asProguardCheckDiscardRule());
} else if (rule instanceof ProguardWhyAreYouKeepingRule) {
markClass(clazz, rule, ifRule);
markMatchingVisibleMethods(clazz, memberKeepRules, rule, null, true, ifRule);
@@ -349,6 +339,7 @@
} finally {
application.timing.end();
}
+ finalizeCheckDiscardedInformation();
generateAssumeNoSideEffectsWarnings();
if (!noSideEffects.isEmpty() || !assumedValues.isEmpty()) {
BottomUpClassHierarchyTraversal.forAllClasses(appView, subtypingInfo)
@@ -371,7 +362,6 @@
return new RootSet(
dependentMinimumKeepInfo,
ImmutableList.copyOf(reasonAsked.values()),
- ImmutableList.copyOf(checkDiscarded.values()),
alwaysInline,
neverInline,
neverInlineDueToSingleCaller,
@@ -1180,9 +1170,10 @@
assumedValues.put(item.asMember().getReference(), rule);
context.markAsUsed();
}
- } else if (context instanceof ProguardCheckDiscardRule) {
- checkDiscarded.computeIfAbsent(item.getReference(), i -> i);
- context.markAsUsed();
+ } else if (context.isProguardCheckDiscardRule()) {
+ assert item.isProgramMember();
+ evaluateCheckDiscardMemberRule(
+ item.asProgramMember(), context.asProguardCheckDiscardRule());
} else if (context instanceof InlineRule) {
if (item.isMethod()) {
DexMethod reference = item.asMethod().getReference();
@@ -1313,7 +1304,64 @@
}
}
- private synchronized void evaluateKeepRule(
+ private void evaluateCheckDiscardRule(DexClass clazz, ProguardCheckDiscardRule rule) {
+ if (clazz.isProgramClass()) {
+ evaluateCheckDiscardRule(clazz.asProgramClass(), rule.asProguardCheckDiscardRule());
+ } else {
+ StringDiagnostic warning =
+ new StringDiagnostic("The rule `" + rule + "` matches a class not in the program.");
+ appView.reporter().warning(warning);
+ }
+ }
+
+ private void evaluateCheckDiscardRule(DexProgramClass clazz, ProguardCheckDiscardRule rule) {
+ if (rule.getMemberRules().isEmpty()) {
+ evaluateCheckDiscardClassAndAllMembersRule(clazz, rule);
+ } else if (clazz.hasFields() || clazz.hasMethods()) {
+ markMatchingFields(clazz, rule.getMemberRules(), rule, null, null);
+ markMatchingMethods(clazz, rule.getMemberRules(), rule, null, null);
+ classesWithCheckDiscardedMembers.add(clazz);
+ }
+ }
+
+ private void evaluateCheckDiscardClassAndAllMembersRule(
+ DexProgramClass clazz, ProguardCheckDiscardRule rule) {
+ setCheckDiscarded(clazz);
+ clazz.forEachProgramMember(this::setCheckDiscarded);
+ rule.markAsUsed();
+ }
+
+ private void evaluateCheckDiscardMemberRule(
+ ProgramMember<?, ?> member, ProguardCheckDiscardRule rule) {
+ setCheckDiscarded(member);
+ rule.markAsUsed();
+ }
+
+ private void setCheckDiscarded(ProgramDefinition definition) {
+ dependentMinimumKeepInfo
+ .getOrCreateUnconditionalMinimumKeepInfo()
+ .getOrCreateMinimumKeepInfoFor(definition.getReference())
+ .setCheckDiscarded();
+ }
+
+ private void finalizeCheckDiscardedInformation() {
+ MinimumKeepInfoCollection unconditionalKeepInfo =
+ dependentMinimumKeepInfo.getUnconditionalMinimumKeepInfoOrDefault(
+ MinimumKeepInfoCollection.empty());
+ for (DexProgramClass clazz : classesWithCheckDiscardedMembers) {
+ TraversalContinuation continueIfAllMembersMarkedAsCheckDiscarded =
+ clazz.traverseProgramMembers(
+ member ->
+ TraversalContinuation.continueIf(
+ unconditionalKeepInfo.hasMinimumKeepInfoThatMatches(
+ member.getReference(), Joiner::isCheckDiscardedEnabled)));
+ if (continueIfAllMembersMarkedAsCheckDiscarded.shouldContinue()) {
+ setCheckDiscarded(clazz);
+ }
+ }
+ }
+
+ private void evaluateKeepRule(
ProgramDefinition item,
ProguardKeepRule context,
ProguardMemberRule rule,
@@ -1553,7 +1601,6 @@
public static class RootSet extends RootSetBase {
public final ImmutableList<DexReference> reasonAsked;
- public final ImmutableList<DexReference> checkDiscarded;
public final Set<DexMethod> alwaysInline;
public final Set<DexMethod> bypassClinitForInlining;
public final Set<DexMethod> whyAreYouNotInlining;
@@ -1575,7 +1622,6 @@
private RootSet(
DependentMinimumKeepInfoCollection dependentMinimumKeepInfo,
ImmutableList<DexReference> reasonAsked,
- ImmutableList<DexReference> checkDiscarded,
Set<DexMethod> alwaysInline,
Set<DexMethod> neverInline,
Set<DexMethod> neverInlineDueToSingleCaller,
@@ -1608,7 +1654,6 @@
delayedRootSetActionItems,
pendingMethodMoveInverse);
this.reasonAsked = reasonAsked;
- this.checkDiscarded = checkDiscarded;
this.alwaysInline = alwaysInline;
this.bypassClinitForInlining = bypassClinitForInlining;
this.whyAreYouNotInlining = whyAreYouNotInlining;
@@ -1865,7 +1910,6 @@
StringBuilder builder = new StringBuilder();
builder.append("RootSet");
builder.append("\nreasonAsked: " + reasonAsked.size());
- builder.append("\ncheckDiscarded: " + checkDiscarded.size());
builder.append("\nnoSideEffects: " + noSideEffects.size());
builder.append("\nassumedValues: " + assumedValues.size());
builder.append("\nidentifierNameStrings: " + identifierNameStrings.size());
@@ -1959,7 +2003,6 @@
return new MainDexRootSet(
rootSet.getDependentMinimumKeepInfo(),
rootSet.reasonAsked,
- rootSet.checkDiscarded,
rootSet.ifRules,
rootSet.delayedRootSetActionItems);
}
@@ -1970,13 +2013,11 @@
public MainDexRootSet(
DependentMinimumKeepInfoCollection dependentMinimumKeepInfo,
ImmutableList<DexReference> reasonAsked,
- ImmutableList<DexReference> checkDiscarded,
Set<ProguardIfRule> ifRules,
List<DelayedRootSetActionItem> delayedRootSetActionItems) {
super(
dependentMinimumKeepInfo,
reasonAsked,
- checkDiscarded,
Collections.emptySet(),
Collections.emptySet(),
Collections.emptySet(),
@@ -2019,11 +2060,6 @@
return this;
}
- ImmutableList.Builder<DexReference> rewrittenCheckDiscarded = ImmutableList.builder();
- checkDiscarded.forEach(
- reference ->
- rewriteAndApplyIfNotPrimitiveType(
- graphLens, reference, rewrittenCheckDiscarded::add));
ImmutableList.Builder<DexReference> rewrittenReasonAsked = ImmutableList.builder();
reasonAsked.forEach(
reference ->
@@ -2036,7 +2072,6 @@
return new MainDexRootSet(
getDependentMinimumKeepInfo().rewrittenWithLens(graphLens),
rewrittenReasonAsked.build(),
- rewrittenCheckDiscarded.build(),
ifRules,
delayedRootSetActionItems);
}
@@ -2053,7 +2088,6 @@
return new MainDexRootSet(
getDependentMinimumKeepInfo(),
reasonAsked,
- checkDiscarded,
ifRules,
delayedRootSetActionItems);
}
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 2b8affa..e407c3a 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
@@ -717,9 +717,6 @@
builder.setName(methodReference.getName());
builder.setProto(methodReference.getProto());
buildMethodCallback.accept(builder);
- // TODO(b/183998768): Make this safe for recursive definitions.
- // For example, the builder should be split into the creation of the method structure
- // and the creation of the method code. The code can then be constructed outside the lock.
methodDefinition = builder.build();
methodCollection.addMethod(methodDefinition);
newMethodCallback.accept((T) DexClassAndMethod.create(clazz, methodDefinition));
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 308862a..b5235d2 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -220,7 +220,6 @@
enableDevirtualization = false;
enableVerticalClassMerging = false;
enableEnumUnboxing = false;
- enableUninstantiatedTypeOptimization = false;
outline.enabled = false;
enableEnumValueOptimization = false;
enableValuePropagation = false;
@@ -329,7 +328,6 @@
public boolean enableInitializedClassesInInstanceMethodsAnalysis = true;
public boolean enableRedundantFieldLoadElimination = true;
public boolean enableValuePropagation = true;
- public boolean enableUninstantiatedTypeOptimization = true;
// Currently disabled, see b/146957343.
public boolean enableUninstantiatedTypeOptimizationForInterfaces = false;
// TODO(b/138917494): Disable until we have numbers on potential performance penalties.
diff --git a/src/main/java/com/android/tools/r8/utils/ListUtils.java b/src/main/java/com/android/tools/r8/utils/ListUtils.java
index 1ff7079..c5326b3 100644
--- a/src/main/java/com/android/tools/r8/utils/ListUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/ListUtils.java
@@ -128,10 +128,19 @@
* were rewritten, otherwise returns defaultValue.
*/
public static <T> List<T> mapOrElse(List<T> list, Function<T, T> fn, List<T> defaultValue) {
+ return mapOrElse(list, (index, element) -> fn.apply(element), defaultValue);
+ }
+
+ /**
+ * Rewrites the input list based on the given function. Returns the mapped list if any elements
+ * were rewritten, otherwise returns defaultValue.
+ */
+ public static <T> List<T> mapOrElse(
+ List<T> list, IntObjToObjFunction<T, T> fn, List<T> defaultValue) {
ArrayList<T> result = null;
for (int i = 0; i < list.size(); i++) {
T oldElement = list.get(i);
- T newElement = fn.apply(oldElement);
+ T newElement = fn.apply(i, oldElement);
if (newElement == oldElement) {
if (result != null) {
result.add(oldElement);
diff --git a/src/main/java/com/android/tools/r8/utils/TraversalContinuation.java b/src/main/java/com/android/tools/r8/utils/TraversalContinuation.java
index df59f20..2d8efe3 100644
--- a/src/main/java/com/android/tools/r8/utils/TraversalContinuation.java
+++ b/src/main/java/com/android/tools/r8/utils/TraversalContinuation.java
@@ -9,6 +9,10 @@
CONTINUE,
BREAK;
+ public static TraversalContinuation continueIf(boolean condition) {
+ return condition ? CONTINUE : BREAK;
+ }
+
public final boolean shouldBreak() {
return this == BREAK;
}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/ProgramMemberMap.java b/src/main/java/com/android/tools/r8/utils/collections/ProgramMemberMap.java
index ef58a2d..3a648fe 100644
--- a/src/main/java/com/android/tools/r8/utils/collections/ProgramMemberMap.java
+++ b/src/main/java/com/android/tools/r8/utils/collections/ProgramMemberMap.java
@@ -32,6 +32,10 @@
return backing.computeIfAbsent(wrap(member), key -> fn.apply(key.get()));
}
+ public boolean containsKey(K member) {
+ return backing.containsKey(wrap(member));
+ }
+
public void forEach(BiConsumer<K, V> consumer) {
backing.forEach((wrapper, value) -> consumer.accept(wrapper.get(), value));
}
diff --git a/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithNamingLens.java b/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithNamingLens.java
index 7569929..6ccce86 100644
--- a/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithNamingLens.java
+++ b/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithNamingLens.java
@@ -17,6 +17,9 @@
public static <T> int run(
T item1, T item2, NamingLens namingLens, CompareToAccept<T> compareToAccept) {
+ if (item1 == item2) {
+ return 0;
+ }
CompareToVisitorWithNamingLens state = new CompareToVisitorWithNamingLens(namingLens);
return compareToAccept.acceptCompareTo(item1, item2, state);
}
@@ -29,6 +32,9 @@
@Override
public int visitDexType(DexType type1, DexType type2) {
+ if (type1 == type2) {
+ return 0;
+ }
return debug(
namingLens
.lookupDescriptor(type1)
@@ -37,6 +43,9 @@
@Override
public int visitDexField(DexField field1, DexField field2) {
+ if (field1 == field2) {
+ return 0;
+ }
int order = field1.holder.acceptCompareTo(field2.holder, this);
if (order != 0) {
return debug(order);
@@ -50,6 +59,9 @@
@Override
public int visitDexMethod(DexMethod method1, DexMethod method2) {
+ if (method1 == method2) {
+ return 0;
+ }
int order = method1.holder.acceptCompareTo(method2.holder, this);
if (order != 0) {
return debug(order);
diff --git a/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithStringTable.java b/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithStringTable.java
index 78fb663..398e32f 100644
--- a/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithStringTable.java
+++ b/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithStringTable.java
@@ -19,6 +19,9 @@
@Override
public int visitDexString(DexString string1, DexString string2) {
+ if (string1 == string2) {
+ return 0;
+ }
return visitInt(stringTable.applyAsInt(string1), stringTable.applyAsInt(string2));
}
}
diff --git a/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithTypeEquivalence.java b/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithTypeEquivalence.java
index ccb5c9e..f139bc9 100644
--- a/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithTypeEquivalence.java
+++ b/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithTypeEquivalence.java
@@ -14,6 +14,9 @@
public static <T> int run(
T item1, T item2, RepresentativeMap map, CompareToAccept<T> compareToAccept) {
+ if (item1 == item2) {
+ return 0;
+ }
CompareToVisitorWithTypeEquivalence state = new CompareToVisitorWithTypeEquivalence(map);
return compareToAccept.acceptCompareTo(item1, item2, state);
}
@@ -26,6 +29,9 @@
@Override
public int visitDexType(DexType type1, DexType type2) {
+ if (type1 == type2) {
+ return 0;
+ }
DexType repr1 = representatives.getRepresentative(type1);
DexType repr2 = representatives.getRepresentative(type2);
return debug(repr1.getDescriptor().acceptCompareTo(repr2.getDescriptor(), this));
diff --git a/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithTypeTable.java b/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithTypeTable.java
index 52a718a..2ec2980 100644
--- a/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithTypeTable.java
+++ b/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorWithTypeTable.java
@@ -22,6 +22,9 @@
@Override
public int visitDexType(DexType type1, DexType type2) {
+ if (type1 == type2) {
+ return 0;
+ }
return visitInt(typeTable.applyAsInt(type1), typeTable.applyAsInt(type2));
}
}
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/EmptyInterfaceTypeToClassTypeLensCodeRewriterHelper.java b/src/main/java/com/android/tools/r8/verticalclassmerging/EmptyInterfaceTypeToClassTypeLensCodeRewriterHelper.java
new file mode 100644
index 0000000..dce166b
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/EmptyInterfaceTypeToClassTypeLensCodeRewriterHelper.java
@@ -0,0 +1,63 @@
+// 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.verticalclassmerging;
+
+import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
+import com.android.tools.r8.ir.code.FieldPut;
+import com.android.tools.r8.ir.code.InstructionListIterator;
+import com.android.tools.r8.ir.code.InvokeMethod;
+import com.android.tools.r8.ir.code.InvokeStatic;
+import com.android.tools.r8.ir.code.Return;
+
+public class EmptyInterfaceTypeToClassTypeLensCodeRewriterHelper
+ extends InterfaceTypeToClassTypeLensCodeRewriterHelper {
+
+ @Override
+ public void insertCastsForOperandsIfNeeded(
+ InvokeMethod originalInvoke,
+ InvokeMethod rewrittenInvoke,
+ MethodLookupResult lookupResult,
+ BasicBlockIterator blockIterator,
+ BasicBlock block,
+ InstructionListIterator instructionIterator) {
+ // Intentionally empty.
+ }
+
+ @Override
+ public void insertCastsForOperandsIfNeeded(
+ Return rewrittenReturn,
+ BasicBlockIterator blockIterator,
+ BasicBlock block,
+ InstructionListIterator instructionIterator) {
+ // Intentionally empty.
+ }
+
+ @Override
+ public void insertCastsForOperandsIfNeeded(
+ FieldPut originalFieldPut,
+ InvokeStatic rewrittenFieldPut,
+ BasicBlockIterator blockIterator,
+ BasicBlock block,
+ InstructionListIterator instructionIterator) {
+ // Intentionally empty.
+ }
+
+ @Override
+ public void insertCastsForOperandsIfNeeded(
+ FieldPut originalFieldPut,
+ FieldPut rewrittenFieldPut,
+ BasicBlockIterator blockIterator,
+ BasicBlock block,
+ InstructionListIterator instructionIterator) {
+ // Intentionally empty.
+ }
+
+ @Override
+ public void processWorklist() {
+ // Intentionally empty.
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/InterfaceTypeToClassTypeLensCodeRewriterHelper.java b/src/main/java/com/android/tools/r8/verticalclassmerging/InterfaceTypeToClassTypeLensCodeRewriterHelper.java
new file mode 100644
index 0000000..558fdf6
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/InterfaceTypeToClassTypeLensCodeRewriterHelper.java
@@ -0,0 +1,80 @@
+// 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.verticalclassmerging;
+
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
+import com.android.tools.r8.ir.code.FieldPut;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.InstructionListIterator;
+import com.android.tools.r8.ir.code.InvokeMethod;
+import com.android.tools.r8.ir.code.InvokeStatic;
+import com.android.tools.r8.ir.code.Return;
+import com.android.tools.r8.ir.conversion.MethodProcessor;
+
+/**
+ * Inserts check-cast instructions after vertical class merging when this is needed for the program
+ * to type check.
+ *
+ * <p>Any class type is assignable to any interface type. If an interface I is merged into its
+ * unique (non-interface) subtype C, then assignments that used to be valid may no longer be valid
+ * due to the stronger type checking imposed by the JVM. Therefore, casts are inserted where
+ * necessary for the program to type check after vertical class merging.
+ *
+ * <p>Example: If the interface I is merged into its unique subclass C, then the invoke-interface
+ * instruction will be rewritten by the {@link com.android.tools.r8.ir.conversion.LensCodeRewriter}
+ * to an invoke-virtual instruction. After this rewriting, the program no longer type checks, and
+ * therefore a cast is inserted before the invoke-virtual instruction: {@code C c = (C) o}.
+ *
+ * <pre>
+ * Object o = get();
+ * o.m(); // invoke-interface {o}, void I.m()
+ * </pre>
+ */
+public abstract class InterfaceTypeToClassTypeLensCodeRewriterHelper {
+
+ public static InterfaceTypeToClassTypeLensCodeRewriterHelper create(
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ IRCode code,
+ MethodProcessor methodProcessor) {
+ if (methodProcessor.isPrimaryMethodProcessor() && appView.hasVerticallyMergedClasses()) {
+ return new InterfaceTypeToClassTypeLensCodeRewriterHelperImpl(appView, code);
+ }
+ return new EmptyInterfaceTypeToClassTypeLensCodeRewriterHelper();
+ }
+
+ public abstract void insertCastsForOperandsIfNeeded(
+ InvokeMethod originalInvoke,
+ InvokeMethod rewrittenInvoke,
+ MethodLookupResult lookupResult,
+ BasicBlockIterator blockIterator,
+ BasicBlock block,
+ InstructionListIterator instructionIterator);
+
+ public abstract void insertCastsForOperandsIfNeeded(
+ Return rewrittenReturn,
+ BasicBlockIterator blockIterator,
+ BasicBlock block,
+ InstructionListIterator instructionIterator);
+
+ public abstract void insertCastsForOperandsIfNeeded(
+ FieldPut originalFieldPut,
+ InvokeStatic rewrittenFieldPut,
+ BasicBlockIterator blockIterator,
+ BasicBlock block,
+ InstructionListIterator instructionIterator);
+
+ public abstract void insertCastsForOperandsIfNeeded(
+ FieldPut originalFieldPut,
+ FieldPut rewrittenFieldPut,
+ BasicBlockIterator blockIterator,
+ BasicBlock block,
+ InstructionListIterator instructionIterator);
+
+ public abstract void processWorklist();
+}
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/InterfaceTypeToClassTypeLensCodeRewriterHelperImpl.java b/src/main/java/com/android/tools/r8/verticalclassmerging/InterfaceTypeToClassTypeLensCodeRewriterHelperImpl.java
new file mode 100644
index 0000000..e97d8c5
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/InterfaceTypeToClassTypeLensCodeRewriterHelperImpl.java
@@ -0,0 +1,275 @@
+// 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.verticalclassmerging;
+
+import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
+import static com.android.tools.r8.utils.MapUtils.ignoreKey;
+
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
+import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
+import com.android.tools.r8.ir.code.CheckCast;
+import com.android.tools.r8.ir.code.FieldPut;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.InstructionListIterator;
+import com.android.tools.r8.ir.code.InvokeMethod;
+import com.android.tools.r8.ir.code.InvokeStatic;
+import com.android.tools.r8.ir.code.Return;
+import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.utils.OptionalBool;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.IdentityHashMap;
+import java.util.Map;
+
+// TODO(b/199561570): Extend this to insert casts for users that are not an instance of
+// invoke-method (e.g., array-put, instance-put, static-put, return).
+public class InterfaceTypeToClassTypeLensCodeRewriterHelperImpl
+ extends InterfaceTypeToClassTypeLensCodeRewriterHelper {
+
+ private final AppView<? extends AppInfoWithClassHierarchy> appView;
+ private final IRCode code;
+
+ private final Map<Instruction, Deque<WorklistItem>> worklist = new IdentityHashMap<>();
+
+ public InterfaceTypeToClassTypeLensCodeRewriterHelperImpl(
+ AppView<? extends AppInfoWithClassHierarchy> appView, IRCode code) {
+ this.appView = appView;
+ this.code = code;
+ }
+
+ @Override
+ public void insertCastsForOperandsIfNeeded(
+ InvokeMethod originalInvoke,
+ InvokeMethod rewrittenInvoke,
+ MethodLookupResult lookupResult,
+ BasicBlockIterator blockIterator,
+ BasicBlock block,
+ InstructionListIterator instructionIterator) {
+ DexMethod originalInvokedMethod = originalInvoke.getInvokedMethod();
+ DexMethod rewrittenInvokedMethod = rewrittenInvoke.getInvokedMethod();
+ if (lookupResult.getPrototypeChanges().getArgumentInfoCollection().hasRemovedArguments()) {
+ // There is no argument removal before the primary optimization pass.
+ assert false;
+ return;
+ }
+
+ if (originalInvoke.arguments().size()
+ != originalInvokedMethod.getNumberOfArguments(originalInvoke.isInvokeStatic())) {
+ // Wrong number of arguments, this instruction always fails.
+ return;
+ }
+
+ // Intentionally iterate the arguments of the original invoke, since the rewritten invoke could
+ // have extra arguments added.
+ for (int operandIndex = 0; operandIndex < originalInvoke.arguments().size(); operandIndex++) {
+ Value operand = rewrittenInvoke.getArgument(operandIndex);
+ DexType originalType =
+ originalInvokedMethod.getArgumentType(operandIndex, originalInvoke.isInvokeStatic());
+ DexType rewrittenType =
+ rewrittenInvokedMethod.getArgumentType(operandIndex, rewrittenInvoke.isInvokeStatic());
+ if (needsCastForOperand(operand, block, originalType, rewrittenType).isPossiblyTrue()) {
+ addWorklistItem(rewrittenInvoke, operandIndex, originalType, rewrittenType);
+ }
+ }
+ }
+
+ @Override
+ public void insertCastsForOperandsIfNeeded(
+ Return rewrittenReturn,
+ BasicBlockIterator blockIterator,
+ BasicBlock block,
+ InstructionListIterator instructionIterator) {
+ assert !rewrittenReturn.isReturnVoid();
+ DexMethod originalMethodSignature =
+ appView.graphLens().getOriginalMethodSignature(code.context().getReference());
+ DexType originalReturnType = originalMethodSignature.getReturnType();
+ DexType rewrittenReturnType = code.context().getReturnType();
+ if (needsCastForOperand(
+ rewrittenReturn.returnValue(), block, originalReturnType, rewrittenReturnType)
+ .isPossiblyTrue()) {
+ addWorklistItem(rewrittenReturn, 0, originalReturnType, rewrittenReturnType);
+ }
+ }
+
+ @Override
+ public void insertCastsForOperandsIfNeeded(
+ FieldPut originalFieldPut,
+ InvokeStatic rewrittenFieldPut,
+ BasicBlockIterator blockIterator,
+ BasicBlock block,
+ InstructionListIterator instructionIterator) {
+ DexType originalFieldType = originalFieldPut.getField().getType();
+ int valueIndex = originalFieldPut.getValueIndex();
+ DexType rewrittenFieldType = rewrittenFieldPut.getInvokedMethod().getParameter(valueIndex);
+ Value operand = rewrittenFieldPut.getOperand(valueIndex);
+ if (needsCastForOperand(operand, block, originalFieldType, rewrittenFieldType)
+ .isPossiblyTrue()) {
+ addWorklistItem(rewrittenFieldPut, valueIndex, originalFieldType, rewrittenFieldType);
+ }
+ }
+
+ @Override
+ public void insertCastsForOperandsIfNeeded(
+ FieldPut originalFieldPut,
+ FieldPut rewrittenFieldPut,
+ BasicBlockIterator blockIterator,
+ BasicBlock block,
+ InstructionListIterator instructionIterator) {
+ DexType originalFieldType = originalFieldPut.getField().getType();
+ DexType rewrittenFieldType = rewrittenFieldPut.getField().getType();
+ if (needsCastForOperand(rewrittenFieldPut.value(), block, originalFieldType, rewrittenFieldType)
+ .isPossiblyTrue()) {
+ addWorklistItem(
+ rewrittenFieldPut.asFieldInstruction(),
+ rewrittenFieldPut.getValueIndex(),
+ originalFieldType,
+ rewrittenFieldType);
+ }
+ }
+
+ @Override
+ public void processWorklist() {
+ if (worklist.isEmpty()) {
+ return;
+ }
+
+ BasicBlockIterator blockIterator = code.listIterator();
+ boolean isCodeFullyRewrittenWithLens = true;
+ while (blockIterator.hasNext()) {
+ BasicBlock block = blockIterator.next();
+ InstructionListIterator instructionIterator = block.listIterator(code);
+ while (instructionIterator.hasNext()) {
+ Instruction instruction = instructionIterator.next();
+ Deque<WorklistItem> worklistItems = worklist.get(instruction);
+ if (worklistItems == null) {
+ continue;
+ }
+ for (WorklistItem worklistItem : worklistItems) {
+ Value operand = instruction.getOperand(worklistItem.operandIndex);
+ DexType originalType = worklistItem.originalType;
+ DexType rewrittenType = worklistItem.rewrittenType;
+ OptionalBool needsCastForOperand =
+ needsCastForOperand(
+ operand, block, originalType, rewrittenType, isCodeFullyRewrittenWithLens);
+ assert !needsCastForOperand.isUnknown();
+ if (needsCastForOperand.isTrue()) {
+ insertCastForOperand(
+ operand, rewrittenType, instruction, blockIterator, block, instructionIterator);
+ }
+ }
+ }
+ }
+ }
+
+ private void addWorklistItem(
+ Instruction rewrittenInstruction,
+ int operandIndex,
+ DexType originalType,
+ DexType rewrittenType) {
+ worklist
+ .computeIfAbsent(rewrittenInstruction, ignoreKey(ArrayDeque::new))
+ .addLast(new WorklistItem(operandIndex, originalType, rewrittenType));
+ }
+
+ private void insertCastForOperand(
+ Value operand,
+ DexType castType,
+ Instruction rewrittenUser,
+ BasicBlockIterator blockIterator,
+ BasicBlock block,
+ InstructionListIterator instructionIterator) {
+ Instruction previous = instructionIterator.previous();
+ assert previous == rewrittenUser;
+
+ CheckCast checkCast =
+ CheckCast.builder()
+ .setCastType(castType)
+ .setObject(operand)
+ .setFreshOutValue(code, castType.toTypeElement(appView), operand.getLocalInfo())
+ .setPosition(rewrittenUser)
+ .build();
+ if (block.hasCatchHandlers()) {
+ instructionIterator
+ .splitCopyCatchHandlers(code, blockIterator, appView.options())
+ .listIterator(code)
+ .add(checkCast);
+ } else {
+ instructionIterator.add(checkCast);
+ }
+ rewrittenUser.replaceValue(operand, checkCast.outValue());
+
+ Instruction next = instructionIterator.next();
+ assert next == rewrittenUser;
+ }
+
+ private boolean isOperandRewrittenWithLens(
+ Value operand, BasicBlock blockWithUser, boolean isCodeFullyRewrittenWithLens) {
+ if (isCodeFullyRewrittenWithLens) {
+ return true;
+ }
+ if (operand.isPhi()) {
+ return false;
+ }
+ Instruction definition = operand.getDefinition();
+ return definition.isArgument() || operand.getBlock() == blockWithUser;
+ }
+
+ private OptionalBool needsCastForOperand(
+ Value operand, BasicBlock blockWithUser, DexType originalType, DexType rewrittenType) {
+ return needsCastForOperand(operand, blockWithUser, originalType, rewrittenType, false);
+ }
+
+ private OptionalBool needsCastForOperand(
+ Value operand,
+ BasicBlock blockWithUser,
+ DexType originalType,
+ DexType rewrittenType,
+ boolean isCodeFullyRewrittenWithLens) {
+ if (!originalType.isClassType() || !rewrittenType.isClassType()) {
+ return OptionalBool.FALSE;
+ }
+ // The original type should be an interface type.
+ DexProgramClass originalClass = asProgramClassOrNull(appView.definitionFor(originalType));
+ if (originalClass == null || !originalClass.isInterface()) {
+ return OptionalBool.FALSE;
+ }
+ // The rewritten type should be a (non-interface) class type.
+ DexProgramClass rewrittenClass = asProgramClassOrNull(appView.definitionFor(rewrittenType));
+ if (rewrittenClass == null || rewrittenClass.isInterface()) {
+ return OptionalBool.FALSE;
+ }
+ // If the operand has not yet been rewritten with the lens, we delay the type check until
+ // after lens code rewriting.
+ if (!isOperandRewrittenWithLens(operand, blockWithUser, isCodeFullyRewrittenWithLens)) {
+ assert !isCodeFullyRewrittenWithLens;
+ return OptionalBool.UNKNOWN;
+ }
+ // The operand should not be subtype of the rewritten type.
+ TypeElement rewrittenTypeElement = rewrittenType.toTypeElement(appView);
+ return OptionalBool.of(
+ !operand.getType().lessThanOrEqualUpToNullability(rewrittenTypeElement, appView));
+ }
+
+ private static class WorklistItem {
+
+ final int operandIndex;
+ final DexType originalType;
+ final DexType rewrittenType;
+
+ WorklistItem(int operandIndex, DexType originalType, DexType rewrittenType) {
+ this.operandIndex = operandIndex;
+ this.originalType = originalType;
+ this.rewrittenType = rewrittenType;
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ProguardMapMarkerTest.java b/src/test/java/com/android/tools/r8/ProguardMapMarkerTest.java
index 59f6159..deaaef4 100644
--- a/src/test/java/com/android/tools/r8/ProguardMapMarkerTest.java
+++ b/src/test/java/com/android/tools/r8/ProguardMapMarkerTest.java
@@ -18,13 +18,26 @@
import java.util.HashSet;
import java.util.Set;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
-public class ProguardMapMarkerTest {
- private static final int EXPECTED_NUMBER_OF_KEYS_DEX = 5;
- private static final int EXPECTED_NUMBER_OF_KEYS_CF = 4;
+@RunWith(Parameterized.class)
+public class ProguardMapMarkerTest extends TestBase {
+ private static final int EXPECTED_NUMBER_OF_KEYS_DEX = 6;
+ private static final int EXPECTED_NUMBER_OF_KEYS_CF = 5;
private static final String CLASS_FILE =
ToolHelper.EXAMPLES_BUILD_DIR + "classes/trivial/Trivial.class";
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
+
+ public ProguardMapMarkerTest(TestParameters parameters) {
+ parameters.assertNoneRuntime();
+ }
+
@Test
public void proguardMapMarkerTest24() throws CompilationFailedException {
proguardMapMarkerTestDex(AndroidApiLevel.N);
@@ -128,6 +141,7 @@
String[] lines = proguardMap.split("\n");
Set<String> keysFound = new HashSet<>();
String proguardMapId = null;
+ String proguardMapHash = null;
for (String line : lines) {
if (!line.startsWith("#")) {
continue;
@@ -150,6 +164,8 @@
assertEquals(VersionProperties.INSTANCE.getSha(), value);
} else if (key.equals(ProguardMapSupplier.MARKER_KEY_PG_MAP_ID)) {
proguardMapId = value;
+ } else if (key.equals(ProguardMapSupplier.MARKER_KEY_PG_MAP_HASH)) {
+ proguardMapHash = value;
} else {
continue;
}
diff --git a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
index 4004a47..dbaa9c9 100644
--- a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
@@ -102,6 +102,13 @@
return addKeepRules(Arrays.asList(rules));
}
+ public T addDontObfuscate(Class<?> clazz) {
+ return addKeepRules(
+ "-keep,allowaccessmodification,allowannotationremoval,allowoptimization,allowshrinking"
+ + " class "
+ + clazz.getTypeName());
+ }
+
public T addDontOptimize() {
return addKeepRules("-dontoptimize");
}
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 14db34c..be6c8f0 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -144,6 +144,7 @@
private static final AndroidApiLevel DEFAULT_MIN_SDK = AndroidApiLevel.I;
public static final String JDK_11_TESTS_DIR = "third_party/openjdk/jdk-11-test/";
+ public static final String JDK_11_TIME_TESTS_DIR = JDK_11_TESTS_DIR + "java/time/";
private static final String PROGUARD5_2_1 = "third_party/proguard/proguard5.2.1/bin/proguard";
private static final String PROGUARD6_0_1 = "third_party/proguard/proguard6.0.1/bin/proguard";
diff --git a/src/test/java/com/android/tools/r8/checkdiscarded/CheckAllMembersDiscardedTest.java b/src/test/java/com/android/tools/r8/checkdiscarded/CheckAllMembersDiscardedTest.java
new file mode 100644
index 0000000..dbcd8a3
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/checkdiscarded/CheckAllMembersDiscardedTest.java
@@ -0,0 +1,114 @@
+// 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.checkdiscarded;
+
+import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.errors.CheckDiscardDiagnostic;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.AssertUtils;
+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 CheckAllMembersDiscardedTest extends TestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameter(1)
+ public boolean shrinkMethodReferences;
+
+ @Parameter(2)
+ public boolean shrinkTypeReference;
+
+ @Parameters(name = "{0}, shrink method references: {1}, shrink type reference: {2}")
+ public static List<Object[]> parameters() {
+ return buildParameters(
+ getTestParameters().withAllRuntimesAndApiLevels().build(),
+ BooleanUtils.values(),
+ BooleanUtils.values());
+ }
+
+ @Test
+ public void test() throws Exception {
+ AssertUtils.assertFailsCompilationIf(
+ !shrinkMethodReferences || !shrinkTypeReference,
+ () ->
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .addKeepRules(
+ "-assumenosideeffects class " + Main.class.getTypeName() + " {",
+ " static boolean shrinkMethodReferences() return "
+ + shrinkMethodReferences
+ + ";",
+ " static boolean shrinkTypeReference() return " + shrinkTypeReference + ";",
+ "}",
+ // When all members on a class are marked by -checkdiscard, we interpret it as
+ // if the class should also be fully discarded.
+ getRuleForSecret("checkdiscard"),
+ getRuleForSecret("keep,allowshrinking"))
+ .setMinApi(parameters.getApiLevel())
+ .compileWithExpectedDiagnostics(
+ diagnostics -> {
+ if (shrinkMethodReferences && shrinkTypeReference) {
+ diagnostics.assertNoMessages();
+ } else {
+ diagnostics.assertErrorsMatch(diagnosticType(CheckDiscardDiagnostic.class));
+ }
+ })
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithEmptyOutput());
+ }
+
+ private static String getRuleForSecret(String directive) {
+ return StringUtils.joinLines(
+ "-" + directive + " class " + Secret.class.getTypeName() + " {",
+ " void <init>();",
+ " static void foo();",
+ " static void bar();",
+ "}");
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ if (!shrinkMethodReferences()) {
+ Secret.foo();
+ Secret.bar();
+ }
+ if (!shrinkTypeReference()) {
+ System.out.println(Secret.class);
+ }
+ }
+
+ static boolean shrinkMethodReferences() {
+ throw new RuntimeException();
+ }
+
+ static boolean shrinkTypeReference() {
+ throw new RuntimeException();
+ }
+ }
+
+ static class Secret {
+
+ static void foo() {
+ System.out.println("Secret Foo");
+ }
+
+ static void bar() {
+ System.out.println("Secret Bar");
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/checkdiscarded/CheckClassDiscardedEntirelyTest.java b/src/test/java/com/android/tools/r8/checkdiscarded/CheckClassDiscardedEntirelyTest.java
new file mode 100644
index 0000000..97a8f50
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/checkdiscarded/CheckClassDiscardedEntirelyTest.java
@@ -0,0 +1,106 @@
+// 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.checkdiscarded;
+
+import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
+import static com.android.tools.r8.utils.codeinspector.AssertUtils.assertFailsCompilationIf;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.errors.CheckDiscardDiagnostic;
+import com.android.tools.r8.utils.BooleanUtils;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class CheckClassDiscardedEntirelyTest extends TestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameter(1)
+ public boolean shrink;
+
+ @Parameter(2)
+ public boolean wildcard;
+
+ @Parameters(name = "{0}, shrink: {1}, wildcard: {2}")
+ public static List<Object[]> parameters() {
+ return buildParameters(
+ getTestParameters().withAllRuntimesAndApiLevels().build(),
+ BooleanUtils.values(),
+ BooleanUtils.values());
+ }
+
+ @Test
+ public void test() throws Exception {
+ assertFailsCompilationIf(
+ !shrink,
+ () ->
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .addKeepRules(
+ "-assumenosideeffects class " + Main.class.getTypeName() + " {",
+ " static boolean shrink() return " + shrink + ";",
+ "}",
+ getRuleForSecret("checkdiscard", wildcard),
+ // The following call intentionally passes 'true' instead of 'wildcard'. Indeed,
+ // the -checkdiscard rule for a class implicitly expands to a -checkdiscard rule
+ // for the class and all of its members. Therefore, the corresponding rule to
+ // disallow optimizations must apply to all members.
+ getRuleForSecret("keep,allowshrinking", true))
+ .setMinApi(parameters.getApiLevel())
+ .compileWithExpectedDiagnostics(
+ diagnostics -> {
+ if (shrink) {
+ diagnostics.assertNoMessages();
+ } else {
+ diagnostics.assertAllErrorsMatch(
+ diagnosticType(CheckDiscardDiagnostic.class));
+ }
+ })
+ .inspect(
+ inspector -> {
+ // We only get here if the branch in Main.main() is pruned, or the
+ // -checkdiscard rule should have failed.
+ assertTrue(shrink);
+ assertThat(inspector.clazz(Secret.class), isAbsent());
+ })
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithEmptyOutput());
+ }
+
+ private static String getRuleForSecret(String directive, boolean wildcard) {
+ return "-" + directive + " class " + Secret.class.getTypeName() + (wildcard ? " { *; }" : "");
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ if (!shrink()) {
+ System.out.println(Secret.get());
+ }
+ }
+
+ static boolean shrink() {
+ throw new RuntimeException();
+ }
+ }
+
+ static class Secret {
+
+ static String get() {
+ return "Secret";
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/checkdiscarded/CheckDiscardedTest.java b/src/test/java/com/android/tools/r8/checkdiscarded/CheckDiscardedTest.java
index da2e4cb..389d347 100644
--- a/src/test/java/com/android/tools/r8/checkdiscarded/CheckDiscardedTest.java
+++ b/src/test/java/com/android/tools/r8/checkdiscarded/CheckDiscardedTest.java
@@ -72,7 +72,7 @@
options.enableInlining = false;
}
- private String checkDiscardRule(boolean member, Class annotation) {
+ private String checkDiscardRule(boolean member, Class<?> annotation) {
if (member) {
return "-checkdiscard class * { @" + annotation.getName() + " *; }";
} else {
diff --git a/src/test/java/com/android/tools/r8/checkdiscarded/CheckSingleMemberDiscardedTest.java b/src/test/java/com/android/tools/r8/checkdiscarded/CheckSingleMemberDiscardedTest.java
new file mode 100644
index 0000000..1ca8851
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/checkdiscarded/CheckSingleMemberDiscardedTest.java
@@ -0,0 +1,85 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.checkdiscarded;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.AssertUtils;
+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 CheckSingleMemberDiscardedTest extends TestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameter(1)
+ public boolean shrink;
+
+ @Parameters(name = "{0}, shrink: {1}")
+ public static List<Object[]> parameters() {
+ return buildParameters(
+ getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values());
+ }
+
+ @Test
+ public void test() throws Exception {
+ AssertUtils.assertFailsCompilationIf(
+ !shrink,
+ () ->
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .addKeepRules(
+ "-assumenosideeffects class " + Main.class.getTypeName() + " {",
+ " static boolean shrink() return " + shrink + ";",
+ "}",
+ getRuleForSecret("checkdiscard"),
+ getRuleForSecret("keep,allowshrinking"))
+ .enableInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("Public"));
+ }
+
+ private static String getRuleForSecret(String directive) {
+ return StringUtils.joinLines(
+ "-" + directive + " class " + Main.class.getTypeName() + " {",
+ " static void printSecret();",
+ "}");
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ printPublic();
+ if (!shrink()) {
+ printSecret();
+ }
+ }
+
+ @NeverInline
+ static void printPublic() {
+ System.out.println("Public");
+ }
+
+ static void printSecret() {
+ System.out.println("Secret");
+ }
+
+ static boolean shrink() {
+ throw new RuntimeException();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/checkdiscarded/CheckSubclassDiscardedEntirelyTest.java b/src/test/java/com/android/tools/r8/checkdiscarded/CheckSubclassDiscardedEntirelyTest.java
new file mode 100644
index 0000000..0b2fa97
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/checkdiscarded/CheckSubclassDiscardedEntirelyTest.java
@@ -0,0 +1,153 @@
+// 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.checkdiscarded;
+
+import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
+import static com.android.tools.r8.utils.codeinspector.AssertUtils.assertFailsCompilationIf;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+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.checkdiscarded.CheckClassDiscardedEntirelyTest.Main;
+import com.android.tools.r8.checkdiscarded.CheckClassDiscardedEntirelyTest.Secret;
+import com.android.tools.r8.errors.CheckDiscardDiagnostic;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.VerticallyMergedClassesInspector;
+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 CheckSubclassDiscardedEntirelyTest extends TestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameter(1)
+ public boolean shrink;
+
+ @Parameter(2)
+ public boolean wildcard;
+
+ @Parameters(name = "{0}, shrink: {1}, wildcard: {2}")
+ public static List<Object[]> parameters() {
+ return buildParameters(
+ getTestParameters().withAllRuntimesAndApiLevels().build(),
+ BooleanUtils.values(),
+ BooleanUtils.values());
+ }
+
+ @Test
+ public void test() throws Exception {
+ assertFailsCompilationIf(
+ !shrink,
+ () ->
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .addKeepRules(
+ "-assumenosideeffects class " + Main.class.getTypeName() + " {",
+ " static boolean shrink() return " + shrink + ";",
+ "}",
+ "-checkdiscard class "
+ + Secret.class.getTypeName()
+ + (wildcard ? " { *; }" : ""),
+ // Disable optimizations for items hit by the -checkdiscard rule. Note that
+ // the evaluation of -checkdiscard rules does not recurse into super classes,
+ // thus
+ // to match only the items hit by the -checkdiscard rule we use an -if rule that
+ // matches the methods on Secret. Specifically, this rule should not keep the
+ // method Public.printPublicAllowInlining().
+ "-if class " + Secret.class.getTypeName() + " { *** *(...); }",
+ "-keep,allowshrinking class " + Secret.class.getTypeName() + " {",
+ " <1> <2>(...);",
+ "}")
+ .addVerticallyMergedClassesInspector(
+ VerticallyMergedClassesInspector::assertNoClassesMerged)
+ .enableInliningAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .compileWithExpectedDiagnostics(
+ diagnostics -> {
+ if (shrink) {
+ diagnostics.assertNoMessages();
+ } else {
+ diagnostics.assertAllErrorsMatch(
+ diagnosticType(CheckDiscardDiagnostic.class));
+ }
+ })
+ .inspect(
+ inspector -> {
+ // We only get here if the branch in Main.main() is pruned, or the
+ // -checkdiscard
+ // rule should have failed.
+ assertTrue(shrink);
+
+ ClassSubject mainClassSubject = inspector.clazz(Main.class);
+ assertThat(mainClassSubject, isPresent());
+ assertTrue(
+ mainClassSubject
+ .mainMethod()
+ .streamInstructions()
+ .anyMatch(instruction -> instruction.isConstString("Public 2")));
+
+ ClassSubject publicClassSubject = inspector.clazz(Public.class);
+ assertThat(publicClassSubject, isPresent());
+ assertThat(
+ publicClassSubject.uniqueMethodWithName("printPublic"), isPresent());
+ assertThat(
+ publicClassSubject.uniqueMethodWithName("printPublicAllowInlining"),
+ isAbsent());
+
+ assertThat(inspector.clazz(Secret.class), isAbsent());
+ })
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("Public 1", "Public 2"));
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ Public.printPublic();
+ Public.printPublicAllowInlining();
+ if (!shrink()) {
+ Secret.printSecret();
+ }
+ }
+
+ static boolean shrink() {
+ throw new RuntimeException();
+ }
+ }
+
+ @NoVerticalClassMerging
+ static class Public {
+
+ @NeverInline
+ static void printPublic() {
+ System.out.println("Public 1");
+ }
+
+ static void printPublicAllowInlining() {
+ System.out.println("Public 2");
+ }
+ }
+
+ static class Secret extends Public {
+
+ static void printSecret() {
+ System.out.println("Secret");
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/compatproguard/ShrinkFieldsWhileKeepingFieldNameTest.java b/src/test/java/com/android/tools/r8/compatproguard/ShrinkFieldsWhileKeepingFieldNameTest.java
new file mode 100644
index 0000000..9358839
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/compatproguard/ShrinkFieldsWhileKeepingFieldNameTest.java
@@ -0,0 +1,111 @@
+// 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.compatproguard;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.util.Objects;
+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 ShrinkFieldsWhileKeepingFieldNameTest extends TestBase {
+
+ private static final String KEEP_FIELD_NAMES_RULE =
+ "-keepclassmembernames,allowoptimization class"
+ + " com.android.tools.r8.compatproguard.ShrinkFieldsWhileKeepingFieldNameTest$Person {"
+ + " <fields>; }";
+ private static final String EXPECTED_RESULT =
+ StringUtils.lines("Person[name=John; age=42]", "Person[name=Jane; age=42]");
+
+ private final TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public ShrinkFieldsWhileKeepingFieldNameTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testShrinkFieldWhileKeepingFieldNameR8() throws Throwable {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(Person.class, Main.class)
+ .enableNeverClassInliningAnnotations()
+ .addKeepMainRule(Main.class)
+ .addKeepRules(KEEP_FIELD_NAMES_RULE)
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(this::assertSingleFieldWithOriginalName)
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutput(EXPECTED_RESULT);
+ }
+
+ @Test
+ public void testShrinkFieldWhileKeepingFieldNameR8Compat() throws Throwable {
+ testForR8Compat(parameters.getBackend())
+ .addProgramClasses(Person.class, Main.class)
+ .enableNeverClassInliningAnnotations()
+ .addKeepMainRule(Main.class)
+ .addKeepRules(KEEP_FIELD_NAMES_RULE)
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ // TODO(b/200933020): this assert shall pass.
+ // .inspect(this::assertSingleFieldWithOriginalName)
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutput(EXPECTED_RESULT);
+ }
+
+ private void assertSingleFieldWithOriginalName(CodeInspector inspector) {
+ ClassSubject clazz = inspector.clazz(Person.class);
+ assertEquals(1, clazz.allInstanceFields().size());
+ assertEquals("name", clazz.field("java.lang.String", "name").getFinalName());
+ }
+
+ @NeverClassInline
+ static class Person {
+
+ private final String name;
+ private final int age;
+
+ Person(String name, int age) {
+ this.name = name;
+ this.age = age;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Person)) {
+ return false;
+ }
+ Person person = (Person) o;
+ return age == person.age && Objects.equals(name, person.name);
+ }
+
+ @Override
+ public String toString() {
+ return "Person[name=" + name + "; age=" + age + "]";
+ }
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ System.out.println(new Person("John", 42));
+ System.out.println(new Person("Jane", 42));
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeTests.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeTests.java
index 2d6b833..a0a51c0 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeTests.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeTests.java
@@ -5,19 +5,29 @@
package com.android.tools.r8.desugar.desugaredlibrary.jdktests;
import static com.android.tools.r8.ToolHelper.JDK_TESTS_BUILD_DIR;
+import static com.android.tools.r8.utils.FileUtils.CLASS_EXTENSION;
+import static com.android.tools.r8.utils.FileUtils.JAVA_EXTENSION;
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.D8TestCompileResult;
import com.android.tools.r8.D8TestRunResult;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.StringUtils;
+import com.google.common.collect.ImmutableList;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
+import java.util.stream.Collectors;
+import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -47,6 +57,54 @@
this.parameters = parameters;
}
+ private static final Path JDK_11_TCK_TEST_FILES_DIR =
+ Paths.get(ToolHelper.JDK_11_TIME_TESTS_DIR).resolve("tck");
+ private static final Path JDK_11_TIME_TEST_FILES_DIR =
+ Paths.get(ToolHelper.JDK_11_TIME_TESTS_DIR).resolve("test");
+ private static final String JDK_11_TIME_TEST_EXCLUDE = "TestZoneTextPrinterParser.java";
+ private static Path[] JDK_11_TIME_TEST_COMPILED_FILES;
+
+ private static List<Path> getJdk11TimeTestFiles() throws Exception {
+ List<Path> tckFiles =
+ Files.walk(JDK_11_TCK_TEST_FILES_DIR)
+ .filter(path -> path.toString().endsWith(JAVA_EXTENSION))
+ .filter(path -> !path.toString().endsWith(JDK_11_TIME_TEST_EXCLUDE))
+ .collect(Collectors.toList());
+ List<Path> timeFiles =
+ Files.walk(JDK_11_TIME_TEST_FILES_DIR)
+ .filter(path -> path.toString().endsWith(JAVA_EXTENSION))
+ .filter(path -> !path.toString().endsWith(JDK_11_TIME_TEST_EXCLUDE))
+ .collect(Collectors.toList());
+ ArrayList<Path> files = new ArrayList<>();
+ files.addAll(timeFiles);
+ files.addAll(tckFiles);
+ assert files.size() > 0;
+ return files;
+ }
+
+ @BeforeClass
+ public static void compileJdk11StreamTests() throws Exception {
+ Path tmpDirectory = getStaticTemp().newFolder("time").toPath();
+ List<String> options =
+ Arrays.asList(
+ "--add-reads",
+ "java.base=ALL-UNNAMED",
+ "--patch-module",
+ "java.base=" + JDK_11_JAVA_BASE_EXTENSION_CLASSES_DIR);
+ javac(TestRuntime.getCheckedInJdk11(), getStaticTemp())
+ .addOptions(options)
+ .addClasspathFiles(
+ ImmutableList.of(
+ Paths.get(JDK_TESTS_BUILD_DIR + "testng-6.10.jar"),
+ Paths.get(JDK_TESTS_BUILD_DIR + "jcommander-1.48.jar")))
+ .addSourceFiles(getJdk11TimeTestFiles())
+ .setOutputPath(tmpDirectory)
+ .compile();
+ JDK_11_TIME_TEST_COMPILED_FILES =
+ getAllFilesWithSuffixInDirectory(tmpDirectory, CLASS_EXTENSION);
+ assert JDK_11_TIME_TEST_COMPILED_FILES.length > 0;
+ }
+
// Following tests are also failing on the Bazel build, they cannot be run easily on
// Android (difference in time precision, iAndroid printing, etc.).
private static String[] wontFixFailures =
@@ -145,9 +203,12 @@
testForD8()
.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
.addProgramFiles(getPathsFiles())
- .addProgramFiles(Paths.get(JDK_TESTS_BUILD_DIR + "jdk11TimeTests.jar"))
+ .addProgramFiles(JDK_11_TIME_TEST_COMPILED_FILES)
.addProgramFiles(Paths.get(JDK_TESTS_BUILD_DIR + "testng-6.10.jar"))
.addProgramFiles(Paths.get(JDK_TESTS_BUILD_DIR + "jcommander-1.48.jar"))
+ .addProgramFiles(
+ Paths.get(
+ ToolHelper.JAVA_CLASSES_DIR + "examplesTestNGRunner/TestNGMainRunner.class"))
.setMinApi(parameters.getApiLevel())
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.compile()
diff --git a/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java b/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java
index 5e7aa9a..56dab1e 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java
@@ -67,23 +67,41 @@
@Test
public void testD8Intermediate() throws Exception {
Assume.assumeTrue(parameters.isDexRuntime());
- Path path =
- testForD8(Backend.DEX)
- .addProgramClassFileData(PROGRAM_DATA)
- .setMinApi(parameters.getApiLevel())
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
- .setIntermediate(true)
- .compile()
- .writeToZip();
+ Path path = compileIntermediate();
testForD8()
.addProgramFiles(path)
.setMinApi(parameters.getApiLevel())
- .compile()
+ .setIncludeClassesChecksum(true)
.run(parameters.getRuntime(), MAIN_TYPE)
.assertSuccessWithOutput(EXPECTED_RESULT);
}
@Test
+ public void testD8IntermediateNoDesugaringInStep2() throws Exception {
+ Assume.assumeTrue(parameters.isDexRuntime());
+ Path path = compileIntermediate();
+ // In Android Studio they disable desugaring at this point to improve build speed.
+ testForD8()
+ .addProgramFiles(path)
+ .setMinApi(parameters.getApiLevel())
+ .setIncludeClassesChecksum(true)
+ .disableDesugaring()
+ .run(parameters.getRuntime(), MAIN_TYPE)
+ .assertSuccessWithOutput(EXPECTED_RESULT);
+ }
+
+ private Path compileIntermediate() throws Exception {
+ return testForD8(Backend.DEX)
+ .addProgramClassFileData(PROGRAM_DATA)
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
+ .setIntermediate(true)
+ .setIncludeClassesChecksum(true)
+ .compile()
+ .writeToZip();
+ }
+
+ @Test
public void testR8() throws Exception {
R8FullTestBuilder builder =
testForR8(parameters.getBackend())
diff --git a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterMemberValuePropagationRegression.java b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterMemberValuePropagationRegression.java
index 938a8f6..38d19da 100644
--- a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterMemberValuePropagationRegression.java
+++ b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterMemberValuePropagationRegression.java
@@ -14,7 +14,6 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.R8TestBuilder;
import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -33,7 +32,7 @@
@RunWith(Parameterized.class)
public class DexSplitterMemberValuePropagationRegression extends SplitterTestBase {
- public static final String EXPECTED = StringUtils.lines("42");
+ public static final String EXPECTED = StringUtils.lines(FeatureEnum.class.getTypeName(), "42");
@Parameters(name = "{0}")
public static TestParametersCollection params() {
@@ -78,7 +77,8 @@
ImmutableSet.of(FeatureClass.class, FeatureEnum.class),
FeatureClass.class,
ThrowableConsumer.empty(),
- R8TestBuilder::enableInliningAnnotations);
+ testBuilder ->
+ testBuilder.enableInliningAnnotations().addDontObfuscate(FeatureEnum.class));
assertEquals(processResult.exitCode, 0);
assertEquals(processResult.stdout, EXPECTED);
}
@@ -88,17 +88,26 @@
@NeverInline
@Override
public void run() {
- System.out.println(getFromFeature());
+ System.out.println(getClassFromFeature().getName());
+ System.out.println(getEnumFromFeature());
}
- public abstract Enum<?> getFromFeature();
+ public abstract Class<?> getClassFromFeature();
+
+ public abstract Enum<?> getEnumFromFeature();
}
public static class FeatureClass extends BaseSuperClass {
@NeverInline
@Override
- public Enum<?> getFromFeature() {
+ public Class<?> getClassFromFeature() {
+ return FeatureEnum.class;
+ }
+
+ @NeverInline
+ @Override
+ public Enum<?> getEnumFromFeature() {
return FeatureEnum.A;
}
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/ObjectsRequireNonNullTest.java b/src/test/java/com/android/tools/r8/ir/optimize/ObjectsRequireNonNullTest.java
index ca64a9f..77da418 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/ObjectsRequireNonNullTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/ObjectsRequireNonNullTest.java
@@ -140,9 +140,7 @@
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutput(JAVA_OUTPUT);
- // TODO(b/157427150): would be able to remove the call to requireNonNull() if we knew that it
- // throws an NullPointerException that does not have a message.
- test(result, 0, 1);
+ test(result, 0, 0);
}
static class ObjectsRequireNonNullTestMain {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classmerger/vertical/ArrayPutToInterfaceWithObjectMergingTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classmerger/vertical/ArrayPutToInterfaceWithObjectMergingTest.java
new file mode 100644
index 0000000..1411ce8
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classmerger/vertical/ArrayPutToInterfaceWithObjectMergingTest.java
@@ -0,0 +1,120 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.optimize.classmerger.vertical;
+
+import static org.junit.Assume.assumeFalse;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoVerticalClassMerging;
+import com.android.tools.r8.R8TestBuilder;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
+import com.android.tools.r8.utils.BooleanUtils;
+import java.io.IOException;
+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 ArrayPutToInterfaceWithObjectMergingTest extends TestBase {
+
+ @Parameter(0)
+ public boolean enableVerticalClassMerging;
+
+ @Parameter(1)
+ public TestParameters parameters;
+
+ @Parameters(name = "{1}, vertical class merging: {0}")
+ public static List<Object[]> parameters() {
+ return buildParameters(
+ BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+ }
+
+ @Test
+ public void testRuntime() throws Exception {
+ assumeFalse(enableVerticalClassMerging);
+ testForRuntime(parameters)
+ .addProgramClasses(I.class, A.class)
+ .addProgramClassFileData(getTransformedMain())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("A");
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(I.class, A.class)
+ .addProgramClassFileData(getTransformedMain())
+ .addKeepMainRule(Main.class)
+ // Keep get() to prevent that we optimize it into having static return type A.
+ .addKeepRules("-keepclassmembers class " + Main.class.getTypeName() + " { *** get(...); }")
+ .addNoVerticalClassMergingAnnotations()
+ .applyIf(
+ !enableVerticalClassMerging, R8TestBuilder::enableNoVerticalClassMergingAnnotations)
+ .addVerticallyMergedClassesInspector(
+ inspector -> {
+ if (enableVerticalClassMerging) {
+ inspector.assertMergedIntoSubtype(I.class);
+ } else {
+ inspector.assertNoClassesMerged();
+ }
+ })
+ .enableInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("A");
+ }
+
+ private static byte[] getTransformedMain() throws IOException {
+ return transformer(Main.class)
+ .transformMethodInsnInMethod(
+ "main",
+ (opcode, owner, name, descriptor, isInterface, visitor) -> {
+ if (name.equals("get")) {
+ visitor.visitMethodInsn(opcode, owner, name, "()Ljava/lang/Object;", isInterface);
+ } else {
+ visitor.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
+ }
+ })
+ .setReturnType(MethodPredicate.onName("get"), Object.class.getTypeName())
+ .transform();
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ I[] is = new I[1];
+ // Transformed from `I get()` to `Object get()`.
+ is[0] = get();
+ print(is);
+ }
+
+ // @Keep
+ static /*Object*/ I get() {
+ return new A();
+ }
+
+ @NeverInline
+ static void print(I[] is) {
+ System.out.println(is[0]);
+ }
+ }
+
+ @NoVerticalClassMerging
+ interface I {}
+
+ static class A implements I {
+
+ @Override
+ public String toString() {
+ return "A";
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classmerger/vertical/InstancePutToInterfaceWithObjectMergingTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classmerger/vertical/InstancePutToInterfaceWithObjectMergingTest.java
new file mode 100644
index 0000000..980eebb
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classmerger/vertical/InstancePutToInterfaceWithObjectMergingTest.java
@@ -0,0 +1,122 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.optimize.classmerger.vertical;
+
+import static org.junit.Assume.assumeFalse;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoVerticalClassMerging;
+import com.android.tools.r8.R8TestBuilder;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
+import com.android.tools.r8.utils.BooleanUtils;
+import java.io.IOException;
+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 InstancePutToInterfaceWithObjectMergingTest extends TestBase {
+
+ @Parameter(0)
+ public boolean enableVerticalClassMerging;
+
+ @Parameter(1)
+ public TestParameters parameters;
+
+ @Parameters(name = "{1}, vertical class merging: {0}")
+ public static List<Object[]> parameters() {
+ return buildParameters(
+ BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+ }
+
+ @Test
+ public void testRuntime() throws Exception {
+ assumeFalse(enableVerticalClassMerging);
+ testForRuntime(parameters)
+ .addProgramClasses(I.class, A.class)
+ .addProgramClassFileData(getTransformedMain())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("A");
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(I.class, A.class)
+ .addProgramClassFileData(getTransformedMain())
+ .addKeepMainRule(Main.class)
+ // Keep get() to prevent that we optimize it into having static return type A.
+ .addKeepRules("-keepclassmembers class " + Main.class.getTypeName() + " { *** get(...); }")
+ .addNoVerticalClassMergingAnnotations()
+ .applyIf(
+ !enableVerticalClassMerging, R8TestBuilder::enableNoVerticalClassMergingAnnotations)
+ .addVerticallyMergedClassesInspector(
+ inspector -> {
+ if (enableVerticalClassMerging) {
+ inspector.assertMergedIntoSubtype(I.class);
+ } else {
+ inspector.assertNoClassesMerged();
+ }
+ })
+ .enableInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("A");
+ }
+
+ private static byte[] getTransformedMain() throws IOException {
+ return transformer(Main.class)
+ .transformMethodInsnInMethod(
+ "main",
+ (opcode, owner, name, descriptor, isInterface, visitor) -> {
+ if (name.equals("get")) {
+ visitor.visitMethodInsn(opcode, owner, name, "()Ljava/lang/Object;", isInterface);
+ } else {
+ visitor.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
+ }
+ })
+ .setReturnType(MethodPredicate.onName("get"), Object.class.getTypeName())
+ .transform();
+ }
+
+ static class Main {
+
+ I f;
+
+ public static void main(String[] args) {
+ Main main = new Main();
+ // Transformed from `I get()` to `Object get()`.
+ main.f = get();
+ print(main);
+ }
+
+ // @Keep
+ static /*Object*/ I get() {
+ return new A();
+ }
+
+ @NeverInline
+ static void print(Main main) {
+ System.out.println(main.f);
+ }
+ }
+
+ @NoVerticalClassMerging
+ interface I {}
+
+ static class A implements I {
+
+ @Override
+ public String toString() {
+ return "A";
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classmerger/vertical/ReturnObjectAsInterfaceMergingTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classmerger/vertical/ReturnObjectAsInterfaceMergingTest.java
new file mode 100644
index 0000000..48b234b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classmerger/vertical/ReturnObjectAsInterfaceMergingTest.java
@@ -0,0 +1,120 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.optimize.classmerger.vertical;
+
+import static org.junit.Assume.assumeFalse;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoVerticalClassMerging;
+import com.android.tools.r8.R8TestBuilder;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
+import com.android.tools.r8.utils.BooleanUtils;
+import java.io.IOException;
+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 ReturnObjectAsInterfaceMergingTest extends TestBase {
+
+ @Parameter(0)
+ public boolean enableVerticalClassMerging;
+
+ @Parameter(1)
+ public TestParameters parameters;
+
+ @Parameters(name = "{1}, vertical class merging: {0}")
+ public static List<Object[]> parameters() {
+ return buildParameters(
+ BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+ }
+
+ @Test
+ public void testRuntime() throws Exception {
+ assumeFalse(enableVerticalClassMerging);
+ testForRuntime(parameters)
+ .addProgramClasses(I.class, A.class)
+ .addProgramClassFileData(getTransformedMain())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("A");
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(I.class, A.class)
+ .addProgramClassFileData(getTransformedMain())
+ .addKeepMainRule(Main.class)
+ // Keep get() to prevent that we optimize it into having static return type A.
+ .addKeepRules("-keepclassmembers class " + Main.class.getTypeName() + " { *** get(...); }")
+ .addNoVerticalClassMergingAnnotations()
+ .applyIf(
+ !enableVerticalClassMerging, R8TestBuilder::enableNoVerticalClassMergingAnnotations)
+ .addVerticallyMergedClassesInspector(
+ inspector -> {
+ if (enableVerticalClassMerging) {
+ inspector.assertMergedIntoSubtype(I.class);
+ } else {
+ inspector.assertNoClassesMerged();
+ }
+ })
+ .enableInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("A");
+ }
+
+ private static byte[] getTransformedMain() throws IOException {
+ return transformer(Main.class)
+ .transformMethodInsnInMethod(
+ "test",
+ (opcode, owner, name, descriptor, isInterface, visitor) -> {
+ if (name.equals("get")) {
+ visitor.visitMethodInsn(opcode, owner, name, "()Ljava/lang/Object;", isInterface);
+ } else {
+ visitor.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
+ }
+ })
+ .setReturnType(MethodPredicate.onName("get"), Object.class.getTypeName())
+ .transform();
+ }
+
+ static class Main {
+
+ static I f;
+
+ public static void main(String[] args) {
+ System.out.println(test());
+ }
+
+ @NeverInline
+ static I test() {
+ // Transformed from `I get()` to `Object get()`.
+ return get();
+ }
+
+ // @Keep
+ static /*Object*/ I get() {
+ return new A();
+ }
+ }
+
+ @NoVerticalClassMerging
+ interface I {}
+
+ static class A implements I {
+
+ @Override
+ public String toString() {
+ return "A";
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classmerger/vertical/StaticPutToInterfaceWithObjectMergingTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classmerger/vertical/StaticPutToInterfaceWithObjectMergingTest.java
new file mode 100644
index 0000000..bb948cbe
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classmerger/vertical/StaticPutToInterfaceWithObjectMergingTest.java
@@ -0,0 +1,121 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.optimize.classmerger.vertical;
+
+import static org.junit.Assume.assumeFalse;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoVerticalClassMerging;
+import com.android.tools.r8.R8TestBuilder;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
+import com.android.tools.r8.utils.BooleanUtils;
+import java.io.IOException;
+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 StaticPutToInterfaceWithObjectMergingTest extends TestBase {
+
+ @Parameter(0)
+ public boolean enableVerticalClassMerging;
+
+ @Parameter(1)
+ public TestParameters parameters;
+
+ @Parameters(name = "{1}, vertical class merging: {0}")
+ public static List<Object[]> parameters() {
+ return buildParameters(
+ BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+ }
+
+ @Test
+ public void testRuntime() throws Exception {
+ assumeFalse(enableVerticalClassMerging);
+ testForRuntime(parameters)
+ .addProgramClasses(I.class, A.class)
+ .addProgramClassFileData(getTransformedMain())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("A");
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(I.class, A.class)
+ .addProgramClassFileData(getTransformedMain())
+ .addKeepMainRule(Main.class)
+ // Keep get() to prevent that we optimize it into having static return type A.
+ .addKeepRules("-keepclassmembers class " + Main.class.getTypeName() + " { *** get(...); }")
+ .addNoVerticalClassMergingAnnotations()
+ .applyIf(
+ !enableVerticalClassMerging, R8TestBuilder::enableNoVerticalClassMergingAnnotations)
+ .addVerticallyMergedClassesInspector(
+ inspector -> {
+ if (enableVerticalClassMerging) {
+ inspector.assertMergedIntoSubtype(I.class);
+ } else {
+ inspector.assertNoClassesMerged();
+ }
+ })
+ .enableInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("A");
+ }
+
+ private static byte[] getTransformedMain() throws IOException {
+ return transformer(Main.class)
+ .transformMethodInsnInMethod(
+ "main",
+ (opcode, owner, name, descriptor, isInterface, visitor) -> {
+ if (name.equals("get")) {
+ visitor.visitMethodInsn(opcode, owner, name, "()Ljava/lang/Object;", isInterface);
+ } else {
+ visitor.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
+ }
+ })
+ .setReturnType(MethodPredicate.onName("get"), Object.class.getTypeName())
+ .transform();
+ }
+
+ static class Main {
+
+ static I f;
+
+ public static void main(String[] args) {
+ // Transformed from `I get()` to `Object get()`.
+ f = get();
+ print();
+ }
+
+ // @Keep
+ static /*Object*/ I get() {
+ return new A();
+ }
+
+ @NeverInline
+ static void print() {
+ System.out.println(f);
+ }
+ }
+
+ @NoVerticalClassMerging
+ interface I {}
+
+ static class A implements I {
+
+ @Override
+ public String toString() {
+ return "A";
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InterfaceInvokeWithObjectReceiverInliningTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InterfaceInvokeWithObjectReceiverInliningTest.java
new file mode 100644
index 0000000..8573c7b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InterfaceInvokeWithObjectReceiverInliningTest.java
@@ -0,0 +1,129 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.optimize.inliner;
+import static org.junit.Assume.assumeFalse;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoVerticalClassMerging;
+import com.android.tools.r8.R8TestBuilder;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
+import com.android.tools.r8.utils.BooleanUtils;
+import java.io.IOException;
+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 InterfaceInvokeWithObjectReceiverInliningTest extends TestBase {
+
+ @Parameter(0)
+ public boolean enableInlining;
+
+ @Parameter(1)
+ public boolean enableVerticalClassMerging;
+
+ @Parameter(2)
+ public TestParameters parameters;
+
+ @Parameters(name = "{2}, inlining: {0}, vertical class merging: {1}")
+ public static List<Object[]> parameters() {
+ return buildParameters(
+ BooleanUtils.values(),
+ BooleanUtils.values(),
+ getTestParameters().withAllRuntimesAndApiLevels().build());
+ }
+
+ @Test
+ public void testRuntime() throws Exception {
+ assumeFalse(enableInlining);
+ assumeFalse(enableVerticalClassMerging);
+ testForRuntime(parameters)
+ .addProgramClasses(I.class, A.class)
+ .addProgramClassFileData(getTransformedMain())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("0");
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(I.class, A.class)
+ .addProgramClassFileData(getTransformedMain())
+ .addKeepMainRule(Main.class)
+ // Keep get() to prevent that we optimize it into having static return type A.
+ .addKeepRules("-keepclassmembers class " + Main.class.getTypeName() + " { *** get(...); }")
+ .addInliningAnnotations()
+ .addNoVerticalClassMergingAnnotations()
+ .applyIf(!enableInlining, R8TestBuilder::enableInliningAnnotations)
+ .applyIf(
+ !enableVerticalClassMerging, R8TestBuilder::enableNoVerticalClassMergingAnnotations)
+ .addVerticallyMergedClassesInspector(
+ inspector -> {
+ if (enableVerticalClassMerging) {
+ inspector.assertMergedIntoSubtype(I.class);
+ } else {
+ inspector.assertNoClassesMerged();
+ }
+ })
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("0");
+ }
+
+ private static byte[] getTransformedMain() throws IOException {
+ return transformer(Main.class)
+ .transformMethodInsnInMethod(
+ "main",
+ (opcode, owner, name, descriptor, isInterface, visitor) -> {
+ if (name.equals("get")) {
+ visitor.visitMethodInsn(opcode, owner, name, "(I)Ljava/lang/Object;", isInterface);
+ } else {
+ visitor.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
+ }
+ })
+ .setReturnType(MethodPredicate.onName("get"), Object.class.getTypeName())
+ .transform();
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ // Transformed from `I get(int)` to `Object get(int)`.
+ get(args.length).m();
+ }
+
+ // @Keep
+ static /*Object*/ I get(int f) {
+ return new A(f);
+ }
+ }
+
+ @NoVerticalClassMerging
+ interface I {
+
+ void m();
+ }
+
+ static class A implements I {
+
+ int f;
+
+ A(int f) {
+ this.f = f;
+ }
+
+ @NeverInline
+ @Override
+ public void m() {
+ System.out.println(f);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/StaticInvokeWithMultipleObjectsForInterfaceTypesTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/StaticInvokeWithMultipleObjectsForInterfaceTypesTest.java
new file mode 100644
index 0000000..0c9a135
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/StaticInvokeWithMultipleObjectsForInterfaceTypesTest.java
@@ -0,0 +1,160 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.optimize.inliner;
+
+import static org.junit.Assume.assumeFalse;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoHorizontalClassMerging;
+import com.android.tools.r8.NoVerticalClassMerging;
+import com.android.tools.r8.R8TestBuilder;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
+import com.android.tools.r8.utils.BooleanUtils;
+import java.io.IOException;
+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 StaticInvokeWithMultipleObjectsForInterfaceTypesTest extends TestBase {
+
+ @Parameter(0)
+ public boolean enableInlining;
+
+ @Parameter(1)
+ public boolean enableVerticalClassMerging;
+
+ @Parameter(2)
+ public TestParameters parameters;
+
+ @Parameters(name = "{2}, inlining: {0}, vertical class merging: {1}")
+ public static List<Object[]> parameters() {
+ return buildParameters(
+ BooleanUtils.values(),
+ BooleanUtils.values(),
+ getTestParameters().withAllRuntimesAndApiLevels().build());
+ }
+
+ @Test
+ public void testRuntime() throws Exception {
+ assumeFalse(enableInlining);
+ assumeFalse(enableVerticalClassMerging);
+ testForRuntime(parameters)
+ .addProgramClasses(I.class, J.class, A.class, B.class)
+ .addProgramClassFileData(getTransformedMain())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("0", "0");
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(I.class, J.class, A.class, B.class)
+ .addProgramClassFileData(getTransformedMain())
+ .addKeepMainRule(Main.class)
+ // Keep getA() and getB() to prevent that we optimize it into having static return type A/B.
+ .addKeepRules("-keepclassmembers class " + Main.class.getTypeName() + " { *** get?(...); }")
+ .addInliningAnnotations()
+ .addNoVerticalClassMergingAnnotations()
+ .applyIf(!enableInlining, R8TestBuilder::enableInliningAnnotations)
+ .applyIf(
+ !enableVerticalClassMerging, R8TestBuilder::enableNoVerticalClassMergingAnnotations)
+ .enableNoHorizontalClassMergingAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("0", "0");
+ }
+
+ private static byte[] getTransformedMain() throws IOException {
+ return transformer(Main.class)
+ .transformMethodInsnInMethod(
+ "main",
+ (opcode, owner, name, descriptor, isInterface, visitor) -> {
+ if (name.startsWith("get")) {
+ visitor.visitMethodInsn(opcode, owner, name, "(I)Ljava/lang/Object;", isInterface);
+ } else {
+ visitor.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
+ }
+ })
+ .setReturnType(MethodPredicate.onName("getA"), Object.class.getTypeName())
+ .setReturnType(MethodPredicate.onName("getB"), Object.class.getTypeName())
+ .transform();
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ // Transformed from `I getA(int)` to `Object getA(int)` and `J getB(int)` to
+ // `Object getB(int)`.
+ test(getA(args.length), getB(args.length));
+ }
+
+ // @Keep
+ static /*Object*/ I getA(int f) {
+ return new A(f);
+ }
+
+ // @Keep
+ static /*Object*/ J getB(int f) {
+ return new B(f);
+ }
+
+ @NeverInline
+ static void test(I i, J j) {
+ i.m();
+ j.m();
+ }
+ }
+
+ @NoHorizontalClassMerging
+ @NoVerticalClassMerging
+ interface I {
+
+ void m();
+ }
+
+ @NoHorizontalClassMerging
+ static class A implements I {
+
+ int f;
+
+ A(int f) {
+ this.f = f;
+ }
+
+ @Override
+ public void m() {
+ System.out.println(f);
+ }
+ }
+
+ @NoHorizontalClassMerging
+ @NoVerticalClassMerging
+ interface J {
+
+ void m();
+ }
+
+ @NoHorizontalClassMerging
+ static class B implements J {
+
+ int f;
+
+ B(int f) {
+ this.f = f;
+ }
+
+ @Override
+ public void m() {
+ System.out.println(f);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java
index c3f71e3..615aa20 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java
@@ -204,9 +204,9 @@
assertEquals(
Lists.newArrayList(
- "STATIC: SimpleWithThrowingGetter SimpleWithThrowingGetter.getInstance()",
- "STATIC: SimpleWithThrowingGetter SimpleWithThrowingGetter.getInstance()",
"STATIC: String TrivialTestClass.next()",
+ "STATIC: void SimpleWithThrowingGetter.getInstance()",
+ "STATIC: void SimpleWithThrowingGetter.getInstance()",
"SimpleWithThrowingGetter SimpleWithThrowingGetter.INSTANCE",
"VIRTUAL: String SimpleWithThrowingGetter.bar(String)",
"VIRTUAL: String SimpleWithThrowingGetter.foo()"),
@@ -399,7 +399,6 @@
private void configure(InternalOptions options) {
options.enableClassInlining = false;
- options.enableUninstantiatedTypeOptimization = false;
}
@Test
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/InvokeStaticWithNullOutvalueTest.java b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/InvokeStaticWithNullOutvalueTest.java
index fe09d69..6750562 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/InvokeStaticWithNullOutvalueTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/InvokeStaticWithNullOutvalueTest.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NeverPropagateValue;
import com.android.tools.r8.NoHorizontalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
@@ -45,6 +46,7 @@
.addInnerClasses(InvokeStaticWithNullOutvalueTest.class)
.addKeepMainRule(MAIN)
.enableInliningAnnotations()
+ .enableMemberValuePropagationAnnotations()
.enableNeverClassInliningAnnotations()
.enableNoHorizontalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
@@ -84,6 +86,7 @@
@NoHorizontalClassMerging
static class Companion {
@NeverInline
+ @NeverPropagateValue
private static Object boo() {
System.out.println("Companion#boo");
return null;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/StringValueOfTest.java b/src/test/java/com/android/tools/r8/ir/optimize/string/StringValueOfTest.java
index 3861a06..e3fe71a 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/string/StringValueOfTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/string/StringValueOfTest.java
@@ -89,7 +89,7 @@
int expectedCount = isR8 ? 4 : (isRelease ? 5 : 7);
assertEquals(expectedCount, countCall(mainMethod, "String", "valueOf"));
// Due to the different behavior regarding constant canonicalization.
- expectedCount = isR8 ? (parameters.isCfRuntime() ? 3 : 1) : 1;
+ expectedCount = isR8 ? (parameters.isCfRuntime() ? 4 : 1) : 1;
assertEquals(expectedCount, countConstNullNumber(mainMethod));
expectedCount = isR8 ? 1 : (isRelease ? 1 : 0);
assertEquals(expectedCount, countNullStringNumber(mainMethod));
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InterfaceMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InterfaceMethodTest.java
index 209f9f9..91a886d 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InterfaceMethodTest.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.ir.optimize.uninstantiatedtypes;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.google.common.base.Predicates.alwaysTrue;
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.NeverClassInline;
@@ -12,10 +13,12 @@
import com.android.tools.r8.NoHorizontalClassMerging;
import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
import com.google.common.collect.ImmutableList;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -25,45 +28,53 @@
@RunWith(Parameterized.class)
public class InterfaceMethodTest extends TestBase {
- private final Backend backend;
+ private final TestParameters parameters;
- @Parameters(name = "Backend: {0}")
- public static Backend[] data() {
- return ToolHelper.getBackends();
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
}
- public InterfaceMethodTest(Backend backend) {
- this.backend = backend;
+ public InterfaceMethodTest(TestParameters parameters) {
+ this.parameters = parameters;
}
@Test
public void test() throws Exception {
String expectedOutput = StringUtils.lines("In A.m()", "In B.m()");
- if (backend == Backend.CF) {
- testForJvm().addTestClasspath().run(TestClass.class).assertSuccessWithOutput(expectedOutput);
+ if (parameters.isCfRuntime()) {
+ testForJvm()
+ .addTestClasspath()
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(expectedOutput);
}
CodeInspector inspector =
- testForR8(backend)
+ testForR8(parameters.getBackend())
.addInnerClasses(InterfaceMethodTest.class)
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.enableNoVerticalClassMergingAnnotations()
.enableNoHorizontalClassMergingAnnotations()
- .run(TestClass.class)
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutput(expectedOutput)
.inspector();
ClassSubject interfaceSubject = inspector.clazz(I.class);
assertThat(interfaceSubject, isPresent());
- assertThat(interfaceSubject.method(Uninstantiated.class.getTypeName(), "m"), isPresent());
+
+ MethodSubject interfaceMethodSubject = interfaceSubject.uniqueMethodThatMatches(alwaysTrue());
+ assertThat(interfaceMethodSubject, isPresent());
for (Class<?> clazz : ImmutableList.of(A.class, B.class)) {
ClassSubject classSubject = inspector.clazz(clazz);
assertThat(classSubject, isPresent());
- assertThat(classSubject.method(Uninstantiated.class.getTypeName(), "m"), isPresent());
+ assertThat(
+ classSubject.method(interfaceMethodSubject.getProgramMethod().getMethodReference()),
+ isPresent());
}
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InvokeMethodWithReceiverOptimizationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InvokeMethodWithReceiverOptimizationTest.java
index 06aae25..eca11f0 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InvokeMethodWithReceiverOptimizationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InvokeMethodWithReceiverOptimizationTest.java
@@ -64,10 +64,8 @@
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
.addOptionsModification(
- options -> {
- options.enableUninstantiatedTypeOptimization = enableArgumentPropagation;
- options.callSiteOptimizationOptions().setEnabled(enableArgumentPropagation);
- })
+ options ->
+ options.callSiteOptimizationOptions().setEnabled(enableArgumentPropagation))
// TODO(b/120764902): The calls to getOriginalName() below does not work in presence of
// argument removal.
.noMinification()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/NestedInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/NestedInterfaceMethodTest.java
index f07d6b6..44d3e31 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/NestedInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/NestedInterfaceMethodTest.java
@@ -18,6 +18,7 @@
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -43,7 +44,10 @@
String expectedOutput = StringUtils.lines("In A.m()", "In A.m()");
if (parameters.isCfRuntime()) {
- testForJvm().addTestClasspath().run(TestClass.class).assertSuccessWithOutput(expectedOutput);
+ testForJvm()
+ .addTestClasspath()
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(expectedOutput);
}
CodeInspector inspector =
@@ -66,11 +70,19 @@
ClassSubject interfaceSubject = inspector.clazz(I.class);
assertThat(interfaceSubject, isPresent());
- assertThat(interfaceSubject.method(Uninstantiated.class.getTypeName(), "m"), isPresent());
+
+ MethodSubject interfaceMethodSubject =
+ interfaceSubject.uniqueMethodThatMatches(
+ method -> method.getProgramMethod().getReturnType().isVoidType());
+ assertThat(interfaceMethodSubject, isPresent());
ClassSubject classSubject = inspector.clazz(A.class);
assertThat(classSubject, isPresent());
- assertThat(classSubject.method(Uninstantiated.class.getTypeName(), "m"), isPresent());
+ assertThat(
+ classSubject.uniqueMethodThatMatches(
+ method ->
+ method.getProgramMethod().getReference().match(interfaceMethodSubject.getMethod())),
+ isPresent());
}
static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/VoidReturnTypeRewritingTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/VoidReturnTypeRewritingTest.java
index 5e5345a..472ec24 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/VoidReturnTypeRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/VoidReturnTypeRewritingTest.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.optimize.uninstantiatedtypes;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertTrue;
@@ -76,15 +77,9 @@
ClassSubject subSubFactoryClassSubject = inspector.clazz(SubSubFactory.class);
assertThat(subSubFactoryClassSubject.method("void", "createVirtual"), isPresent());
- assertThat(
- subSubFactoryClassSubject.method(SubUninstantiated.class.getTypeName(), "createVirtual"),
- isPresent());
-
- // TODO(b/110806787): Uninstantiated is kept because SubUninstantiated inherits from it.
- // We should consider rewriting SubUninstantiated such that it no longer inherits from
- // Uninstantiated.
- assertThat(inspector.clazz(Uninstantiated.class), isPresent());
- assertThat(inspector.clazz(SubUninstantiated.class), isPresent());
+ assertThat(subSubFactoryClassSubject.method("void", "createVirtual$1"), isPresent());
+ assertThat(inspector.clazz(Uninstantiated.class), isAbsent());
+ assertThat(inspector.clazz(SubUninstantiated.class), isAbsent());
}
static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/CollisionWithLibraryMethodsTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/CollisionWithLibraryMethodsTest.java
index 612a0b5..e990830 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/CollisionWithLibraryMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/CollisionWithLibraryMethodsTest.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NeverPropagateValue;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.utils.BooleanUtils;
@@ -32,7 +33,8 @@
@Parameters(name = "{1}, minification: {0}")
public static List<Object[]> params() {
- return buildParameters(BooleanUtils.values(), getTestParameters().withAllRuntimes().build());
+ return buildParameters(
+ BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
}
public CollisionWithLibraryMethodsTest(boolean minification, TestParameters parameters) {
@@ -46,10 +48,11 @@
testForR8(parameters.getBackend())
.addInnerClasses(CollisionWithLibraryMethodsTest.class)
.addKeepMainRule(TestClass.class)
+ .enableMemberValuePropagationAnnotations()
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.minification(minification)
- .setMinApi(parameters.getRuntime())
+ .setMinApi(parameters.getApiLevel())
.compile()
.inspect(this::verify)
.run(parameters.getRuntime(), TestClass.class)
@@ -83,6 +86,7 @@
static class Greeting {
@NeverInline
+ @NeverPropagateValue
public String toString(Object unused) {
System.out.print("Hello ");
return "world!";
diff --git a/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java b/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
index 105008c..f3db67c 100644
--- a/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.graph.DebugLocalInfo;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
@@ -203,7 +204,7 @@
IRCode inlinee,
ListIterator<BasicBlock> blockIterator,
Set<BasicBlock> blocksToRemove,
- DexType downcast) {
+ DexProgramClass downcast) {
throw new Unimplemented();
}
}
diff --git a/src/test/java/com/android/tools/r8/naming/MappingFileHashTest.java b/src/test/java/com/android/tools/r8/naming/MappingFileHashTest.java
new file mode 100644
index 0000000..23f8605
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/MappingFileHashTest.java
@@ -0,0 +1,69 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.naming;
+
+import static 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.naming.ProguardMapSupplier.ProguardMapChecker;
+import com.android.tools.r8.naming.ProguardMapSupplier.ProguardMapChecker.VerifyMappingFileHashResult;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class MappingFileHashTest extends TestBase {
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
+
+ public MappingFileHashTest(TestParameters parameters) {
+ parameters.assertNoneRuntime();
+ }
+
+ @Test
+ public void testUnixLineEnd() throws Exception {
+ String newline = "\n";
+ // Hash as given by sha256 command on the content using unix-style newlines.
+ String hash = "539a6b5614c65c7473a995507163a4559cea3229d3cada164a2ca4935bbbd597";
+ verifyHash(newline, hash);
+ }
+
+ @Test
+ public void testWindowsLineEnd() throws Exception {
+ // R8 will only use \n in mapping files, but if a file is written using dos-style newlines,
+ // those newlines will be part of the content hashing. This is a regression test that the file
+ // will compute the right hash in such cases.
+ String newline = "\r\n";
+ // Hash as given by sha256 command on the content using dos-style newlines.
+ String hash = "6ef47f7b9b6d5013628073ebdadad27dd2e7e57ef911e9d6cbee0f92c434e48a";
+ verifyHash(newline, hash);
+ }
+
+ private void verifyHash(String newline, String hash) throws Exception {
+ // Some header info. This should never affect the hash.
+ String header =
+ String.join(
+ newline,
+ "# compiler: R8",
+ "", // Empty header line.
+ "# junk header info: " + System.nanoTime(),
+ "# pg_map_hash: SHA-256 " + hash);
+ // Actually hashed content (modulo newlines).
+ String hashed =
+ String.join(
+ newline,
+ "triviæl.Triviål -> a.œ:",
+ " void main(java.lang.String[]) -> a",
+ "" // Always end with newline.
+ );
+ String content = String.join(newline, header, hashed);
+ VerifyMappingFileHashResult result = ProguardMapChecker.validateProguardMapHash(content);
+ assertTrue(result.isOk());
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/naming/b72391662/B72391662.java b/src/test/java/com/android/tools/r8/naming/b72391662/B72391662.java
index c4c9fdf..8771ff4 100644
--- a/src/test/java/com/android/tools/r8/naming/b72391662/B72391662.java
+++ b/src/test/java/com/android/tools/r8/naming/b72391662/B72391662.java
@@ -10,6 +10,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import com.android.tools.r8.NeverPropagateValue;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.errors.Unreachable;
@@ -41,7 +42,8 @@
Super.class,
TestClass.class,
OtherPackageSuper.class,
- OtherPackageTestClass.class);
+ OtherPackageTestClass.class,
+ NeverPropagateValue.class);
private final Shrinker shrinker;
private final String repackagePrefix;
@@ -212,7 +214,7 @@
@Test
public void test_keepPublic() throws Exception {
Assume.assumeFalse(shrinker.generatesDex() && vmVersionIgnored());
- Class mainClass = TestMain.class;
+ Class<?> mainClass = TestMain.class;
String keep = !minify ? "-keep" : "-keep,allowobfuscation";
Iterable<String> config = ImmutableList.of(
"-printmapping",
@@ -238,6 +240,9 @@
"-assumemayhavesideeffects class " + TestClass.class.getCanonicalName() + " {",
" * staticMethod();",
"}",
+ "-neverpropagatevalue class * {",
+ " @com.android.tools.r8.NeverPropagateValue <methods>;",
+ "}",
"-neverinline class " + TestClass.class.getCanonicalName() + " {",
" * staticMethod();",
"}"));
diff --git a/src/test/java/com/android/tools/r8/naming/b72391662/TestClass.java b/src/test/java/com/android/tools/r8/naming/b72391662/TestClass.java
index f13700c..451a817 100644
--- a/src/test/java/com/android/tools/r8/naming/b72391662/TestClass.java
+++ b/src/test/java/com/android/tools/r8/naming/b72391662/TestClass.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.naming.b72391662;
+import com.android.tools.r8.NeverPropagateValue;
import java.util.function.IntSupplier;
import java.util.function.Supplier;
@@ -22,6 +23,7 @@
System.out.println("This should be discarded unless there is a keep rule.");
}
+ @NeverPropagateValue
static String staticMethod() {
return "1";
}
diff --git a/src/test/java/com/android/tools/r8/naming/overloadaggressively/B.java b/src/test/java/com/android/tools/r8/naming/overloadaggressively/B.java
index 6660196..298c597 100644
--- a/src/test/java/com/android/tools/r8/naming/overloadaggressively/B.java
+++ b/src/test/java/com/android/tools/r8/naming/overloadaggressively/B.java
@@ -3,19 +3,24 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.naming.overloadaggressively;
+import com.android.tools.r8.NeverPropagateValue;
+
public class B {
volatile int f1 = 8;
volatile Object f2 = "d8";
volatile String f3 = "r8";
+ @NeverPropagateValue
public int getF1() {
return f1;
}
+ @NeverPropagateValue
public Object getF2() {
return f2;
}
+ @NeverPropagateValue
public String getF3() {
return f3;
}
diff --git a/src/test/java/com/android/tools/r8/naming/overloadaggressively/OverloadAggressivelyTest.java b/src/test/java/com/android/tools/r8/naming/overloadaggressively/OverloadAggressivelyTest.java
index 5c48866..e691d86 100644
--- a/src/test/java/com/android/tools/r8/naming/overloadaggressively/OverloadAggressivelyTest.java
+++ b/src/test/java/com/android/tools/r8/naming/overloadaggressively/OverloadAggressivelyTest.java
@@ -17,6 +17,7 @@
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.google.common.collect.ImmutableList;
@@ -41,7 +42,7 @@
this.backend = backend;
}
- private AndroidApp runR8(AndroidApp app, Class main, Path out, boolean overloadaggressively)
+ private AndroidApp runR8(AndroidApp app, Class<?> main, Path out, boolean overloadaggressively)
throws Exception {
R8Command command =
ToolHelper.addProguardConfigurationConsumer(
@@ -172,21 +173,36 @@
}
private void methodResolution(boolean overloadaggressively) throws Exception {
- byte[][] classes = {
- ToolHelper.getClassAsBytes(MethodResolution.class),
- ToolHelper.getClassAsBytes(B.class)
- };
- AndroidApp originalApp = buildAndroidApp(classes);
- Path out = temp.getRoot().toPath();
- AndroidApp processedApp = runR8(originalApp, MethodResolution.class, out, overloadaggressively);
+ String expected = StringUtils.lines("diff: 0", "d8 v.s. d8", "r8 v.s. r8");
+ String expectedOverloadAggressively = StringUtils.lines("diff: 0", "d8 v.s. 8", "r8 v.s. 8");
- CodeInspector codeInspector = new CodeInspector(processedApp);
+ if (backend.isCf()) {
+ testForJvm().addTestClasspath().run(MethodResolution.class).assertSuccessWithOutput(expected);
+ }
+
+ testForR8Compat(backend)
+ .addProgramClasses(MethodResolution.class, B.class)
+ .addKeepMainRule(MethodResolution.class)
+ .addOptionsModification(options -> options.enableInlining = false)
+ .applyIf(overloadaggressively, builder -> builder.addKeepRules("-overloadaggressively"))
+ .enableMemberValuePropagationAnnotations()
+ .compile()
+ .inspect(inspector -> inspect(inspector, overloadaggressively))
+ .run(MethodResolution.class)
+ .applyIf(
+ overloadaggressively,
+ runResult -> runResult.assertSuccessWithOutput(expectedOverloadAggressively),
+ runResult -> runResult.assertSuccessWithOutput(expected));
+ }
+
+ private void inspect(CodeInspector codeInspector, boolean overloadaggressively) {
ClassSubject b = codeInspector.clazz(B.class.getCanonicalName());
DexEncodedMethod m1 =
b.method("int", "getF1", ImmutableList.of()).getMethod();
assertNotNull(m1);
DexEncodedMethod m2 =
b.method("java.lang.Object", "getF2", ImmutableList.of()).getMethod();
+ assertNotNull(m2);
// TODO(b/72858955): due to the potential reflective access, they should have different names.
assertEquals(overloadaggressively, m1.getReference().name == m2.getReference().name);
DexEncodedMethod m3 =
@@ -196,21 +212,6 @@
assertEquals(overloadaggressively, m1.getReference().name == m3.getReference().name);
// TODO(b/72858955): ditto
assertEquals(overloadaggressively, m2.getReference().name == m3.getReference().name);
-
- String main = MethodResolution.class.getCanonicalName();
- ProcessResult javaOutput = runOnJavaRaw(main, classes);
- assertEquals(0, javaOutput.exitCode);
- ProcessResult output = runRaw(processedApp, main);
- // TODO(b/72858955): R8 should avoid method resolution conflict even w/ -overloadaggressively.
- if (overloadaggressively) {
- assertEquals(0, output.exitCode);
- assertNotEquals(javaOutput.stdout.trim(), output.stdout.trim());
- } else {
- assertEquals(0, output.exitCode);
- assertEquals(javaOutput.stdout.trim(), output.stdout.trim());
- // ART may dump its own debugging info through stderr.
- // assertEquals(javaOutput.stderr.trim(), artOutput.stderr.trim());
- }
}
@Test
diff --git a/src/test/java/com/android/tools/r8/naming/retrace/RetraceInlineeWithNullCheck.java b/src/test/java/com/android/tools/r8/naming/retrace/RetraceInlineeWithNullCheck.java
new file mode 100644
index 0000000..232fe30
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/retrace/RetraceInlineeWithNullCheck.java
@@ -0,0 +1,89 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.naming.retrace;
+
+import static com.android.tools.r8.naming.retrace.StackTrace.isSame;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfRuntime;
+import java.util.List;
+import org.junit.Before;
+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 RetraceInlineeWithNullCheck extends TestBase {
+
+ @Parameter() public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build());
+ }
+
+ public StackTrace expectedStackTrace;
+
+ @Before
+ public void setup() throws Exception {
+ // Get the expected stack trace by running on the JVM.
+ expectedStackTrace =
+ testForJvm()
+ .addTestClasspath()
+ .run(CfRuntime.getSystemRuntime(), Caller.class)
+ .assertFailure()
+ .map(StackTrace::extractFromJvm);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Caller.class)
+ .addKeepAttributeLineNumberTable()
+ .addKeepAttributeSourceFile()
+ .setMinApi(parameters.getApiLevel())
+ .enableInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
+ .run(parameters.getRuntime(), Caller.class)
+ .assertFailureWithErrorThatThrows(NullPointerException.class)
+ // TODO(b/197936862): The two should be the same
+ .inspectStackTrace(
+ (stackTrace, codeInspector) -> {
+ assertThat(stackTrace, not(isSame(expectedStackTrace)));
+ });
+ }
+
+ static class Foo {
+ @NeverInline
+ Object notInlinable() {
+ System.out.println("Hello, world!");
+ throw new RuntimeException("Foo");
+ }
+
+ Object inlinable() {
+ return notInlinable();
+ }
+ }
+
+ @NeverClassInline
+ static class Caller {
+ @NeverInline
+ static void caller(Foo f) {
+ f.inlinable();
+ }
+
+ public static void main(String[] args) {
+ caller(System.currentTimeMillis() < 0 ? new Foo() : null);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ConstantReturnAfterArgumentPropagationTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ConstantReturnAfterArgumentPropagationTest.java
new file mode 100644
index 0000000..ba07988
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ConstantReturnAfterArgumentPropagationTest.java
@@ -0,0 +1,71 @@
+// 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.optimize.argumentpropagation;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static junit.framework.TestCase.assertTrue;
+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.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+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 ConstantReturnAfterArgumentPropagationTest extends TestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection parameters() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .enableInliningAnnotations()
+ // TODO(b/173398086): uniqueMethodWithName() does not work with argument removal.
+ .noMinification()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(
+ inspector -> {
+ ClassSubject mainClassSubject = inspector.clazz(Main.class);
+ assertThat(mainClassSubject, isPresent());
+
+ MethodSubject identityMethodSubject =
+ mainClassSubject.uniqueMethodWithName("identity");
+ assertThat(identityMethodSubject, isPresent());
+ assertTrue(identityMethodSubject.getProgramMethod().getParameters().isEmpty());
+ assertTrue(identityMethodSubject.getProgramMethod().getReturnType().isVoidType());
+ })
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("identity(42) = 42");
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ System.out.println(identity("42"));
+ }
+
+ @NeverInline
+ static Object identity(Object constant) {
+ System.out.print("identity(" + constant + ") = ");
+ return constant;
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceCommandLineTests.java b/src/test/java/com/android/tools/r8/retrace/RetraceCommandLineTests.java
index 9872e09..4bba10f 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceCommandLineTests.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceCommandLineTests.java
@@ -21,6 +21,7 @@
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.StringUtils;
import com.google.common.base.Charsets;
+import com.google.common.collect.ImmutableList;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
@@ -206,6 +207,44 @@
assertFalse(processResult.stdout.startsWith(WAITING_MESSAGE));
}
+ @Test
+ public void testNoMappingFileHash() throws IOException {
+ Path mappingFile = folder.newFile("mapping.txt").toPath();
+ Files.write(mappingFile, ("# other header\n" + "foo.bar -> a.a\n").getBytes());
+ ProcessResult result =
+ runRetraceCommandLine(
+ null, ImmutableList.of(mappingFile.toString(), "--verify-mapping-file-hash"));
+ assertEquals(result.toString(), 0, result.exitCode);
+ assertEquals("", result.stdout);
+ assertThat(result.stderr, containsString("Failure to find map hash"));
+ }
+
+ @Test
+ public void testValidMappingFileHash() throws IOException {
+ Path mappingFile = folder.newFile("mapping.txt").toPath();
+ Files.write(
+ mappingFile,
+ ("# pg_map_hash: SHA-256 aaf7c0230ea6fa768189170543c86ec202c6180d1e0a37b620e5c1fce1bd3ae7\n"
+ + "foo.bar -> a.a\n")
+ .getBytes());
+ ProcessResult result =
+ runRetraceCommandLine(
+ null, ImmutableList.of(mappingFile.toString(), "--verify-mapping-file-hash"));
+ assertEquals(result.toString(), 0, result.exitCode);
+ assertEquals("", result.stdout);
+ assertEquals("", result.stderr);
+ }
+
+ @Test
+ public void testInvalidMappingFileHash() throws IOException {
+ Path mappingFile = folder.newFile("mapping.txt").toPath();
+ Files.write(mappingFile, ("# pg_map_hash: SHA-256 abcd1234\n" + "foo.bar -> a.a\n").getBytes());
+ runAbortTest(
+ containsString("Mismatching map hash"),
+ mappingFile.toString(),
+ "--verify-mapping-file-hash");
+ }
+
private final String nonMappableStackTrace =
StringUtils.lines(
"com.android.r8.R8Exception: Problem when compiling program",
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceTests.java b/src/test/java/com/android/tools/r8/retrace/RetraceTests.java
index d1a074b..34e4ca8 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceTests.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceTests.java
@@ -28,6 +28,7 @@
import com.android.tools.r8.retrace.stacktraces.AutoStackTrace;
import com.android.tools.r8.retrace.stacktraces.CircularReferenceStackTrace;
import com.android.tools.r8.retrace.stacktraces.ColonInFileNameStackTrace;
+import com.android.tools.r8.retrace.stacktraces.DifferentLineNumberSpanStackTrace;
import com.android.tools.r8.retrace.stacktraces.FileNameExtensionStackTrace;
import com.android.tools.r8.retrace.stacktraces.FoundMethodVerboseStackTrace;
import com.android.tools.r8.retrace.stacktraces.InlineFileNameStackTrace;
@@ -39,6 +40,7 @@
import com.android.tools.r8.retrace.stacktraces.MemberFieldOverlapStackTrace;
import com.android.tools.r8.retrace.stacktraces.MultipleDotsInFileNameStackTrace;
import com.android.tools.r8.retrace.stacktraces.MultipleLinesNoLineNumberStackTrace;
+import com.android.tools.r8.retrace.stacktraces.MultipleOriginalLinesNoLineNumberStackTrace;
import com.android.tools.r8.retrace.stacktraces.NamedModuleStackTrace;
import com.android.tools.r8.retrace.stacktraces.NoObfuscatedLineNumberWithOverrideTest;
import com.android.tools.r8.retrace.stacktraces.NoObfuscationRangeMappingWithStackTrace;
@@ -315,6 +317,16 @@
runExperimentalRetraceTest(new NpeInlineRetraceStackTrace());
}
+ @Test
+ public void testMultipleOriginalLinesNoLineNumberStackTrace() throws Exception {
+ runRetraceTest(new MultipleOriginalLinesNoLineNumberStackTrace());
+ }
+
+ @Test
+ public void testDifferentLineNumberSpanStackTrace() throws Exception {
+ runRetraceTest(new DifferentLineNumberSpanStackTrace());
+ }
+
private void inspectRetraceTest(
StackTraceForTest stackTraceForTest, Consumer<Retracer> inspection) {
inspection.accept(
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiRewriteFrameInlineNpeResidualTest.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiRewriteFrameInlineNpeResidualTest.java
new file mode 100644
index 0000000..d54bafa
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiRewriteFrameInlineNpeResidualTest.java
@@ -0,0 +1,136 @@
+// 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.retrace.api;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.retrace.ProguardMapProducer;
+import com.android.tools.r8.retrace.RetraceFrameElement;
+import com.android.tools.r8.retrace.RetraceStackTraceContext;
+import com.android.tools.r8.retrace.RetraceThrownExceptionElement;
+import com.android.tools.r8.retrace.RetracedMethodReference;
+import com.android.tools.r8.retrace.Retracer;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.OptionalInt;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class RetraceApiRewriteFrameInlineNpeResidualTest extends RetraceApiTestBase {
+
+ public RetraceApiRewriteFrameInlineNpeResidualTest(TestParameters parameters) {
+ super(parameters);
+ }
+
+ @Override
+ protected Class<? extends RetraceApiBinaryTest> binaryTestClass() {
+ return ApiTest.class;
+ }
+
+ public static class ApiTest implements RetraceApiBinaryTest {
+
+ private final ClassReference originalException = Reference.classFromTypeName("foo.bar.baz");
+ private final ClassReference renamedException = Reference.classFromTypeName("c");
+
+ private final ClassReference originalSomeClass = Reference.classFromTypeName("some.Class");
+ private final ClassReference renamedSomeClass = Reference.classFromTypeName("a");
+
+ private final ClassReference originalSomeOtherClass =
+ Reference.classFromTypeName("some.other.Class");
+ private final ClassReference renamedSomeOtherClass = Reference.classFromTypeName("b");
+
+ private final String mapping =
+ "# { id: 'com.android.tools.r8.mapping', version: 'experimental' }\n"
+ + originalException.getTypeName()
+ + " -> "
+ + renamedException.getTypeName()
+ + ":\n"
+ + originalSomeClass.getTypeName()
+ + " -> "
+ + renamedSomeClass.getTypeName()
+ + ":\n"
+ + " 4:4:void other.Class.inlinee():23:23 -> a\n"
+ + " 4:4:void caller(other.Class):7 -> a\n"
+ + " # { id: 'com.android.tools.r8.rewriteFrame', "
+ + " conditions: ['throws(Lc;)'], "
+ + " actions: ['removeInnerFrames(1)'] "
+ + " }\n"
+ + originalSomeOtherClass.getTypeName()
+ + " -> "
+ + renamedSomeOtherClass.getTypeName()
+ + ":\n"
+ + " 4:4:void other.Class.inlinee2():23:23 -> a\n"
+ + " 4:4:void caller(other.Class):7 -> a\n"
+ + " # { id: 'com.android.tools.r8.rewriteFrame', "
+ + " conditions: ['throws(Lfoo/bar/baz;)'], "
+ + " actions: ['removeInnerFrames(1)'] "
+ + " }";
+
+ @Test
+ public void testUsingObfuscatedName() {
+ Retracer retracer =
+ Retracer.createExperimental(
+ ProguardMapProducer.fromString(mapping), new DiagnosticsHandler() {});
+ List<RetraceThrownExceptionElement> npeRetraced =
+ retracer
+ .retraceThrownException(renamedException, RetraceStackTraceContext.empty())
+ .stream()
+ .collect(Collectors.toList());
+ assertEquals(1, npeRetraced.size());
+ assertEquals(originalException, npeRetraced.get(0).getRetracedClass().getClassReference());
+
+ checkRewrittenFrame(
+ retracer, npeRetraced.get(0).getContext(), renamedSomeClass.getTypeName(), "a", true);
+ checkRewrittenFrame(
+ retracer,
+ npeRetraced.get(0).getContext(),
+ renamedSomeOtherClass.getTypeName(),
+ "a",
+ false);
+ }
+
+ private void checkRewrittenFrame(
+ Retracer retracer,
+ RetraceStackTraceContext throwingContext,
+ String typeName,
+ String methodName,
+ boolean shouldRemove) {
+ List<RetraceFrameElement> retraceFrameElements =
+ retracer.retraceClass(Reference.classFromTypeName(typeName)).stream()
+ .flatMap(
+ element ->
+ element.lookupFrame(throwingContext, OptionalInt.of(4), methodName).stream())
+ .collect(Collectors.toList());
+ assertEquals(1, retraceFrameElements.size());
+
+ RetraceFrameElement retraceFrameElement = retraceFrameElements.get(0);
+ // Check that rewriting the frames will remove the top 1 frames if the condition is active.
+ Map<Integer, RetracedMethodReference> results = new LinkedHashMap<>();
+ retraceFrameElement.forEachRewritten(
+ throwingContext,
+ frame -> {
+ RetracedMethodReference existingValue =
+ results.put(frame.getIndex(), frame.getMethodReference());
+ assertNull(existingValue);
+ });
+ if (shouldRemove) {
+ assertEquals(1, results.size());
+ assertEquals(7, results.get(0).getOriginalPositionOrDefault(4));
+ assertEquals(results.get(0).getMethodName(), "caller");
+ } else {
+ assertEquals(2, results.size());
+ }
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiRewriteFrameInlineNpeTest.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiRewriteFrameInlineNpeTest.java
index 41c56cc..9759f21 100644
--- a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiRewriteFrameInlineNpeTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiRewriteFrameInlineNpeTest.java
@@ -12,16 +12,16 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.retrace.ProguardMapProducer;
-import com.android.tools.r8.retrace.RetraceClassElement;
import com.android.tools.r8.retrace.RetraceFrameElement;
import com.android.tools.r8.retrace.RetraceStackTraceContext;
+import com.android.tools.r8.retrace.RetraceThrownExceptionElement;
import com.android.tools.r8.retrace.RetracedMethodReference;
import com.android.tools.r8.retrace.Retracer;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-import java.util.Optional;
+import java.util.OptionalInt;
import java.util.stream.Collectors;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -62,28 +62,34 @@
Retracer.createExperimental(
ProguardMapProducer.fromString(mapping), testDiagnosticsHandler);
- List<RetraceClassElement> npeRetraced =
- retracer.retraceClass(Reference.classFromDescriptor(npeDescriptor)).stream()
+ List<RetraceThrownExceptionElement> npeRetraced =
+ retracer
+ .retraceThrownException(
+ Reference.classFromDescriptor(npeDescriptor), RetraceStackTraceContext.empty())
+ .stream()
.collect(Collectors.toList());
assertEquals(1, npeRetraced.size());
- RetraceStackTraceContext context = npeRetraced.get(0).getContextWhereClassWasThrown();
+ RetraceStackTraceContext throwingContext = npeRetraced.get(0).getContext();
List<RetraceFrameElement> retraceFrameElements =
retracer.retraceClass(Reference.classFromTypeName("a")).stream()
- .flatMap(element -> element.lookupFrame(Optional.of(4), "a").stream())
+ .flatMap(
+ element -> element.lookupFrame(throwingContext, OptionalInt.of(4), "a").stream())
.collect(Collectors.toList());
assertEquals(1, retraceFrameElements.size());
RetraceFrameElement retraceFrameElement = retraceFrameElements.get(0);
// Check that rewriting the frames will remove the top 1 frames if the condition is active.
Map<Integer, RetracedMethodReference> results = new LinkedHashMap<>();
- retraceFrameElement.visitRewrittenFrames(
- context,
- (methodReference, index) -> {
- RetracedMethodReference existingValue = results.put(index, methodReference);
- assertNull(existingValue);
- });
+ retraceFrameElement
+ .streamRewritten(throwingContext)
+ .forEach(
+ frame -> {
+ RetracedMethodReference existingValue =
+ results.put(frame.getIndex(), frame.getMethodReference());
+ assertNull(existingValue);
+ });
assertEquals(1, results.size());
assertEquals(7, results.get(0).getOriginalPositionOrDefault(4));
assertEquals(results.get(0).getMethodName(), "caller");
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiSynthesizedFrameTest.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiSynthesizedFrameTest.java
index 376a274..b4c2595 100644
--- a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiSynthesizedFrameTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiSynthesizedFrameTest.java
@@ -13,10 +13,10 @@
import com.android.tools.r8.retrace.RetraceFrameElement;
import com.android.tools.r8.retrace.RetraceStackTraceContext;
import com.android.tools.r8.retrace.RetracedMethodReference;
+import com.android.tools.r8.retrace.RetracedSingleFrame;
import com.android.tools.r8.retrace.Retracer;
-import java.util.ArrayList;
import java.util.List;
-import java.util.Optional;
+import java.util.OptionalInt;
import java.util.stream.Collectors;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -50,17 +50,24 @@
ProguardMapProducer.fromString(mapping), new DiagnosticsHandler() {})
.retraceClass(Reference.classFromTypeName("a"))
.stream()
- .flatMap(element -> element.lookupFrame(Optional.of(3), "a").stream())
+ .flatMap(
+ element ->
+ element
+ .lookupFrame(RetraceStackTraceContext.empty(), OptionalInt.of(3), "a")
+ .stream())
.collect(Collectors.toList());
assertEquals(1, frameResults.size());
RetraceFrameElement retraceFrameElement = frameResults.get(0);
- List<RetracedMethodReference> allFrames = new ArrayList<>();
- retraceFrameElement.visitAllFrames((method, ignored) -> allFrames.add(method));
+ List<RetracedMethodReference> allFrames =
+ retraceFrameElement.stream()
+ .map(RetracedSingleFrame::getMethodReference)
+ .collect(Collectors.toList());
assertEquals(2, allFrames.size());
- List<RetracedMethodReference> nonSyntheticFrames = new ArrayList<>();
- retraceFrameElement.visitRewrittenFrames(
- RetraceStackTraceContext.getInitialContext(),
- (method, ignored) -> nonSyntheticFrames.add(method));
+ List<RetracedMethodReference> nonSyntheticFrames =
+ retraceFrameElement
+ .streamRewritten(RetraceStackTraceContext.empty())
+ .map(RetracedSingleFrame::getMethodReference)
+ .collect(Collectors.toList());
assertEquals(1, nonSyntheticFrames.size());
assertEquals(nonSyntheticFrames.get(0), allFrames.get(0));
assertEquals("mango", allFrames.get(1).getMethodName());
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiSynthesizedInnerFrameTest.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiSynthesizedInnerFrameTest.java
index c7b8d7a..1b10739 100644
--- a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiSynthesizedInnerFrameTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiSynthesizedInnerFrameTest.java
@@ -13,10 +13,10 @@
import com.android.tools.r8.retrace.RetraceFrameElement;
import com.android.tools.r8.retrace.RetraceStackTraceContext;
import com.android.tools.r8.retrace.RetracedMethodReference;
+import com.android.tools.r8.retrace.RetracedSingleFrame;
import com.android.tools.r8.retrace.Retracer;
-import java.util.ArrayList;
import java.util.List;
-import java.util.Optional;
+import java.util.OptionalInt;
import java.util.stream.Collectors;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -50,17 +50,24 @@
ProguardMapProducer.fromString(mapping), new DiagnosticsHandler() {})
.retraceClass(Reference.classFromTypeName("a"))
.stream()
- .flatMap(element -> element.lookupFrame(Optional.of(3), "a").stream())
+ .flatMap(
+ element ->
+ element
+ .lookupFrame(RetraceStackTraceContext.empty(), OptionalInt.of(3), "a")
+ .stream())
.collect(Collectors.toList());
assertEquals(1, frameResults.size());
RetraceFrameElement retraceFrameElement = frameResults.get(0);
- List<RetracedMethodReference> allFrames = new ArrayList<>();
- retraceFrameElement.visitAllFrames((method, ignored) -> allFrames.add(method));
+ List<RetracedMethodReference> allFrames =
+ retraceFrameElement.stream()
+ .map(RetracedSingleFrame::getMethodReference)
+ .collect(Collectors.toList());
assertEquals(2, allFrames.size());
- List<RetracedMethodReference> nonSyntheticFrames = new ArrayList<>();
- retraceFrameElement.visitRewrittenFrames(
- RetraceStackTraceContext.getInitialContext(),
- (method, ignored) -> nonSyntheticFrames.add(method));
+ List<RetracedMethodReference> nonSyntheticFrames =
+ retraceFrameElement
+ .streamRewritten(RetraceStackTraceContext.empty())
+ .map(RetracedSingleFrame::getMethodReference)
+ .collect(Collectors.toList());
assertEquals(allFrames, nonSyntheticFrames);
}
}
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestHelper.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestHelper.java
index 98ccb02..3bbb842 100644
--- a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestHelper.java
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestHelper.java
@@ -47,7 +47,7 @@
RetraceApiUnknownJsonTest.ApiTest.class,
RetraceApiRewriteFrameInlineNpeTest.ApiTest.class);
public static List<Class<? extends RetraceApiBinaryTest>> CLASSES_PENDING_BINARY_COMPATIBILITY =
- ImmutableList.of();
+ ImmutableList.of(RetraceApiRewriteFrameInlineNpeResidualTest.ApiTest.class);
public static void runJunitOnTests(
CfRuntime runtime,
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/DifferentLineNumberSpanStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/DifferentLineNumberSpanStackTrace.java
new file mode 100644
index 0000000..16a2725
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/DifferentLineNumberSpanStackTrace.java
@@ -0,0 +1,48 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.retrace.stacktraces;
+
+import com.android.tools.r8.utils.StringUtils;
+import java.util.Arrays;
+import java.util.List;
+
+public class DifferentLineNumberSpanStackTrace implements StackTraceForTest {
+
+ @Override
+ public List<String> obfuscatedStackTrace() {
+ return Arrays.asList(
+ "Exception in thread \"main\" java.lang.NullPointerException",
+ "\tat a.a(Unknown Source:1)");
+ }
+
+ @Override
+ public String mapping() {
+ return StringUtils.lines(
+ "com.android.tools.r8.naming.retrace.Main -> a:",
+ " 1:1:void method1(java.lang.String):42:44 -> a");
+ }
+
+ @Override
+ public List<String> retracedStackTrace() {
+ return Arrays.asList(
+ "Exception in thread \"main\" java.lang.NullPointerException",
+ // TODO(b/201042571): Should be ambiguous or have line number removed
+ "\tat com.android.tools.r8.naming.retrace.Main.method1(Main.java:42)");
+ }
+
+ @Override
+ public List<String> retraceVerboseStackTrace() {
+ return Arrays.asList(
+ "Exception in thread \"main\" java.lang.NullPointerException",
+ "\tat com.android.tools.r8.naming.retrace.Main.void"
+ // TODO(b/201042571): Should be ambiguous or have line number removed
+ + " method1(java.lang.String)(Main.java:42)");
+ }
+
+ @Override
+ public int expectedWarnings() {
+ return 0;
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/MultipleOriginalLinesNoLineNumberStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/MultipleOriginalLinesNoLineNumberStackTrace.java
new file mode 100644
index 0000000..d4688c9
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/MultipleOriginalLinesNoLineNumberStackTrace.java
@@ -0,0 +1,47 @@
+// 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.retrace.stacktraces;
+
+import com.android.tools.r8.utils.StringUtils;
+import java.util.Arrays;
+import java.util.List;
+
+public class MultipleOriginalLinesNoLineNumberStackTrace implements StackTraceForTest {
+
+ @Override
+ public List<String> obfuscatedStackTrace() {
+ return Arrays.asList(
+ "Exception in thread \"main\" java.lang.NullPointerException", "\tat a.a(Unknown Source)");
+ }
+
+ @Override
+ public String mapping() {
+ return StringUtils.lines(
+ "com.android.tools.r8.naming.retrace.Main -> a:",
+ " void method1(java.lang.String):42:43 -> a");
+ }
+
+ @Override
+ public List<String> retracedStackTrace() {
+ return Arrays.asList(
+ "Exception in thread \"main\" java.lang.NullPointerException",
+ // TODO(b/201042571): Should not report a line number
+ "\tat com.android.tools.r8.naming.retrace.Main.method1(Main.java:42)");
+ }
+
+ @Override
+ public List<String> retraceVerboseStackTrace() {
+ return Arrays.asList(
+ "Exception in thread \"main\" java.lang.NullPointerException",
+ "\tat com.android.tools.r8.naming.retrace.Main.void"
+ // TODO(b/201042571): Should not report a line number
+ + " method1(java.lang.String)(Main.java:42)");
+ }
+
+ @Override
+ public int expectedWarnings() {
+ return 0;
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/rewrite/enums/EnumOptimizationTest.java b/src/test/java/com/android/tools/r8/rewrite/enums/EnumOptimizationTest.java
index 76e8f34..b666291 100644
--- a/src/test/java/com/android/tools/r8/rewrite/enums/EnumOptimizationTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/enums/EnumOptimizationTest.java
@@ -60,6 +60,7 @@
.addKeepMainRule(Ordinals.class)
.enableConstantArgumentAnnotations()
.enableInliningAnnotations()
+ .enableMemberValuePropagationAnnotations()
.enableSideEffectAnnotations()
.addOptionsModification(this::configure)
.setMinApi(parameters.getApiLevel())
@@ -111,6 +112,7 @@
.addKeepMainRule(Names.class)
.enableConstantArgumentAnnotations()
.enableInliningAnnotations()
+ .enableMemberValuePropagationAnnotations()
.enableSideEffectAnnotations()
.addOptionsModification(this::configure)
.setMinApi(parameters.getApiLevel())
@@ -159,6 +161,7 @@
.addKeepMainRule(ToStrings.class)
.enableConstantArgumentAnnotations()
.enableInliningAnnotations()
+ .enableMemberValuePropagationAnnotations()
.enableSideEffectAnnotations()
.addOptionsModification(this::configure)
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/rewrite/enums/Names.java b/src/test/java/com/android/tools/r8/rewrite/enums/Names.java
index 10a70c4a..7eeae7c 100644
--- a/src/test/java/com/android/tools/r8/rewrite/enums/Names.java
+++ b/src/test/java/com/android/tools/r8/rewrite/enums/Names.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.AssumeMayHaveSideEffects;
import com.android.tools.r8.KeepConstantArguments;
import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NeverPropagateValue;
import java.util.concurrent.TimeUnit;
class Names {
@@ -23,12 +24,14 @@
@AssumeMayHaveSideEffects
@NeverInline
+ @NeverPropagateValue
private static String simple() {
return Number.TWO.name();
}
@AssumeMayHaveSideEffects
@NeverInline
+ @NeverPropagateValue
private static String local() {
Number two = Number.TWO;
return two.name();
@@ -36,6 +39,7 @@
@AssumeMayHaveSideEffects
@NeverInline
+ @NeverPropagateValue
private static String multipleUsages() {
Number two = Number.TWO;
return two.ordinal() + two.name();
@@ -43,6 +47,7 @@
@AssumeMayHaveSideEffects
@NeverInline
+ @NeverPropagateValue
private static String inlined() {
return inlined2(Number.TWO);
}
@@ -58,12 +63,14 @@
@AssumeMayHaveSideEffects
@NeverInline
+ @NeverPropagateValue
private static String differentTypeStaticField() {
return Number.DOWN.name();
}
@AssumeMayHaveSideEffects
@NeverInline
+ @NeverPropagateValue
private static String nonValueStaticField() {
return Number.DEFAULT.name();
}
@@ -80,6 +87,7 @@
@AssumeMayHaveSideEffects
@NeverInline
+ @NeverPropagateValue
private static String nonStaticGet() {
return new Names().two.name();
}
diff --git a/src/test/java/com/android/tools/r8/rewrite/enums/Ordinals.java b/src/test/java/com/android/tools/r8/rewrite/enums/Ordinals.java
index de4677d..79aaeaa 100644
--- a/src/test/java/com/android/tools/r8/rewrite/enums/Ordinals.java
+++ b/src/test/java/com/android/tools/r8/rewrite/enums/Ordinals.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.AssumeMayHaveSideEffects;
import com.android.tools.r8.KeepConstantArguments;
import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NeverPropagateValue;
import java.util.concurrent.TimeUnit;
class Ordinals {
@@ -34,6 +35,7 @@
@AssumeMayHaveSideEffects
@NeverInline
+ @NeverPropagateValue
private static String multipleUsages() {
Number two = Number.TWO;
return two.name() + two.ordinal();
@@ -50,6 +52,7 @@
@AssumeMayHaveSideEffects
@NeverInline
+ @NeverPropagateValue
private static int inSwitch() {
// Unlike normal invocations of Enum.ordinal(), a switch on enum will emit an invoke-virtual
// where the receiver is the enum subtype and not java.lang.Enum. This test ensures that case
diff --git a/src/test/java/com/android/tools/r8/rewrite/enums/ToStrings.java b/src/test/java/com/android/tools/r8/rewrite/enums/ToStrings.java
index 957a5e1..c518868 100644
--- a/src/test/java/com/android/tools/r8/rewrite/enums/ToStrings.java
+++ b/src/test/java/com/android/tools/r8/rewrite/enums/ToStrings.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.AssumeMayHaveSideEffects;
import com.android.tools.r8.KeepConstantArguments;
import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NeverPropagateValue;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
@@ -48,6 +49,7 @@
@AssumeMayHaveSideEffects
@NeverInline
+ @NeverPropagateValue
private static String valueWithToString() {
return ValueToString.ONE.toString();
}
@@ -59,18 +61,21 @@
@AssumeMayHaveSideEffects
@NeverInline
+ @NeverPropagateValue
private static String noToString() {
return NoToString.TWO.toString();
}
@AssumeMayHaveSideEffects
@NeverInline
+ @NeverPropagateValue
private static String local() {
NoToString two = NoToString.TWO;
return two.toString();
}
@NeverInline
+ @NeverPropagateValue
private static String multipleUsages() {
NoToString two = NoToString.TWO;
// Side-effect instead of concatenation avoids two toString calls.
@@ -80,6 +85,7 @@
@AssumeMayHaveSideEffects
@NeverInline
+ @NeverPropagateValue
private static String inlined() {
return inlined2(NoToString.TWO);
}
@@ -95,12 +101,14 @@
@AssumeMayHaveSideEffects
@NeverInline
+ @NeverPropagateValue
private static String differentTypeStaticField() {
return NoToString.DOWN.toString();
}
@AssumeMayHaveSideEffects
@NeverInline
+ @NeverPropagateValue
private static String nonValueStaticField() {
return NoToString.DEFAULT.toString();
}
@@ -117,6 +125,7 @@
@AssumeMayHaveSideEffects
@NeverInline
+ @NeverPropagateValue
private static String nonStaticGet() {
return new ToStrings().two.toString();
}
diff --git a/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java b/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
index bc72103..a38f6f2 100644
--- a/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
+++ b/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
@@ -619,6 +619,40 @@
});
}
+ public ClassFileTransformer setFieldType(FieldPredicate predicate, String newFieldType) {
+ return addClassTransformer(
+ new ClassTransformer() {
+ @Override
+ public FieldVisitor visitField(
+ int access, String name, String descriptor, String signature, Object value) {
+ if (predicate.test(access, name, descriptor, signature, value)) {
+ String newDescriptor = DescriptorUtils.javaTypeToDescriptor(newFieldType);
+ return super.visitField(access, name, newDescriptor, signature, value);
+ }
+ return super.visitField(access, name, descriptor, signature, value);
+ }
+ });
+ }
+
+ public ClassFileTransformer setReturnType(MethodPredicate predicate, String newReturnType) {
+ return addClassTransformer(
+ new ClassTransformer() {
+ @Override
+ public MethodVisitor visitMethod(
+ int access, String name, String descriptor, String signature, String[] exceptions) {
+ if (predicate.test(access, name, descriptor, signature, exceptions)) {
+ String oldDescriptorExcludingReturnType =
+ descriptor.substring(0, descriptor.lastIndexOf(')') + 1);
+ String newDescriptor =
+ oldDescriptorExcludingReturnType
+ + DescriptorUtils.javaTypeToDescriptor(newReturnType);
+ return super.visitMethod(access, name, newDescriptor, signature, exceptions);
+ }
+ return super.visitMethod(access, name, descriptor, signature, exceptions);
+ }
+ });
+ }
+
public ClassFileTransformer setGenericSignature(MethodPredicate predicate, String newSignature) {
return addClassTransformer(
new ClassTransformer() {
@@ -721,6 +755,13 @@
MethodVisitor visitor);
}
+ /** Abstraction of the MethodVisitor.visitFieldInsn method with its sub visitor. */
+ @FunctionalInterface
+ public interface FieldInsnTransform {
+ void visitFieldInsn(
+ int opcode, String owner, String name, String descriptor, MethodVisitor visitor);
+ }
+
/** Abstraction of the MethodVisitor.visitMethodInsn method with its sub visitor. */
@FunctionalInterface
public interface MethodInsnTransform {
@@ -945,6 +986,41 @@
}
@FunctionalInterface
+ private interface VisitFieldInsnCallback {
+ void visitFieldInsn(int opcode, String owner, String name, String descriptor);
+ }
+
+ private MethodVisitor redirectVisitFieldInsn(
+ MethodVisitor visitor, VisitFieldInsnCallback callback) {
+ return new MethodVisitor(ASM7, visitor) {
+ @Override
+ public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {
+ callback.visitFieldInsn(opcode, owner, name, descriptor);
+ }
+ };
+ }
+
+ public ClassFileTransformer transformFieldInsnInMethod(
+ String methodName, FieldInsnTransform transform) {
+ return addMethodTransformer(
+ new MethodTransformer() {
+ @Override
+ public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {
+ if (getContext().method.getMethodName().equals(methodName)) {
+ transform.visitFieldInsn(
+ opcode,
+ owner,
+ name,
+ descriptor,
+ redirectVisitFieldInsn(this, super::visitFieldInsn));
+ } else {
+ super.visitMethodInsn(opcode, owner, name, descriptor);
+ }
+ }
+ });
+ }
+
+ @FunctionalInterface
private interface VisitMethodInsnCallback {
void visitMethodInsn(
int opcode, String owner, String name, String descriptor, boolean isInterface);
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/InstructionSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/InstructionSubject.java
index 36d9ed5..4e2b27d 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/InstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/InstructionSubject.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.retrace.RetraceFrameResult;
import com.android.tools.r8.retrace.RetraceMethodResult;
+import com.android.tools.r8.retrace.RetraceStackTraceContext;
import com.android.tools.r8.retrace.Retracer;
public interface InstructionSubject {
@@ -162,10 +163,11 @@
}
default RetraceFrameResult retraceLinePosition(Retracer retracer) {
- return retrace(retracer).narrowByPosition(getLineNumber());
+ return retrace(retracer).narrowByPosition(RetraceStackTraceContext.empty(), getLineNumber());
}
default RetraceFrameResult retracePcPosition(Retracer retracer, MethodSubject methodSubject) {
- return retrace(retracer).narrowByPosition(getOffset(methodSubject).offset);
+ return retrace(retracer)
+ .narrowByPosition(RetraceStackTraceContext.empty(), getOffset(methodSubject).offset);
}
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/Matchers.java b/src/test/java/com/android/tools/r8/utils/codeinspector/Matchers.java
index edeed5a..8b54ae2 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/Matchers.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/Matchers.java
@@ -21,6 +21,7 @@
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.retrace.RetraceFrameElement;
import com.android.tools.r8.retrace.RetraceFrameResult;
+import com.android.tools.r8.retrace.RetracedMethodReference;
import com.android.tools.r8.utils.Box;
import com.android.tools.r8.utils.Visibility;
import com.google.common.collect.ImmutableList;
@@ -588,27 +589,29 @@
RetraceFrameElement single = item.stream().collect(Collectors.toSingle());
Box<LinePosition> currentPosition = new Box<>(startPosition);
Box<Boolean> returnValue = new Box<>();
- single.visitAllFrames(
- (method, __) -> {
- LinePosition currentInline = currentPosition.get();
- if (currentInline == null) {
- returnValue.set(false);
- return;
- }
- if (method.isUnknown()) {
- returnValue.set(false);
- return;
- }
- boolean sameMethod =
- method.asKnown().getMethodReference().equals(currentInline.methodReference);
- boolean samePosition =
- method.getOriginalPositionOrDefault(currentInline.minifiedPosition)
- == currentInline.originalPosition;
- if (!returnValue.isSet() || returnValue.get()) {
- returnValue.set(sameMethod & samePosition);
- }
- currentPosition.set(currentInline.caller);
- });
+ single.stream()
+ .forEach(
+ frame -> {
+ LinePosition currentInline = currentPosition.get();
+ if (currentInline == null) {
+ returnValue.set(false);
+ return;
+ }
+ RetracedMethodReference method = frame.getMethodReference();
+ if (method.isUnknown()) {
+ returnValue.set(false);
+ return;
+ }
+ boolean sameMethod =
+ method.asKnown().getMethodReference().equals(currentInline.methodReference);
+ boolean samePosition =
+ method.getOriginalPositionOrDefault(currentInline.minifiedPosition)
+ == currentInline.originalPosition;
+ if (!returnValue.isSet() || returnValue.get()) {
+ returnValue.set(sameMethod & samePosition);
+ }
+ currentPosition.set(currentInline.caller);
+ });
return returnValue.isSet() && returnValue.get();
}
@@ -625,18 +628,17 @@
@Override
protected boolean matchesSafely(RetraceFrameResult item) {
RetraceFrameElement single = item.stream().collect(Collectors.toSingle());
- Box<Boolean> matches = new Box<>(true);
- single.visitAllFrames(
- (method, index) -> {
- StackTraceLine stackTraceLine = stackTrace.get(index);
- if (!stackTraceLine.methodName.equals(method.getMethodName())
- || !stackTraceLine.className.equals(method.getHolderClass().getTypeName())
- || stackTraceLine.lineNumber
- != method.getOriginalPositionOrDefault(minifiedPositions.get(index))) {
- matches.set(false);
- }
- });
- return matches.get();
+ return !single.stream()
+ .anyMatch(
+ frame -> {
+ StackTraceLine stackTraceLine = stackTrace.get(frame.getIndex());
+ RetracedMethodReference method = frame.getMethodReference();
+ return !stackTraceLine.methodName.equals(method.getMethodName())
+ || !stackTraceLine.className.equals(method.getHolderClass().getTypeName())
+ || stackTraceLine.lineNumber
+ != method.getOriginalPositionOrDefault(
+ minifiedPositions.get(frame.getIndex()));
+ });
}
@Override
diff --git a/third_party/retrace/binary_compatibility.tar.gz.sha1 b/third_party/retrace/binary_compatibility.tar.gz.sha1
index 7fbd228..6b09100 100644
--- a/third_party/retrace/binary_compatibility.tar.gz.sha1
+++ b/third_party/retrace/binary_compatibility.tar.gz.sha1
@@ -1 +1 @@
-6b7ccd6aa40c22bea72017bfabca022d4d90d70a
\ No newline at end of file
+e7ea0fbb97ccfb2faa89b58d60f8b54f5bca0130
\ No newline at end of file
diff --git a/tools/compiledump.py b/tools/compiledump.py
index e8070da..504496e 100755
--- a/tools/compiledump.py
+++ b/tools/compiledump.py
@@ -209,12 +209,21 @@
return dump.version()
return args.version
-def determine_compiler(args, dump):
+def determine_compiler(args, build_properties):
compilers = ['d8', 'r8', 'r8full', 'l8']
- if args.compiler not in compilers:
+ compiler = args.compiler
+ if not compiler and 'tool' in build_properties:
+ compiler = build_properties.get('tool').lower()
+ if (compiler == 'r8'):
+ if not 'force-proguard-compatibility' in build_properties:
+ error("Unable to determine R8 compiler variant from build.properties."
+ " No value for 'force-proguard-compatibility'.")
+ if build_properties.get('force-proguard-compatibility').lower() == 'false':
+ compiler = compiler + 'full'
+ if compiler not in compilers:
error("Unable to determine a compiler to use. Specified %s,"
" Valid options: %s" % (args.compiler, ', '.join(compilers)))
- return args.compiler
+ return compiler
def determine_output(args, temp):
return os.path.join(temp, 'out.jar')
@@ -295,7 +304,7 @@
print("WARNING: Unexpected lack of library classes in dump")
build_properties = determine_build_properties(args, dump)
version = determine_version(args, dump)
- compiler = determine_compiler(args, dump)
+ compiler = determine_compiler(args, build_properties)
out = determine_output(args, temp)
min_api = determine_min_api(args, build_properties)
classfile = determine_class_file(args, build_properties)
diff --git a/tools/r8_release.py b/tools/r8_release.py
index 0446d64..f9d14f9 100755
--- a/tools/r8_release.py
+++ b/tools/r8_release.py
@@ -602,7 +602,7 @@
redir_command = ("/google/data/ro/teams/android-devtools-infra/tools/redir "
+ "--alsologtostderr "
- + "--gcs_bucket_path=/studio_staging/maven2/${USER}/%s "
+ + "--gcs_bucket_path=/bigstore/gmaven-staging/${USER}/%s "
+ "--port=1480") % release_id
get_command = ("mvn org.apache.maven.plugins:maven-dependency-plugin:2.4:get "
@@ -620,6 +620,10 @@
repositories {
maven {
url 'http://localhost:1480'
+ allowInsecureProtocol true
+ }
+ dependencies {
+ classpath '%s' // Must be before the Gradle Plugin for Android.
}
}
@@ -627,7 +631,7 @@
rm -rf /tmp/maven_repo_local
%s
-""" % (redir_command, get_command))
+""" % (redir_command, artifact, get_command))
def gmaven_publisher_publish(args, release_id):
diff --git a/tools/retrace.py b/tools/retrace.py
index d28c222..94ec1b3 100755
--- a/tools/retrace.py
+++ b/tools/retrace.py
@@ -55,6 +55,11 @@
default=None,
help='Sets a custom regular expression used for parsing'
)
+ parser.add_argument(
+ '--verbose',
+ default=None,
+ action='store_true',
+ help='Enables verbose retracing.')
return parser.parse_args()
@@ -68,9 +73,10 @@
args.no_r8lib,
quiet=args.quiet,
debug=args.debug_agent,
- regex=args.regex)
+ regex=args.regex,
+ verbose=args.verbose)
-def run(map_path, stacktrace, no_r8lib, quiet=False, debug=False, regex=None):
+def run(map_path, stacktrace, no_r8lib, quiet=False, debug=False, regex=None, verbose=False):
retrace_args = [jdk.GetJavaExecutable()]
if debug:
@@ -94,6 +100,9 @@
if stacktrace:
retrace_args.append(stacktrace)
+ if verbose:
+ retrace_args.append('--verbose')
+
utils.PrintCmd(retrace_args, quiet=quiet)
return subprocess.call(retrace_args)
diff --git a/tools/test.py b/tools/test.py
index c719ea2..6f27a56 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -39,7 +39,7 @@
# Should be short enough that we ensure that two calls are close enough
# to happen before bot times out.
# A false positiv, i.e., printing the stacks of non hanging processes
-# is not a problem, no harm done except some logging in the stdout.
+# is not a problem, no harm done except some logging in stdout.
TIMEOUT_HANDLER_PERIOD = 60 * 18
BUCKET = 'r8-test-results'