Merge commit 'cabf75990652cb25d391888b898667da0ba90fd4' into dev-release
diff --git a/.gitignore b/.gitignore
index b6fb8c3..45852a0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -100,8 +100,6 @@
third_party/jacoco/0.8.6.tar.gz
third_party/jasmin
third_party/jasmin.tar.gz
-third_party/jctf
-third_party/jctf.tar.gz
third_party/jdwp-tests
third_party/jdwp-tests.tar.gz
third_party/jsr223-api-1.0
diff --git a/build.gradle b/build.gradle
index e2ca554..67074c7 100644
--- a/build.gradle
+++ b/build.gradle
@@ -48,8 +48,6 @@
testngVersion = '6.10'
}
-apply from: 'copyAdditionalJctfCommonFiles.gradle'
-
repositories {
maven {
url 'https://storage.googleapis.com/r8-deps/maven_mirror/'
@@ -176,29 +174,6 @@
compileClasspath += fileTree(dir: "build/generated/test/proto", include: "*.jar")
output.resourcesDir = 'build/classes/examplesProto'
}
- jctfCommon {
- java {
- srcDirs = [
- 'third_party/jctf/Harness/src',
- 'third_party/jctf/LibTests/src/com/google/jctf/test/categories',
- 'third_party/jctf/LibTests/src/com/google/jctf/test/helper',
- 'third_party/jctf/LibTests/src/com/google/jctf/testHelpers',
- 'third_party/jctf/LibTests/src/org',
- 'build/additionalJctfCommonFiles'
- ]
- }
- resources {
- srcDirs = ['third_party/jctf/LibTests/resources']
- }
- }
- jctfTests {
- java {
- srcDirs = [
- 'third_party/jctf/LibTests/src/com/google/jctf/test/lib',
- // 'third_party/jctf/VMTests/src',
- ]
- }
- }
kotlinR8TestResources {
java {
srcDirs = ['src/test/kotlinR8TestResources']
@@ -286,9 +261,6 @@
testCompile group: 'org.ow2.asm', name: 'asm-util', version: asmVersion
testCompile group: 'it.unimi.dsi', name: 'fastutil', version: fastutilVersion
- jctfCommonCompile "junit:junit:$junitVersion"
- jctfTestsCompile "junit:junit:$junitVersion"
- jctfTestsCompile sourceSets.jctfCommon.output
examplesAndroidOCompile group: 'org.ow2.asm', name: 'asm', version: asmVersion
examplesAndroidPCompile group: 'org.ow2.asm', name: 'asm', version: asmVersion
// Import Guava for @Nullable annotation
@@ -352,7 +324,6 @@
"jacoco/0.8.2",
"jacoco/0.8.6",
"jasmin",
- "jctf",
"junit",
"jdwp-tests",
"jsr223-api-1.0",
@@ -379,6 +350,7 @@
"proguard/proguard5.2.1",
"proguard/proguard6.0.1",
"proguard/proguard-7.0.0",
+ "retrace_benchmark",
"retrace/binary_compatibility",
"r8",
"r8-releases/2.0.74",
@@ -709,16 +681,6 @@
}
}
-compileJctfCommonJava {
- dependsOn 'copyAdditionalJctfCommonFiles'
- options.compilerArgs = ['-Xlint:none']
-}
-
-compileJctfTestsJava {
- dependsOn 'jctfCommonClasses'
- options.compilerArgs = ['-Xlint:none']
-}
-
task consolidatedLicense {
def license = new File(new File(buildDir, 'generatedLicense'), 'LICENSE')
@@ -1064,16 +1026,6 @@
])
}
-task buildDesugaredLibrary(type: Exec) {
- def outputDir = "build/libs"
- def script = "tools/create_jctf_tests.py"
- inputs.file script
- outputs.dir outputDir
- dependsOn downloadDeps
- commandLine "python3", script
- workingDir = projectDir
-}
-
task generateR8LibKeepRules(type: Exec) {
// Depend on r8WithRelocatedDeps to ensure that we do not have external
// dependencies crossing the boundary.
@@ -1173,11 +1125,6 @@
from sourceSets.main.allSource
}
-task jctfCommonJar(type: Jar) {
- from sourceSets.jctfCommon.output
- archiveFileName = 'jctfCommon.jar'
-}
-
artifacts {
archives sourceJar
}
@@ -1192,19 +1139,8 @@
workingDir = projectDir
}
-task createJctfTests(type: Exec) {
- def outputDir = "build/generated/test/java/com/android/tools/r8/jctf"
- def script = "tools/create_jctf_tests.py"
- inputs.file script
- outputs.dir outputDir
- dependsOn downloadDeps
- commandLine "python3", script
- workingDir = projectDir
-}
-
compileTestJava {
dependsOn createArtTests
- dependsOn createJctfTests
}
task buildCfSegments(type: Jar, dependsOn: downloadDeps) {
@@ -2315,29 +2251,14 @@
include "com/android/tools/r8/" + project.getProperty('test_namespace') + "/**"
}
- if (project.hasProperty('tool')) {
- if (project.property('tool') == 'r8') {
- exclude "com/android/tools/r8/jctf/**"
- } else if (project.property('tool') == 'd8') {
- if (project.hasProperty('only_jctf')) {
- include "com/android/tools/r8/jctf/d8/**"
- } else {
- // Don't run anything, deprecated
- println "Running with deprecated tool d8, not running any tests"
- include ""
- }
- } else {
- assert(project.property('tool') == 'r8cf')
- assert(project.hasProperty('only_jctf'))
- include "com/android/tools/r8/jctf/r8cf/**"
- }
+ if (project.hasProperty('tool') && project.property('tool') == 'd8') {
+ // Don't run anything, deprecated
+ println "Running with deprecated tool d8, not running any tests"
+ include ""
}
if (!project.hasProperty('all_tests')) {
exclude "com/android/tools/r8/art/dx/**"
}
- if (!project.hasProperty('jctf') && !project.hasProperty('only_jctf')) {
- exclude "com/android/tools/r8/jctf/**"
- }
if (project.hasProperty('shard_count') ) {
assert project.hasProperty('shard_number')
int shard_count = project.getProperty('shard_count') as Integer
@@ -2355,10 +2276,6 @@
return hash % shard_count != shard_number
}
}
- if (project.hasProperty('jctf_compile_only')) {
- println "JCTF: compiling only"
- systemProperty 'jctf_compile_only', '1'
- }
if (project.hasProperty('test_dir')) {
systemProperty 'test_dir', project.property('test_dir')
}
@@ -2388,8 +2305,6 @@
dependsOn buildExamples
dependsOn buildKotlinR8TestResources
dependsOn buildSmali
- dependsOn jctfCommonJar
- dependsOn jctfTestsClasses
dependsOn buildPreNJdwpTestsJar
dependsOn buildPreNJdwpTestsDex
dependsOn compileTestNGRunner
diff --git a/copyAdditionalJctfCommonFiles.gradle b/copyAdditionalJctfCommonFiles.gradle
deleted file mode 100644
index 9cf6dfe..0000000
--- a/copyAdditionalJctfCommonFiles.gradle
+++ /dev/null
@@ -1,220 +0,0 @@
-// Copyright (c) 2017, 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.
-
-
-// The `copyAdditionalJctfCommonFiles` task copies files common to all JCTF test
-// cases into an intermediate directory which is then passed to gradle as a
-// source set.
-//
-// Details:
-//
-// The JCTF source tree consists of individual test cases and other sources
-// common to all test cases. The latter is compiled into a single jar file.
-//
-// The problem is the many common source files are scattered under the same
-// directory where the test cases are and gradle has no simple way to add
-// individual files to a source set.
-//
-// That's why we first copy over the common files into an intermediate directory
-// then pass gradle the source set as a single directory.
-
-task copyAdditionalJctfCommonFiles(type: Copy) {
- def prefix = 'LibTests/src/com/google/jctf/test/lib/java'
- def inputDir = 'third_party/jctf'
- def outputDir = 'build/additionalJctfCommonFiles'
- doFirst {
- delete outputDir
- }
-
- // All the files containing "@Test" and also the files located in a directory where there is "@Test"
- // file will be compiled into individual, per-test dex files.
- // Here we need the files not containing "@Test" which are not siblings of "@Test" files. We compile
- // them into a common jar file which will be added into each test's dex file.
- //
- // The following list is compiled with this script:
- //
- // # create list of directories that contain non-"@Test" files but do not contain "@Test" files
- // dirlist=$(comm -23 \
- // <(grep -rL "@Test" "third_party/jctf/LibTests/src/com/google/jctf/test/lib" --include=*.java | sed 's;/[^/]*\.java$;;' | sort | uniq) \
- // <(grep -rl "@Test" "third_party/jctf/LibTests/src/com/google/jctf/test/lib" --include=*.java | sed 's;/[^/]*\.java$;;' | sort | uniq))
- //
- // # all the java files from these dirs
- // (for d in $dirlist; do ls -1 $d/*.java; done) \
- // | sort | sed 's,.*test/lib/java/,,' | sed -E "s/(.*)/'\1',/"
- def files = [
- 'lang/annotation/Annotation/AllTypesAntn2.java',
- 'lang/annotation/Annotation/AllTypesAntn.java',
- 'lang/Character/CharacterData.java',
- 'lang/Character/CharacterUtils.java',
- 'lang/Character/Subset/TestSubset.java',
- 'lang/Class/ClassAnnotationsData.java',
- 'lang/ClassLoader/EmptyCertificate.java',
- 'lang/ClassLoader/EmptyClassLoader.java',
- 'lang/ClassLoader/setPackageAssertionStatusLjava_lang_StringZ/pckg1/pckg11/C01.java',
- 'lang/ClassLoader/setPackageAssertionStatusLjava_lang_StringZ/pckg1/pckg11/pckg111/C01.java',
- 'lang/ClassLoader/setPackageAssertionStatusLjava_lang_StringZ/pckg1/pckg11/pckg111/C02.java',
- 'lang/ClassLoader/setPackageAssertionStatusLjava_lang_StringZ/pckg1/pckg12/C01.java',
- 'lang/Class/PackageAccessible.java',
- 'lang/Class/PackageInstantiable.java',
- 'lang/Enum/EnumMocks.java',
- 'lang/InheritableThreadLocal/TestThread.java',
- 'lang/Number/TestNumber.java',
- 'lang/Package/PackageAnnotationsData.java',
- 'lang/Package/PackageLoader.java',
- 'lang/ProcessBuilder/ProcessBuilderHelper.java',
- 'lang/reflect/AccessibleObject/ChildTestClass.java',
- 'lang/reflect/AccessibleObject/ClassTestAnnotation.java',
- 'lang/reflect/AccessibleObject/DefaultTestAnnotation.java',
- 'lang/reflect/AccessibleObject/Helper.java',
- 'lang/reflect/AccessibleObject/Runtime1TestAnnotation.java',
- 'lang/reflect/AccessibleObject/Runtime2TestAnnotation.java',
- 'lang/reflect/AccessibleObject/Runtime3TestAnnotation.java',
- 'lang/reflect/AccessibleObject/SourceTestAnnotation.java',
- 'lang/reflect/AccessibleObject/TestClass.java',
- 'lang/reflect/Constructor/ConstructorAnnotationsData.java',
- 'lang/reflect/Constructor/ConstructorTestHelper.java',
- 'lang/reflect/Constructor/PrivateClass.java',
- 'lang/reflect/Constructor/PrivateConstructor.java',
- 'lang/reflect/Field/FieldAnnotationsData.java',
- 'lang/reflect/Field/TestExceptionInInitializerError.java',
- 'lang/reflect/Field/TestFinalObjectField.java',
- 'lang/reflect/Field/TestFinalPrimitiveField.java',
- 'lang/reflect/Field/TestObjectField.java',
- 'lang/reflect/Field/TestOtherField.java',
- 'lang/reflect/Field/TestPrimitiveField.java',
- 'lang/reflect/Field/TestStaticFinalObjectField.java',
- 'lang/reflect/Field/TestStaticFinalPrimitiveField.java',
- 'lang/reflect/Field/TestStaticObjectField.java',
- 'lang/reflect/Field/TestStaticPrimitiveField.java',
- 'lang/reflect/Method/AbstractTestMethod.java',
- 'lang/reflect/Method/MethodAnnotationsData.java',
- 'lang/reflect/Method/PrivateClass.java',
- 'lang/reflect/Method/PrivateMethod.java',
- 'lang/reflect/Method/TestMethod.java',
- 'lang/reflect/Method/TestMethodSub.java',
- 'lang/reflect/Proxy/HiddenInterface.java',
- 'lang/reflect/Proxy/NullHandler.java',
- 'lang/ref/MemoryHog.java',
- 'lang/ref/MyReferenceQueue.java',
- 'lang/ref/PhantomReference/MyPhantomReference.java',
- 'lang/ref/SoftReference/MySoftReference.java',
- 'lang/ref/WeakReference/MyWeakReference.java',
- 'lang/Runtime/CountLoads.java',
- 'lang/Runtime/CWD.java',
- 'lang/Runtime/EchoArgs.java',
- 'lang/Runtime/EchoEnv.java',
- 'lang/SecurityManager/CheckingDomain.java',
- 'lang/SecurityManager/SecurityManagerTest.java',
- 'lang/StackTraceElement/ElementData.java',
- 'lang/StackTraceElement/InitTestFixture.java',
- 'lang/StackTraceElement/StaticInitTestFixture.java',
- 'lang/StackTraceElement/TestFixture.java',
- 'lang/StrictMath/FPUtil.java',
- 'lang/StringBuffer/MultiThreadTestHelper.java',
- 'lang/String/String_Character.java',
- 'lang/String/StringHelper.java',
- 'lang/String/String_ISO88591.java',
- 'lang/String/String_UnicodeCodePoint.java',
- 'lang/String/String_USASCII.java',
- 'lang/String/String_UTF16BE.java',
- 'lang/String/String_UTF16.java',
- 'lang/String/String_UTF16LE.java',
- 'lang/String/String_UTF8.java',
- 'lang/System/System_propertyKeys.java',
- 'lang/Thread/CatchThread.java',
- 'lang/Thread/CheckHandler.java',
- 'lang/Thread/CheckRun.java',
- 'lang/ThreadGroup/AccessCheckThread.java',
- 'lang/ThreadGroup/CatchGroup.java',
- 'lang/ThreadGroup/MyThread.java',
- 'lang/ThreadGroup/SMTestCheckAccessThreadGroupThrowSE.java',
- 'lang/ThreadGroup/SMTestCheckAccessThreadGroupWasCalled.java',
- 'lang/ThreadGroup/SMTestCheckAccessThreadThrowSE.java',
- 'lang/ThreadGroup/ThreadGroupHelper.java',
- 'lang/Thread/SlowIncThread.java',
- 'lang/Thread/StepThread.java',
- 'lang/Thread/WaitRun.java',
- 'lang/Throwable/Exception1.java',
- 'lang/Throwable/Exception2.java',
- 'lang/Throwable/Exception3.java',
- 'lang/Throwable/MethodStackFixture.java',
- 'lang/Throwable/MultipleExceptionsFixture.java',
- 'lang/Throwable/MultipleExceptionsStackChecker.java',
- 'util/concurrent/AbstractExecutorService/DirectExecutorService.java',
- 'util/concurrent/AdjustablePolicy.java',
- 'util/concurrent/ArrayBlockingQueue/ArrayBlockingQueueHelper.java',
- 'util/concurrent/CheckedCallable.java',
- 'util/concurrent/CheckedInterruptedCallable.java',
- 'util/concurrent/CheckedInterruptedRunnable.java',
- 'util/concurrent/CheckedRunnable.java',
- 'util/concurrent/ConcurrentHashMap/ConcurrentHashMapHelper.java',
- 'util/concurrent/ConcurrentLinkedQueue/ConcurrentLinkedQueueHelper.java',
- 'util/concurrent/ConcurrentSkipListMap/ConcurrentSkipListMapHelper.java',
- 'util/concurrent/ConcurrentSkipListSet/ConcurrentSkipListSetHelper.java',
- 'util/concurrent/ConcurrentSkipListSet/MyReverseComparator.java',
- 'util/concurrent/CopyOnWriteArrayList/CopyOnWriteArrayListHelper.java',
- 'util/concurrent/CopyOnWriteArraySet/CopyOnWriteArraySetHelper.java',
- 'util/concurrent/CyclicBarrier/MyAction.java',
- 'util/concurrent/DelayQueue/DelayQueueHelper.java',
- 'util/concurrent/DelayQueue/NanoDelay.java',
- 'util/concurrent/DelayQueue/PDelay.java',
- 'util/concurrent/FutureTask/CounterCallable.java',
- 'util/concurrent/FutureTask/PublicFutureTask.java',
- 'util/concurrent/Helper.java',
- 'util/concurrent/InterruptedCallable.java',
- 'util/concurrent/InterruptingCallable.java',
- 'util/concurrent/LinkedBlockingDeque/LinkedBlockingDequeHelper.java',
- 'util/concurrent/LinkedBlockingQueue/LinkedBlockingQueueHelper.java',
- 'util/concurrent/MediumPossiblyInterruptedRunnable.java',
- 'util/concurrent/MediumRunnable.java',
- 'util/concurrent/NoOpCallable.java',
- 'util/concurrent/NoOpREHandler.java',
- 'util/concurrent/NoOpRunnable.java',
- 'util/concurrent/NPETask.java',
- 'util/concurrent/PriorityBlockingQueue/MyReverseComparator.java',
- 'util/concurrent/PriorityBlockingQueue/PriorityBlockingQueueHelper.java',
- 'util/concurrent/RunnableShouldThrow.java',
- 'util/concurrent/ScheduledThreadPoolExecutor/CustomExecutor.java',
- 'util/concurrent/ScheduledThreadPoolExecutor/CustomTask.java',
- 'util/concurrent/ScheduledThreadPoolExecutor/RunnableCounter.java',
- 'util/concurrent/Semaphore/InterruptedLockRunnable.java',
- 'util/concurrent/Semaphore/InterruptibleLockRunnable.java',
- 'util/concurrent/Semaphore/PublicSemaphore.java',
- 'util/concurrent/ShortRunnable.java',
- 'util/concurrent/SimpleThreadFactory.java',
- 'util/concurrent/SmallCallable.java',
- 'util/concurrent/SmallPossiblyInterruptedRunnable.java',
- 'util/concurrent/SmallRunnable.java',
- 'util/concurrent/StringTask.java',
- 'util/concurrent/ThreadPoolExecutor/CustomTask.java',
- 'util/concurrent/ThreadPoolExecutor/CustomTPE.java',
- 'util/concurrent/ThreadPoolExecutor/ExtendedTPE.java',
- 'util/concurrent/ThreadPoolExecutor/FailingThreadFactory.java',
- 'util/concurrent/ThreadShouldThrow.java',
- 'util/concurrent/TrackedCallable.java',
- 'util/concurrent/TrackedLongRunnable.java',
- 'util/concurrent/TrackedNoOpRunnable.java',
- 'util/concurrent/TrackedShortRunnable.java',
- ]
- files.each {
- def dir = new File(it).parent
- from ("$inputDir/$prefix/$it") {
- into "$prefix/$dir"
- }
-
- }
-
- def prefixNoPackage = 'LibTests/src'
- def filesNoPackage = [
- 'DefaultPackageInterface.java',
- 'UnnamedPackageClass.java'
- ]
- filesNoPackage.each {
- from ("$inputDir/$prefixNoPackage/$it") {
- into "$prefixNoPackage"
- }
- }
-
- into outputDir
-}
diff --git a/infra/config/global/generated/cr-buildbucket.cfg b/infra/config/global/generated/cr-buildbucket.cfg
index 6661615..0323612 100644
--- a/infra/config/global/generated/cr-buildbucket.cfg
+++ b/infra/config/global/generated/cr-buildbucket.cfg
@@ -94,6 +94,8 @@
' "builder_group": "internal.client.r8",'
' "recipe": "rex",'
' "test_options": ['
+ ' "--one_line_per_test",'
+ ' "--archive_failures",'
' "--no_internal",'
' "--desugared-library",'
' "HEAD"'
@@ -127,6 +129,8 @@
' "builder_group": "internal.client.r8",'
' "recipe": "rex",'
' "test_options": ['
+ ' "--one_line_per_test",'
+ ' "--archive_failures",'
' "--no_internal",'
' "--desugared-library",'
' "HEAD",'
@@ -914,80 +918,6 @@
}
}
builders {
- name: "linux-d8_jctf"
- swarming_host: "chrome-swarming.appspot.com"
- swarming_tags: "vpython:native-python-wrapper"
- dimensions: "cores:8"
- dimensions: "cpu:x86-64"
- dimensions: "jctf:true"
- dimensions: "os:Ubuntu-16.04"
- dimensions: "pool:luci.r8.ci"
- exe {
- cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
- cipd_version: "refs/heads/master"
- cmd: "luciexe"
- }
- properties:
- '{'
- ' "builder_group": "internal.client.r8",'
- ' "recipe": "rex",'
- ' "test_options": ['
- ' "--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.recipes.use_python3"
- value: 100
- }
- }
- builders {
- name: "linux-d8_jctf_release"
- swarming_host: "chrome-swarming.appspot.com"
- swarming_tags: "vpython:native-python-wrapper"
- dimensions: "cores:8"
- dimensions: "cpu:x86-64"
- dimensions: "jctf:true"
- dimensions: "os:Ubuntu-16.04"
- dimensions: "pool:luci.r8.ci"
- exe {
- cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
- cipd_version: "refs/heads/master"
- cmd: "luciexe"
- }
- properties:
- '{'
- ' "builder_group": "internal.client.r8",'
- ' "recipe": "rex",'
- ' "test_options": ['
- ' "--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.recipes.use_python3"
- value: 100
- }
- }
- builders {
name: "linux-dex_default"
swarming_host: "chrome-swarming.appspot.com"
swarming_tags: "vpython:native-python-wrapper"
@@ -1198,6 +1128,78 @@
}
}
builders {
+ name: "linux-jdk17"
+ swarming_host: "chrome-swarming.appspot.com"
+ swarming_tags: "vpython:native-python-wrapper"
+ dimensions: "cores:8"
+ dimensions: "cpu:x86-64"
+ dimensions: "normal:true"
+ dimensions: "os:Ubuntu-16.04"
+ dimensions: "pool:luci.r8.ci"
+ exe {
+ cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
+ cipd_version: "refs/heads/master"
+ cmd: "luciexe"
+ }
+ properties:
+ '{'
+ ' "builder_group": "internal.client.r8",'
+ ' "recipe": "rex",'
+ ' "test_options": ['
+ ' "--runtimes=jdk17",'
+ ' "--tool=r8",'
+ ' "--no_internal",'
+ ' "--one_line_per_test",'
+ ' "--archive_failures"'
+ ' ]'
+ '}'
+ priority: 26
+ execution_timeout_secs: 21600
+ expiration_secs: 126000
+ build_numbers: YES
+ service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.recipes.use_python3"
+ value: 100
+ }
+ }
+ builders {
+ name: "linux-jdk17_release"
+ swarming_host: "chrome-swarming.appspot.com"
+ swarming_tags: "vpython:native-python-wrapper"
+ dimensions: "cores:8"
+ dimensions: "cpu:x86-64"
+ dimensions: "normal:true"
+ dimensions: "os:Ubuntu-16.04"
+ dimensions: "pool:luci.r8.ci"
+ exe {
+ cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
+ cipd_version: "refs/heads/master"
+ cmd: "luciexe"
+ }
+ properties:
+ '{'
+ ' "builder_group": "internal.client.r8",'
+ ' "recipe": "rex",'
+ ' "test_options": ['
+ ' "--runtimes=jdk17",'
+ ' "--tool=r8",'
+ ' "--no_internal",'
+ ' "--one_line_per_test",'
+ ' "--archive_failures"'
+ ' ]'
+ '}'
+ priority: 26
+ execution_timeout_secs: 21600
+ expiration_secs: 126000
+ build_numbers: YES
+ service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+ experiments {
+ key: "luci.recipes.use_python3"
+ value: 100
+ }
+ }
+ builders {
name: "linux-jdk8"
swarming_host: "chrome-swarming.appspot.com"
swarming_tags: "vpython:native-python-wrapper"
@@ -1488,80 +1490,6 @@
}
}
builders {
- name: "linux-r8cf_jctf"
- swarming_host: "chrome-swarming.appspot.com"
- swarming_tags: "vpython:native-python-wrapper"
- dimensions: "cores:8"
- dimensions: "cpu:x86-64"
- dimensions: "jctf:true"
- dimensions: "os:Ubuntu-16.04"
- dimensions: "pool:luci.r8.ci"
- exe {
- cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
- cipd_version: "refs/heads/master"
- cmd: "luciexe"
- }
- properties:
- '{'
- ' "builder_group": "internal.client.r8",'
- ' "recipe": "rex",'
- ' "test_options": ['
- ' "--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.recipes.use_python3"
- value: 100
- }
- }
- builders {
- name: "linux-r8cf_jctf_release"
- swarming_host: "chrome-swarming.appspot.com"
- swarming_tags: "vpython:native-python-wrapper"
- dimensions: "cores:8"
- dimensions: "cpu:x86-64"
- dimensions: "jctf:true"
- dimensions: "os:Ubuntu-16.04"
- dimensions: "pool:luci.r8.ci"
- exe {
- cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
- cipd_version: "refs/heads/master"
- cmd: "luciexe"
- }
- properties:
- '{'
- ' "builder_group": "internal.client.r8",'
- ' "recipe": "rex",'
- ' "test_options": ['
- ' "--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.recipes.use_python3"
- value: 100
- }
- }
- builders {
name: "linux-run-on-app-dump"
swarming_host: "chrome-swarming.appspot.com"
swarming_tags: "vpython:native-python-wrapper"
diff --git a/infra/config/global/generated/luci-milo.cfg b/infra/config/global/generated/luci-milo.cfg
index 8bbf1b1..e07a48e 100644
--- a/infra/config/global/generated/luci-milo.cfg
+++ b/infra/config/global/generated/luci-milo.cfg
@@ -41,6 +41,11 @@
short_name: "jdk11"
}
builders {
+ name: "buildbucket/luci.r8.ci/linux-jdk17"
+ category: "R8"
+ short_name: "jdk17"
+ }
+ builders {
name: "buildbucket/luci.r8.ci/linux-android-4.0.4"
category: "R8"
short_name: "4.0.4"
@@ -116,16 +121,6 @@
short_name: "kotlin_old"
}
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"
@@ -171,6 +166,11 @@
short_name: "jdk11"
}
builders {
+ name: "buildbucket/luci.r8.ci/linux-jdk17_release"
+ category: "Release|R8"
+ short_name: "jdk17"
+ }
+ builders {
name: "buildbucket/luci.r8.ci/linux-android-4.0.4_release"
category: "Release|R8"
short_name: "4.0.4"
@@ -235,14 +235,4 @@
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 d98d266..c9717b2 100644
--- a/infra/config/global/generated/luci-notify.cfg
+++ b/infra/config/global/generated/luci-notify.cfg
@@ -300,30 +300,6 @@
}
builders {
bucket: "ci"
- name: "linux-d8_jctf"
- repository: "https://r8.googlesource.com/r8"
- }
-}
-notifiers {
- notifications {
- on_failure: true
- on_new_failure: true
- notify_blamelist {}
- }
- builders {
- bucket: "ci"
- name: "linux-d8_jctf_release"
- repository: "https://r8.googlesource.com/r8"
- }
-}
-notifiers {
- notifications {
- on_failure: true
- on_new_failure: true
- notify_blamelist {}
- }
- builders {
- bucket: "ci"
name: "linux-dex_default"
repository: "https://r8.googlesource.com/r8"
}
@@ -396,6 +372,30 @@
}
builders {
bucket: "ci"
+ name: "linux-jdk17"
+ repository: "https://r8.googlesource.com/r8"
+ }
+}
+notifiers {
+ notifications {
+ on_failure: true
+ on_new_failure: true
+ notify_blamelist {}
+ }
+ builders {
+ bucket: "ci"
+ name: "linux-jdk17_release"
+ repository: "https://r8.googlesource.com/r8"
+ }
+}
+notifiers {
+ notifications {
+ on_failure: true
+ on_new_failure: true
+ notify_blamelist {}
+ }
+ builders {
+ bucket: "ci"
name: "linux-jdk8"
repository: "https://r8.googlesource.com/r8"
}
@@ -492,30 +492,6 @@
}
builders {
bucket: "ci"
- name: "linux-r8cf_jctf"
- repository: "https://r8.googlesource.com/r8"
- }
-}
-notifiers {
- notifications {
- on_failure: true
- on_new_failure: true
- notify_blamelist {}
- }
- builders {
- bucket: "ci"
- name: "linux-r8cf_jctf_release"
- repository: "https://r8.googlesource.com/r8"
- }
-}
-notifiers {
- notifications {
- on_failure: true
- on_new_failure: true
- notify_blamelist {}
- }
- builders {
- bucket: "ci"
name: "linux-run-on-app-dump"
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 cb2a721..58167f9 100644
--- a/infra/config/global/generated/luci-scheduler.cfg
+++ b/infra/config/global/generated/luci-scheduler.cfg
@@ -368,35 +368,6 @@
}
}
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: "ci"
- builder: "linux-d8_jctf"
- }
-}
-job {
- id: "linux-d8_jctf_release"
- realm: "ci"
- acl_sets: "ci"
- triggering_policy {
- kind: GREEDY_BATCHING
- max_concurrent_invocations: 4
- max_batch_size: 1
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "ci"
- builder: "linux-d8_jctf_release"
- }
-}
-job {
id: "linux-dex_default"
realm: "ci"
acl_sets: "ci"
@@ -432,6 +403,7 @@
triggering_policy {
kind: GREEDY_BATCHING
max_concurrent_invocations: 1
+ max_batch_size: 1
}
buildbucket {
server: "cr-buildbucket.appspot.com"
@@ -446,6 +418,7 @@
triggering_policy {
kind: GREEDY_BATCHING
max_concurrent_invocations: 1
+ max_batch_size: 1
}
buildbucket {
server: "cr-buildbucket.appspot.com"
@@ -483,6 +456,35 @@
}
}
job {
+ id: "linux-jdk17"
+ realm: "ci"
+ acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ }
+ buildbucket {
+ server: "cr-buildbucket.appspot.com"
+ bucket: "ci"
+ builder: "linux-jdk17"
+ }
+}
+job {
+ id: "linux-jdk17_release"
+ realm: "ci"
+ acl_sets: "ci"
+ triggering_policy {
+ kind: GREEDY_BATCHING
+ max_concurrent_invocations: 4
+ max_batch_size: 1
+ }
+ buildbucket {
+ server: "cr-buildbucket.appspot.com"
+ bucket: "ci"
+ builder: "linux-jdk17_release"
+ }
+}
+job {
id: "linux-jdk8"
realm: "ci"
acl_sets: "ci"
@@ -598,35 +600,6 @@
}
}
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: "ci"
- builder: "linux-r8cf_jctf"
- }
-}
-job {
- id: "linux-r8cf_jctf_release"
- realm: "ci"
- acl_sets: "ci"
- triggering_policy {
- kind: GREEDY_BATCHING
- max_concurrent_invocations: 4
- max_batch_size: 1
- }
- buildbucket {
- server: "cr-buildbucket.appspot.com"
- bucket: "ci"
- builder: "linux-r8cf_jctf_release"
- }
-}
-job {
id: "linux-run-on-app-dump"
realm: "ci"
acl_sets: "ci"
@@ -700,6 +673,7 @@
realm: "ci"
acl_sets: "ci"
triggers: "linux-android-13.0.0_release"
+ triggers: "linux-jdk17_release"
gitiles {
repo: "https://r8.googlesource.com/r8"
refs: "regexp:refs/heads/([3]\\.[3-9]+(\\.[0-9]+)?|[4-9]\\.[0-9]+(\\.[0-9]+)?)"
@@ -719,14 +693,12 @@
triggers: "linux-android-7.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"
triggers: "linux-jdk11_release"
triggers: "linux-jdk8_release"
triggers: "linux-jdk9_release"
triggers: "linux-none_release"
- triggers: "linux-r8cf_jctf_release"
triggers: "linux-run-on-app-dump_release"
triggers: "windows_release"
gitiles {
@@ -752,16 +724,15 @@
triggers: "linux-android-7.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-jdk17"
triggers: "linux-jdk8"
triggers: "linux-jdk9"
triggers: "linux-kotlin_dev"
triggers: "linux-kotlin_old"
triggers: "linux-none"
- triggers: "linux-r8cf_jctf"
triggers: "linux-run-on-app-dump"
triggers: "windows"
gitiles {
diff --git a/infra/config/global/generated/project.cfg b/infra/config/global/generated/project.cfg
index 974c534..6153ae8 100644
--- a/infra/config/global/generated/project.cfg
+++ b/infra/config/global/generated/project.cfg
@@ -7,7 +7,7 @@
name: "r8"
access: "group:all"
lucicfg {
- version: "1.30.9"
+ version: "1.30.10"
package_dir: ".."
config_dir: "generated"
entry_point: "main.star"
diff --git a/infra/config/global/main.star b/infra/config/global/main.star
index d6eb25a..303dffe 100755
--- a/infra/config/global/main.star
+++ b/infra/config/global/main.star
@@ -161,7 +161,7 @@
"--archive_failures"
]
-def get_dimensions(windows=False, jctf=False, internal=False, normal=False):
+def get_dimensions(windows=False, internal=False, normal=False):
dimensions = {
"cores" : "2" if internal else "8",
"cpu" : "x86-64",
@@ -171,8 +171,6 @@
dimensions["os"] = "Windows-10"
else:
dimensions["os"] = "Ubuntu-16.04"
- if jctf:
- dimensions["jctf"] = "true"
if internal:
dimensions["internal"] = "true"
if normal:
@@ -270,6 +268,9 @@
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-jdk17", ["--runtimes=jdk17"],
+ release_trigger=["branch-gitiles-3.3-forward"])
+
r8_tester_with_default("linux-android-4.0.4",
["--dex_vm=4.0.4", "--all_tests"])
@@ -304,7 +305,8 @@
dimensions = get_dimensions(internal=True),
triggering_policy = scheduler.policy(
kind = scheduler.GREEDY_BATCHING_KIND,
- max_concurrent_invocations = 1
+ max_concurrent_invocations = 1,
+ max_batch_size = 1
),
priority = 25,
properties = {
@@ -336,7 +338,13 @@
def desugared_library():
for name in ["head", "jdk11_head"]:
- test_options = ["--no_internal", "--desugared-library", "HEAD"]
+ test_options = [
+ "--one_line_per_test",
+ "--archive_failures",
+ "--no_internal",
+ "--desugared-library",
+ "HEAD"
+ ]
if "jdk11" in name:
test_options = test_options + ["--desugared-library-configuration", "jdk11"]
properties = {
@@ -376,38 +384,12 @@
}
)
-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():
diff --git a/scripts/add-openjdk.sh b/scripts/add-openjdk.sh
index f6b3284..e8714f3 100755
--- a/scripts/add-openjdk.sh
+++ b/scripts/add-openjdk.sh
@@ -23,6 +23,9 @@
# For ea versions the full version name has a postfix.
# JDK_VERSION_FULL="${JDK_VERSION}-ea+33"
+rm -rf linux
+rm -f linux.tar.gz
+rm -f linux.tar.gz.sha1
tar xf ~/Downloads/openjdk-${JDK_VERSION_FULL}_linux-x64_bin.tar.gz
cp -rL jdk-${JDK_VERSION} linux
cp README.google linux
@@ -31,20 +34,26 @@
rm -rf linux
rm linux.tar.gz
+rm -rf osx
+rm -f osx.tar.gz
+rm -f osx.tar.gz.sha1
tar xf ~/Downloads/openjdk-${JDK_VERSION_FULL}_macos-x64_bin.tar.gz
cp -rL jdk-${JDK_VERSION}.jdk osx
cp README.google osx
upload_to_google_storage.py -a --bucket r8-deps osx
-rm -rf osx
rm -rf jdk-${JDK_VERSION}.jdk
+rm -rf osx
rm osx.tar.gz
+rm -rf windows
+rm -f windows.tar.gz
+rm -f windows.tar.gz.sha1
unzip ~/Downloads/openjdk-${JDK_VERSION_FULL}_windows-x64_bin.zip
cp -rL jdk-${JDK_VERSION} windows
cp README.google windows
upload_to_google_storage.py -a --bucket r8-deps windows
-rm -rf windows
rm -rf jdk-${JDK_VERSION}
+rm -rf windows
rm windows.tar.gz
git add *.sha1
diff --git a/src/library_desugar/desugar_jdk_libs_comments.md b/src/library_desugar/desugar_jdk_libs_legacy_comments.md
similarity index 96%
rename from src/library_desugar/desugar_jdk_libs_comments.md
rename to src/library_desugar/desugar_jdk_libs_legacy_comments.md
index 2ba5908..f2bb6d8 100644
--- a/src/library_desugar/desugar_jdk_libs_comments.md
+++ b/src/library_desugar/desugar_jdk_libs_legacy_comments.md
@@ -1,4 +1,4 @@
-# Description of the desugared library configuration file
+# Description of the legacy desugared library configuration file
## Version
diff --git a/src/library_desugar/jdk11/chm_only_desugar_jdk_libs.json b/src/library_desugar/jdk11/chm_only_desugar_jdk_libs.json
index f240706..5f43015 100644
--- a/src/library_desugar/jdk11/chm_only_desugar_jdk_libs.json
+++ b/src/library_desugar/jdk11/chm_only_desugar_jdk_libs.json
@@ -1,7 +1,7 @@
{
"identifier": "com.tools.android:chm_only_desugar_jdk_libs:1.0.12",
"configuration_format_version": 100,
- "required_compilation_api_level": 30,
+ "required_compilation_api_level": 26,
"synthesized_library_classes_package_prefix": "j$.",
"support_all_callbacks_from_library": false,
"common_flags": [
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs.json b/src/library_desugar/jdk11/desugar_jdk_libs.json
index c201e1d..41ac1e6 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs.json
@@ -245,7 +245,6 @@
"java.nio.channels.CompletionHandler": "j$.nio.channels.CompletionHandler",
"java.nio.channels.Desugar": "j$.nio.channels.Desugar",
"java.nio.file.": "j$.nio.file.",
- "wrapper." : "j$.wrapper.",
"jdk.internal.": "j$.jdk.internal.",
"sun.misc.Desugar": "j$.sun.misc.Desugar",
"sun.nio.cs.": "j$.sun.nio.cs.",
@@ -253,11 +252,12 @@
"sun.nio.fs.AbstractFileTypeDetector": "j$.sun.nio.fs.AbstractFileTypeDetector",
"sun.nio.fs.BasicFileAttributesHolder": "j$.sun.nio.fs.BasicFileAttributesHolder",
"sun.nio.fs.DynamicFileAttributeView": "j$.sun.nio.fs.DynamicFileAttributeView",
- "sun.util.PreHashedMap": "j$.sun.util.PreHashedMap"
+ "sun.util.PreHashedMap": "j$.sun.util.PreHashedMap",
+ "wrapper." : "j$.wrapper."
},
"rewrite_derived_prefix": {
- "java.nio.file.attribute.": {
- "j$.nio.file.attribute.": "java.nio.file.attribute."
+ "java.nio.file.attribute.FileTime": {
+ "j$.nio.file.attribute.FileTime": "java.nio.file.attribute.FileTime"
},
"java.io.": {
"__wrapper__.j$.io.": "j$.io.",
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json b/src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json
index 558386a..57f7c3e 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json
@@ -55,7 +55,6 @@
"api_level_below_or_equal": 23,
"rewrite_prefix": {
"java.io.DesugarBufferedReader": "j$.io.DesugarBufferedReader",
- "java.io.UncheckedIOException": "j$.io.UncheckedIOException",
"java.util.DoubleSummaryStatistics": "j$.util.DoubleSummaryStatistics",
"java.util.IntSummaryStatistics": "j$.util.IntSummaryStatistics",
"java.util.LongSummaryStatistics": "j$.util.LongSummaryStatistics",
@@ -70,6 +69,9 @@
"java.util.function.": "j$.util.function.",
"java.util.stream.": "j$.util.stream."
},
+ "maintain_prefix": [
+ "java.io.UncheckedIOException"
+ ],
"emulate_interface": {
"java.lang.Iterable": "j$.lang.Iterable",
"java.util.Collection": "j$.util.Collection",
@@ -223,24 +225,13 @@
],
"library_flags": [
{
- "api_level_below_or_equal": 10000,
+ "api_level_below_or_equal": 32,
"rewrite_prefix": {
"desugar.": "j$.desugar.",
"libcore.": "j$.libcore.",
"java.lang.Desugar": "j$.lang.Desugar",
"java.lang.ref.Cleaner": "j$.lang.ref.Cleaner",
- "wrapper." : "j$.wrapper.",
"sun.security.action.": "j$.sun.security.action."
- },
- "rewrite_derived_prefix": {
- "java.io.": {
- "__wrapper__.j$.io.": "j$.io.",
- "__wrapper__.java.io.": "java.io."
- },
- "java.nio.": {
- "__wrapper__.j$.nio.": "j$.nio.",
- "__wrapper__.java.nio.": "java.nio."
- }
}
},
{
@@ -267,11 +258,20 @@
"sun.nio.fs.AbstractFileTypeDetector": "j$.sun.nio.fs.AbstractFileTypeDetector",
"sun.nio.fs.BasicFileAttributesHolder": "j$.sun.nio.fs.BasicFileAttributesHolder",
"sun.nio.fs.DynamicFileAttributeView": "j$.sun.nio.fs.DynamicFileAttributeView",
- "sun.util.PreHashedMap": "j$.sun.util.PreHashedMap"
+ "sun.util.PreHashedMap": "j$.sun.util.PreHashedMap",
+ "wrapper." : "j$.wrapper."
},
"rewrite_derived_prefix": {
- "java.nio.file.attribute.": {
- "j$.nio.file.attribute.": "java.nio.file.attribute."
+ "java.nio.file.attribute.FileTime": {
+ "j$.nio.file.attribute.FileTime": "java.nio.file.attribute.FileTime"
+ },
+ "java.io.": {
+ "__wrapper__.j$.io.": "j$.io.",
+ "__wrapper__.java.io.": "java.io."
+ },
+ "java.nio.": {
+ "__wrapper__.j$.nio.": "j$.nio.",
+ "__wrapper__.java.nio.": "java.nio."
}
},
"retarget_method": {
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs_human_comments.md b/src/library_desugar/jdk11/desugar_jdk_libs_human_comments.md
new file mode 100644
index 0000000..3fdcd72
--- /dev/null
+++ b/src/library_desugar/jdk11/desugar_jdk_libs_human_comments.md
@@ -0,0 +1,178 @@
+# Description of the human desugared library configuration file
+
+## Version
+
+The field `configuration_format_version` encodes a versioning number internal to
+R8/D8 in the form of an unsigned integer. It allows R8/D8 to know if the file
+given is supported. If the number if greater or equal to 100, the file is
+encoded using the human flags (by opposition to the legacy flags). Human flags
+are not shipped to external users. Human flags can be converted to machine flags
+which are shipped to external users. Users internal to Google are allowed to use
+directly human flags if we can easily update the file without backward
+compatibility issues.
+
+The field `identifier` is the maven-coordinated id for the desugared library
+configuration file.
+
+## Required compilation API level
+
+The field `required_compilation_api_level` encodes the minimal Android API level
+required for the desugared library to be compiled correctly. If the API of
+library used for compilation of the library or a program using the library is
+lower than this level, one has to upgrade the SDK version used to be able to use
+desugared libraries.
+
+## Synthesize prefix
+
+The field `synthesized_library_classes_package_prefix` is used both to prefix
+type names of synthetic classes created during the L8 compilation and for some
+of the rewritings.
+
+## Library callbacks
+
+The field `support_all_callbacks_from_library` is set if D8/R8 should generate
+extra callbacks, i.e., methods that may be called from specific library
+implementations into the program. Setting it to false may lead to invalid
+behavior if the library effectively use one of the callbacks, but reduces code
+size.
+
+## Common, library and program flags
+
+The fields `common_flags`, `library_flags` and `program_flags` include the set
+of rewriting flags required for respectively rewriting both the library and the
+program, only the library or only the program.
+
+The flags are in a list, where each list entry specifies up to which min API
+level the set of flags should be applied. During compilation, R8/D8 adds up all
+the required flags for the min API level specified at compilation.
+
+The following subsections describe each rewriting flag.
+
+### Flag rewrite_prefix
+
+`prefix: rewrittenPrefix`
+D8/R8 identifies any class type matching the prefix, and rewrite such types with
+the new prefix. Types not present as class types are not rewritten. Implicitly,
+all synthetic types derived from the matching type are also rewritten (lambdas
+and backports in the class, etc.).
+
+Example:
+`foo.: f$.`
+A class present with the type foo.Foo will generate a rewrite rule:
+foo.Foo -> f$.Foo. A type present foo.Bar, which is not the type of any class,
+will not generate any rewrite rule.
+
+### Flag rewrite_derived_prefix
+
+`prefix: { fromPrefix: toPrefix }`
+D8/R8 identifies any class type matching the prefix, and rewrite the type with
+the fromPrefix to the type with the toPrefix. This can be useful to generate
+rewrite rules from types not present in the input.
+
+Example:
+`foo.: { f$.: foo. }`
+A class present with the type foo.Foo will generate a rewrite rule:
+f$.Foo -> foo.Foo.
+
+### Flag retarget_method
+
+`methodToRetarget: retargetType`
+D8/R8 identifies all invokes which method resolve to the methodToRetarget, and
+rewrite it to an invoke to the same method but with the retargetType as holder.
+If the method is virtual, this converts the invoke to an invoke-static and adds
+the receiver type as the first parameter.
+
+The retargeting is valid for static methods, private methods and methods
+effectively final (methods with the final keyword, methods on final classes,
+which do not override any other method).
+
+When using the flag, the method, if virtual, is considered as effectively final.
+For retargeting of virtual methods that can be overridden, see
+retarget_method_with_emulated_dispatch.
+
+Example:
+`Foo Bar#foo(Zorg): DesugarBar`
+Any invoke which method resolves into the method with return type Foo, name foo,
+parameter Zorg on the holder Bar, is rewritten to an invoke-static to the same
+method on DesugarBar. If the method is not static, the rewritten method takes an
+extra first parameter of type Bar.
+
+### Flag retarget_method_with_emulated_dispatch
+
+`methodToRetarget: retargetType`
+Essentially the same as retarget_method, but for non effectively final virtual
+method. The flag fails the compilation if the methodToRetarget is static. D8/R8
+generates an emulated dispatch scheme so that the method can be retargeted, but
+the virtual dispatch is still valid and will correctly call the overrides if
+present.
+
+### Flag amend_library_method
+
+`modifiers method`
+For the retarget_method and retarget_method_with_emulated_dispatch flags to
+work, resolution has to find the method to retarget to. In some cases, the
+method is missing because it's not present on the required compilation level
+Android SDK, or because the method is private.
+
+This flag amends the library to introduce the method, so resolution can find it
+and retarget it correctly.
+
+### Flag dont_retarget
+
+`type`
+In classes with such type, invokes are not retargeted with the retarget_method
+and the retarget_method_with_emulated_dispatch flag. In addition, forwarding
+methods required for retarget_method_with_emulated_dispatch are not introduced
+in such classes.
+
+### Flag emulate_interface
+
+`libraryInterface: desugaredLibraryInterface`
+D8/R8 assume the libraryInterface is already in the library, but without the
+default and static methods present on it. It generates a companion class holding
+the code for the default and static methods, and a dispatch class which hold the
+code to support emulated dispatch for the default methods.
+
+### Flag dont_rewrite
+
+`methodNotToRewrite`
+D8/R8 ignroes the methods present here from the emulated interface.
+
+### Flag wrapper_conversion
+
+`type`
+Generate wrappers for the given type, including methods from the type and all
+its super types and interface types. In addition, analyse all invokes resolving
+into the library. If the invoke includes the type as return or parameter type,
+automatically surround the library call with conversion code using wrappers. The
+sequence of instructions with the conversions and the library invoke is outlined
+and shared if possible.
+
+### Flag wrapper_conversion_excluding
+
+`type: [methods]`
+Similar to wrapper_conversion, generate wrappers for the given type but ignore
+the methods listed. This can be used for methods not accessing fields or private
+methods, either to reduce code size or to work around final methods.
+
+### Flag custom_conversion
+
+`type: conversionType`
+Similar to wrapper_conversion, but instead of generating wrappers, rely on hand
+written conversions present on conversionType. The conversions methods must be
+of the form:
+Type convert(RewrittenType)
+RewrittenType convert(Type)
+
+## Extra keep rules
+
+The last field is `extra_keep_rules`, it includes keep rules that are appended
+by L8 when shrinking the desugared library. It includes keep rules related to
+reflection inside the desugared library, related to enum to have EnumSet working
+and to keep the j$ prefix.
+
+## Copyright
+
+Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file for
+details. All rights reserved. Use of this source code is governed by a BSD-style
+license that can be found in the LICENSE file.
\ No newline at end of file
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index 43868c3..26a14b4 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -20,6 +20,7 @@
import com.android.tools.r8.graph.LazyLoadedDexApplication;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.analysis.ClassInitializerAssertionEnablingAnalysis;
+import com.android.tools.r8.horizontalclassmerging.HorizontalClassMerger;
import com.android.tools.r8.inspector.internal.InspectorImpl;
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.desugar.TypeRewriter;
@@ -276,57 +277,54 @@
namingLens = PrefixRewritingNamingLens.createPrefixRewritingNamingLens(appView, namingLens);
namingLens = RecordRewritingNamingLens.createRecordRewritingNamingLens(appView, namingLens);
+ if (options.isGeneratingDex()
+ && hasDexResources
+ && hasClassResources
+ && appView.typeRewriter.isRewriting()) {
+ // There are both cf and dex inputs in the program, and rewriting is required for
+ // desugared library only on cf inputs. We cannot easily rewrite part of the program
+ // without iterating again the IR. We fall-back to writing one app with rewriting and
+ // merging it with the other app in rewriteNonDexInputs.
+ timing.begin("Rewrite non-dex inputs");
+ DexApplication app =
+ rewriteNonDexInputs(
+ appView, inputApp, options, executor, timing, appView.appInfo().app(), namingLens);
+ timing.end();
+ appView.setAppInfo(
+ new AppInfo(
+ appView.appInfo().getSyntheticItems().commit(app),
+ appView.appInfo().getMainDexInfo()));
+ namingLens = NamingLens.getIdentityLens();
+ } else if (options.isGeneratingDex() && hasDexResources) {
+ namingLens = NamingLens.getIdentityLens();
+ }
+
+ // Since tracing is not lens aware, this needs to be done prior to synthetic finalization
+ // which will construct a graph lens.
+ if (options.isGeneratingDex() && !options.mainDexKeepRules.isEmpty()) {
+ appView.dexItemFactory().clearTypeElementsCache();
+ MainDexInfo mainDexInfo =
+ new GenerateMainDexList(options)
+ .traceMainDex(
+ executor, appView.appInfo().app(), appView.appInfo().getMainDexInfo());
+ appView.setAppInfo(appView.appInfo().rebuildWithMainDexInfo(mainDexInfo));
+ }
+
+ finalizeApplication(appView, executor);
+
+ HorizontalClassMerger.createForD8ClassMerging(appView).runIfNecessary(executor, timing);
+
+ new GenericSignatureRewriter(appView, namingLens)
+ .runForD8(appView.appInfo().classes(), executor);
+ new KotlinMetadataRewriter(appView, namingLens).runForD8(executor);
+
if (options.isGeneratingClassFiles()) {
- finalizeApplication(appView, executor);
new CfApplicationWriter(appView, marker, namingLens)
.write(options.getClassFileConsumer(), inputApp);
} else {
- if (!hasDexResources || !hasClassResources || !appView.typeRewriter.isRewriting()) {
- // All inputs are either dex or cf, or there is nothing to rewrite.
- namingLens = hasDexResources ? NamingLens.getIdentityLens() : namingLens;
- new GenericSignatureRewriter(appView, namingLens)
- .run(appView.appInfo().classes(), executor);
- new KotlinMetadataRewriter(appView, namingLens).runForD8(executor);
- } else {
- // There are both cf and dex inputs in the program, and rewriting is required for
- // desugared library only on cf inputs. We cannot easily rewrite part of the program
- // without iterating again the IR. We fall-back to writing one app with rewriting and
- // merging it with the other app in rewriteNonDexInputs.
- timing.begin("Rewrite non-dex inputs");
- DexApplication app =
- rewriteNonDexInputs(
- appView,
- inputApp,
- options,
- executor,
- timing,
- appView.appInfo().app(),
- namingLens);
- timing.end();
- appView.setAppInfo(
- new AppInfo(
- appView.appInfo().getSyntheticItems().commit(app),
- appView.appInfo().getMainDexInfo()));
- namingLens = NamingLens.getIdentityLens();
- }
-
- // Since tracing is not lens aware, this needs to be done prior to synthetic finalization
- // which will construct a graph lens.
- if (!options.mainDexKeepRules.isEmpty()) {
- appView.dexItemFactory().clearTypeElementsCache();
- MainDexInfo mainDexInfo =
- new GenerateMainDexList(options)
- .traceMainDex(
- executor, appView.appInfo().app(), appView.appInfo().getMainDexInfo());
- appView.setAppInfo(appView.appInfo().rebuildWithMainDexInfo(mainDexInfo));
- }
-
- finalizeApplication(appView, executor);
-
- if (options.apiModelingOptions().enableStubbingOfClasses && !appView.options().debug) {
+ if (options.apiModelingOptions().enableStubbingOfClasses) {
new ApiReferenceStubber(appView).run(executor);
}
-
new ApplicationWriter(
appView,
marker == null ? null : ImmutableList.copyOf(markers),
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index 583c6bb..acbd677 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -10,7 +10,6 @@
import com.android.tools.r8.dump.DumpOptions;
import com.android.tools.r8.errors.DexFileOverflowDiagnostic;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.horizontalclassmerging.HorizontalClassMerger;
import com.android.tools.r8.inspector.Inspector;
import com.android.tools.r8.inspector.internal.InspectorImpl;
import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
@@ -24,6 +23,7 @@
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.AssertionConfigurationWithDefault;
import com.android.tools.r8.utils.DumpInputFlags;
+import com.android.tools.r8.utils.InternalGlobalSyntheticsProgramProvider;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.InternalOptions.DesugarState;
import com.android.tools.r8.utils.InternalOptions.HorizontalClassMergerOptions;
@@ -83,6 +83,9 @@
public static class Builder extends BaseCompilerCommand.Builder<D8Command, Builder> {
private boolean intermediate = false;
+ private GlobalSyntheticsConsumer globalSyntheticsConsumer = null;
+ private List<GlobalSyntheticsResourceProvider> globalSyntheticsResourceProviders =
+ new ArrayList<>();
private DesugarGraphConsumer desugarGraphConsumer = null;
private StringConsumer desugaredLibraryKeepRuleConsumer = null;
private String synthesizedClassPrefix = "";
@@ -145,6 +148,16 @@
/**
* Indicate if compilation is to intermediate results, i.e., intended for later merging.
*
+ * <p>When compiling to intermediate mode, the compiler will avoid sharing of synthetic items,
+ * and instead annotate them as synthetics for possible later merging. For global synthetics,
+ * the compiler will emit these to a separate consumer (see {@code GlobalSyntheticsConsumer}
+ * with the expectation that a later build step will consume them again as part of a
+ * non-intermediate build (see {@code GlobalSyntheticsResourceProvider}. Synthetic items
+ * typically come from the desugaring of various language features, such as lambdas and default
+ * interface methods. Global synthetics are non-local in that many compilation units may
+ * reference the same synthetic. For example, desugaring records requires a global tag to
+ * distinguish the class of all records.
+ *
* <p>Intermediate mode is implied if compiling results to a "file-per-class-file".
*/
public Builder setIntermediate(boolean value) {
@@ -153,6 +166,43 @@
}
/**
+ * Set a consumer for receiving the global synthetic content for the given compilation.
+ *
+ * <p>Note: this consumer is ignored if the compilation is not an "intermediate mode"
+ * compilation.
+ */
+ public Builder setGlobalSyntheticsConsumer(GlobalSyntheticsConsumer globalSyntheticsConsumer) {
+ this.globalSyntheticsConsumer = globalSyntheticsConsumer;
+ return self();
+ }
+
+ /** Add global synthetics resource providers. */
+ public Builder addGlobalSyntheticsResourceProviders(
+ GlobalSyntheticsResourceProvider... providers) {
+ return addGlobalSyntheticsResourceProviders(Arrays.asList(providers));
+ }
+
+ /** Add global synthetics resource providers. */
+ public Builder addGlobalSyntheticsResourceProviders(
+ Collection<GlobalSyntheticsResourceProvider> providers) {
+ providers.forEach(globalSyntheticsResourceProviders::add);
+ return self();
+ }
+
+ /** Add global synthetics resource files. */
+ public Builder addGlobalSyntheticsFiles(Path... files) {
+ return addGlobalSyntheticsFiles(Arrays.asList(files));
+ }
+
+ /** Add global synthetics resource files. */
+ public Builder addGlobalSyntheticsFiles(Collection<Path> files) {
+ for (Path file : files) {
+ addGlobalSyntheticsResourceProviders(new GlobalSyntheticsResourceFile(file));
+ }
+ return self();
+ }
+
+ /**
* Set a consumer for receiving the keep rules to use when compiling the desugared library for
* the program being compiled in this compilation.
*
@@ -295,6 +345,11 @@
ImmutableList<ProguardConfigurationRule> mainDexKeepRules =
ProguardConfigurationParser.parse(mainDexRules, factory, getReporter());
+ if (!globalSyntheticsResourceProviders.isEmpty()) {
+ addProgramResourceProvider(
+ new InternalGlobalSyntheticsProgramProvider(globalSyntheticsResourceProviders));
+ }
+
return new D8Command(
getAppBuilder().build(),
getMode(),
@@ -304,6 +359,7 @@
getReporter(),
getDesugaringState(),
intermediate,
+ intermediate ? globalSyntheticsConsumer : null,
isOptimizeMultidexForLinearAlloc(),
getIncludeClassesChecksum(),
getDexClassChecksumFilter(),
@@ -327,6 +383,7 @@
static final String USAGE_MESSAGE = D8CommandParser.USAGE_MESSAGE;
private final boolean intermediate;
+ private final GlobalSyntheticsConsumer globalSyntheticsConsumer;
private final DesugarGraphConsumer desugarGraphConsumer;
private final StringConsumer desugaredLibraryKeepRuleConsumer;
private final DesugaredLibrarySpecification desugaredLibrarySpecification;
@@ -386,6 +443,7 @@
Reporter diagnosticsHandler,
DesugarState enableDesugaring,
boolean intermediate,
+ GlobalSyntheticsConsumer globalSyntheticsConsumer,
boolean optimizeMultidexForLinearAlloc,
boolean encodeChecksum,
BiPredicate<String, Long> dexClassChecksumFilter,
@@ -421,6 +479,7 @@
mapIdProvider,
null);
this.intermediate = intermediate;
+ this.globalSyntheticsConsumer = globalSyntheticsConsumer;
this.desugarGraphConsumer = desugarGraphConsumer;
this.desugaredLibraryKeepRuleConsumer = desugaredLibraryKeepRuleConsumer;
this.desugaredLibrarySpecification = desugaredLibrarySpecification;
@@ -435,6 +494,7 @@
private D8Command(boolean printHelp, boolean printVersion) {
super(printHelp, printVersion);
intermediate = false;
+ globalSyntheticsConsumer = null;
desugarGraphConsumer = null;
desugaredLibraryKeepRuleConsumer = null;
desugaredLibrarySpecification = null;
@@ -469,6 +529,7 @@
internal.setMinApiLevel(AndroidApiLevel.getAndroidApiLevel(getMinApiLevel()));
internal.intermediate = intermediate;
internal.retainCompileTimeAnnotations = intermediate;
+ internal.setGlobalSyntheticsConsumer(globalSyntheticsConsumer);
internal.desugarGraphConsumer = desugarGraphConsumer;
internal.mainDexKeepRules = mainDexKeepRules;
internal.lineNumberOptimization = LineNumberOptimization.OFF;
@@ -478,7 +539,6 @@
assert !internal.isMinifying();
assert !internal.passthroughDexCode;
internal.passthroughDexCode = true;
- assert internal.neverMergePrefixes.contains("j$.");
// Assert some of R8 optimizations are disabled.
assert !internal.inlinerOptions().enableInlining;
@@ -516,12 +576,14 @@
// Disable global optimizations.
internal.disableGlobalOptimizations();
- // TODO(b/187675788): Enable class merging for synthetics in D8.
HorizontalClassMergerOptions horizontalClassMergerOptions =
internal.horizontalClassMergerOptions();
- horizontalClassMergerOptions.disable();
- assert !horizontalClassMergerOptions.isEnabled(HorizontalClassMerger.Mode.INITIAL);
- assert !horizontalClassMergerOptions.isEnabled(HorizontalClassMerger.Mode.FINAL);
+ if (internal.isGeneratingDex()) {
+ horizontalClassMergerOptions.setRestrictToSynthetics();
+ } else {
+ assert internal.isGeneratingClassFiles();
+ horizontalClassMergerOptions.disable();
+ }
internal.setDumpInputFlags(getDumpInputFlags(), skipDump);
internal.dumpOptions = dumpOptions();
diff --git a/src/main/java/com/android/tools/r8/DesugarGraphConsumer.java b/src/main/java/com/android/tools/r8/DesugarGraphConsumer.java
index 2210490..fd553b3 100644
--- a/src/main/java/com/android/tools/r8/DesugarGraphConsumer.java
+++ b/src/main/java/com/android/tools/r8/DesugarGraphConsumer.java
@@ -10,6 +10,29 @@
public interface DesugarGraphConsumer {
/**
+ * Callback indicating that the {@code node} is a program input which is part of the current
+ * compilation unit for desugaring.
+ *
+ * <p>Note: this callback is guaranteed to be called on every *program-input* origin that could be
+ * passed as a {@code dependent} in a callback to {@code accept(Orign dependent, Origin
+ * dependency)}. It is also guaranteed to be called before any such call. In effect, this callback
+ * will receive the complete set of program-input origins for the compilation unit that is being
+ * desugared and it can reliably be used to remove any existing and potentially stale edges
+ * pertaining to those origins from a dependency graph maintained in the client.
+ *
+ * <p>Note: this will not receive a callback for classpath origins.
+ *
+ * <p>Note: this callback may be called on multiple threads.
+ *
+ * <p>Note: this callback places no guarantees on order of calls or on duplicate calls.
+ *
+ * @param node Origin of code that is part of the program input in the compilation unit.
+ */
+ default void acceptProgramNode(Origin node) {
+ // Default behavior ignores the node callbacks.
+ }
+
+ /**
* Callback indicating that code originating from {@code dependency} is needed to correctly
* desugar code originating from {@code dependent}.
*
diff --git a/src/main/java/com/android/tools/r8/GlobalSyntheticsConsumer.java b/src/main/java/com/android/tools/r8/GlobalSyntheticsConsumer.java
new file mode 100644
index 0000000..ea8ad11
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/GlobalSyntheticsConsumer.java
@@ -0,0 +1,31 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8;
+
+/**
+ * Consumer receiving the data representing global synthetics for the program.
+ *
+ * <p>Global synthetic information is only produced as part of D8 intermediate builds (e.g., for
+ * incremental compilation.) The global synthetic information represents desugaring content that may
+ * be duplicated among many intermediate-mode builds and will need to be merged to ensure a valid
+ * final program (i.e., a program that does not contain any duplicate definitions).
+ *
+ * <p>The data obtained for global synthetics must be passed to the subsequent compilation unit that
+ * builds a non-intermediate output. That compilation output can then be packaged as a final
+ * application. It is valid to merge just the globals in such a final step. See {@code
+ * GlobalSyntheticsResourceProvider}.
+ */
+@Keep
+public interface GlobalSyntheticsConsumer {
+
+ /**
+ * Callback to receive the data representing the global synthetics for the program.
+ *
+ * <p>The encoding of the global synthetics is compiler internal and may vary between compiler
+ * versions. The data received here is thus only valid as inputs to the same compiler version.
+ *
+ * @param bytes Opaque encoding of the global synthetics for the program.
+ */
+ void accept(byte[] bytes);
+}
diff --git a/src/main/java/com/android/tools/r8/GlobalSyntheticsResourceFile.java b/src/main/java/com/android/tools/r8/GlobalSyntheticsResourceFile.java
new file mode 100644
index 0000000..598a074
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/GlobalSyntheticsResourceFile.java
@@ -0,0 +1,36 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8;
+
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.origin.PathOrigin;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+public class GlobalSyntheticsResourceFile implements GlobalSyntheticsResourceProvider {
+
+ private final Path file;
+ private final Origin origin;
+
+ public GlobalSyntheticsResourceFile(Path file) {
+ this.file = file;
+ this.origin = new PathOrigin(file);
+ }
+
+ @Override
+ public Origin getOrigin() {
+ return origin;
+ }
+
+ @Override
+ public InputStream getByteStream() throws ResourceException {
+ try {
+ return Files.newInputStream(file);
+ } catch (IOException e) {
+ throw new ResourceException(origin, e);
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/GlobalSyntheticsResourceProvider.java b/src/main/java/com/android/tools/r8/GlobalSyntheticsResourceProvider.java
new file mode 100644
index 0000000..4cfdbb1
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/GlobalSyntheticsResourceProvider.java
@@ -0,0 +1,23 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8;
+
+import com.android.tools.r8.origin.Origin;
+import java.io.InputStream;
+
+/**
+ * Interface to provide global synthetic information to the compiler.
+ *
+ * <p>The global synthetic information can only be obtained by consuming it from a previous
+ * compilation unit for the same compiler version. See {@code GlobalSyntheticsConsumer}.
+ */
+@Keep
+public interface GlobalSyntheticsResourceProvider {
+
+ /** Get the origin of the global synthetics resource. */
+ Origin getOrigin();
+
+ /** Get the bytes of the global synthetics resource. */
+ InputStream getByteStream() throws ResourceException;
+}
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index d479e46..1c8ba99 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -406,6 +406,11 @@
GenericSignatureCorrectnessHelper.createForInitialCheck(appView, genericContextBuilder)
.run(appView.appInfo().classes());
+ // TODO(b/226539525): Implement enum lite proto shrinking as deferred tracing.
+ if (appView.options().protoShrinking().isEnumLiteProtoShrinkingEnabled()) {
+ appView.protoShrinker().enumLiteProtoShrinker.clearDeadEnumLiteMaps();
+ }
+
TreePruner pruner = new TreePruner(appViewWithLiveness);
DirectMappedDexApplication prunedApp = pruner.run(executorService);
@@ -422,10 +427,6 @@
appViewWithLiveness, appViewWithLiveness.appInfo().computeSubtypingInfo())
.run();
- if (appView.options().protoShrinking().isEnumLiteProtoShrinkingEnabled()) {
- appView.protoShrinker().enumLiteProtoShrinker.clearDeadEnumLiteMaps();
- }
-
AnnotationRemover annotationRemover =
annotationRemoverBuilder
.build(appViewWithLiveness, removedClasses);
@@ -508,7 +509,7 @@
assert appView.verticallyMergedClasses() != null;
HorizontalClassMerger.createForInitialClassMerging(appViewWithLiveness)
- .runIfNecessary(runtimeTypeCheckInfo, executorService, timing);
+ .runIfNecessary(executorService, timing, runtimeTypeCheckInfo);
}
new ProtoNormalizer(appViewWithLiveness).run(executorService, timing);
@@ -751,11 +752,11 @@
// are always merged.
HorizontalClassMerger.createForFinalClassMerging(appView)
.runIfNecessary(
+ executorService,
+ timing,
classMergingEnqueuerExtensionBuilder != null
? classMergingEnqueuerExtensionBuilder.build(appView.graphLens())
- : null,
- executorService,
- timing);
+ : null);
// Perform minification.
NamingLens namingLens;
@@ -975,7 +976,9 @@
return true;
}
for (DexDebugEvent event : code.getDebugInfo().asEventBasedInfo().events) {
- assert !event.isSetInlineFrame() || event.asSetInlineFrame().hasOuterPosition(originalMethod);
+ assert !event.isPositionFrame()
+ || event.asSetPositionFrame().getPosition().getOutermostCaller().getMethod()
+ == originalMethod;
}
return true;
}
diff --git a/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java b/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
index 5725955..15bf742 100644
--- a/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
+++ b/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.androidapi;
+import com.android.tools.r8.errors.MissingGlobalSyntheticsConsumerDiagnostic;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DefaultInstanceInitializerCode;
@@ -233,7 +234,8 @@
appView
.appInfo()
.getSyntheticItems()
- .ensureFixedClassFromType(
+ .ensureGlobalClass(
+ () -> new MissingGlobalSyntheticsConsumerDiagnostic("API stubbing"),
kinds -> kinds.API_MODEL_STUB,
libraryClass.getType(),
appView,
diff --git a/src/main/java/com/android/tools/r8/cf/CfRegisterAllocator.java b/src/main/java/com/android/tools/r8/cf/CfRegisterAllocator.java
index 28d7592..351a3a1 100644
--- a/src/main/java/com/android/tools/r8/cf/CfRegisterAllocator.java
+++ b/src/main/java/com/android/tools/r8/cf/CfRegisterAllocator.java
@@ -175,8 +175,7 @@
private ImmutableList<BasicBlock> computeLivenessInformation() {
ImmutableList<BasicBlock> blocks = code.numberInstructions();
liveAtEntrySets = code.computeLiveAtEntrySets();
- LinearScanRegisterAllocator.computeLiveRanges(
- appView.options(), code, liveAtEntrySets, liveIntervals);
+ LinearScanRegisterAllocator.computeLiveRanges(appView, code, liveAtEntrySets, liveIntervals);
return blocks;
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java b/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
index efad6db..67e44d4 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
@@ -162,6 +162,11 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ return 1;
+ }
+
+ @Override
public boolean canThrow() {
return (type != NumericType.FLOAT && type != NumericType.DOUBLE)
&& (opcode == Opcode.Div || opcode == Opcode.Rem);
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
index 0af6a11..35a03f2 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
@@ -40,6 +40,11 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ return 1;
+ }
+
+ @Override
public int getCompareToId() {
return Opcodes.ARRAYLENGTH;
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
index 44f0e60..dc6a732 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
@@ -89,6 +89,11 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ return 1;
+ }
+
+ @Override
public void print(CfPrinter printer) {
printer.print(this);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
index 68d6b2d..39db93e 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
@@ -87,6 +87,11 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ return 1;
+ }
+
+ @Override
public void print(CfPrinter printer) {
printer.print(this);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java b/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
index 6098e98..edd6603 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
@@ -92,6 +92,11 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ return 3;
+ }
+
+ @Override
public void print(CfPrinter printer) {
printer.print(this);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfCmp.java b/src/main/java/com/android/tools/r8/cf/code/CfCmp.java
index c997da1..5b3c937 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfCmp.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfCmp.java
@@ -112,6 +112,11 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ return 1;
+ }
+
+ @Override
public void buildIR(IRBuilder builder, CfState state, CfSourceCode code) {
int right = state.pop().register;
int left = state.pop().register;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java b/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
index c135288..abc6070 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
@@ -38,6 +38,9 @@
}
public CfConstClass(DexType type, boolean ignoreCompatRules) {
+ // Primitive types and void should be retrieved using, for example, java.lang.Integer.TYPE.
+ assert !type.isPrimitiveType();
+ assert !type.isVoidType();
this.type = type;
this.ignoreCompatRules = ignoreCompatRules;
}
@@ -91,6 +94,12 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ // ldc or ldc_w
+ return 3;
+ }
+
+ @Override
public void print(CfPrinter printer) {
printer.print(this);
}
@@ -106,22 +115,6 @@
case '[':
case 'L':
return namingLens.lookupInternalName(rewrittenType);
- case 'Z':
- return "java/lang/Boolean/TYPE";
- case 'B':
- return "java/lang/Byte/TYPE";
- case 'S':
- return "java/lang/Short/TYPE";
- case 'C':
- return "java/lang/Character/TYPE";
- case 'I':
- return "java/lang/Integer/TYPE";
- case 'F':
- return "java/lang/Float/TYPE";
- case 'J':
- return "java/lang/Long/TYPE";
- case 'D':
- return "java/lang/Double/TYPE";
default:
throw new Unreachable("Unexpected type in const-class: " + rewrittenType);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstDynamic.java b/src/main/java/com/android/tools/r8/cf/code/CfConstDynamic.java
index 4efa8ae..3416ff7 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstDynamic.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstDynamic.java
@@ -189,6 +189,12 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ // ldc or ldc_w
+ return 3;
+ }
+
+ @Override
public void print(CfPrinter printer) {
printer.print(this);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
index 5f5837a..48db7ef 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
@@ -67,6 +67,12 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ // ldc or ldc_w
+ return 3;
+ }
+
+ @Override
public void print(CfPrinter printer) {
printer.print(this);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
index 3ef0e8d..855690f 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
@@ -65,6 +65,12 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ // ldc or ldc_w
+ return 3;
+ }
+
+ @Override
public void print(CfPrinter printer) {
printer.print(this);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java b/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java
index 4d7dbb7..d58b161 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java
@@ -40,6 +40,11 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ return 1;
+ }
+
+ @Override
public int getCompareToId() {
return Opcodes.ACONST_NULL;
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java b/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
index ca9cdf0..b1d9c5b 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
@@ -36,6 +36,7 @@
}
public CfConstNumber(long value, ValueType type) {
+ assert !type.isObject() : "Should use CfConstNull";
this.value = value;
this.type = type;
}
@@ -145,6 +146,64 @@
}
}
+ @Override
+ public int bytecodeSizeUpperBound() {
+ switch (type) {
+ case INT:
+ {
+ int value = getIntValue();
+ if (-1 <= value && value <= 5) {
+ // iconst_0 .. iconst_5
+ return 1;
+ } else if (Byte.MIN_VALUE <= value && value <= Byte.MAX_VALUE) {
+ // bipush byte
+ return 2;
+ } else if (Short.MIN_VALUE <= value && value <= Short.MAX_VALUE) {
+ // sipush byte1 byte2
+ return 3;
+ } else {
+ // ldc or ldc_w
+ return 3;
+ }
+ }
+ case LONG:
+ {
+ long value = getLongValue();
+ if (value == 0 || value == 1) {
+ // lconst_0 .. lconst_1
+ return 1;
+ } else {
+ // ldc or ldc_w
+ return 3;
+ }
+ }
+ case FLOAT:
+ {
+ float value = getFloatValue();
+ if (value == 0 || value == 1 || value == 2) {
+ // fconst_0 .. fconst_2 followed by fneg if negative
+ return isNegativeZeroFloat(value) ? 2 : 1;
+ } else {
+ // ldc or ldc_w
+ return 3;
+ }
+ }
+ case DOUBLE:
+ {
+ double value = getDoubleValue();
+ if (value == 0 || value == 1) {
+ // dconst_0 .. dconst_2 followed by dneg if negative
+ return isNegativeZeroDouble(value) ? 2 : 1;
+ } else {
+ // ldc2_w
+ return 3;
+ }
+ }
+ default:
+ throw new Unreachable("Non supported type in cf backend: " + type);
+ }
+ }
+
public static boolean isNegativeZeroDouble(double value) {
return Double.doubleToLongBits(value) == Double.doubleToLongBits(-0.0);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstString.java b/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
index 1b46a48..f03e9c7 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
@@ -74,6 +74,12 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ // ldc or ldc_w
+ return 3;
+ }
+
+ @Override
public void print(CfPrinter printer) {
printer.print(this);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java b/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
index 0a6887a..cdc4235 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
@@ -82,6 +82,12 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ // ldc or ldc_w
+ return 3;
+ }
+
+ @Override
public void print(CfPrinter printer) {
printer.print(this);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
index 99c9151..29dc73f 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
@@ -122,6 +122,11 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ return 3;
+ }
+
+ @Override
public void print(CfPrinter printer) {
printer.print(this);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFrame.java b/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
index 31bc71c..7f7f08b 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
@@ -404,6 +404,11 @@
visitor.visitFrame(F_NEW, localsCount, localsTypes, stackCount, stackTypes);
}
+ @Override
+ public int bytecodeSizeUpperBound() {
+ return 0;
+ }
+
private int computeStackCount() {
return stack.size();
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfGoto.java b/src/main/java/com/android/tools/r8/cf/code/CfGoto.java
index eb82f47..fa3a8a5 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfGoto.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfGoto.java
@@ -76,6 +76,11 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ return 3;
+ }
+
+ @Override
public void print(CfPrinter printer) {
printer.print(this);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIf.java b/src/main/java/com/android/tools/r8/cf/code/CfIf.java
index 9db12ec..833ac44 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfIf.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfIf.java
@@ -104,6 +104,11 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ return 3;
+ }
+
+ @Override
public boolean isConditionalJump() {
return true;
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java b/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java
index 2340a89..c8129a6 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java
@@ -105,6 +105,11 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ return 3;
+ }
+
+ @Override
public boolean isConditionalJump() {
return true;
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIinc.java b/src/main/java/com/android/tools/r8/cf/code/CfIinc.java
index 735dde8..1b5763c 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfIinc.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfIinc.java
@@ -64,6 +64,12 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ // iinc or wide iinc
+ return var < 256 && increment < 256 ? 3 : 6;
+ }
+
+ @Override
public void print(CfPrinter printer) {
printer.print(this);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java b/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
index 1092bfe..c307d45 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
@@ -82,6 +82,11 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ return 3;
+ }
+
+ @Override
public void print(CfPrinter printer) {
printer.print(this);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java b/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
index 0f93c4d..0469499 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
@@ -91,6 +91,11 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ return 3;
+ }
+
+ @Override
public void print(CfPrinter printer) {
printer.print(this);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
index a1b7023..40b9737 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
@@ -6,6 +6,7 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.code.CfOrDexInstruction;
import com.android.tools.r8.code.Instruction;
+import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
@@ -66,6 +67,10 @@
public abstract int internalAcceptCompareTo(
CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper);
+ public int bytecodeSizeUpperBound() {
+ throw new Unreachable("Instruction must specify size");
+ }
+
public final int acceptCompareTo(
CfInstruction o, CompareToVisitor visitor, CfCompareHelper helper) {
int diff = visitor.visitInt(getCompareToId(), o.getCompareToId());
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
index 9fb383a..8397bc6 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
@@ -112,6 +112,11 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ return opcode == Opcodes.INVOKEINTERFACE ? 5 : 3;
+ }
+
+ @Override
public void print(CfPrinter printer) {
printer.print(this);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java b/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
index 2082290..a02060b 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
@@ -92,6 +92,11 @@
bsmArgs);
}
+ @Override
+ public int bytecodeSizeUpperBound() {
+ return 5;
+ }
+
private Object decodeBootstrapArgument(DexValue value, NamingLens lens) {
switch (value.getValueKind()) {
case DOUBLE:
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java b/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
index 51829ec..bc866cb 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
@@ -62,6 +62,11 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ throw error();
+ }
+
+ @Override
public void print(CfPrinter printer) {
printer.print(this);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLabel.java b/src/main/java/com/android/tools/r8/cf/code/CfLabel.java
index 1f611b1..9e3b1ee 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfLabel.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfLabel.java
@@ -74,6 +74,11 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ return 0;
+ }
+
+ @Override
public void buildIR(IRBuilder builder, CfState state, CfSourceCode code) {
// Intentionally left empty.
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLoad.java b/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
index 4f9a4db..99a32da 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
@@ -88,6 +88,12 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ // xload_0 .. xload_3, xload or wide xload, where x is a, i, f, l or d
+ return var <= 3 ? 1 : ((var < 256) ? 2 : 4);
+ }
+
+ @Override
public void print(CfPrinter printer) {
printer.print(this);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java b/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java
index 71e31d8..2407b10 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java
@@ -137,6 +137,11 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ return 1;
+ }
+
+ @Override
public void buildIR(IRBuilder builder, CfState state, CfSourceCode code) {
int right = state.pop().register;
int left = state.pop().register;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java b/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java
index 557d380..11df4ee 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java
@@ -62,6 +62,11 @@
visitor.visitInsn(getAsmOpcode());
}
+ @Override
+ public int bytecodeSizeUpperBound() {
+ return 1;
+ }
+
private int getAsmOpcode() {
return type == Type.ENTER ? Opcodes.MONITORENTER : Opcodes.MONITOREXIT;
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java b/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
index 33fed6e..509e0cf 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
@@ -93,6 +93,11 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ return 4;
+ }
+
+ @Override
public void print(CfPrinter printer) {
printer.print(this);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNeg.java b/src/main/java/com/android/tools/r8/cf/code/CfNeg.java
index a2621a8..da12fc5 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNeg.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNeg.java
@@ -64,6 +64,11 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ return 1;
+ }
+
+ @Override
public void print(CfPrinter printer) {
printer.print(this);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNew.java b/src/main/java/com/android/tools/r8/cf/code/CfNew.java
index 95deb22..b4c070a 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNew.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNew.java
@@ -82,6 +82,11 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ return 3;
+ }
+
+ @Override
public void print(CfPrinter printer) {
printer.print(this);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java b/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
index 50f82d0..5149789 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
@@ -128,6 +128,11 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ return 2;
+ }
+
+ @Override
public void print(CfPrinter printer) {
printer.print(this);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNewUnboxedEnum.java b/src/main/java/com/android/tools/r8/cf/code/CfNewUnboxedEnum.java
index 0d283d4..0c75328 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNewUnboxedEnum.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNewUnboxedEnum.java
@@ -85,6 +85,11 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ throw new Unreachable();
+ }
+
+ @Override
public void print(CfPrinter printer) {
printer.print(this);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNop.java b/src/main/java/com/android/tools/r8/cf/code/CfNop.java
index 3518f2a..f77241e 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNop.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNop.java
@@ -50,6 +50,11 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ return 1;
+ }
+
+ @Override
public void print(CfPrinter printer) {
printer.print(this);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java b/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java
index 13c737d..b8fe9c1 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java
@@ -74,6 +74,11 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ return 1;
+ }
+
+ @Override
public void print(CfPrinter printer) {
printer.print(this);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfPosition.java b/src/main/java/com/android/tools/r8/cf/code/CfPosition.java
index e7bf24a..6f82c07 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfPosition.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfPosition.java
@@ -63,6 +63,11 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ return 0;
+ }
+
+ @Override
public void print(CfPrinter printer) {
printer.print(this);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfRecordFieldValues.java b/src/main/java/com/android/tools/r8/cf/code/CfRecordFieldValues.java
index ec9b7df..f8fad92 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfRecordFieldValues.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfRecordFieldValues.java
@@ -54,6 +54,11 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ throw new Unreachable();
+ }
+
+ @Override
public CfRecordFieldValues asRecordFieldValues() {
return this;
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfReturn.java b/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
index 68038a4..d06db87 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
@@ -67,6 +67,11 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ return 1;
+ }
+
+ @Override
public boolean isJump() {
return true;
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java b/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java
index 9072b97..d492b04 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java
@@ -55,6 +55,11 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ return 1;
+ }
+
+ @Override
public void print(CfPrinter printer) {
printer.print(this);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java
index 289846f..366033d 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java
@@ -108,6 +108,11 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ return 1;
+ }
+
+ @Override
public void print(CfPrinter printer) {
printer.print(this);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStore.java b/src/main/java/com/android/tools/r8/cf/code/CfStore.java
index b096223..616ed84 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStore.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStore.java
@@ -91,6 +91,12 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ // xstore_0 .. xstore_3, xstore or wide xstore, where x is a, i, f, l or d
+ return var <= 3 ? 1 : ((var < 256) ? 2 : 4);
+ }
+
+ @Override
public void print(CfPrinter printer) {
printer.print(this);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java b/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java
index 6321c35..a86bcd1 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
@@ -121,6 +122,20 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ switch (kind) {
+ case LOOKUP:
+ return 8 + keys.length * 8;
+ case TABLE:
+ int min = keys[0];
+ int max = min + targets.size() - 1;
+ return 16 + (max - min + 1) * 4;
+ default:
+ throw new Unreachable();
+ }
+ }
+
+ @Override
public void print(CfPrinter printer) {
printer.print(this);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfThrow.java b/src/main/java/com/android/tools/r8/cf/code/CfThrow.java
index fc36a53..6e5eb78 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfThrow.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfThrow.java
@@ -66,6 +66,11 @@
}
@Override
+ public int bytecodeSizeUpperBound() {
+ return 1;
+ }
+
+ @Override
public void print(CfPrinter printer) {
printer.print(this);
}
diff --git a/src/main/java/com/android/tools/r8/debuginfo/DebugRepresentation.java b/src/main/java/com/android/tools/r8/debuginfo/DebugRepresentation.java
index 7a33b3c..173ddd1 100644
--- a/src/main/java/com/android/tools/r8/debuginfo/DebugRepresentation.java
+++ b/src/main/java/com/android/tools/r8/debuginfo/DebugRepresentation.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.LebUtils;
@@ -79,18 +80,19 @@
// (the sum of the normal debug info for all methods sharing the same max pc and param count.)
Int2ReferenceMap<CostSummary> paramCountToCosts = new Int2ReferenceOpenHashMap<>();
for (DexProgramClass clazz : file.classes()) {
- IdentityHashMap<DexString, List<DexEncodedMethod>> overloads =
+ IdentityHashMap<DexString, List<ProgramMethod>> overloads =
LineNumberOptimizer.groupMethodsByRenamedName(graphLens, namingLens, clazz);
- for (List<DexEncodedMethod> methods : overloads.values()) {
+ for (List<ProgramMethod> methods : overloads.values()) {
if (methods.size() != 1) {
// Never use PC info for overloaded methods. They need distinct lines to disambiguate.
continue;
}
- DexEncodedMethod method = methods.get(0);
- if (!isPcCandidate(method)) {
+ ProgramMethod method = methods.get(0);
+ DexEncodedMethod definition = method.getDefinition();
+ if (!isPcCandidate(definition)) {
continue;
}
- DexCode code = method.getCode().asDexCode();
+ DexCode code = definition.getCode().asDexCode();
DexDebugInfo debugInfo = code.getDebugInfo();
Instruction lastInstruction = getLastExecutableInstruction(code);
if (lastInstruction == null) {
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 3bb7190..1e62a10 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -20,6 +20,7 @@
import com.android.tools.r8.debuginfo.DebugRepresentation;
import com.android.tools.r8.debuginfo.DebugRepresentation.DebugRepresentationPredicate;
import com.android.tools.r8.dex.FileWriter.ByteBufferResult;
+import com.android.tools.r8.dex.VirtualFile.FilePerInputClassDistributor;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.features.FeatureSplitConfiguration.DataResourceProvidersAndConsumer;
import com.android.tools.r8.graph.AppServices;
@@ -51,6 +52,7 @@
import com.android.tools.r8.utils.Box;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.ExceptionUtils;
+import com.android.tools.r8.utils.InternalGlobalSyntheticsProgramConsumer.InternalGlobalSyntheticsDexConsumer;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.OriginalSourceFiles;
import com.android.tools.r8.utils.PredicateUtils;
@@ -85,8 +87,10 @@
private final Predicate<DexType> isTypeMissing;
public List<Marker> markers;
public List<DexString> markerStrings;
+ public Set<VirtualFile> globalSyntheticFiles;
public DexIndexedConsumer programConsumer;
+ public InternalGlobalSyntheticsDexConsumer globalsSyntheticsConsumer;
private static class SortAnnotations extends MixedSectionCollection {
@@ -179,20 +183,47 @@
private List<VirtualFile> distribute(ExecutorService executorService)
throws ExecutionException, IOException {
+ Collection<DexProgramClass> classes = appView.appInfo().classes();
+ Collection<DexProgramClass> globalSynthetics = new ArrayList<>();
+ if (appView.options().intermediate && appView.options().hasGlobalSyntheticsConsumer()) {
+ Collection<DexProgramClass> allClasses = classes;
+ classes = new ArrayList<>(allClasses.size());
+ for (DexProgramClass clazz : allClasses) {
+ if (appView.getSyntheticItems().isGlobalSyntheticClass(clazz)) {
+ globalSynthetics.add(clazz);
+ } else {
+ classes.add(clazz);
+ }
+ }
+ }
+
// Distribute classes into dex files.
VirtualFile.Distributor distributor;
if (options.isGeneratingDexFilePerClassFile()) {
- distributor = new VirtualFile.FilePerInputClassDistributor(this,
- options.getDexFilePerClassFileConsumer().combineSyntheticClassesWithPrimaryClass());
+ distributor =
+ new VirtualFile.FilePerInputClassDistributor(
+ this,
+ classes,
+ options.getDexFilePerClassFileConsumer().combineSyntheticClassesWithPrimaryClass());
} else if (!options.canUseMultidex()
&& options.mainDexKeepRules.isEmpty()
&& appView.appInfo().getMainDexInfo().isEmpty()
&& options.enableMainDexListCheck) {
- distributor = new VirtualFile.MonoDexDistributor(this, options);
+ distributor = new VirtualFile.MonoDexDistributor(this, classes, options);
} else {
- distributor = new VirtualFile.FillFilesDistributor(this, options, executorService);
+ distributor = new VirtualFile.FillFilesDistributor(this, classes, options, executorService);
}
- return distributor.run();
+
+ List<VirtualFile> virtualFiles = distributor.run();
+ if (!globalSynthetics.isEmpty()) {
+ List<VirtualFile> files =
+ new FilePerInputClassDistributor(this, globalSynthetics, false).run();
+ globalSyntheticFiles = new HashSet<>(files);
+ virtualFiles.addAll(globalSyntheticFiles);
+ globalsSyntheticsConsumer =
+ new InternalGlobalSyntheticsDexConsumer(options.getGlobalSyntheticsConsumer());
+ }
+ return virtualFiles;
}
/**
@@ -330,6 +361,9 @@
executorService);
merger.add(timings);
merger.end();
+ if (globalsSyntheticsConsumer != null) {
+ globalsSyntheticsConsumer.finished(options.reporter);
+ }
}
// A consumer can manage the generated keep rules.
@@ -460,7 +494,11 @@
ProgramConsumer consumer;
ByteBufferProvider byteBufferProvider;
- if (programConsumer != null) {
+
+ if (globalSyntheticFiles != null && globalSyntheticFiles.contains(virtualFile)) {
+ consumer = globalsSyntheticsConsumer;
+ byteBufferProvider = globalsSyntheticsConsumer;
+ } else if (programConsumer != null) {
consumer = programConsumer;
byteBufferProvider = programConsumer;
} else if (virtualFile.getPrimaryClassDescriptor() != null) {
@@ -777,7 +815,7 @@
mapping,
application.dexItemFactory,
options.testing.forceJumboStringProcessing);
- method.getDefinition().setCode(rewrittenCode.asCode(), appView);
+ method.setCode(rewrittenCode.asCode(), appView);
});
}
}
diff --git a/src/main/java/com/android/tools/r8/dex/CodeToKeep.java b/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
index 3e33ca8..7bfd947 100644
--- a/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
+++ b/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
@@ -25,6 +25,7 @@
static CodeToKeep createCodeToKeep(InternalOptions options, NamingLens namingLens) {
if ((!namingLens.hasPrefixRewritingLogic()
+ && options.machineDesugaredLibrarySpecification.getMaintainType().isEmpty()
&& !options.machineDesugaredLibrarySpecification.hasEmulatedInterfaces())
|| options.isDesugaredLibraryCompilation()
|| options.testing.enableExperimentalDesugaredLibraryKeepRuleGenerator) {
@@ -67,6 +68,7 @@
private boolean shouldKeep(DexType type) {
return namingLens.prefixRewrittenType(type) != null
+ || options.machineDesugaredLibrarySpecification.getMaintainType().contains(type)
|| options.machineDesugaredLibrarySpecification.isCustomConversionRewrittenType(type)
|| options.machineDesugaredLibrarySpecification.isEmulatedInterfaceRewrittenType(type)
// TODO(b/158632510): This should prefix match on DexString.
diff --git a/src/main/java/com/android/tools/r8/dex/VirtualFile.java b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
index 7d88ac7..827f43bd 100644
--- a/src/main/java/com/android/tools/r8/dex/VirtualFile.java
+++ b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
@@ -307,6 +307,7 @@
}
public abstract List<VirtualFile> run() throws ExecutionException, IOException;
+
}
/**
@@ -316,11 +317,15 @@
* may then be distributed in several individual virtual files.
*/
public static class FilePerInputClassDistributor extends Distributor {
+ private final Collection<DexProgramClass> classes;
private final boolean combineSyntheticClassesWithPrimaryClass;
- FilePerInputClassDistributor(ApplicationWriter writer,
+ FilePerInputClassDistributor(
+ ApplicationWriter writer,
+ Collection<DexProgramClass> classes,
boolean combineSyntheticClassesWithPrimaryClass) {
super(writer);
+ this.classes = classes;
this.combineSyntheticClassesWithPrimaryClass = combineSyntheticClassesWithPrimaryClass;
}
@@ -329,7 +334,7 @@
HashMap<DexProgramClass, VirtualFile> files = new HashMap<>();
Collection<DexProgramClass> synthetics = new ArrayList<>();
// Assign dedicated virtual files for all program classes.
- for (DexProgramClass clazz : appView.appInfo().classes()) {
+ for (DexProgramClass clazz : classes) {
// TODO(b/181636450): Simplify this making use of the assumption that synthetics are never
// duplicated.
if (!combineSyntheticClassesWithPrimaryClass
@@ -370,9 +375,11 @@
protected final VirtualFile mainDexFile;
protected final InternalOptions options;
- DistributorBase(ApplicationWriter writer, InternalOptions options) {
+ DistributorBase(
+ ApplicationWriter writer, Collection<DexProgramClass> classes, InternalOptions options) {
super(writer);
this.options = options;
+ this.classes = SetUtils.newIdentityHashSet(classes);
// Create the primary dex file. The distribution will add more if needed.
mainDexFile = new VirtualFile(0, writer.appView, writer.namingLens);
@@ -380,7 +387,6 @@
virtualFiles.add(mainDexFile);
addMarkers(mainDexFile);
- classes = SetUtils.newIdentityHashSet(appView.appInfo().classes());
originalNames =
computeOriginalNameMapping(
classes, appView.graphLens(), appView.appInfo().app().getProguardMap());
@@ -513,9 +519,12 @@
public static class FillFilesDistributor extends DistributorBase {
private final ExecutorService executorService;
- FillFilesDistributor(ApplicationWriter writer, InternalOptions options,
+ FillFilesDistributor(
+ ApplicationWriter writer,
+ Collection<DexProgramClass> classes,
+ InternalOptions options,
ExecutorService executorService) {
- super(writer, options);
+ super(writer, classes, options);
this.executorService = executorService;
}
@@ -576,8 +585,9 @@
}
public static class MonoDexDistributor extends DistributorBase {
- MonoDexDistributor(ApplicationWriter writer, InternalOptions options) {
- super(writer, options);
+ MonoDexDistributor(
+ ApplicationWriter writer, Collection<DexProgramClass> classes, InternalOptions options) {
+ super(writer, classes, options);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/errors/MissingGlobalSyntheticsConsumerDiagnostic.java b/src/main/java/com/android/tools/r8/errors/MissingGlobalSyntheticsConsumerDiagnostic.java
new file mode 100644
index 0000000..ff99d05
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/errors/MissingGlobalSyntheticsConsumerDiagnostic.java
@@ -0,0 +1,34 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.errors;
+
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.position.Position;
+
+public class MissingGlobalSyntheticsConsumerDiagnostic implements DesugarDiagnostic {
+
+ private final String generatingReason;
+
+ public MissingGlobalSyntheticsConsumerDiagnostic(String generatingReason) {
+ this.generatingReason = generatingReason;
+ }
+
+ @Override
+ public Origin getOrigin() {
+ return Origin.unknown();
+ }
+
+ @Override
+ public Position getPosition() {
+ return Position.UNKNOWN;
+ }
+
+ @Override
+ public String getDiagnosticMessage() {
+ return "Invalid build configuration. "
+ + "Attempt to create a global synthetic for '"
+ + generatingReason
+ + "' without a global-synthetics consumer.";
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/AbstractAccessContexts.java b/src/main/java/com/android/tools/r8/graph/AbstractAccessContexts.java
index 616fcf5..3e180df 100644
--- a/src/main/java/com/android/tools/r8/graph/AbstractAccessContexts.java
+++ b/src/main/java/com/android/tools/r8/graph/AbstractAccessContexts.java
@@ -58,6 +58,10 @@
abstract int getNumberOfAccessContexts();
+ public final boolean hasAccesses() {
+ return !isEmpty();
+ }
+
public boolean isBottom() {
return false;
}
@@ -66,7 +70,7 @@
return false;
}
- abstract boolean isEmpty();
+ public abstract boolean isEmpty();
public ConcreteAccessContexts asConcrete() {
return null;
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java b/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
index 4ecd71c..f5cb1a3 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
@@ -8,12 +8,6 @@
import static com.android.tools.r8.utils.TraversalContinuation.doContinue;
import com.android.tools.r8.features.ClassToFeatureSplitMap;
-import com.android.tools.r8.graph.MethodResolutionResult.ArrayCloneMethodResult;
-import com.android.tools.r8.graph.MethodResolutionResult.ClassNotFoundResult;
-import com.android.tools.r8.graph.MethodResolutionResult.IllegalAccessOrNoSuchMethodResult;
-import com.android.tools.r8.graph.MethodResolutionResult.IncompatibleClassResult;
-import com.android.tools.r8.graph.MethodResolutionResult.NoSuchMethodResult;
-import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
import com.android.tools.r8.ir.analysis.type.InterfaceCollection;
import com.android.tools.r8.ir.analysis.type.InterfaceCollection.Builder;
import com.android.tools.r8.ir.desugar.LambdaDescriptor;
@@ -21,7 +15,6 @@
import com.android.tools.r8.shaking.MissingClasses;
import com.android.tools.r8.synthesis.CommittedItems;
import com.android.tools.r8.synthesis.SyntheticItems;
-import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.Pair;
import com.android.tools.r8.utils.TraversalContinuation;
import com.android.tools.r8.utils.TriConsumer;
@@ -30,12 +23,9 @@
import com.google.common.collect.Sets;
import java.util.ArrayDeque;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.Deque;
-import java.util.LinkedHashMap;
import java.util.List;
-import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
@@ -540,12 +530,18 @@
* may be abstract.
*/
public DexClassAndMethod lookupMaximallySpecificMethod(DexClass clazz, DexMethod method) {
- return lookupMaximallySpecificTarget(clazz, method);
+ return new MethodResolution(this::definitionFor, dexItemFactory())
+ .lookupMaximallySpecificTarget(clazz, method);
}
- public DexClassAndMethod lookupMaximallySpecificMethod(
- LambdaDescriptor lambda, DexMethod method) {
- return lookupMaximallySpecificTarget(lambda, method);
+ MethodResolutionResult resolveMaximallySpecificTarget(DexClass clazz, DexMethod method) {
+ return new MethodResolution(this::definitionFor, dexItemFactory())
+ .resolveMaximallySpecificTarget(clazz, method);
+ }
+
+ MethodResolutionResult resolveMaximallySpecificTarget(LambdaDescriptor lambda, DexMethod method) {
+ return new MethodResolution(this::definitionFor, dexItemFactory())
+ .resolveMaximallySpecificTarget(lambda, method);
}
/**
@@ -643,359 +639,111 @@
}
/**
- * Implements resolution of a method descriptor.
- *
- * <p>This method will query the definition of the holder to decide on which resolution to use. If
- * the holder is an interface, it delegates to {@link #resolveMethodOnInterface(DexType,
- * DexMethod)}, otherwise {@link #resolveMethodOnClass(DexMethod, DexType)} is used.
+ * This method will query the definition of the holder to decide on which resolution to use.
*
* <p>This is to overcome the shortcoming of the DEX file format that does not allow to encode the
* kind of a method reference.
*/
public MethodResolutionResult unsafeResolveMethodDueToDexFormat(DexMethod method) {
assert checkIfObsolete();
- DexType holder = method.holder;
- if (holder.isArrayType()) {
- return resolveMethodOnArray(holder, method.getProto(), method.getName());
- }
- DexClass definition = definitionFor(holder);
- if (definition == null) {
- return ClassNotFoundResult.INSTANCE;
- }
- return resolveMethodOn(definition, method);
+ return new MethodResolution(this::definitionFor, dexItemFactory())
+ .unsafeResolveMethodDueToDexFormat(method);
}
- public MethodResolutionResult resolveMethod(DexMethod method, boolean isInterface) {
- return isInterface
- ? resolveMethodOnInterface(method.holder, method)
- : resolveMethodOnClass(method, method.holder);
+ public MethodResolutionResult resolveMethod(DexMethod invokedMethod, boolean isInterface) {
+ assert checkIfObsolete();
+ return resolveMethodOn(invokedMethod.getHolderType(), invokedMethod, isInterface);
}
- public MethodResolutionResult resolveMethodOn(DexClass holder, DexMethod method) {
- return resolveMethodOn(holder, method.getProto(), method.getName());
- }
-
- public MethodResolutionResult resolveMethodOn(DexClass holder, DexMethodSignature method) {
- return resolveMethodOn(holder, method.getProto(), method.getName());
+ public MethodResolutionResult resolveMethodOn(DexClass clazz, DexMethod method) {
+ assert checkIfObsolete();
+ return clazz.isInterface()
+ ? resolveMethodOnInterface(clazz, method)
+ : resolveMethodOnClass(clazz, method);
}
public MethodResolutionResult resolveMethodOn(
- DexClass holder, DexProto methodProto, DexString methodName) {
- return holder.isInterface()
- ? resolveMethodOnInterface(holder, methodProto, methodName)
- : resolveMethodOnClass(methodProto, methodName, holder);
+ DexClass clazz, DexMethodSignature methodSignature) {
+ assert checkIfObsolete();
+ return clazz.isInterface()
+ ? resolveMethodOnInterface(clazz, methodSignature)
+ : resolveMethodOnClass(clazz, methodSignature);
}
- /**
- * Implements resolution of a method descriptor against a target type.
- *
- * <p>The boolean isInterface parameter denotes if the method reference is an interface method
- * reference, and if so method resolution is done according to interface method resolution.
- *
- * @param holder Type at which to initiate the resolution.
- * @param method Method descriptor for resolution (the field method.holder is ignored).
- * @param isInterface Indicates if resolution is to be done according to class or interface.
- * @return The result of resolution.
- */
public MethodResolutionResult resolveMethodOn(
DexType holder, DexMethod method, boolean isInterface) {
assert checkIfObsolete();
return isInterface
? resolveMethodOnInterface(holder, method)
- : resolveMethodOnClass(method, holder);
+ : resolveMethodOnClass(holder, method);
}
- /**
- * Implements resolution of a method descriptor against an array type.
- *
- * <p>See <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-10.html#jls-10.7">Section
- * 10.7 of the Java Language Specification</a>. All invokations will have target java.lang.Object
- * except clone which has no target.
- */
- private MethodResolutionResult resolveMethodOnArray(
- DexType holder, DexProto methodProto, DexString methodName) {
+ public MethodResolutionResult resolveMethodOnClassHolder(DexMethod method) {
assert checkIfObsolete();
- assert holder.isArrayType();
- if (methodName == dexItemFactory().cloneMethodName) {
- return ArrayCloneMethodResult.INSTANCE;
- } else {
- return resolveMethodOnClass(methodProto, methodName, dexItemFactory().objectType);
- }
+ return resolveMethodOnClass(method.getHolderType(), method);
}
- public MethodResolutionResult resolveMethodOnClass(DexMethod method) {
- return resolveMethodOnClass(method.getProto(), method.getName(), method.getHolderType());
- }
-
- public MethodResolutionResult resolveMethodOnClass(DexMethod method, DexType holder) {
- return resolveMethodOnClass(method.getProto(), method.getName(), holder);
- }
-
- /**
- * Implements resolution of a method descriptor against a class type.
- *
- * <p>See <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.3">
- * Section 5.4.3.3 of the JVM Spec</a>.
- *
- * <p>The resolved method is not the method that will actually be invoked. Which methods gets
- * invoked depends on the invoke instruction used. However, it is always safe to rewrite any
- * invoke on the given descriptor to a corresponding invoke on the resolved descriptor, as the
- * resolved method is used as basis for dispatch.
- */
- public MethodResolutionResult resolveMethodOnClass(
- DexProto methodProto, DexString methodName, DexType holder) {
+ public MethodResolutionResult resolveMethodOnClass(DexType holder, DexMethod method) {
assert checkIfObsolete();
- if (holder.isArrayType()) {
- return resolveMethodOnArray(holder, methodProto, methodName);
- }
- DexClass clazz = definitionFor(holder);
- if (clazz == null) {
- return ClassNotFoundResult.INSTANCE;
- }
- // Step 1: If holder is an interface, resolution fails with an ICCE. We return null.
- if (clazz.isInterface()) {
- return IncompatibleClassResult.INSTANCE;
- }
- return resolveMethodOnClass(methodProto, methodName, clazz);
+ return resolveMethodOnClass(holder, method.getProto(), method.getName());
}
- public MethodResolutionResult resolveMethodOnClass(DexMethodSignature method, DexType holder) {
+ public MethodResolutionResult resolveMethodOnClass(DexType holder, DexMethodSignature signature) {
assert checkIfObsolete();
- if (holder.isArrayType()) {
- return resolveMethodOnArray(holder, method.getProto(), method.getName());
- }
- DexClass clazz = definitionFor(holder);
- if (clazz == null) {
- return ClassNotFoundResult.INSTANCE;
- }
- // Step 1: If holder is an interface, resolution fails with an ICCE. We return null.
- if (clazz.isInterface()) {
- return IncompatibleClassResult.INSTANCE;
- }
- return resolveMethodOnClass(method, clazz);
- }
-
- public MethodResolutionResult resolveMethodOnClass(DexMethod method, DexClass clazz) {
- return resolveMethodOnClass(method.getProto(), method.getName(), clazz);
- }
-
- public MethodResolutionResult resolveMethodOnClass(DexMethodSignature method, DexClass clazz) {
- return resolveMethodOnClass(method.getProto(), method.getName(), clazz);
+ return resolveMethodOnClass(holder, signature.getProto(), signature.getName());
}
public MethodResolutionResult resolveMethodOnClass(
- DexProto methodProto, DexString methodName, DexClass clazz) {
+ DexType holder, DexProto proto, DexString name) {
assert checkIfObsolete();
- assert !clazz.isInterface();
- // Step 2:
- MethodResolutionResult result =
- resolveMethodOnClassStep2(clazz, methodProto, methodName, clazz);
- if (result != null) {
- return result;
- }
- // Finally Step 3:
- return resolveMethodStep3(clazz, methodProto, methodName);
+ return new MethodResolution(this::definitionFor, dexItemFactory())
+ .resolveMethodOnClass(holder, proto, name);
}
- /**
- * Implements step 2 of method resolution on classes as per <a
- * href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.3">Section
- * 5.4.3.3 of the JVM Spec</a>.
- */
- private MethodResolutionResult resolveMethodOnClassStep2(
- DexClass clazz,
- DexProto methodProto,
- DexString methodName,
- DexClass initialResolutionHolder) {
- // Pt. 1: Signature polymorphic method check.
- // See also <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.9">
- // Section 2.9 of the JVM Spec</a>.
- DexEncodedMethod result = clazz.lookupSignaturePolymorphicMethod(methodName, dexItemFactory());
- if (result != null) {
- return new SingleResolutionResult(initialResolutionHolder, clazz, result);
- }
- // Pt 2: Find a method that matches the descriptor.
- result = clazz.lookupMethod(methodProto, methodName);
- if (result != null) {
- // If the resolved method is private, then it can only be accessed if the symbolic reference
- // that initiated the resolution was the type at which the method resolved on. If that is not
- // the case, then the error is either an IllegalAccessError, or in the case where access is
- // allowed because of nests, a NoSuchMethodError. Which error cannot be determined without
- // knowing the calling context.
- if (result.isPrivateMethod() && clazz != initialResolutionHolder) {
- return new IllegalAccessOrNoSuchMethodResult(initialResolutionHolder, result);
- }
- return new SingleResolutionResult(initialResolutionHolder, clazz, result);
- }
- // Pt 3: Apply step two to direct superclass of holder.
- if (clazz.superType != null) {
- DexClass superClass = definitionFor(clazz.superType);
- if (superClass != null) {
- return resolveMethodOnClassStep2(
- superClass, methodProto, methodName, initialResolutionHolder);
- }
- }
- return null;
- }
-
- /**
- * Implements step 3 of <a
- * href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.3">Section
- * 5.4.3.3 of the JVM Spec</a>. As this is the same for interfaces and classes, we share one
- * implementation.
- */
- private MethodResolutionResult resolveMethodStep3(
- DexClass clazz, DexProto methodProto, DexString methodName) {
- MaximallySpecificMethodsBuilder builder = new MaximallySpecificMethodsBuilder();
- resolveMethodStep3Helper(methodProto, methodName, clazz, builder);
- return builder.resolve(clazz);
- }
-
- MethodResolutionResult resolveMaximallySpecificTarget(DexClass clazz, DexMethod method) {
- return resolveMaximallySpecificTargetHelper(clazz, method).resolve(clazz);
- }
-
- private MaximallySpecificMethodsBuilder resolveMaximallySpecificTargetHelper(
- DexClass clazz, DexMethod method) {
- MaximallySpecificMethodsBuilder builder = new MaximallySpecificMethodsBuilder();
- resolveMethodStep3Helper(method.getProto(), method.getName(), clazz, builder);
- return builder;
- }
-
- MethodResolutionResult resolveMaximallySpecificTarget(LambdaDescriptor lambda, DexMethod method) {
- return resolveMaximallySpecificTargetHelper(lambda, method).internalResolve(null);
- }
-
- private MaximallySpecificMethodsBuilder resolveMaximallySpecificTargetHelper(
- LambdaDescriptor lambda, DexMethod method) {
- MaximallySpecificMethodsBuilder builder = new MaximallySpecificMethodsBuilder();
- resolveMethodStep3Helper(
- method.getProto(),
- method.getName(),
- dexItemFactory().objectType,
- lambda.interfaces,
- builder);
- return builder;
- }
-
- // Non-private lookup (ie, not resolution) to find interface targets.
- DexClassAndMethod lookupMaximallySpecificTarget(DexClass clazz, DexMethod method) {
- return resolveMaximallySpecificTargetHelper(clazz, method).lookup();
- }
-
- // Non-private lookup (ie, not resolution) to find interface targets.
- DexClassAndMethod lookupMaximallySpecificTarget(LambdaDescriptor lambda, DexMethod method) {
- return resolveMaximallySpecificTargetHelper(lambda, method).lookup();
- }
-
- /** Helper method that builds the set of maximally specific methods. */
- private void resolveMethodStep3Helper(
- DexProto methodProto,
- DexString methodName,
- DexClass clazz,
- MaximallySpecificMethodsBuilder builder) {
- resolveMethodStep3Helper(
- methodProto, methodName, clazz.superType, Arrays.asList(clazz.interfaces.values), builder);
- }
-
- private void resolveMethodStep3Helper(
- DexProto methodProto,
- DexString methodName,
- DexType superType,
- List<DexType> interfaces,
- MaximallySpecificMethodsBuilder builder) {
- for (DexType iface : interfaces) {
- DexClass definition = definitionFor(iface);
- if (definition == null) {
- // Ignore missing interface definitions.
- continue;
- }
- assert definition.isInterface();
- DexEncodedMethod result = definition.lookupMethod(methodProto, methodName);
- if (isMaximallySpecificCandidate(result)) {
- // The candidate is added and doing so will prohibit shadowed methods from being in the set.
- builder.addCandidate(definition, result, this);
- } else {
- // Look at the super-interfaces of this class and keep searching.
- resolveMethodStep3Helper(methodProto, methodName, definition, builder);
- }
- }
- // Now look at indirect super interfaces.
- if (superType != null) {
- DexClass superClass = definitionFor(superType);
- if (superClass != null) {
- resolveMethodStep3Helper(methodProto, methodName, superClass, builder);
- }
- }
- }
-
- /**
- * A candidate for being a maximally specific method must have neither its private, nor its static
- * flag set. A candidate may still not be maximally specific, which entails that no subinterfaces
- * from also contribute with a candidate to the type. That is not determined by this method.
- */
- private boolean isMaximallySpecificCandidate(DexEncodedMethod method) {
- return method != null && !method.accessFlags.isPrivate() && !method.accessFlags.isStatic();
- }
-
- public MethodResolutionResult resolveMethodOnInterface(DexMethod method) {
- return resolveMethodOnInterface(method.holder, method);
- }
-
- /**
- * Implements resolution of a method descriptor against an interface type.
- *
- * <p>See <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.3">
- * Section 5.4.3.4 of the JVM Spec</a>.
- *
- * <p>The resolved method is not the method that will actually be invoked. Which methods gets
- * invoked depends on the invoke instruction used. However, it is always save to rewrite any
- * invoke on the given descriptor to a corresponding invoke on the resolved descriptor, as the
- * resolved method is used as basis for dispatch.
- */
- public MethodResolutionResult resolveMethodOnInterface(DexType holder, DexMethod desc) {
+ public MethodResolutionResult resolveMethodOnClass(DexClass clazz, DexMethod method) {
assert checkIfObsolete();
- if (holder.isArrayType()) {
- return IncompatibleClassResult.INSTANCE;
- }
- // Step 1: Lookup interface.
- DexClass definition = definitionFor(holder);
- // If the definition is not an interface, resolution fails with an ICCE. We just return the
- // empty result here.
- if (definition == null) {
- return ClassNotFoundResult.INSTANCE;
- }
- if (!definition.isInterface()) {
- return IncompatibleClassResult.INSTANCE;
- }
- return resolveMethodOnInterface(definition, desc);
+ return resolveMethodOnClass(clazz, method.getProto(), method.getName());
}
- public MethodResolutionResult resolveMethodOnInterface(DexClass definition, DexMethod desc) {
- return resolveMethodOnInterface(definition, desc.getProto(), desc.getName());
+ public MethodResolutionResult resolveMethodOnClass(DexClass clazz, DexMethodSignature signature) {
+ assert checkIfObsolete();
+ return resolveMethodOnClass(clazz, signature.getProto(), signature.getName());
+ }
+
+ public MethodResolutionResult resolveMethodOnClass(
+ DexClass clazz, DexProto proto, DexString name) {
+ assert checkIfObsolete();
+ return new MethodResolution(this::definitionFor, dexItemFactory())
+ .resolveMethodOnClass(clazz, proto, name);
+ }
+
+ public MethodResolutionResult resolveMethodOnInterfaceHolder(DexMethod method) {
+ assert checkIfObsolete();
+ return resolveMethodOnInterface(method.getHolderType(), method);
+ }
+
+ public MethodResolutionResult resolveMethodOnInterface(DexType holder, DexMethod method) {
+ assert checkIfObsolete();
+ return new MethodResolution(this::definitionFor, dexItemFactory())
+ .resolveMethodOnInterface(holder, method.getProto(), method.getName());
+ }
+
+ public MethodResolutionResult resolveMethodOnInterface(DexClass clazz, DexMethod method) {
+ assert checkIfObsolete();
+ return resolveMethodOnInterface(clazz, method.getProto(), method.getName());
}
public MethodResolutionResult resolveMethodOnInterface(
- DexClass definition, DexProto methodProto, DexString methodName) {
+ DexClass clazz, DexMethodSignature methodSignature) {
assert checkIfObsolete();
- assert definition.isInterface();
- // Step 2: Look for exact method on interface.
- DexEncodedMethod result = definition.lookupMethod(methodProto, methodName);
- if (result != null) {
- return new SingleResolutionResult(definition, definition, result);
- }
- // Step 3: Look for matching method on object class.
- DexClass objectClass = definitionFor(dexItemFactory().objectType);
- if (objectClass == null) {
- return ClassNotFoundResult.INSTANCE;
- }
- result = objectClass.lookupMethod(methodProto, methodName);
- if (result != null && result.accessFlags.isPublic() && !result.accessFlags.isAbstract()) {
- return new SingleResolutionResult(definition, objectClass, result);
- }
- // Step 3: Look for maximally-specific superinterface methods or any interface definition.
- // This is the same for classes and interfaces.
- return resolveMethodStep3(definition, methodProto, methodName);
+ return resolveMethodOnInterface(clazz, methodSignature.getProto(), methodSignature.getName());
+ }
+
+ public MethodResolutionResult resolveMethodOnInterface(
+ DexClass clazz, DexProto proto, DexString name) {
+ assert checkIfObsolete();
+ return new MethodResolution(this::definitionFor, dexItemFactory())
+ .resolveMethodOnInterface(clazz, proto, name);
}
/**
@@ -1025,105 +773,4 @@
assert checkIfObsolete();
return new FieldResolution(this).resolveFieldOn(clazz, field);
}
-
- private static class MaximallySpecificMethodsBuilder {
-
- // The set of actual maximally specific methods.
- // This set is linked map so that in the case where a number of methods remain a deterministic
- // choice can be made. The map is from definition classes to their maximally specific method, or
- // in the case that a type has a candidate which is shadowed by a subinterface, the map will
- // map the class to a null entry, thus any addition to the map must check for key containment
- // prior to writing.
- LinkedHashMap<DexClass, DexEncodedMethod> maximallySpecificMethods = new LinkedHashMap<>();
-
- void addCandidate(DexClass holder, DexEncodedMethod method, AppInfo appInfo) {
- // If this candidate is already a candidate or it is shadowed, then no need to continue.
- if (maximallySpecificMethods.containsKey(holder)) {
- return;
- }
- maximallySpecificMethods.put(holder, method);
- // Prune exiting candidates and prohibit future candidates in the super hierarchy.
- assert holder.isInterface();
- assert holder.superType == appInfo.dexItemFactory().objectType;
- for (DexType iface : holder.interfaces.values) {
- markShadowed(iface, appInfo);
- }
- }
-
- private void markShadowed(DexType type, AppInfo appInfo) {
- if (type == null) {
- return;
- }
- DexClass clazz = appInfo.definitionFor(type);
- if (clazz == null) {
- return;
- }
- assert clazz.isInterface();
- assert clazz.superType == appInfo.dexItemFactory().objectType;
- // A null entry signifies that the candidate is shadowed blocking future candidates.
- // If the candidate is already shadowed at this type there is no need to shadow further up.
- if (maximallySpecificMethods.containsKey(clazz)
- && maximallySpecificMethods.get(clazz) == null) {
- return;
- }
- maximallySpecificMethods.put(clazz, null);
- for (DexType iface : clazz.interfaces.values) {
- markShadowed(iface, appInfo);
- }
- }
-
- DexClassAndMethod lookup() {
- return internalResolve(null).getResolutionPair();
- }
-
- MethodResolutionResult resolve(DexClass initialResolutionHolder) {
- assert initialResolutionHolder != null;
- return internalResolve(initialResolutionHolder);
- }
-
- private MethodResolutionResult internalResolve(DexClass initialResolutionHolder) {
- if (maximallySpecificMethods.isEmpty()) {
- return NoSuchMethodResult.INSTANCE;
- }
- // Fast path in the common case of a single method.
- if (maximallySpecificMethods.size() == 1) {
- return singleResultHelper(
- initialResolutionHolder, maximallySpecificMethods.entrySet().iterator().next());
- }
- Entry<DexClass, DexEncodedMethod> firstMaximallySpecificMethod = null;
- List<Entry<DexClass, DexEncodedMethod>> nonAbstractMethods =
- new ArrayList<>(maximallySpecificMethods.size());
- for (Entry<DexClass, DexEncodedMethod> entry : maximallySpecificMethods.entrySet()) {
- DexEncodedMethod method = entry.getValue();
- if (method == null) {
- // Ignore shadowed candidates.
- continue;
- }
- if (firstMaximallySpecificMethod == null) {
- firstMaximallySpecificMethod = entry;
- }
- if (method.isNonAbstractVirtualMethod()) {
- nonAbstractMethods.add(entry);
- }
- }
- // If there are no non-abstract methods, then any candidate will suffice as a target.
- // For deterministic resolution, we return the first mapped method (of the linked map).
- if (nonAbstractMethods.isEmpty()) {
- return singleResultHelper(initialResolutionHolder, firstMaximallySpecificMethod);
- }
- // If there is exactly one non-abstract method (a default method) it is the resolution target.
- if (nonAbstractMethods.size() == 1) {
- return singleResultHelper(initialResolutionHolder, nonAbstractMethods.get(0));
- }
- return IncompatibleClassResult.create(ListUtils.map(nonAbstractMethods, Entry::getValue));
- }
-
- private static SingleResolutionResult singleResultHelper(
- DexClass initialResolutionResult, Entry<DexClass, DexEncodedMethod> entry) {
- return new SingleResolutionResult(
- initialResolutionResult != null ? initialResolutionResult : entry.getKey(),
- entry.getKey(),
- entry.getValue());
- }
- }
}
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 db99838..300092c 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -697,9 +697,13 @@
// Even if we can compute isSubtype by having class hierarchy we may not be allowed to ask the
// question for all code paths in D8. Having the check for liveness ensure that we are in R8
// territory.
- return appInfo().hasLiveness()
- ? OptionalBool.of(appInfo().withLiveness().isSubtype(subtype, supertype))
- : OptionalBool.unknown();
+ if (hasClassHierarchy()) {
+ return OptionalBool.of(appInfo().withClassHierarchy().isSubtype(subtype, supertype));
+ }
+ if (subtype == supertype || supertype == dexItemFactory().objectType) {
+ return OptionalBool.TRUE;
+ }
+ return OptionalBool.unknown();
}
public boolean isCfByteCodePassThrough(DexEncodedMethod method) {
diff --git a/src/main/java/com/android/tools/r8/graph/CfCode.java b/src/main/java/com/android/tools/r8/graph/CfCode.java
index 4358a27..910d5f5 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -35,6 +35,8 @@
import com.android.tools.r8.ir.conversion.ExtraParameter;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.ThrowingMethodConversionOptions;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.ClassNameMapper;
@@ -60,7 +62,6 @@
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
-import java.util.Map.Entry;
import java.util.function.BiPredicate;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
@@ -310,6 +311,16 @@
return estimatedSizeForInlining() * Base5Format.SIZE;
}
+ public int bytecodeSizeUpperBound() {
+ int result = 0;
+ for (CfInstruction instruction : instructions) {
+ int delta = instruction.bytecodeSizeUpperBound();
+ assert delta > 0 || !instruction.emitsIR();
+ result += delta;
+ }
+ return result;
+ }
+
private int countNonStackOperations(int threshold) {
int result = 0;
for (CfInstruction instruction : instructions) {
@@ -443,8 +454,8 @@
}
if (parameterLabel != null) {
assert localVariables.isEmpty();
- Map<Integer, DebugLocalInfo> parameterInfo = method.getDefinition().getParameterInfo();
- for (Entry<Integer, DebugLocalInfo> entry : parameterInfo.entrySet()) {
+ Int2ReferenceMap<DebugLocalInfo> parameterInfo = method.getDefinition().getParameterInfo();
+ for (Int2ReferenceMap.Entry<DebugLocalInfo> entry : parameterInfo.int2ReferenceEntrySet()) {
writeLocalVariableEntry(
visitor,
graphLens,
@@ -452,7 +463,7 @@
entry.getValue(),
parameterLabel,
parameterLabel,
- entry.getKey());
+ entry.getIntKey());
}
} else {
for (LocalVariableInfo local : localVariables) {
@@ -503,10 +514,14 @@
}
@Override
- public IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
+ public IRCode buildIR(
+ ProgramMethod method,
+ AppView<?> appView,
+ Origin origin,
+ MutableMethodConversionOptions conversionOptions) {
verifyFramesOrRemove(method, appView, getCodeLens(appView));
return internalBuildPossiblyWithLocals(
- method, method, appView, appView.codeLens(), null, null, origin, null);
+ method, method, appView, appView.codeLens(), null, null, origin, null, conversionOptions);
}
@Override
@@ -531,7 +546,8 @@
valueNumberGenerator,
callerPosition,
origin,
- protoChanges);
+ protoChanges,
+ new ThrowingMethodConversionOptions(appView.options()));
}
private void verifyFramesOrRemove(ProgramMethod method, AppView<?> appView, GraphLens codeLens) {
@@ -552,8 +568,9 @@
NumberGenerator valueNumberGenerator,
Position callerPosition,
Origin origin,
- RewrittenPrototypeDescription protoChanges) {
- if (!method.getDefinition().keepLocals(appView.options())) {
+ RewrittenPrototypeDescription protoChanges,
+ MutableMethodConversionOptions conversionOptions) {
+ if (!method.keepLocals(appView)) {
return internalBuild(
Collections.emptyList(),
context,
@@ -563,7 +580,8 @@
valueNumberGenerator,
callerPosition,
origin,
- protoChanges);
+ protoChanges,
+ conversionOptions);
} else {
return internalBuildWithLocals(
context,
@@ -573,7 +591,8 @@
valueNumberGenerator,
callerPosition,
origin,
- protoChanges);
+ protoChanges,
+ conversionOptions);
}
}
@@ -586,7 +605,8 @@
NumberGenerator valueNumberGenerator,
Position callerPosition,
Origin origin,
- RewrittenPrototypeDescription protoChanges) {
+ RewrittenPrototypeDescription protoChanges,
+ MutableMethodConversionOptions conversionOptions) {
try {
return internalBuild(
Collections.unmodifiableList(localVariables),
@@ -597,7 +617,8 @@
valueNumberGenerator,
callerPosition,
origin,
- protoChanges);
+ protoChanges,
+ conversionOptions);
} catch (InvalidDebugInfoException e) {
appView.options().warningInvalidDebugInfo(method, origin, e);
return internalBuild(
@@ -609,7 +630,8 @@
valueNumberGenerator,
callerPosition,
origin,
- protoChanges);
+ protoChanges,
+ conversionOptions);
}
}
@@ -623,7 +645,8 @@
NumberGenerator valueNumberGenerator,
Position callerPosition,
Origin origin,
- RewrittenPrototypeDescription protoChanges) {
+ RewrittenPrototypeDescription protoChanges,
+ MutableMethodConversionOptions conversionOptions) {
CfSourceCode source =
new CfSourceCode(
this,
@@ -642,7 +665,7 @@
IRBuilder.createForInlining(
method, appView, codeLens, source, origin, valueNumberGenerator, protoChanges);
}
- return builder.build(context);
+ return builder.build(context, conversionOptions);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/graph/Code.java b/src/main/java/com/android/tools/r8/graph/Code.java
index 0f4233d..8152305 100644
--- a/src/main/java/com/android/tools/r8/graph/Code.java
+++ b/src/main/java/com/android/tools/r8/graph/Code.java
@@ -12,13 +12,22 @@
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.code.Position;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
public abstract class Code extends CachedHashValueDexItem {
- public abstract IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin);
+ public final IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
+ return buildIR(method, appView, origin, new MutableMethodConversionOptions(appView.options()));
+ }
+
+ public abstract IRCode buildIR(
+ ProgramMethod method,
+ AppView<?> appView,
+ Origin origin,
+ MutableMethodConversionOptions conversionOptions);
public IRCode buildInliningIR(
ProgramMethod context,
diff --git a/src/main/java/com/android/tools/r8/graph/DefaultInstanceInitializerCode.java b/src/main/java/com/android/tools/r8/graph/DefaultInstanceInitializerCode.java
index a544337..07fd8c4 100644
--- a/src/main/java/com/android/tools/r8/graph/DefaultInstanceInitializerCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DefaultInstanceInitializerCode.java
@@ -24,6 +24,8 @@
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.ThrowingMethodConversionOptions;
import com.android.tools.r8.ir.conversion.SyntheticStraightLineSourceCode;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.naming.NamingLens;
@@ -66,7 +68,7 @@
public static boolean canonicalizeCodeIfPossible(AppView<?> appView, ProgramMethod method) {
if (hasDefaultInstanceInitializerCode(method, appView)) {
- method.getDefinition().setCode(get(), appView);
+ method.setCode(get(), appView);
return true;
}
return false;
@@ -80,7 +82,7 @@
AppView<?> appView, ProgramMethod method, DexType superType) {
DexEncodedMethod definition = method.getDefinition();
assert definition.getCode().isDefaultInstanceInitializerCode();
- definition.setCode(get().toCfCode(method, appView.dexItemFactory(), superType), appView);
+ method.setCode(get().toCfCode(method, appView.dexItemFactory(), superType), appView);
}
private static boolean hasDefaultInstanceInitializerCode(
@@ -134,12 +136,16 @@
}
@Override
- public IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
+ public IRCode buildIR(
+ ProgramMethod method,
+ AppView<?> appView,
+ Origin origin,
+ MutableMethodConversionOptions conversionOptions) {
DexMethod originalMethod =
appView.graphLens().getOriginalMethodSignature(method.getReference());
DefaultInstanceInitializerSourceCode source =
new DefaultInstanceInitializerSourceCode(originalMethod);
- return IRBuilder.create(method, appView, source, origin).build(method);
+ return IRBuilder.create(method, appView, source, origin).build(method, conversionOptions);
}
@Override
@@ -158,7 +164,7 @@
new DefaultInstanceInitializerSourceCode(originalMethod, callerPosition);
return IRBuilder.createForInlining(
method, appView, codeLens, source, origin, valueNumberGenerator, protoChanges)
- .build(context);
+ .build(context, new ThrowingMethodConversionOptions(appView.options()));
}
@Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexCode.java b/src/main/java/com/android/tools/r8/graph/DexCode.java
index 3c3ce77..c99b310 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCode.java
@@ -13,7 +13,7 @@
import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexCode.TryHandler.TypeAddrPair;
-import com.android.tools.r8.graph.DexDebugEvent.SetInlineFrame;
+import com.android.tools.r8.graph.DexDebugEvent.SetPositionFrame;
import com.android.tools.r8.graph.DexDebugEvent.StartLocal;
import com.android.tools.r8.graph.DexDebugInfo.EventBasedDebugInfo;
import com.android.tools.r8.graph.bytecodemetadata.BytecodeInstructionMetadata;
@@ -26,6 +26,8 @@
import com.android.tools.r8.ir.conversion.DexSourceCode;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.ThrowingMethodConversionOptions;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.ArrayUtils;
@@ -277,6 +279,12 @@
DexMethod caller, DexMethod callee, DexItemFactory factory) {
Position callerPosition = SyntheticPosition.builder().setLine(0).setMethod(caller).build();
EventBasedDebugInfo eventBasedInfo = DexDebugInfo.convertToEventBased(this, factory);
+ Position inlinePosition =
+ SyntheticPosition.builder()
+ .setMethod(caller)
+ .setCallerPosition(callerPosition)
+ .disableLineCheck()
+ .build();
if (eventBasedInfo == null) {
// If the method has no debug info we generate a preamble position to denote the inlining.
// This is consistent with the building IR for inlining which will always ensure the method
@@ -285,22 +293,20 @@
0,
new DexString[callee.getArity()],
new DexDebugEvent[] {
- new DexDebugEvent.SetInlineFrame(callee, callerPosition), factory.zeroChangeDefaultEvent
+ new SetPositionFrame(inlinePosition), factory.zeroChangeDefaultEvent
});
}
DexDebugEvent[] oldEvents = eventBasedInfo.events;
DexDebugEvent[] newEvents = new DexDebugEvent[oldEvents.length + 1];
int i = 0;
- newEvents[i++] = new DexDebugEvent.SetInlineFrame(callee, callerPosition);
+ newEvents[i++] = new SetPositionFrame(inlinePosition);
for (DexDebugEvent event : oldEvents) {
- if (event instanceof SetInlineFrame) {
- SetInlineFrame oldFrame = (SetInlineFrame) event;
+ if (event instanceof SetPositionFrame) {
+ SetPositionFrame oldFrame = (SetPositionFrame) event;
+ assert oldFrame.getPosition() != null;
newEvents[i++] =
- new SetInlineFrame(
- oldFrame.callee,
- oldFrame.caller == null
- ? callerPosition
- : oldFrame.caller.withOutermostCallerPosition(callerPosition));
+ new SetPositionFrame(
+ oldFrame.getPosition().withOutermostCallerPosition(callerPosition));
} else {
newEvents[i++] = event;
}
@@ -366,7 +372,11 @@
}
@Override
- public IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
+ public IRCode buildIR(
+ ProgramMethod method,
+ AppView<?> appView,
+ Origin origin,
+ MutableMethodConversionOptions conversionOptions) {
DexSourceCode source =
new DexSourceCode(
this,
@@ -374,7 +384,7 @@
appView.graphLens().getOriginalMethodSignature(method.getReference()),
null,
appView.dexItemFactory());
- return IRBuilder.create(method, appView, source, origin).build(method);
+ return IRBuilder.create(method, appView, source, origin).build(method, conversionOptions);
}
@Override
@@ -396,7 +406,7 @@
appView.dexItemFactory());
return IRBuilder.createForInlining(
method, appView, codeLens, source, origin, valueNumberGenerator, protoChanges)
- .build(context);
+ .build(context, new ThrowingMethodConversionOptions(appView.options()));
}
@Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugEntry.java b/src/main/java/com/android/tools/r8/graph/DexDebugEntry.java
index 2547996..f89353c 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugEntry.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugEntry.java
@@ -4,11 +4,18 @@
package com.android.tools.r8.graph;
import com.android.tools.r8.ir.code.Position;
+import com.android.tools.r8.ir.code.Position.OutlineCallerPosition;
+import com.android.tools.r8.ir.code.Position.OutlineCallerPosition.OutlineCallerPositionBuilder;
+import com.android.tools.r8.ir.code.Position.OutlinePosition;
+import com.android.tools.r8.ir.code.Position.PositionBuilder;
+import com.android.tools.r8.ir.code.Position.SourcePosition;
+import com.android.tools.r8.utils.Int2StructuralItemArrayMap;
import com.android.tools.r8.utils.StringUtils;
import com.google.common.collect.ImmutableMap;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
+import java.util.function.Function;
public class DexDebugEntry {
@@ -21,6 +28,9 @@
public final Map<Integer, DebugLocalInfo> locals;
public final DexMethod method;
public final Position callerPosition;
+ public final boolean isOutline;
+ public final DexMethod outlineCallee;
+ public final Int2StructuralItemArrayMap<Position> outlineCallerPositions;
public DexDebugEntry(
boolean lineEntry,
@@ -31,7 +41,10 @@
boolean epilogueBegin,
ImmutableMap<Integer, DebugLocalInfo> locals,
DexMethod method,
- Position callerPosition) {
+ Position callerPosition,
+ boolean isOutline,
+ DexMethod outlineCallee,
+ Int2StructuralItemArrayMap<Position> outlineCallerPositions) {
this.lineEntry = lineEntry;
this.address = address;
this.line = line;
@@ -42,6 +55,9 @@
this.method = method;
assert method != null;
this.callerPosition = callerPosition;
+ this.isOutline = isOutline;
+ this.outlineCallee = outlineCallee;
+ this.outlineCallerPositions = outlineCallerPositions;
}
@Override
@@ -67,6 +83,15 @@
caller = caller.getCallerPosition();
}
}
+ if (isOutline) {
+ builder.append(", isOutline = true");
+ }
+ if (outlineCallee != null) {
+ builder.append(", outlineCallee = ").append(outlineCallee);
+ }
+ if (outlineCallerPositions != null) {
+ builder.append(", outlineCallerPositions = ").append(outlineCallerPositions);
+ }
if (prologueEnd) {
builder.append(", prologue_end = true");
}
@@ -89,4 +114,23 @@
}
return builder.toString();
}
+
+ public Position toPosition(Function<Position, Position> canonicalizeCallerPosition) {
+ PositionBuilder<?, ?> positionBuilder;
+ if (outlineCallee != null) {
+ OutlineCallerPositionBuilder outlineCallerPositionBuilder =
+ OutlineCallerPosition.builder().setOutlineCallee(outlineCallee).setIsOutline(isOutline);
+ outlineCallerPositions.forEach(outlineCallerPositionBuilder::addOutlinePosition);
+ positionBuilder = outlineCallerPositionBuilder;
+ } else if (isOutline) {
+ positionBuilder = OutlinePosition.builder();
+ } else {
+ positionBuilder = SourcePosition.builder().setFile(sourceFile);
+ }
+ return positionBuilder
+ .setLine(line)
+ .setMethod(method)
+ .setCallerPosition(canonicalizeCallerPosition.apply(callerPosition))
+ .build();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugEntryBuilder.java b/src/main/java/com/android/tools/r8/graph/DexDebugEntryBuilder.java
index d8b6a9b..5a4fd84 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugEntryBuilder.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugEntryBuilder.java
@@ -3,8 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
-import com.android.tools.r8.graph.DexDebugEvent.SetOutlineCallerFrame;
-import com.android.tools.r8.graph.DexDebugEvent.SetOutlineFrame;
+import com.android.tools.r8.graph.DexDebugEvent.SetPositionFrame;
import com.android.tools.r8.graph.DexDebugInfo.EventBasedDebugInfo;
import com.android.tools.r8.ir.code.ValueType;
import com.google.common.collect.ImmutableMap;
@@ -111,18 +110,8 @@
}
@Override
- public void visit(DexDebugEvent.SetInlineFrame setInlineFrame) {
- positionState.visit(setInlineFrame);
- }
-
- @Override
- public void visit(SetOutlineFrame setOutlineFrame) {
- positionState.visit(setOutlineFrame);
- }
-
- @Override
- public void visit(SetOutlineCallerFrame setOutlineCallerFrame) {
- positionState.visit(setOutlineCallerFrame);
+ public void visit(SetPositionFrame setPositionFrame) {
+ positionState.visit(setPositionFrame);
}
@Override
@@ -181,7 +170,10 @@
pending.epilogueBegin,
getLocals(),
pending.method,
- pending.callerPosition));
+ pending.callerPosition,
+ pending.isOutline,
+ pending.outlineCallee,
+ pending.outlineCallerPositions));
}
pending =
new DexDebugEntry(
@@ -193,7 +185,10 @@
epilogueBegin,
null,
positionState.getCurrentMethod(),
- positionState.getCurrentCallerPosition());
+ positionState.getCurrentCallerPosition(),
+ positionState.isOutline(),
+ positionState.getOutlineCallee(),
+ positionState.getOutlineCallerPositions());
prologueEnd = false;
epilogueBegin = false;
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java b/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java
index 60cc65a..27aacbe 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java
@@ -9,7 +9,6 @@
import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.ir.code.Position;
-import com.android.tools.r8.utils.Int2StructuralItemArrayMap;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
import com.android.tools.r8.utils.structural.StructuralItem;
@@ -20,9 +19,7 @@
public abstract class DexDebugEvent extends DexItem implements StructuralItem<DexDebugEvent> {
// Compare ID(s) for virtual debug events.
- private static final int DBG_SET_INLINE_FRAME_COMPARE_ID = Constants.DBG_LAST_SPECIAL + 1;
- private static final int DBG_SET_OUTLINE_FRAME_COMPARE_ID = Constants.DBG_LAST_SPECIAL + 2;
- private static final int DBG_SET_OUTLINE_CALLER_COMPARE_ID = Constants.DBG_LAST_SPECIAL + 3;
+ private static final int DBG_SET_POSITION_FRAME_COMPARE_ID = Constants.DBG_LAST_SPECIAL + 1;
public static final DexDebugEvent[] EMPTY_ARRAY = {};
@@ -92,23 +89,11 @@
public abstract void accept(DexDebugEventVisitor visitor);
- public boolean isSetInlineFrame() {
+ public boolean isPositionFrame() {
return false;
}
- public boolean isSetOutlineFrame() {
- return false;
- }
-
- public boolean isSetOutlineCallerFrame() {
- return false;
- }
-
- public SetInlineFrame asSetInlineFrame() {
- return null;
- }
-
- public SetOutlineCallerFrame asSetOutlineCallerFrame() {
+ public SetPositionFrame asSetPositionFrame() {
return null;
}
@@ -575,19 +560,20 @@
}
}
- public static class SetInlineFrame extends DexDebugEvent {
+ public static class SetPositionFrame extends DexDebugEvent {
- final DexMethod callee;
- final Position caller;
+ private final Position position;
- private static void specify(StructuralSpecification<SetInlineFrame, ?> spec) {
- spec.withItem(e -> e.callee).withNullableItem(e -> e.caller);
+ private static void specify(StructuralSpecification<SetPositionFrame, ?> spec) {
+ spec.withNullableItem(e -> e.position);
}
- SetInlineFrame(DexMethod callee, Position caller) {
- assert callee != null;
- this.callee = callee;
- this.caller = caller;
+ SetPositionFrame(Position position) {
+ this.position = position;
+ }
+
+ public Position getPosition() {
+ return position;
}
@Override
@@ -597,140 +583,36 @@
@Override
public String toString() {
- return String.format("SET_INLINE_FRAME %s %s", callee, caller);
+ return String.format("SET_POSITION_FRAME %s", position);
}
@Override
public int hashCode() {
- return 31 * callee.hashCode() + Objects.hashCode(caller);
+ return 31 * Objects.hashCode(position);
}
@Override
int getCompareToId() {
- return DBG_SET_INLINE_FRAME_COMPARE_ID;
+ return DBG_SET_POSITION_FRAME_COMPARE_ID;
}
@Override
int internalAcceptCompareTo(DexDebugEvent other, CompareToVisitor visitor) {
- return visitor.visit(this, (SetInlineFrame) other, SetInlineFrame::specify);
+ return visitor.visit(this, (SetPositionFrame) other, SetPositionFrame::specify);
}
@Override
void internalAcceptHashing(HashingVisitor visitor) {
- visitor.visit(this, SetInlineFrame::specify);
+ visitor.visit(this, SetPositionFrame::specify);
}
@Override
- public boolean isSetInlineFrame() {
+ public boolean isPositionFrame() {
return true;
}
@Override
- public SetInlineFrame asSetInlineFrame() {
- return this;
- }
-
- public boolean hasOuterPosition(DexMethod method) {
- return (caller == null && callee == method)
- || (caller != null && caller.getOutermostCaller().getMethod() == method);
- }
- }
-
- public static class SetOutlineFrame extends DexDebugEvent {
-
- @Override
- public String toString() {
- return "SET_OUTLINE_FRAME";
- }
-
- @Override
- public int hashCode() {
- return 7;
- }
-
- @Override
- int getCompareToId() {
- return DBG_SET_OUTLINE_FRAME_COMPARE_ID;
- }
-
- @Override
- int internalAcceptCompareTo(DexDebugEvent other, CompareToVisitor visitor) {
- return 0;
- }
-
- @Override
- void internalAcceptHashing(HashingVisitor visitor) {
- // Intentionally empty: no content besides the compare-id
- }
-
- @Override
- public void accept(DexDebugEventVisitor visitor) {
- visitor.visit(this);
- }
- }
-
- public static class SetOutlineCallerFrame extends DexDebugEvent {
-
- private final DexMethod outlineCallee;
- private final Int2StructuralItemArrayMap<Position> outlinePositions;
-
- private static void specify(StructuralSpecification<SetOutlineCallerFrame, ?> spec) {
- spec.withItem(e -> e.outlineCallee).withNullableItem(e -> e.outlinePositions);
- }
-
- SetOutlineCallerFrame(
- DexMethod outlineCallee, Int2StructuralItemArrayMap<Position> outlinePositions) {
- assert outlineCallee != null;
- assert !outlinePositions.isEmpty();
- this.outlineCallee = outlineCallee;
- this.outlinePositions = outlinePositions;
- }
-
- public DexMethod getOutlineCallee() {
- return outlineCallee;
- }
-
- public Int2StructuralItemArrayMap<Position> getOutlinePositions() {
- return outlinePositions;
- }
-
- @Override
- public void accept(DexDebugEventVisitor visitor) {
- visitor.visit(this);
- }
-
- @Override
- public String toString() {
- return String.format("SET_OUTLINE_CALLER_FRAME %s %s", outlineCallee, outlinePositions);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(outlineCallee, outlinePositions);
- }
-
- @Override
- int getCompareToId() {
- return DBG_SET_OUTLINE_CALLER_COMPARE_ID;
- }
-
- @Override
- int internalAcceptCompareTo(DexDebugEvent other, CompareToVisitor visitor) {
- return visitor.visit(this, (SetOutlineCallerFrame) other, SetOutlineCallerFrame::specify);
- }
-
- @Override
- void internalAcceptHashing(HashingVisitor visitor) {
- visitor.visit(this, SetOutlineCallerFrame::specify);
- }
-
- @Override
- public boolean isSetOutlineCallerFrame() {
- return true;
- }
-
- @Override
- public SetOutlineCallerFrame asSetOutlineCallerFrame() {
+ public SetPositionFrame asSetPositionFrame() {
return this;
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java b/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java
index dc90361..e4c29aa 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java
@@ -249,18 +249,14 @@
|| previousPosition.hasCallerPosition()
|| nextPosition.getMethod() == previousPosition.getMethod()
|| optimizingLineNumbers;
- if (nextPosition.getCallerPosition() != previousPosition.getCallerPosition()
- || nextPosition.getMethod() != previousPosition.getMethod()) {
- events.add(
- factory.createSetInlineFrame(nextPosition.getMethod(), nextPosition.getCallerPosition()));
- }
- if (nextPosition.isOutline()) {
- events.add(factory.createSetOutlineFrame());
- }
- if (nextPosition.getOutlineCallee() != null && !nextPosition.getOutlinePositions().isEmpty()) {
- events.add(
- factory.createSetOutlineCallerFrame(
- nextPosition.getOutlineCallee(), nextPosition.getOutlinePositions()));
+ boolean isNewPosition =
+ nextPosition.getCallerPosition() != previousPosition.getCallerPosition()
+ || nextPosition.getMethod() != previousPosition.getMethod();
+ boolean isOutline = nextPosition.isOutline();
+ boolean isOutlineCallee =
+ nextPosition.getOutlineCallee() != null && !nextPosition.getOutlinePositions().isEmpty();
+ if (isNewPosition || isOutline || isOutlineCallee) {
+ events.add(factory.createPositionFrame(nextPosition));
}
addDefaultEventWithAdvancePcIfNecessary(lineDelta, pcDelta, events, factory);
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugEventVisitor.java b/src/main/java/com/android/tools/r8/graph/DexDebugEventVisitor.java
index 165858b..b09f62d 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugEventVisitor.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugEventVisitor.java
@@ -10,9 +10,7 @@
import com.android.tools.r8.graph.DexDebugEvent.RestartLocal;
import com.android.tools.r8.graph.DexDebugEvent.SetEpilogueBegin;
import com.android.tools.r8.graph.DexDebugEvent.SetFile;
-import com.android.tools.r8.graph.DexDebugEvent.SetInlineFrame;
-import com.android.tools.r8.graph.DexDebugEvent.SetOutlineCallerFrame;
-import com.android.tools.r8.graph.DexDebugEvent.SetOutlineFrame;
+import com.android.tools.r8.graph.DexDebugEvent.SetPositionFrame;
import com.android.tools.r8.graph.DexDebugEvent.SetPrologueEnd;
import com.android.tools.r8.graph.DexDebugEvent.StartLocal;
@@ -21,11 +19,7 @@
void visit(AdvanceLine advanceLine);
- void visit(SetInlineFrame setInlineFrame);
-
- void visit(SetOutlineFrame setOutlineFrame);
-
- void visit(SetOutlineCallerFrame setOutlineCallerFrame);
+ void visit(SetPositionFrame setPositionFrame);
void visit(Default defaultEvent);
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugPositionState.java b/src/main/java/com/android/tools/r8/graph/DexDebugPositionState.java
index 9c5ffd6..10a06d5 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugPositionState.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugPositionState.java
@@ -11,9 +11,7 @@
import com.android.tools.r8.graph.DexDebugEvent.RestartLocal;
import com.android.tools.r8.graph.DexDebugEvent.SetEpilogueBegin;
import com.android.tools.r8.graph.DexDebugEvent.SetFile;
-import com.android.tools.r8.graph.DexDebugEvent.SetInlineFrame;
-import com.android.tools.r8.graph.DexDebugEvent.SetOutlineCallerFrame;
-import com.android.tools.r8.graph.DexDebugEvent.SetOutlineFrame;
+import com.android.tools.r8.graph.DexDebugEvent.SetPositionFrame;
import com.android.tools.r8.graph.DexDebugEvent.SetPrologueEnd;
import com.android.tools.r8.graph.DexDebugEvent.StartLocal;
import com.android.tools.r8.ir.code.Position;
@@ -51,20 +49,14 @@
}
@Override
- public void visit(SetInlineFrame setInlineFrame) {
- currentMethod = setInlineFrame.callee;
- currentCallerPosition = setInlineFrame.caller;
- }
-
- @Override
- public void visit(SetOutlineFrame setOutlineFrame) {
- isOutline = true;
- }
-
- @Override
- public void visit(SetOutlineCallerFrame setOutlineCallerFrame) {
- outlineCallee = setOutlineCallerFrame.getOutlineCallee();
- outlineCallerPositions = setOutlineCallerFrame.getOutlinePositions();
+ public void visit(SetPositionFrame setPositionFrame) {
+ assert setPositionFrame.getPosition() != null;
+ Position position = setPositionFrame.getPosition();
+ currentMethod = position.getMethod();
+ currentCallerPosition = position.getCallerPosition();
+ outlineCallee = position.getOutlineCallee();
+ outlineCallerPositions = position.getOutlinePositions();
+ isOutline = position.isOutline();
}
@Override
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 c33d18d..4196ca2 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -43,12 +43,9 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexAnnotation.AnnotatedKind;
import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
-import com.android.tools.r8.graph.bytecodemetadata.BytecodeMetadataProvider;
import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
-import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.NumericType;
import com.android.tools.r8.ir.code.ValueType;
-import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.Inliner.Reason;
import com.android.tools.r8.ir.optimize.NestUtils;
@@ -57,7 +54,6 @@
import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfoFixer;
import com.android.tools.r8.ir.optimize.info.MutableMethodOptimizationInfo;
import com.android.tools.r8.ir.optimize.inliner.WhyAreYouNotInliningReporter;
-import com.android.tools.r8.ir.regalloc.RegisterAllocator;
import com.android.tools.r8.ir.synthetic.ForwardMethodBuilder;
import com.android.tools.r8.kotlin.KotlinMethodLevelInfo;
import com.android.tools.r8.naming.ClassNameMapper;
@@ -81,7 +77,6 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
@@ -726,24 +721,10 @@
compilationState = CompilationState.NOT_PROCESSED;
}
- public void setCode(Code newCode, AppView<?> appView) {
+ public void setCode(Code code, Int2ReferenceMap<DebugLocalInfo> parameterInfo) {
checkIfObsolete();
- // If the locals are not kept, we might still need information to satisfy -keepparameternames.
- // The information needs to be retrieved on the original code object before replacing it.
- if (code != null && code.isCfCode() && !hasParameterInfo() && !keepLocals(appView.options())) {
- setParameterInfo(code.collectParameterInfo(this, appView));
- }
- code = newCode;
- }
-
- public void setCode(
- IRCode ir,
- BytecodeMetadataProvider bytecodeMetadataProvider,
- RegisterAllocator registerAllocator,
- AppView<?> appView) {
- checkIfObsolete();
- DexBuilder builder = new DexBuilder(ir, bytecodeMetadataProvider, registerAllocator);
- setCode(builder.build(), appView);
+ this.code = code;
+ this.parameterInfo = parameterInfo;
}
public void unsetCode() {
@@ -751,23 +732,11 @@
code = null;
}
- public boolean keepLocals(InternalOptions options) {
- if (options.testing.noLocalsTableOnInput) {
- return false;
- }
- return options.debug || getOptimizationInfo().isReachabilitySensitive();
- }
-
- private void setParameterInfo(Int2ReferenceMap<DebugLocalInfo> parameterInfo) {
- assert this.parameterInfo == NO_PARAMETER_INFO;
- this.parameterInfo = parameterInfo;
- }
-
public boolean hasParameterInfo() {
return parameterInfo != NO_PARAMETER_INFO;
}
- public Map<Integer, DebugLocalInfo> getParameterInfo() {
+ public Int2ReferenceMap<DebugLocalInfo> getParameterInfo() {
return parameterInfo;
}
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 6259d4c..3e5150c 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -17,9 +17,7 @@
import com.android.tools.r8.graph.DexDebugEvent.RestartLocal;
import com.android.tools.r8.graph.DexDebugEvent.SetEpilogueBegin;
import com.android.tools.r8.graph.DexDebugEvent.SetFile;
-import com.android.tools.r8.graph.DexDebugEvent.SetInlineFrame;
-import com.android.tools.r8.graph.DexDebugEvent.SetOutlineCallerFrame;
-import com.android.tools.r8.graph.DexDebugEvent.SetOutlineFrame;
+import com.android.tools.r8.graph.DexDebugEvent.SetPositionFrame;
import com.android.tools.r8.graph.DexDebugEvent.SetPrologueEnd;
import com.android.tools.r8.graph.DexMethodHandle.MethodHandleType;
import com.android.tools.r8.ir.analysis.type.ArrayTypeElement;
@@ -38,7 +36,6 @@
import com.android.tools.r8.synthesis.SyntheticNaming;
import com.android.tools.r8.utils.ArrayUtils;
import com.android.tools.r8.utils.DescriptorUtils;
-import com.android.tools.r8.utils.Int2StructuralItemArrayMap;
import com.android.tools.r8.utils.IterableUtils;
import com.android.tools.r8.utils.LRUCacheTable;
import com.android.tools.r8.utils.ListUtils;
@@ -99,8 +96,7 @@
private final SetEpilogueBegin setEpilogueBegin = new SetEpilogueBegin();
private final SetPrologueEnd setPrologueEnd = new SetPrologueEnd();
private final Map<DexString, SetFile> setFiles = new HashMap<>();
- private final SetOutlineFrame setOutlineFrame = new SetOutlineFrame();
- private final Map<SetInlineFrame, SetInlineFrame> setInlineFrames = new HashMap<>();
+ private final Map<SetPositionFrame, SetPositionFrame> setInlineFrames = new HashMap<>();
public final DexDebugEvent.Default zeroChangeDefaultEvent = createDefault(0, 0);
public final DexDebugEvent.Default oneChangeDefaultEvent = createDefault(1, 1);
@@ -536,6 +532,7 @@
public final FloatMembers floatMembers = new FloatMembers();
public final IntegerMembers integerMembers = new IntegerMembers();
public final LongMembers longMembers = new LongMembers();
+ public final VoidMembers voidMembers = new VoidMembers();
public final ObjectsMethods objectsMethods = new ObjectsMethods();
public final ObjectMembers objectMembers = new ObjectMembers();
public final BufferMembers bufferMembers = new BufferMembers();
@@ -744,6 +741,34 @@
return primitiveToBoxed.get(primitive);
}
+ public BoxedPrimitiveMembers getBoxedMembersForPrimitiveOrVoidType(DexType type) {
+ assert type.isPrimitiveType() || type.isVoidType();
+ char c = (char) type.getDescriptor().content[0];
+ assert c == type.toDescriptorString().charAt(0);
+ switch (c) {
+ case 'B':
+ return byteMembers;
+ case 'C':
+ return charMembers;
+ case 'D':
+ return doubleMembers;
+ case 'F':
+ return floatMembers;
+ case 'I':
+ return integerMembers;
+ case 'J':
+ return longMembers;
+ case 'S':
+ return shortMembers;
+ case 'V':
+ return voidMembers;
+ case 'Z':
+ return booleanMembers;
+ default:
+ throw new Unreachable("Unknown type " + type);
+ }
+ }
+
public DexType getPrimitiveFromBoxed(DexType boxedPrimitive) {
return primitiveToBoxed.inverse().get(boxedPrimitive);
}
@@ -884,6 +909,11 @@
public void forEachFinalField(Consumer<DexField> consumer) {}
}
+ public abstract static class BoxedPrimitiveMembers extends LibraryMembers {
+
+ public abstract DexField getTypeField();
+ }
+
public class AndroidOsBuildMembers extends LibraryMembers {
public final DexField BOOTLOADER = createField(androidOsBuildType, stringType, "BOOTLOADER");
@@ -1004,7 +1034,7 @@
createMethod(androidUtilSparseArrayType, createProto(voidType, intType, objectType), "set");
}
- public class BooleanMembers extends LibraryMembers {
+ public class BooleanMembers extends BoxedPrimitiveMembers {
public final DexField FALSE = createField(boxedBooleanType, boxedBooleanType, "FALSE");
public final DexField TRUE = createField(boxedBooleanType, boxedBooleanType, "TRUE");
@@ -1027,9 +1057,16 @@
consumer.accept(TRUE);
consumer.accept(TYPE);
}
+
+ @Override
+ public DexField getTypeField() {
+ return TYPE;
+ }
}
- public class ByteMembers extends LibraryMembers {
+ public class ByteMembers extends BoxedPrimitiveMembers {
+
+ public final DexField TYPE = createField(boxedByteType, classType, "TYPE");
public final DexMethod byteValue =
createMethod(boxedByteType, createProto(byteType), "byteValue");
@@ -1039,17 +1076,29 @@
createMethod(boxedByteType, createProto(boxedByteType, byteType), "valueOf");
private ByteMembers() {}
+
+ @Override
+ public DexField getTypeField() {
+ return TYPE;
+ }
}
- public class CharMembers extends LibraryMembers {
+ public class CharMembers extends BoxedPrimitiveMembers {
+
+ public final DexField TYPE = createField(boxedCharType, classType, "TYPE");
public final DexMethod toString =
createMethod(boxedCharType, createProto(stringType), "toString");
private CharMembers() {}
+
+ @Override
+ public DexField getTypeField() {
+ return TYPE;
+ }
}
- public class FloatMembers extends LibraryMembers {
+ public class FloatMembers extends BoxedPrimitiveMembers {
public final DexField TYPE = createField(boxedFloatType, classType, "TYPE");
@@ -1062,6 +1111,11 @@
public void forEachFinalField(Consumer<DexField> consumer) {
consumer.accept(TYPE);
}
+
+ @Override
+ public DexField getTypeField() {
+ return TYPE;
+ }
}
public class JavaIoFileMembers extends LibraryMembers {
@@ -1207,7 +1261,7 @@
}
}
- public class LongMembers extends LibraryMembers {
+ public class LongMembers extends BoxedPrimitiveMembers {
public final DexField TYPE = createField(boxedLongType, classType, "TYPE");
@@ -1224,9 +1278,16 @@
public void forEachFinalField(Consumer<DexField> consumer) {
consumer.accept(TYPE);
}
+
+ @Override
+ public DexField getTypeField() {
+ return TYPE;
+ }
}
- public class DoubleMembers {
+ public class DoubleMembers extends BoxedPrimitiveMembers {
+
+ public final DexField TYPE = createField(boxedDoubleType, classType, "TYPE");
public final DexMethod isNaN;
@@ -1241,9 +1302,14 @@
booleanDescriptor,
new DexString[] {doubleDescriptor});
}
+
+ @Override
+ public DexField getTypeField() {
+ return TYPE;
+ }
}
- public class IntegerMembers extends LibraryMembers {
+ public class IntegerMembers extends BoxedPrimitiveMembers {
public final DexField TYPE = createField(boxedIntType, classType, "TYPE");
@@ -1254,6 +1320,11 @@
public void forEachFinalField(Consumer<DexField> consumer) {
consumer.accept(TYPE);
}
+
+ @Override
+ public DexField getTypeField() {
+ return TYPE;
+ }
}
public class StringConcatFactoryMembers {
@@ -1271,6 +1342,16 @@
createString("makeConcatWithConstants"));
}
+ public class VoidMembers extends BoxedPrimitiveMembers {
+
+ public final DexField TYPE = createField(voidType, classType, "TYPE");
+
+ @Override
+ public DexField getTypeField() {
+ return TYPE;
+ }
+ }
+
public class ThrowableMethods {
public final DexMethod addSuppressed;
@@ -1823,12 +1904,19 @@
}
}
- public class ShortMembers extends LibraryMembers {
+ public class ShortMembers extends BoxedPrimitiveMembers {
+
+ public final DexField TYPE = createField(boxedShortType, classType, "TYPE");
public final DexMethod toString =
createMethod(boxedShortType, createProto(stringType), "toString");
private ShortMembers() {}
+
+ @Override
+ public DexField getTypeField() {
+ return TYPE;
+ }
}
public class StringMembers extends LibraryMembers {
@@ -2806,21 +2894,12 @@
}
// TODO(tamaskenez) b/69024229 Measure if canonicalization is worth it.
- public SetInlineFrame createSetInlineFrame(DexMethod callee, Position caller) {
+ public SetPositionFrame createPositionFrame(Position position) {
synchronized (setInlineFrames) {
- return setInlineFrames.computeIfAbsent(new SetInlineFrame(callee, caller), p -> p);
+ return setInlineFrames.computeIfAbsent(new SetPositionFrame(position), p -> p);
}
}
- public SetOutlineFrame createSetOutlineFrame() {
- return setOutlineFrame;
- }
-
- public SetOutlineCallerFrame createSetOutlineCallerFrame(
- DexMethod outlineCallee, Int2StructuralItemArrayMap<Position> outlinePositions) {
- return new SetOutlineCallerFrame(outlineCallee, outlinePositions);
- }
-
public boolean isConstructor(DexMethod method) {
return method.name == constructorMethodName;
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
index 658c2c0..354cc52 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -19,8 +19,9 @@
import com.android.tools.r8.kotlin.KotlinClassLevelInfo;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.synthesis.SyntheticMarker;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.OptionalBool;
import com.android.tools.r8.utils.TraversalContinuation;
import com.android.tools.r8.utils.structural.Ordered;
import com.android.tools.r8.utils.structural.StructuralItem;
@@ -52,6 +53,7 @@
private CfVersion initialClassFileVersion = null;
private boolean deprecated = false;
private KotlinClassLevelInfo kotlinInfo = getNoKotlinInfo();
+ private OptionalBool reachabilitySensitive = OptionalBool.unknown();
private final ChecksumSupplier checksumSupplier;
@@ -160,6 +162,33 @@
return this;
}
+ /**
+ * Is the class reachability sensitive.
+ *
+ * <p>A class is reachability sensitive if the
+ * dalvik.annotation.optimization.ReachabilitySensitive annotation is on any field or method. When
+ * that is the case, dead reference elimination is disabled and locals are kept alive for their
+ * entire scope.
+ */
+ public boolean getOrComputeReachabilitySensitive(AppView<?> appView) {
+ if (reachabilitySensitive.isUnknown()) {
+ reachabilitySensitive = OptionalBool.of(internalComputeReachabilitySensitive(appView));
+ }
+ return reachabilitySensitive.isTrue();
+ }
+
+ private boolean internalComputeReachabilitySensitive(AppView<?> appView) {
+ DexItemFactory dexItemFactory = appView.dexItemFactory();
+ for (DexEncodedMember<?, ?> member : members()) {
+ for (DexAnnotation annotation : member.annotations().annotations) {
+ if (annotation.annotation.type == dexItemFactory.annotationReachabilitySensitive) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
@Override
public StructuralMapping<DexProgramClass> getStructuralMapping() {
return DexProgramClass::specify;
@@ -445,13 +474,11 @@
if (isFinal()) {
return true;
}
- if (appView.enableWholeProgramOptimizations()) {
- assert appView.appInfo().hasLiveness();
- AppInfoWithLiveness appInfo = appView.appInfo().withLiveness();
- if (appInfo.isPinned(type)) {
- return false;
- }
- return !appInfo.isInstantiatedIndirectly(this);
+ if (appView.hasLiveness()) {
+ assert appView.enableWholeProgramOptimizations();
+ InternalOptions options = appView.options();
+ return !appView.getKeepInfo(this).isPinned(options)
+ && !appView.appInfoWithLiveness().isInstantiatedIndirectly(this);
}
return false;
}
@@ -752,25 +779,6 @@
return deprecated;
}
- /**
- * Is the class reachability sensitive.
- *
- * <p>A class is reachability sensitive if the
- * dalvik.annotation.optimization.ReachabilitySensitive annotation is on any field or method. When
- * that is the case, dead reference elimination is disabled and locals are kept alive for their
- * entire scope.
- */
- public boolean hasReachabilitySensitiveAnnotation(DexItemFactory factory) {
- for (DexEncodedMember<?, ?> member : members()) {
- for (DexAnnotation annotation : member.annotations().annotations) {
- if (annotation.annotation.type == factory.annotationReachabilitySensitive) {
- return true;
- }
- }
- }
- return false;
- }
-
public static Iterable<DexProgramClass> asProgramClasses(
Iterable<DexType> types, DexDefinitionSupplier definitions) {
return () ->
diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java
index 72884e9..810874b 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -337,14 +337,6 @@
return isDoubleType() || isLongType();
}
- public boolean isSynthesizedTypeAllowedDuplication() {
- // If we are desugaring Records, then the r8Record type is mapped back to java.lang.Record, and
- // java.lang.Record can be duplicated.
- // If we are not desugaring Records, then the r8Record type can be duplicated instead.
- return descriptor.toString().equals(DexItemFactory.recordDescriptorString)
- || descriptor.toString().equals(DexItemFactory.recordTagDescriptorString);
- }
-
public boolean isLegacySynthesizedTypeAllowedDuplication() {
return oldSynthesizedName(toSourceString());
}
diff --git a/src/main/java/com/android/tools/r8/graph/FieldAccessInfo.java b/src/main/java/com/android/tools/r8/graph/FieldAccessInfo.java
index 2cd2be0..34b3f2b 100644
--- a/src/main/java/com/android/tools/r8/graph/FieldAccessInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/FieldAccessInfo.java
@@ -20,20 +20,32 @@
int getNumberOfWriteContexts();
+ AbstractAccessContexts getReadsWithContexts();
+
+ AbstractAccessContexts getWritesWithContexts();
+
ProgramMethod getUniqueReadContext();
+ boolean hasKnownReadContexts();
+
boolean hasKnownWriteContexts();
void forEachIndirectAccess(Consumer<DexField> consumer);
void forEachIndirectAccessWithContexts(BiConsumer<DexField, ProgramMethodSet> consumer);
+ void forEachAccessContext(Consumer<ProgramMethod> consumer);
+
void forEachReadContext(Consumer<ProgramMethod> consumer);
void forEachWriteContext(Consumer<ProgramMethod> consumer);
boolean hasReflectiveAccess();
+ boolean hasReflectiveRead();
+
+ boolean hasReflectiveWrite();
+
default boolean isAccessedFromMethodHandle() {
return isReadFromMethodHandle() || isWrittenFromMethodHandle();
}
@@ -46,6 +58,8 @@
boolean isReadFromMethodHandle();
+ boolean isReadOnlyInMethodSatisfying(Predicate<ProgramMethod> predicate);
+
boolean isWritten();
boolean isWrittenFromMethodHandle();
@@ -54,7 +68,5 @@
boolean isWrittenOnlyInMethodSatisfying(Predicate<ProgramMethod> predicate);
- boolean isReadOnlyInMethodSatisfying(Predicate<ProgramMethod> predicate);
-
boolean isWrittenOutside(DexEncodedMethod method);
}
diff --git a/src/main/java/com/android/tools/r8/graph/FieldAccessInfoCollectionImpl.java b/src/main/java/com/android/tools/r8/graph/FieldAccessInfoCollectionImpl.java
index 439ef05..8a8b9da 100644
--- a/src/main/java/com/android/tools/r8/graph/FieldAccessInfoCollectionImpl.java
+++ b/src/main/java/com/android/tools/r8/graph/FieldAccessInfoCollectionImpl.java
@@ -63,6 +63,10 @@
infos.values().forEach(consumer);
}
+ public void remove(DexField field) {
+ infos.remove(field);
+ }
+
@Override
public void removeIf(BiPredicate<DexField, FieldAccessInfoImpl> predicate) {
infos.entrySet().removeIf(entry -> predicate.test(entry.getKey(), entry.getValue()));
diff --git a/src/main/java/com/android/tools/r8/graph/FieldAccessInfoImpl.java b/src/main/java/com/android/tools/r8/graph/FieldAccessInfoImpl.java
index 0a7d218..8779817 100644
--- a/src/main/java/com/android/tools/r8/graph/FieldAccessInfoImpl.java
+++ b/src/main/java/com/android/tools/r8/graph/FieldAccessInfoImpl.java
@@ -27,8 +27,9 @@
public static int FLAG_IS_READ_FROM_ANNOTATION = 1 << 0;
public static int FLAG_IS_READ_FROM_METHOD_HANDLE = 1 << 1;
public static int FLAG_IS_WRITTEN_FROM_METHOD_HANDLE = 1 << 2;
- public static int FLAG_HAS_REFLECTIVE_ACCESS = 1 << 3;
- public static int FLAG_IS_READ_FROM_RECORD_INVOKE_DYNAMIC = 1 << 4;
+ public static int FLAG_HAS_REFLECTIVE_READ = 1 << 3;
+ public static int FLAG_HAS_REFLECTIVE_WRITE = 1 << 4;
+ public static int FLAG_IS_READ_FROM_RECORD_INVOKE_DYNAMIC = 1 << 5;
// A direct reference to the definition of the field.
private DexField field;
@@ -72,6 +73,7 @@
return field;
}
+ @Override
public AbstractAccessContexts getReadsWithContexts() {
return readsWithContexts;
}
@@ -80,6 +82,11 @@
this.readsWithContexts = readsWithContexts;
}
+ @Override
+ public AbstractAccessContexts getWritesWithContexts() {
+ return writesWithContexts;
+ }
+
public void setWritesWithContexts(AbstractAccessContexts writesWithContexts) {
this.writesWithContexts = writesWithContexts;
}
@@ -102,6 +109,11 @@
}
@Override
+ public boolean hasKnownReadContexts() {
+ return !readsWithContexts.isTop();
+ }
+
+ @Override
public boolean hasKnownWriteContexts() {
return !writesWithContexts.isTop();
}
@@ -169,6 +181,12 @@
}
@Override
+ public void forEachAccessContext(Consumer<ProgramMethod> consumer) {
+ forEachReadContext(consumer);
+ forEachWriteContext(consumer);
+ }
+
+ @Override
public void forEachReadContext(Consumer<ProgramMethod> consumer) {
readsWithContexts.forEachAccessContext(consumer);
}
@@ -180,17 +198,39 @@
@Override
public boolean hasReflectiveAccess() {
- return (flags & FLAG_HAS_REFLECTIVE_ACCESS) != 0;
+ return hasReflectiveRead() || hasReflectiveWrite();
}
- public void setHasReflectiveAccess() {
- flags |= FLAG_HAS_REFLECTIVE_ACCESS;
+ @Override
+ public boolean hasReflectiveRead() {
+ return (flags & FLAG_HAS_REFLECTIVE_READ) != 0;
+ }
+
+ public void setHasReflectiveRead() {
+ flags |= FLAG_HAS_REFLECTIVE_READ;
+ }
+
+ @Override
+ public boolean hasReflectiveWrite() {
+ return (flags & FLAG_HAS_REFLECTIVE_WRITE) != 0;
+ }
+
+ public void setHasReflectiveWrite() {
+ flags |= FLAG_HAS_REFLECTIVE_WRITE;
}
/** Returns true if this field is read by the program. */
@Override
public boolean isRead() {
- return !readsWithContexts.isEmpty()
+ return isReadDirectly() || isReadIndirectly();
+ }
+
+ private boolean isReadDirectly() {
+ return !readsWithContexts.isEmpty();
+ }
+
+ private boolean isReadIndirectly() {
+ return hasReflectiveRead()
|| isReadFromAnnotation()
|| isReadFromMethodHandle()
|| isReadFromRecordInvokeDynamic();
@@ -210,15 +250,15 @@
return (flags & FLAG_IS_READ_FROM_METHOD_HANDLE) != 0;
}
+ public void setReadFromMethodHandle() {
+ flags |= FLAG_IS_READ_FROM_METHOD_HANDLE;
+ }
+
@Override
public boolean isReadFromRecordInvokeDynamic() {
return (flags & FLAG_IS_READ_FROM_RECORD_INVOKE_DYNAMIC) != 0;
}
- public void setReadFromMethodHandle() {
- flags |= FLAG_IS_READ_FROM_METHOD_HANDLE;
- }
-
public void setReadFromRecordInvokeDynamic() {
flags |= FLAG_IS_READ_FROM_RECORD_INVOKE_DYNAMIC;
}
@@ -227,12 +267,28 @@
flags &= ~FLAG_IS_READ_FROM_RECORD_INVOKE_DYNAMIC;
}
+ /**
+ * Returns true if this field is only read by methods for which {@param predicate} returns true.
+ */
+ @Override
+ public boolean isReadOnlyInMethodSatisfying(Predicate<ProgramMethod> predicate) {
+ return readsWithContexts.isAccessedOnlyInMethodSatisfying(predicate) && !isReadIndirectly();
+ }
+
/** Returns true if this field is written by the program. */
@Override
public boolean isWritten() {
+ return isWrittenDirectly() || isWrittenIndirectly();
+ }
+
+ private boolean isWrittenDirectly() {
return !writesWithContexts.isEmpty();
}
+ private boolean isWrittenIndirectly() {
+ return hasReflectiveWrite() || isWrittenFromMethodHandle();
+ }
+
@Override
public boolean isWrittenFromMethodHandle() {
return (flags & FLAG_IS_WRITTEN_FROM_METHOD_HANDLE) != 0;
@@ -256,15 +312,7 @@
*/
@Override
public boolean isWrittenOnlyInMethodSatisfying(Predicate<ProgramMethod> predicate) {
- return writesWithContexts.isAccessedOnlyInMethodSatisfying(predicate);
- }
-
- /**
- * Returns true if this field is only read by methods for which {@param predicate} returns true.
- */
- @Override
- public boolean isReadOnlyInMethodSatisfying(Predicate<ProgramMethod> predicate) {
- return readsWithContexts.isAccessedOnlyInMethodSatisfying(predicate);
+ return writesWithContexts.isAccessedOnlyInMethodSatisfying(predicate) && !isWrittenIndirectly();
}
/**
@@ -272,7 +320,7 @@
*/
@Override
public boolean isWrittenOutside(DexEncodedMethod method) {
- return writesWithContexts.isAccessedOutside(method);
+ return writesWithContexts.isAccessedOutside(method) || isWrittenIndirectly();
}
public boolean recordRead(DexField access, ProgramMethod context) {
diff --git a/src/main/java/com/android/tools/r8/graph/InvalidCode.java b/src/main/java/com/android/tools/r8/graph/InvalidCode.java
index 5363897..2b9de26 100644
--- a/src/main/java/com/android/tools/r8/graph/InvalidCode.java
+++ b/src/main/java/com/android/tools/r8/graph/InvalidCode.java
@@ -5,6 +5,7 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
@@ -23,7 +24,11 @@
private InvalidCode() {}
@Override
- public IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
+ public IRCode buildIR(
+ ProgramMethod method,
+ AppView<?> appView,
+ Origin origin,
+ MutableMethodConversionOptions conversionOptions) {
throw new Unreachable();
}
diff --git a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
index afbda8d..8e5ec1f 100644
--- a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
@@ -106,6 +106,12 @@
}
}
+ if (classKind == ClassKind.PROGRAM
+ && application.options.isDesugaring()
+ && application.options.desugarGraphConsumer != null) {
+ application.options.desugarGraphConsumer.acceptProgramNode(origin);
+ }
+
ClassReader reader = new ClassReader(bytes);
int parsingOptions = SKIP_FRAMES | SKIP_CODE;
diff --git a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
index b2efb1b..c32d6cb 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
@@ -60,6 +60,7 @@
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.Position.SourcePosition;
import com.android.tools.r8.ir.code.ValueType;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.position.MethodPosition;
@@ -67,6 +68,7 @@
import com.android.tools.r8.position.TextRange;
import com.android.tools.r8.shaking.ProguardConfiguration;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
+import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.ExceptionUtils;
import com.android.tools.r8.utils.InternalOptions;
import it.unimi.dsi.fastutil.ints.Int2ReferenceAVLTreeMap;
@@ -240,8 +242,12 @@
}
@Override
- public IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
- return asCfCode().buildIR(method, appView, origin);
+ public IRCode buildIR(
+ ProgramMethod method,
+ AppView<?> appView,
+ Origin origin,
+ MutableMethodConversionOptions conversionOptions) {
+ return asCfCode().buildIR(method, appView, origin, conversionOptions);
}
@Override
@@ -959,7 +965,9 @@
@Override
public void visitMultiANewArrayInsn(String desc, int dims) {
- if (!application.options.isGeneratingDex()) {
+ InternalOptions options = application.options;
+ if (options.isGeneratingClassFiles()
+ && !options.testing.enableMultiANewArrayDesugaringForClassFiles) {
instructions.add(new CfMultiANewArray(factory.createType(desc), dims));
return;
}
@@ -987,7 +995,18 @@
visitInsn(Opcodes.IASTORE);
// ..., count1, ..., dim-array
}
- visitLdcInsn(Type.getType(desc.substring(dims)));
+ String baseDesc = desc.substring(dims);
+ if (DescriptorUtils.isPrimitiveDescriptor(baseDesc)) {
+ visitFieldInsn(
+ Opcodes.GETSTATIC,
+ DescriptorUtils.primitiveDescriptorToBoxedInternalName(baseDesc.charAt(0)),
+ "TYPE",
+ "Ljava/lang/Class;");
+ } else if (DescriptorUtils.isVoidDescriptor(baseDesc)) {
+ visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Void", "TYPE", "Ljava/lang/Class;");
+ } else {
+ visitLdcInsn(Type.getType(baseDesc));
+ }
// ..., dim-array, dim-member-type
visitInsn(Opcodes.SWAP);
// ..., dim-member-type, dim-array
diff --git a/src/main/java/com/android/tools/r8/graph/MethodResolution.java b/src/main/java/com/android/tools/r8/graph/MethodResolution.java
new file mode 100644
index 0000000..2f6939e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/MethodResolution.java
@@ -0,0 +1,418 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph;
+
+import com.android.tools.r8.graph.MethodResolutionResult.ArrayCloneMethodResult;
+import com.android.tools.r8.graph.MethodResolutionResult.ClassNotFoundResult;
+import com.android.tools.r8.graph.MethodResolutionResult.IllegalAccessOrNoSuchMethodResult;
+import com.android.tools.r8.graph.MethodResolutionResult.IncompatibleClassResult;
+import com.android.tools.r8.graph.MethodResolutionResult.NoSuchMethodResult;
+import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
+import com.android.tools.r8.ir.desugar.LambdaDescriptor;
+import com.android.tools.r8.utils.ListUtils;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.function.Function;
+
+/**
+ * Implements resolution of a method descriptor against a type.
+ *
+ * <p>See <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.3">
+ * Section 5.4.3.3 of the JVM Spec</a>.
+ */
+public class MethodResolution {
+
+ private final Function<DexType, DexClass> definitionFor;
+ private final DexItemFactory factory;
+
+ public MethodResolution(Function<DexType, DexClass> definitionFor, DexItemFactory factory) {
+ this.definitionFor = definitionFor;
+ this.factory = factory;
+ }
+
+ private DexClass definitionFor(DexType type) {
+ return definitionFor.apply(type);
+ }
+
+ /**
+ * This method will query the definition of the holder to decide on which resolution to use. If
+ * the holder is an interface, it delegates to {@link #resolveMethodOnInterface(DexClass,
+ * DexProto, DexString)}, otherwise {@link #resolveMethodOnClass(DexClass, DexProto, DexString)}
+ * is used.
+ *
+ * <p>This is to overcome the shortcoming of the DEX file format that does not allow to encode the
+ * kind of a method reference.
+ */
+ public MethodResolutionResult unsafeResolveMethodDueToDexFormat(DexMethod method) {
+ DexType holder = method.holder;
+ if (holder.isArrayType()) {
+ return resolveMethodOnArray(holder, method.getProto(), method.getName());
+ }
+ DexClass definition = definitionFor(holder);
+ if (definition == null) {
+ return ClassNotFoundResult.INSTANCE;
+ } else if (definition.isInterface()) {
+ return resolveMethodOnInterface(definition, method.getProto(), method.getName());
+ } else {
+ return resolveMethodOnClass(definition, method.getProto(), method.getName());
+ }
+ }
+
+ /**
+ * Implements resolution of a method descriptor against an array type.
+ *
+ * <p>See <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-10.html#jls-10.7">Section
+ * 10.7 of the Java Language Specification</a>. All invokations will have target java.lang.Object
+ * except clone which has no target.
+ */
+ private MethodResolutionResult resolveMethodOnArray(
+ DexType holder, DexProto methodProto, DexString methodName) {
+ assert holder.isArrayType();
+ if (methodName == factory.cloneMethodName) {
+ return ArrayCloneMethodResult.INSTANCE;
+ } else {
+ return resolveMethodOnClass(factory.objectType, methodProto, methodName);
+ }
+ }
+
+ /**
+ * Implements resolution of a method descriptor against a class type.
+ *
+ * <p>See <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.3">
+ * Section 5.4.3.3 of the JVM Spec</a>.
+ *
+ * <p>The resolved method is not the method that will actually be invoked. Which methods gets
+ * invoked depends on the invoke instruction used. However, it is always safe to rewrite any
+ * invoke on the given descriptor to a corresponding invoke on the resolved descriptor, as the
+ * resolved method is used as basis for dispatch.
+ */
+ public MethodResolutionResult resolveMethodOnClass(
+ DexType holder, DexProto methodProto, DexString methodName) {
+ if (holder.isArrayType()) {
+ return resolveMethodOnArray(holder, methodProto, methodName);
+ }
+ DexClass clazz = definitionFor(holder);
+ if (clazz == null) {
+ return ClassNotFoundResult.INSTANCE;
+ }
+ // Step 1: If holder is an interface, resolution fails with an ICCE. We return null.
+ if (clazz.isInterface()) {
+ return IncompatibleClassResult.INSTANCE;
+ }
+ return resolveMethodOnClass(clazz, methodProto, methodName);
+ }
+
+ public MethodResolutionResult resolveMethodOnClass(
+ DexClass clazz, DexProto methodProto, DexString methodName) {
+ assert !clazz.isInterface();
+ // Step 2:
+ MethodResolutionResult result =
+ resolveMethodOnClassStep2(clazz, methodProto, methodName, clazz);
+ if (result != null) {
+ return result;
+ }
+ // Finally Step 3:
+ return resolveMethodStep3(clazz, methodProto, methodName);
+ }
+
+ /**
+ * Implements step 2 of method resolution on classes as per <a
+ * href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.3">Section
+ * 5.4.3.3 of the JVM Spec</a>.
+ */
+ private MethodResolutionResult resolveMethodOnClassStep2(
+ DexClass clazz,
+ DexProto methodProto,
+ DexString methodName,
+ DexClass initialResolutionHolder) {
+ // Pt. 1: Signature polymorphic method check.
+ // See also <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.9">
+ // Section 2.9 of the JVM Spec</a>.
+ DexEncodedMethod result = clazz.lookupSignaturePolymorphicMethod(methodName, factory);
+ if (result != null) {
+ return new SingleResolutionResult(initialResolutionHolder, clazz, result);
+ }
+ // Pt 2: Find a method that matches the descriptor.
+ result = clazz.lookupMethod(methodProto, methodName);
+ if (result != null) {
+ // If the resolved method is private, then it can only be accessed if the symbolic reference
+ // that initiated the resolution was the type at which the method resolved on. If that is not
+ // the case, then the error is either an IllegalAccessError, or in the case where access is
+ // allowed because of nests, a NoSuchMethodError. Which error cannot be determined without
+ // knowing the calling context.
+ if (result.isPrivateMethod() && clazz != initialResolutionHolder) {
+ return new IllegalAccessOrNoSuchMethodResult(initialResolutionHolder, result);
+ }
+ return new SingleResolutionResult(initialResolutionHolder, clazz, result);
+ }
+ // Pt 3: Apply step two to direct superclass of holder.
+ if (clazz.superType != null) {
+ DexClass superClass = definitionFor(clazz.superType);
+ if (superClass != null) {
+ return resolveMethodOnClassStep2(
+ superClass, methodProto, methodName, initialResolutionHolder);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Implements step 3 of <a
+ * href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.3">Section
+ * 5.4.3.3 of the JVM Spec</a>. As this is the same for interfaces and classes, we share one
+ * implementation.
+ */
+ private MethodResolutionResult resolveMethodStep3(
+ DexClass clazz, DexProto methodProto, DexString methodName) {
+ MaximallySpecificMethodsBuilder builder =
+ new MaximallySpecificMethodsBuilder(definitionFor, factory);
+ resolveMethodStep3Helper(methodProto, methodName, clazz, builder);
+ return builder.resolve(clazz);
+ }
+
+ MethodResolutionResult resolveMaximallySpecificTarget(DexClass clazz, DexMethod method) {
+ return resolveMaximallySpecificTargetHelper(clazz, method).resolve(clazz);
+ }
+
+ MethodResolutionResult resolveMaximallySpecificTarget(LambdaDescriptor lambda, DexMethod method) {
+ return resolveMaximallySpecificTargetHelper(lambda, method).internalResolve(null);
+ }
+
+ // Non-private lookup (ie, not resolution) to find interface targets.
+ DexClassAndMethod lookupMaximallySpecificTarget(DexClass clazz, DexMethod method) {
+ return resolveMaximallySpecificTargetHelper(clazz, method).lookup();
+ }
+
+ private MaximallySpecificMethodsBuilder resolveMaximallySpecificTargetHelper(
+ DexClass clazz, DexMethod method) {
+ MaximallySpecificMethodsBuilder builder =
+ new MaximallySpecificMethodsBuilder(definitionFor, factory);
+ resolveMethodStep3Helper(method.getProto(), method.getName(), clazz, builder);
+ return builder;
+ }
+
+ private MaximallySpecificMethodsBuilder resolveMaximallySpecificTargetHelper(
+ LambdaDescriptor lambda, DexMethod method) {
+ MaximallySpecificMethodsBuilder builder =
+ new MaximallySpecificMethodsBuilder(definitionFor, factory);
+ resolveMethodStep3Helper(
+ method.getProto(), method.getName(), factory.objectType, lambda.interfaces, builder);
+ return builder;
+ }
+
+ /** Helper method that builds the set of maximally specific methods. */
+ private void resolveMethodStep3Helper(
+ DexProto methodProto,
+ DexString methodName,
+ DexClass clazz,
+ MaximallySpecificMethodsBuilder builder) {
+ resolveMethodStep3Helper(
+ methodProto, methodName, clazz.superType, Arrays.asList(clazz.interfaces.values), builder);
+ }
+
+ private void resolveMethodStep3Helper(
+ DexProto methodProto,
+ DexString methodName,
+ DexType superType,
+ List<DexType> interfaces,
+ MaximallySpecificMethodsBuilder builder) {
+ for (DexType iface : interfaces) {
+ DexClass definition = definitionFor(iface);
+ if (definition == null) {
+ // Ignore missing interface definitions.
+ continue;
+ }
+ assert definition.isInterface();
+ DexEncodedMethod result = definition.lookupMethod(methodProto, methodName);
+ if (isMaximallySpecificCandidate(result)) {
+ // The candidate is added and doing so will prohibit shadowed methods from being in the set.
+ builder.addCandidate(definition, result);
+ } else {
+ // Look at the super-interfaces of this class and keep searching.
+ resolveMethodStep3Helper(methodProto, methodName, definition, builder);
+ }
+ }
+ // Now look at indirect super interfaces.
+ if (superType != null) {
+ DexClass superClass = definitionFor(superType);
+ if (superClass != null) {
+ resolveMethodStep3Helper(methodProto, methodName, superClass, builder);
+ }
+ }
+ }
+
+ /**
+ * A candidate for being a maximally specific method must have neither its private, nor its static
+ * flag set. A candidate may still not be maximally specific, which entails that no subinterfaces
+ * from also contribute with a candidate to the type. That is not determined by this method.
+ */
+ private boolean isMaximallySpecificCandidate(DexEncodedMethod method) {
+ return method != null && !method.accessFlags.isPrivate() && !method.accessFlags.isStatic();
+ }
+
+ /**
+ * Implements resolution of a method descriptor against an interface type.
+ *
+ * <p>See <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.3">
+ * Section 5.4.3.4 of the JVM Spec</a>.
+ *
+ * <p>The resolved method is not the method that will actually be invoked. Which methods gets
+ * invoked depends on the invoke instruction used. However, it is always save to rewrite any
+ * invoke on the given descriptor to a corresponding invoke on the resolved descriptor, as the
+ * resolved method is used as basis for dispatch.
+ */
+ public MethodResolutionResult resolveMethodOnInterface(
+ DexType holder, DexProto proto, DexString methodName) {
+ if (holder.isArrayType()) {
+ return IncompatibleClassResult.INSTANCE;
+ }
+ // Step 1: Lookup interface.
+ DexClass definition = definitionFor(holder);
+ // If the definition is not an interface, resolution fails with an ICCE. We just return the
+ // empty result here.
+ if (definition == null) {
+ return ClassNotFoundResult.INSTANCE;
+ }
+ if (!definition.isInterface()) {
+ return IncompatibleClassResult.INSTANCE;
+ }
+ return resolveMethodOnInterface(definition, proto, methodName);
+ }
+
+ public MethodResolutionResult resolveMethodOnInterface(
+ DexClass definition, DexProto methodProto, DexString methodName) {
+ assert definition.isInterface();
+ // Step 2: Look for exact method on interface.
+ DexEncodedMethod result = definition.lookupMethod(methodProto, methodName);
+ if (result != null) {
+ return new SingleResolutionResult(definition, definition, result);
+ }
+ // Step 3: Look for matching method on object class.
+ DexClass objectClass = definitionFor(factory.objectType);
+ if (objectClass == null) {
+ return ClassNotFoundResult.INSTANCE;
+ }
+ result = objectClass.lookupMethod(methodProto, methodName);
+ if (result != null && result.accessFlags.isPublic() && !result.accessFlags.isAbstract()) {
+ return new SingleResolutionResult(definition, objectClass, result);
+ }
+ // Step 3: Look for maximally-specific superinterface methods or any interface definition.
+ // This is the same for classes and interfaces.
+ return resolveMethodStep3(definition, methodProto, methodName);
+ }
+
+ static class MaximallySpecificMethodsBuilder {
+
+ // The set of actual maximally specific methods.
+ // This set is linked map so that in the case where a number of methods remain a deterministic
+ // choice can be made. The map is from definition classes to their maximally specific method, or
+ // in the case that a type has a candidate which is shadowed by a subinterface, the map will
+ // map the class to a null entry, thus any addition to the map must check for key containment
+ // prior to writing.
+ private final LinkedHashMap<DexClass, DexEncodedMethod> maximallySpecificMethods =
+ new LinkedHashMap<>();
+ private final Function<DexType, DexClass> definitionFor;
+ private final DexItemFactory factory;
+
+ private MaximallySpecificMethodsBuilder(
+ Function<DexType, DexClass> definitionFor, DexItemFactory factory) {
+ this.definitionFor = definitionFor;
+ this.factory = factory;
+ }
+
+ void addCandidate(DexClass holder, DexEncodedMethod method) {
+ // If this candidate is already a candidate or it is shadowed, then no need to continue.
+ if (maximallySpecificMethods.containsKey(holder)) {
+ return;
+ }
+ maximallySpecificMethods.put(holder, method);
+ // Prune exiting candidates and prohibit future candidates in the super hierarchy.
+ assert holder.isInterface();
+ assert holder.superType == factory.objectType;
+ for (DexType iface : holder.interfaces.values) {
+ markShadowed(iface);
+ }
+ }
+
+ private void markShadowed(DexType type) {
+ if (type == null) {
+ return;
+ }
+ DexClass clazz = definitionFor.apply(type);
+ if (clazz == null) {
+ return;
+ }
+ assert clazz.isInterface();
+ assert clazz.superType == factory.objectType;
+ // A null entry signifies that the candidate is shadowed blocking future candidates.
+ // If the candidate is already shadowed at this type there is no need to shadow further up.
+ if (maximallySpecificMethods.containsKey(clazz)
+ && maximallySpecificMethods.get(clazz) == null) {
+ return;
+ }
+ maximallySpecificMethods.put(clazz, null);
+ for (DexType iface : clazz.interfaces.values) {
+ markShadowed(iface);
+ }
+ }
+
+ DexClassAndMethod lookup() {
+ return internalResolve(null).getResolutionPair();
+ }
+
+ MethodResolutionResult resolve(DexClass initialResolutionHolder) {
+ assert initialResolutionHolder != null;
+ return internalResolve(initialResolutionHolder);
+ }
+
+ private MethodResolutionResult internalResolve(DexClass initialResolutionHolder) {
+ if (maximallySpecificMethods.isEmpty()) {
+ return NoSuchMethodResult.INSTANCE;
+ }
+ // Fast path in the common case of a single method.
+ if (maximallySpecificMethods.size() == 1) {
+ return singleResultHelper(
+ initialResolutionHolder, maximallySpecificMethods.entrySet().iterator().next());
+ }
+ Entry<DexClass, DexEncodedMethod> firstMaximallySpecificMethod = null;
+ List<Entry<DexClass, DexEncodedMethod>> nonAbstractMethods =
+ new ArrayList<>(maximallySpecificMethods.size());
+ for (Entry<DexClass, DexEncodedMethod> entry : maximallySpecificMethods.entrySet()) {
+ DexEncodedMethod method = entry.getValue();
+ if (method == null) {
+ // Ignore shadowed candidates.
+ continue;
+ }
+ if (firstMaximallySpecificMethod == null) {
+ firstMaximallySpecificMethod = entry;
+ }
+ if (method.isNonAbstractVirtualMethod()) {
+ nonAbstractMethods.add(entry);
+ }
+ }
+ // If there are no non-abstract methods, then any candidate will suffice as a target.
+ // For deterministic resolution, we return the first mapped method (of the linked map).
+ if (nonAbstractMethods.isEmpty()) {
+ return singleResultHelper(initialResolutionHolder, firstMaximallySpecificMethod);
+ }
+ // If there is exactly one non-abstract method (a default method) it is the resolution target.
+ if (nonAbstractMethods.size() == 1) {
+ return singleResultHelper(initialResolutionHolder, nonAbstractMethods.get(0));
+ }
+ return IncompatibleClassResult.create(ListUtils.map(nonAbstractMethods, Entry::getValue));
+ }
+
+ private static SingleResolutionResult singleResultHelper(
+ DexClass initialResolutionResult, Entry<DexClass, DexEncodedMethod> entry) {
+ return new SingleResolutionResult(
+ initialResolutionResult != null ? initialResolutionResult : entry.getKey(),
+ entry.getKey(),
+ entry.getValue());
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollection.java b/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollection.java
index 745c558..ef1de89 100644
--- a/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollection.java
@@ -4,9 +4,12 @@
package com.android.tools.r8.graph;
+import com.android.tools.r8.ir.desugar.LambdaDescriptor;
+import com.android.tools.r8.utils.TraversalContinuation;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
+import java.util.function.Function;
/**
* Provides immutable access to {@link ObjectAllocationInfoCollectionImpl}, which stores the set of
@@ -31,6 +34,12 @@
void forEachInstantiatedLambdaInterfaces(Consumer<DexType> consumer);
+ TraversalContinuation<?> traverseInstantiatedSubtypes(
+ DexType type,
+ Function<DexProgramClass, TraversalContinuation<?>> onClass,
+ Function<LambdaDescriptor, TraversalContinuation<?>> onLambda,
+ AppInfo appInfo);
+
ObjectAllocationInfoCollection rewrittenWithLens(
DexDefinitionSupplier definitions, GraphLens lens);
}
diff --git a/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollectionImpl.java b/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollectionImpl.java
index f1a3bda..6b31147 100644
--- a/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollectionImpl.java
+++ b/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollectionImpl.java
@@ -183,6 +183,7 @@
appInfo);
}
+ @Override
public TraversalContinuation<?> traverseInstantiatedSubtypes(
DexType type,
Function<DexProgramClass, TraversalContinuation<?>> onClass,
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
index 3cb1a4c..37d165b 100644
--- a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
@@ -11,12 +11,14 @@
import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.ir.conversion.MethodProcessor;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.kotlin.KotlinMethodLevelInfo;
import com.android.tools.r8.logging.Log;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
/** Type representing a method definition in the programs compilation unit and its holder. */
public final class ProgramMethod extends DexClassAndMethod
@@ -27,8 +29,14 @@
}
public IRCode buildIR(AppView<?> appView) {
+ return buildIR(appView, new MutableMethodConversionOptions(appView.options()));
+ }
+
+ public IRCode buildIR(AppView<?> appView, MutableMethodConversionOptions conversionOptions) {
DexEncodedMethod method = getDefinition();
- return method.hasCode() ? method.getCode().buildIR(this, appView, getOrigin()) : null;
+ return method.hasCode()
+ ? method.getCode().buildIR(this, appView, getOrigin(), conversionOptions)
+ : null;
}
public IRCode buildInliningIR(
@@ -105,7 +113,7 @@
MethodAccessFlags accessFlags = getAccessFlags();
accessFlags.demoteFromAbstract();
getDefinition().setApiLevelForCode(appView.computedMinApiLevel());
- getDefinition().setCode(ThrowNullCode.get(), appView);
+ setCode(ThrowNullCode.get(), appView);
getSimpleFeedback().markProcessed(getDefinition(), ConstraintWithTarget.ALWAYS);
getSimpleFeedback().unsetOptimizationInfoForThrowNullMethod(this);
}
@@ -171,4 +179,29 @@
public KotlinMethodLevelInfo getKotlinInfo() {
return getDefinition().getKotlinInfo();
}
+
+ public boolean getOrComputeReachabilitySensitive(AppView<?> appView) {
+ return getHolder().getOrComputeReachabilitySensitive(appView);
+ }
+
+ public void setCode(Code newCode, AppView<?> appView) {
+ // If the locals are not kept, we might still need information to satisfy -keepparameternames.
+ // The information needs to be retrieved on the original code object before replacing it.
+ Code code = getDefinition().getCode();
+ Int2ReferenceMap<DebugLocalInfo> parameterInfo = getDefinition().getParameterInfo();
+ if (code != null
+ && code.isCfCode()
+ && !getDefinition().hasParameterInfo()
+ && !keepLocals(appView)) {
+ parameterInfo = code.collectParameterInfo(getDefinition(), appView);
+ }
+ getDefinition().setCode(newCode, parameterInfo);
+ }
+
+ public boolean keepLocals(AppView<?> appView) {
+ if (appView.testing().noLocalsTableOnInput) {
+ return false;
+ }
+ return appView.options().debug || getOrComputeReachabilitySensitive(appView);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/graph/ThrowExceptionCode.java b/src/main/java/com/android/tools/r8/graph/ThrowExceptionCode.java
index 3420b1b..55e6f8c 100644
--- a/src/main/java/com/android/tools/r8/graph/ThrowExceptionCode.java
+++ b/src/main/java/com/android/tools/r8/graph/ThrowExceptionCode.java
@@ -18,6 +18,7 @@
import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.structural.HashingVisitor;
@@ -48,7 +49,11 @@
}
@Override
- public IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
+ public IRCode buildIR(
+ ProgramMethod method,
+ AppView<?> appView,
+ Origin origin,
+ MutableMethodConversionOptions conversionOptions) {
throw new Unreachable("Should not be called");
}
diff --git a/src/main/java/com/android/tools/r8/graph/ThrowNullCode.java b/src/main/java/com/android/tools/r8/graph/ThrowNullCode.java
index 03b811f..5b02c12 100644
--- a/src/main/java/com/android/tools/r8/graph/ThrowNullCode.java
+++ b/src/main/java/com/android/tools/r8/graph/ThrowNullCode.java
@@ -19,6 +19,8 @@
import com.android.tools.r8.ir.code.Position.SyntheticPosition;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.ThrowingMethodConversionOptions;
import com.android.tools.r8.ir.conversion.SyntheticStraightLineSourceCode;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.naming.NamingLens;
@@ -52,9 +54,13 @@
}
@Override
- public IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
+ public IRCode buildIR(
+ ProgramMethod method,
+ AppView<?> appView,
+ Origin origin,
+ MutableMethodConversionOptions conversionOptions) {
ThrowNullSourceCode source = new ThrowNullSourceCode(method);
- return IRBuilder.create(method, appView, source, origin).build(method);
+ return IRBuilder.create(method, appView, source, origin).build(method, conversionOptions);
}
@Override
@@ -70,7 +76,7 @@
ThrowNullSourceCode source = new ThrowNullSourceCode(method, callerPosition);
return IRBuilder.createForInlining(
method, appView, codeLens, source, origin, valueNumberGenerator, protoChanges)
- .build(context);
+ .build(context, new ThrowingMethodConversionOptions(appView.options()));
}
@Override
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassInstanceFieldsMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassInstanceFieldsMerger.java
index 682da64..464db91 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassInstanceFieldsMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassInstanceFieldsMerger.java
@@ -23,21 +23,31 @@
import java.util.Set;
import java.util.function.BiConsumer;
-public class ClassInstanceFieldsMerger {
+public interface ClassInstanceFieldsMerger {
- private final AppView<? extends AppInfoWithClassHierarchy> appView;
- private final MergeGroup group;
- private final Builder lensBuilder;
+ void setClassIdField(DexEncodedField classIdField);
- private DexEncodedField classIdField;
+ DexEncodedField[] merge();
- public ClassInstanceFieldsMerger(
- AppView<? extends AppInfoWithClassHierarchy> appView,
- HorizontalClassMergerGraphLens.Builder lensBuilder,
- MergeGroup group) {
- this.appView = appView;
- this.group = group;
- this.lensBuilder = lensBuilder;
+ static ClassInstanceFieldsMerger create(
+ AppView<?> appView, HorizontalClassMergerGraphLens.Builder lensBuilder, MergeGroup group) {
+ if (appView.hasClassHierarchy()) {
+ return new ClassInstanceFieldsMergerImpl(appView.withClassHierarchy(), lensBuilder, group);
+ } else {
+ assert group.getInstanceFieldMap().isEmpty();
+ appView.options().horizontalClassMergerOptions().isRestrictedToSynthetics();
+ return new ClassInstanceFieldsMerger() {
+ @Override
+ public void setClassIdField(DexEncodedField classIdField) {
+ throw new UnsupportedOperationException("No instance field merging in D8");
+ }
+
+ @Override
+ public DexEncodedField[] merge() {
+ return DexEncodedField.EMPTY_ARRAY;
+ }
+ };
+ }
}
/**
@@ -50,7 +60,7 @@
* Bar has fields 'A b' and 'B a'), we make a prepass that matches fields with the same reference
* type.
*/
- public static void mapFields(
+ static void mapFields(
AppView<? extends AppInfoWithClassHierarchy> appView,
DexProgramClass source,
DexProgramClass target,
@@ -90,7 +100,7 @@
}
}
- private static Map<InstanceFieldInfo, LinkedList<DexEncodedField>> getAvailableFieldsByExactInfo(
+ static Map<InstanceFieldInfo, LinkedList<DexEncodedField>> getAvailableFieldsByExactInfo(
DexProgramClass target) {
Map<InstanceFieldInfo, LinkedList<DexEncodedField>> availableFieldsByInfo =
new LinkedHashMap<>();
@@ -102,10 +112,9 @@
return availableFieldsByInfo;
}
- private static Map<InstanceFieldInfo, LinkedList<DexEncodedField>>
- getAvailableFieldsByRelaxedInfo(
- AppView<? extends AppInfoWithClassHierarchy> appView,
- Map<InstanceFieldInfo, LinkedList<DexEncodedField>> availableFieldsByExactInfo) {
+ static Map<InstanceFieldInfo, LinkedList<DexEncodedField>> getAvailableFieldsByRelaxedInfo(
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ Map<InstanceFieldInfo, LinkedList<DexEncodedField>> availableFieldsByExactInfo) {
Map<InstanceFieldInfo, LinkedList<DexEncodedField>> availableFieldsByRelaxedInfo =
new LinkedHashMap<>();
availableFieldsByExactInfo.forEach(
@@ -118,64 +127,85 @@
return availableFieldsByRelaxedInfo;
}
- private void fixAccessFlags(DexEncodedField newField, Collection<DexEncodedField> oldFields) {
- if (newField.isSynthetic() && Iterables.any(oldFields, oldField -> !oldField.isSynthetic())) {
- newField.getAccessFlags().demoteFromSynthetic();
- }
- if (newField.isFinal() && Iterables.any(oldFields, oldField -> !oldField.isFinal())) {
- newField.getAccessFlags().demoteFromFinal();
- }
- }
+ class ClassInstanceFieldsMergerImpl implements ClassInstanceFieldsMerger {
- public void setClassIdField(DexEncodedField classIdField) {
- this.classIdField = classIdField;
- }
+ private final AppView<? extends AppInfoWithClassHierarchy> appView;
+ private final MergeGroup group;
+ private final Builder lensBuilder;
- public DexEncodedField[] merge() {
- assert group.hasInstanceFieldMap();
- List<DexEncodedField> newFields = new ArrayList<>();
- if (classIdField != null) {
- newFields.add(classIdField);
- }
- group
- .getInstanceFieldMap()
- .forEachManyToOneMapping(
- (sourceFields, targetField) ->
- newFields.add(mergeSourceFieldsToTargetField(targetField, sourceFields)));
- return newFields.toArray(DexEncodedField.EMPTY_ARRAY);
- }
+ private DexEncodedField classIdField;
- private DexEncodedField mergeSourceFieldsToTargetField(
- DexEncodedField targetField, Set<DexEncodedField> sourceFields) {
- fixAccessFlags(targetField, sourceFields);
-
- DexEncodedField newField;
- if (needsRelaxedType(targetField, sourceFields)) {
- DexType newFieldType =
- DexTypeUtils.computeLeastUpperBound(
- appView,
- Iterables.transform(
- Iterables.concat(IterableUtils.singleton(targetField), sourceFields),
- DexEncodedField::getType));
- newField =
- targetField.toTypeSubstitutedField(
- appView, targetField.getReference().withType(newFieldType, appView.dexItemFactory()));
- } else {
- newField = targetField;
+ private ClassInstanceFieldsMergerImpl(
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ HorizontalClassMergerGraphLens.Builder lensBuilder,
+ MergeGroup group) {
+ this.appView = appView;
+ this.group = group;
+ this.lensBuilder = lensBuilder;
}
- lensBuilder.recordNewFieldSignature(
- Iterables.transform(
- IterableUtils.append(sourceFields, targetField), DexEncodedField::getReference),
- newField.getReference(),
- targetField.getReference());
+ @Override
+ public void setClassIdField(DexEncodedField classIdField) {
+ this.classIdField = classIdField;
+ }
- return newField;
- }
+ @Override
+ public DexEncodedField[] merge() {
+ assert group.hasInstanceFieldMap();
+ List<DexEncodedField> newFields = new ArrayList<>();
+ if (classIdField != null) {
+ newFields.add(classIdField);
+ }
+ group
+ .getInstanceFieldMap()
+ .forEachManyToOneMapping(
+ (sourceFields, targetField) ->
+ newFields.add(mergeSourceFieldsToTargetField(targetField, sourceFields)));
+ return newFields.toArray(DexEncodedField.EMPTY_ARRAY);
+ }
- private boolean needsRelaxedType(
- DexEncodedField targetField, Iterable<DexEncodedField> sourceFields) {
- return Iterables.any(
- sourceFields, sourceField -> sourceField.getType() != targetField.getType());
+ private DexEncodedField mergeSourceFieldsToTargetField(
+ DexEncodedField targetField, Set<DexEncodedField> sourceFields) {
+ fixAccessFlags(targetField, sourceFields);
+
+ DexEncodedField newField;
+ if (needsRelaxedType(targetField, sourceFields)) {
+ DexType newFieldType =
+ DexTypeUtils.computeLeastUpperBound(
+ appView,
+ Iterables.transform(
+ Iterables.concat(IterableUtils.singleton(targetField), sourceFields),
+ DexEncodedField::getType));
+ newField =
+ targetField.toTypeSubstitutedField(
+ appView,
+ targetField.getReference().withType(newFieldType, appView.dexItemFactory()));
+ } else {
+ newField = targetField;
+ }
+
+ lensBuilder.recordNewFieldSignature(
+ Iterables.transform(
+ IterableUtils.append(sourceFields, targetField), DexEncodedField::getReference),
+ newField.getReference(),
+ targetField.getReference());
+
+ return newField;
+ }
+
+ private void fixAccessFlags(DexEncodedField newField, Collection<DexEncodedField> oldFields) {
+ if (newField.isSynthetic() && Iterables.any(oldFields, oldField -> !oldField.isSynthetic())) {
+ newField.getAccessFlags().demoteFromSynthetic();
+ }
+ if (newField.isFinal() && Iterables.any(oldFields, oldField -> !oldField.isFinal())) {
+ newField.getAccessFlags().demoteFromFinal();
+ }
+ }
+
+ private boolean needsRelaxedType(
+ DexEncodedField targetField, Iterable<DexEncodedField> sourceFields) {
+ return Iterables.any(
+ sourceFields, sourceField -> sourceField.getType() != targetField.getType());
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
index 303efef..0751f8e 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
@@ -7,7 +7,6 @@
import static com.google.common.base.Predicates.not;
import com.android.tools.r8.androidapi.ComputedApiLevel;
-import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexDefinition;
@@ -37,6 +36,7 @@
import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -55,7 +55,7 @@
private static final OptimizationFeedback feedback = OptimizationFeedbackSimple.getInstance();
- private final AppView<? extends AppInfoWithClassHierarchy> appView;
+ private final AppView<?> appView;
private final Mode mode;
private final MergeGroup group;
private final DexItemFactory dexItemFactory;
@@ -74,7 +74,7 @@
private final Collection<VirtualMethodMerger> virtualMethodMergers;
private ClassMerger(
- AppView<? extends AppInfoWithClassHierarchy> appView,
+ AppView<?> appView,
IRCodeProvider codeProvider,
Mode mode,
HorizontalClassMergerGraphLens.Builder lensBuilder,
@@ -88,7 +88,7 @@
// Field mergers.
this.classStaticFieldsMerger = new ClassStaticFieldsMerger(appView, lensBuilder, group);
- this.classInstanceFieldsMerger = new ClassInstanceFieldsMerger(appView, lensBuilder, group);
+ this.classInstanceFieldsMerger = ClassInstanceFieldsMerger.create(appView, lensBuilder, group);
// Method mergers.
this.classInitializerMerger = ClassInitializerMerger.create(group);
@@ -344,16 +344,12 @@
}
public static class Builder {
- private final AppView<? extends AppInfoWithClassHierarchy> appView;
+ private final AppView<?> appView;
private final IRCodeProvider codeProvider;
- private Mode mode;
+ private final Mode mode;
private final MergeGroup group;
- public Builder(
- AppView<? extends AppInfoWithClassHierarchy> appView,
- IRCodeProvider codeProvider,
- MergeGroup group,
- Mode mode) {
+ public Builder(AppView<?> appView, IRCodeProvider codeProvider, MergeGroup group, Mode mode) {
this.appView = appView;
this.codeProvider = codeProvider;
this.group = group;
@@ -361,6 +357,24 @@
}
private List<VirtualMethodMerger> createVirtualMethodMergers() {
+ if (!appView.hasClassHierarchy()) {
+ assert getVirtualMethodMergerBuilders().isEmpty();
+ return Collections.emptyList();
+ }
+ Map<DexMethodSignature, VirtualMethodMerger.Builder> virtualMethodMergerBuilders =
+ getVirtualMethodMergerBuilders();
+ if (virtualMethodMergerBuilders.isEmpty()) {
+ return Collections.emptyList();
+ }
+ List<VirtualMethodMerger> virtualMethodMergers =
+ new ArrayList<>(virtualMethodMergerBuilders.size());
+ for (VirtualMethodMerger.Builder builder : virtualMethodMergerBuilders.values()) {
+ virtualMethodMergers.add(builder.build(appView.withClassHierarchy(), group));
+ }
+ return virtualMethodMergers;
+ }
+
+ private Map<DexMethodSignature, VirtualMethodMerger.Builder> getVirtualMethodMergerBuilders() {
Map<DexMethodSignature, VirtualMethodMerger.Builder> virtualMethodMergerBuilders =
new LinkedHashMap<>();
group.forEach(
@@ -372,12 +386,7 @@
virtualMethod.getReference().getSignature(),
ignore -> new VirtualMethodMerger.Builder())
.add(virtualMethod)));
- List<VirtualMethodMerger> virtualMethodMergers =
- new ArrayList<>(virtualMethodMergerBuilders.size());
- for (VirtualMethodMerger.Builder builder : virtualMethodMergerBuilders.values()) {
- virtualMethodMergers.add(builder.build(appView, group));
- }
- return virtualMethodMergers;
+ return virtualMethodMergerBuilders;
}
private void createClassIdField() {
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
index c0cb840..6671b6a 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
@@ -6,11 +6,12 @@
import static com.android.tools.r8.graph.DexClassAndMethod.asProgramMethodOrNull;
+import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DirectMappedDexApplication;
import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.PrunedItems;
@@ -20,6 +21,7 @@
import com.android.tools.r8.shaking.FieldAccessInfoCollectionModifier;
import com.android.tools.r8.shaking.KeepInfoCollection;
import com.android.tools.r8.shaking.RuntimeTypeCheckInfo;
+import com.android.tools.r8.synthesis.SyntheticItems;
import com.android.tools.r8.utils.InternalOptions.HorizontalClassMergerOptions;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
@@ -47,11 +49,11 @@
}
}
- private final AppView<? extends AppInfoWithClassHierarchy> appView;
+ private final AppView<?> appView;
private final Mode mode;
private final HorizontalClassMergerOptions options;
- private HorizontalClassMerger(AppView<? extends AppInfoWithClassHierarchy> appView, Mode mode) {
+ private HorizontalClassMerger(AppView<?> appView, Mode mode) {
this.appView = appView;
this.mode = mode;
this.options = appView.options().horizontalClassMergerOptions();
@@ -67,12 +69,26 @@
return new HorizontalClassMerger(appView, Mode.FINAL);
}
+ public static HorizontalClassMerger createForD8ClassMerging(AppView<?> appView) {
+ assert appView.options().horizontalClassMergerOptions().isRestrictedToSynthetics();
+ return new HorizontalClassMerger(appView, Mode.FINAL);
+ }
+
+ public void runIfNecessary(ExecutorService executorService, Timing timing)
+ throws ExecutionException {
+ runIfNecessary(executorService, timing, null);
+ }
+
public void runIfNecessary(
- RuntimeTypeCheckInfo runtimeTypeCheckInfo, ExecutorService executorService, Timing timing)
+ ExecutorService executorService, Timing timing, RuntimeTypeCheckInfo runtimeTypeCheckInfo)
throws ExecutionException {
if (options.isEnabled(mode)) {
timing.begin("HorizontalClassMerger (" + mode.toString() + ")");
- run(runtimeTypeCheckInfo, executorService, timing);
+ IRCodeProvider codeProvider =
+ appView.hasClassHierarchy()
+ ? IRCodeProvider.create(appView.withClassHierarchy())
+ : IRCodeProvider.createThrowing();
+ run(runtimeTypeCheckInfo, codeProvider, executorService, timing);
// Clear type elements cache after IR building.
appView.dexItemFactory().clearTypeElementsCache();
@@ -84,10 +100,11 @@
}
private void run(
- RuntimeTypeCheckInfo runtimeTypeCheckInfo, ExecutorService executorService, Timing timing)
+ RuntimeTypeCheckInfo runtimeTypeCheckInfo,
+ IRCodeProvider codeProvider,
+ ExecutorService executorService,
+ Timing timing)
throws ExecutionException {
- IRCodeProvider codeProvider = new IRCodeProvider(appView);
-
// Run the policies on all program classes to produce a final grouping.
List<Policy> policies =
PolicyScheduler.getPolicies(appView, codeProvider, mode, runtimeTypeCheckInfo);
@@ -121,6 +138,7 @@
SyntheticInitializerConverter syntheticInitializerConverter =
syntheticInitializerConverterBuilder.build();
+ assert syntheticInitializerConverter.isEmpty() || appView.enableWholeProgramOptimizations();
syntheticInitializerConverter.convertClassInitializers(executorService);
// Generate the graph lens.
@@ -131,16 +149,34 @@
HorizontalClassMergerGraphLens horizontalClassMergerGraphLens =
createLens(mergedClasses, lensBuilder, mode, syntheticArgumentClass);
- assert verifyNoCyclesInInterfaceHierarchies(groups);
-
- // Prune keep info.
- KeepInfoCollection keepInfo = appView.getKeepInfo();
- keepInfo.mutate(mutator -> mutator.removeKeepInfoForMergedClasses(prunedItems));
+ assert verifyNoCyclesInInterfaceHierarchies(appView, groups);
// Must rewrite AppInfoWithLiveness before pruning the merged classes, to ensure that allocation
// sites, fields accesses, etc. are correctly transferred to the target classes.
- appView.rewriteWithLensAndApplication(
- horizontalClassMergerGraphLens, getNewApplication(mergedClasses));
+ DexApplication newApplication = getNewApplication(mergedClasses);
+ if (appView.enableWholeProgramOptimizations()) {
+ // Prune keep info.
+ KeepInfoCollection keepInfo = appView.getKeepInfo();
+ keepInfo.mutate(mutator -> mutator.removeKeepInfoForMergedClasses(prunedItems));
+ assert appView.hasClassHierarchy();
+ appView.rewriteWithLensAndApplication(
+ horizontalClassMergerGraphLens, newApplication.toDirect());
+ } else {
+ assert mode.isFinal();
+ SyntheticItems syntheticItems = appView.appInfo().getSyntheticItems();
+ assert !syntheticItems.hasPendingSyntheticClasses();
+ appView
+ .withoutClassHierarchy()
+ .setAppInfo(
+ new AppInfo(
+ syntheticItems.commitRewrittenWithLens(
+ newApplication, horizontalClassMergerGraphLens),
+ appView
+ .appInfo()
+ .getMainDexInfo()
+ .rewrittenWithLens(syntheticItems, horizontalClassMergerGraphLens)));
+ appView.setGraphLens(horizontalClassMergerGraphLens);
+ }
codeProvider.setGraphLens(horizontalClassMergerGraphLens);
// Record where the synthesized $r8$classId fields are read and written.
@@ -162,6 +198,10 @@
private void amendKeepInfo(
HorizontalClassMergerGraphLens horizontalClassMergerGraphLens,
List<VirtuallyMergedMethodsKeepInfo> virtuallyMergedMethodsKeepInfos) {
+ if (!appView.enableWholeProgramOptimizations()) {
+ assert virtuallyMergedMethodsKeepInfos.isEmpty();
+ return;
+ }
appView
.getKeepInfo()
.mutate(
@@ -213,6 +253,10 @@
HorizontalClassMergerGraphLens horizontalClassMergerGraphLens,
ExecutorService executorService)
throws ExecutionException {
+ if (!appView.hasClassHierarchy()) {
+ assert verifyNoIncompleteCode(groups, executorService);
+ return;
+ }
ThreadUtils.processItems(
groups,
group -> {
@@ -225,25 +269,47 @@
IncompleteHorizontalClassMergerCode code =
(IncompleteHorizontalClassMergerCode) method.getDefinition().getCode();
method
- .getDefinition()
.setCode(
- code.toCfCode(appView, method, horizontalClassMergerGraphLens), appView);
+ code.toCfCode(
+ appView.withClassHierarchy(), method, horizontalClassMergerGraphLens),
+ appView);
});
},
executorService);
}
- private DirectMappedDexApplication getNewApplication(HorizontallyMergedClasses mergedClasses) {
+ private boolean verifyNoIncompleteCode(
+ Collection<MergeGroup> groups, ExecutorService executorService) throws ExecutionException {
+ ThreadUtils.processItems(
+ groups,
+ group -> {
+ assert !group
+ .getTarget()
+ .methods(
+ method ->
+ method.hasCode()
+ && method.getCode().isIncompleteHorizontalClassMergerCode())
+ .iterator()
+ .hasNext()
+ : "Expected no incomplete code";
+ },
+ executorService);
+ return true;
+ }
+
+ private DexApplication getNewApplication(HorizontallyMergedClasses mergedClasses) {
// In the second round of class merging, we must forcefully remove the merged classes from the
// application, since we won't run tree shaking before writing the application.
- DirectMappedDexApplication application = appView.appInfo().app().asDirect();
- return mode.isInitial()
- ? application
- : application
- .builder()
- .removeProgramClasses(
- clazz -> mergedClasses.hasBeenMergedIntoDifferentType(clazz.getType()))
- .build();
+ if (mode.isInitial()) {
+ return appView.app();
+ } else {
+ return appView
+ .app()
+ .builder()
+ .removeProgramClasses(
+ clazz -> mergedClasses.hasBeenMergedIntoDifferentType(clazz.getType()))
+ .build();
+ }
}
private List<MergeGroup> getInitialGroups() {
@@ -313,13 +379,16 @@
.fixupTypeReferences();
}
- private boolean verifyNoCyclesInInterfaceHierarchies(Collection<MergeGroup> groups) {
+ private static boolean verifyNoCyclesInInterfaceHierarchies(
+ AppView<?> appView, Collection<MergeGroup> groups) {
for (MergeGroup group : groups) {
if (group.isClassGroup()) {
continue;
}
+ assert appView.hasClassHierarchy();
DexProgramClass interfaceClass = group.getTarget();
appView
+ .withClassHierarchy()
.appInfo()
.traverseSuperTypes(
interfaceClass,
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/IRCodeProvider.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/IRCodeProvider.java
index 9f74d8e..166bb1f 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/IRCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/IRCodeProvider.java
@@ -11,31 +11,56 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.IRCode;
-public class IRCodeProvider {
+public interface IRCodeProvider {
- private final AppView<AppInfo> appViewForConversion;
+ IRCode buildIR(ProgramMethod method);
- public IRCodeProvider(AppView<? extends AppInfoWithClassHierarchy> appView) {
- // At this point the code rewritings described by repackaging and synthetic finalization have
- // not been applied to the code objects. These code rewritings will be applied in the
- // application writer. We therefore simulate that we are in D8, to allow building IR for each of
- // the class initializers without applying the unapplied code rewritings, to avoid that we apply
- // the lens more than once to the same piece of code.
- AppView<AppInfo> appViewForConversion =
- AppView.createForD8(AppInfo.createInitialAppInfo(appView.appInfo().app()));
- appViewForConversion.setGraphLens(appView.graphLens());
- appViewForConversion.setCodeLens(appView.codeLens());
- this.appViewForConversion = appViewForConversion;
+ void setGraphLens(GraphLens graphLens);
+
+ static IRCodeProvider create(AppView<? extends AppInfoWithClassHierarchy> appView) {
+ return new IRCodeProviderImpl(appView);
}
- public IRCode buildIR(ProgramMethod method) {
- return method
- .getDefinition()
- .getCode()
- .buildIR(method, appViewForConversion, method.getOrigin());
+ static IRCodeProvider createThrowing() {
+ return new IRCodeProvider() {
+ @Override
+ public IRCode buildIR(ProgramMethod method) {
+ throw new UnsupportedOperationException("Should never build IR for methods in D8");
+ }
+
+ @Override
+ public void setGraphLens(GraphLens graphLens) {}
+ };
}
- public void setGraphLens(GraphLens graphLens) {
- appViewForConversion.setGraphLens(graphLens);
+ class IRCodeProviderImpl implements IRCodeProvider {
+
+ private final AppView<AppInfo> appViewForConversion;
+
+ private IRCodeProviderImpl(AppView<? extends AppInfoWithClassHierarchy> appView) {
+ // At this point the code rewritings described by repackaging and synthetic finalization have
+ // not been applied to the code objects. These code rewritings will be applied in the
+ // application writer. We therefore simulate that we are in D8, to allow building IR for each
+ // of the class initializers without applying the unapplied code rewritings, to avoid that we
+ // apply the lens more than once to the same piece of code.
+ AppView<AppInfo> appViewForConversion =
+ AppView.createForD8(AppInfo.createInitialAppInfo(appView.appInfo().app()));
+ appViewForConversion.setGraphLens(appView.graphLens());
+ appViewForConversion.setCodeLens(appView.codeLens());
+ this.appViewForConversion = appViewForConversion;
+ }
+
+ @Override
+ public IRCode buildIR(ProgramMethod method) {
+ return method
+ .getDefinition()
+ .getCode()
+ .buildIR(method, appViewForConversion, method.getOrigin());
+ }
+
+ @Override
+ public void setGraphLens(GraphLens graphLens) {
+ appViewForConversion.setGraphLens(graphLens);
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteHorizontalClassMergerCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteHorizontalClassMergerCode.java
index d961949..c9c8e34 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteHorizontalClassMergerCode.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteHorizontalClassMergerCode.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
@@ -37,7 +38,11 @@
// Implement Code.
@Override
- public IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
+ public IRCode buildIR(
+ ProgramMethod method,
+ AppView<?> appView,
+ Origin origin,
+ MutableMethodConversionOptions conversionOptions) {
throw new Unreachable();
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMergerCollection.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMergerCollection.java
index dbf0943..952421e 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMergerCollection.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMergerCollection.java
@@ -16,6 +16,7 @@
import com.android.tools.r8.utils.collections.ProgramMethodSet;
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
@@ -37,14 +38,21 @@
}
public static InstanceInitializerMergerCollection create(
- AppView<? extends AppInfoWithClassHierarchy> appView,
+ AppView<?> appView,
Reference2IntMap<DexType> classIdentifiers,
IRCodeProvider codeProvider,
MergeGroup group,
HorizontalClassMergerGraphLens.Builder lensBuilder,
Mode mode) {
+ if (!appView.hasClassHierarchy()) {
+ assert appView.options().horizontalClassMergerOptions().isRestrictedToSynthetics();
+ assert verifyNoInstanceInitializers(group);
+ return new InstanceInitializerMergerCollection(
+ Collections.emptyList(), Collections.emptyMap());
+ }
// Create an instance initializer merger for each group of instance initializers that are
// equivalent.
+ AppView<AppInfoWithClassHierarchy> appViewWithClassHierarchy = appView.withClassHierarchy();
Map<InstanceInitializerDescription, Builder> buildersByDescription = new LinkedHashMap<>();
ProgramMethodSet buildersWithoutDescription = ProgramMethodSet.createLinked();
group.forEach(
@@ -54,7 +62,7 @@
instanceInitializer -> {
InstanceInitializerDescription description =
InstanceInitializerAnalysis.analyze(
- appView, codeProvider, group, instanceInitializer);
+ appViewWithClassHierarchy, codeProvider, group, instanceInitializer);
if (description != null) {
buildersByDescription
.computeIfAbsent(
@@ -62,7 +70,10 @@
ignoreKey(
() ->
new InstanceInitializerMerger.Builder(
- appView, classIdentifiers, lensBuilder, mode)))
+ appViewWithClassHierarchy,
+ classIdentifiers,
+ lensBuilder,
+ mode)))
.addEquivalent(instanceInitializer);
} else {
buildersWithoutDescription.add(instanceInitializer);
@@ -95,7 +106,7 @@
instanceInitializer.getDefinition().getProto(),
ignore ->
new InstanceInitializerMerger.Builder(
- appView, classIdentifiers, lensBuilder, mode))
+ appViewWithClassHierarchy, classIdentifiers, lensBuilder, mode))
.add(instanceInitializer));
for (InstanceInitializerMerger.Builder builder : buildersByProto.values()) {
instanceInitializerMergers.addAll(builder.build(group));
@@ -105,7 +116,7 @@
instanceInitializer ->
instanceInitializerMergers.addAll(
new InstanceInitializerMerger.Builder(
- appView, classIdentifiers, lensBuilder, mode)
+ appViewWithClassHierarchy, classIdentifiers, lensBuilder, mode)
.add(instanceInitializer)
.build(group)));
}
@@ -118,6 +129,14 @@
instanceInitializerMergers, equivalentInstanceInitializerMergers);
}
+ private static boolean verifyNoInstanceInitializers(MergeGroup group) {
+ group.forEach(
+ clazz -> {
+ assert !clazz.programInstanceInitializers().iterator().hasNext();
+ });
+ return true;
+ }
+
public void forEach(Consumer<InstanceInitializerMerger> consumer) {
instanceInitializerMergers.forEach(consumer);
equivalentInstanceInitializerMergers.values().forEach(consumer);
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/MergeGroup.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/MergeGroup.java
index 458f0ba..7c7a68d 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/MergeGroup.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/MergeGroup.java
@@ -14,7 +14,7 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramField;
-import com.android.tools.r8.shaking.KeepClassInfo;
+import com.android.tools.r8.shaking.KeepInfoCollection;
import com.android.tools.r8.utils.IterableUtils;
import com.android.tools.r8.utils.IteratorUtils;
import com.android.tools.r8.utils.collections.BidirectionalManyToOneHashMap;
@@ -167,17 +167,18 @@
return new ProgramField(getTarget(), targetField);
}
- public void selectTarget(AppView<? extends AppInfoWithClassHierarchy> appView) {
+ public void selectTarget(AppView<?> appView) {
Iterable<DexProgramClass> candidates = Iterables.filter(getClasses(), DexClass::isPublic);
if (IterableUtils.isEmpty(candidates)) {
candidates = getClasses();
}
Iterator<DexProgramClass> candidateIterator = candidates.iterator();
DexProgramClass target = IterableUtils.first(candidates);
+ KeepInfoCollection keepInfo = appView.getKeepInfo();
while (candidateIterator.hasNext()) {
DexProgramClass current = candidateIterator.next();
- KeepClassInfo keepClassInfo = appView.getKeepInfo().getClassInfo(current);
- if (keepClassInfo.isMinificationAllowed(appView.options())) {
+ if (keepInfo != null
+ && keepInfo.getClassInfo(current).isMinificationAllowed(appView.options())) {
target = current;
break;
}
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 5e76e2d..2ff1bfb 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.horizontalclassmerging;
+import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.ImmediateProgramSubtypingInfo;
@@ -43,6 +44,7 @@
import com.android.tools.r8.horizontalclassmerging.policies.NoVirtualMethodMerging;
import com.android.tools.r8.horizontalclassmerging.policies.NoWeakerAccessPrivileges;
import com.android.tools.r8.horizontalclassmerging.policies.NotMatchedByNoHorizontalClassMerging;
+import com.android.tools.r8.horizontalclassmerging.policies.OnlyClassesWithStaticDefinitions;
import com.android.tools.r8.horizontalclassmerging.policies.OnlyDirectlyConnectedOrUnrelatedInterfaces;
import com.android.tools.r8.horizontalclassmerging.policies.PreserveMethodCharacteristics;
import com.android.tools.r8.horizontalclassmerging.policies.PreventClassMethodAndDefaultMethodCollisions;
@@ -53,7 +55,8 @@
import com.android.tools.r8.horizontalclassmerging.policies.SameNestHost;
import com.android.tools.r8.horizontalclassmerging.policies.SameParentClass;
import com.android.tools.r8.horizontalclassmerging.policies.SyntheticItemsPolicy;
-import com.android.tools.r8.horizontalclassmerging.policies.VerifyPolicyAlwaysSatisfied;
+import com.android.tools.r8.horizontalclassmerging.policies.VerifyMultiClassPolicyAlwaysSatisfied;
+import com.android.tools.r8.horizontalclassmerging.policies.VerifySingleClassPolicyAlwaysSatisfied;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.RuntimeTypeCheckInfo;
import com.android.tools.r8.utils.ListUtils;
@@ -63,6 +66,31 @@
public class PolicyScheduler {
public static List<Policy> getPolicies(
+ AppView<?> appView,
+ IRCodeProvider codeProvider,
+ Mode mode,
+ RuntimeTypeCheckInfo runtimeTypeCheckInfo) {
+ if (appView.hasClassHierarchy()) {
+ return getPoliciesForR8(
+ appView.withClassHierarchy(), codeProvider, mode, runtimeTypeCheckInfo);
+ } else {
+ return getPoliciesForD8(appView.withoutClassHierarchy(), mode);
+ }
+ }
+
+ private static List<Policy> getPoliciesForD8(AppView<AppInfo> appView, Mode mode) {
+ assert mode.isFinal();
+ List<Policy> policies =
+ ImmutableList.<Policy>builder()
+ .addAll(getSingleClassPoliciesForD8(appView, mode))
+ .addAll(getMultiClassPoliciesForD8(appView, mode))
+ .build();
+ policies = appView.options().testing.horizontalClassMergingPolicyRewriter.apply(policies);
+ assert verifyPolicyOrderingConstraints(policies);
+ return policies;
+ }
+
+ private static List<Policy> getPoliciesForR8(
AppView<? extends AppInfoWithClassHierarchy> appView,
IRCodeProvider codeProvider,
Mode mode,
@@ -104,6 +132,16 @@
return builder.build();
}
+ private static List<SingleClassPolicy> getSingleClassPoliciesForD8(
+ AppView<AppInfo> appView, Mode mode) {
+ ImmutableList.Builder<SingleClassPolicy> builder =
+ ImmutableList.<SingleClassPolicy>builder()
+ .add(new CheckSyntheticClasses(appView))
+ .add(new OnlyClassesWithStaticDefinitions());
+ assert verifySingleClassPoliciesIrrelevantForMergingSyntheticsInD8(appView, mode, builder);
+ return builder.build();
+ }
+
private static void addRequiredSingleClassPolicies(
AppView<? extends AppInfoWithClassHierarchy> appView,
ImmutableList.Builder<SingleClassPolicy> builder) {
@@ -148,7 +186,22 @@
new NoKotlinMetadata(),
new NoNativeMethods(),
new NoServiceLoaders(appView));
- policies.stream().map(VerifyPolicyAlwaysSatisfied::new).forEach(builder::add);
+ policies.stream().map(VerifySingleClassPolicyAlwaysSatisfied::new).forEach(builder::add);
+ return true;
+ }
+
+ private static boolean verifySingleClassPoliciesIrrelevantForMergingSyntheticsInD8(
+ AppView<AppInfo> appView, Mode mode, ImmutableList.Builder<SingleClassPolicy> builder) {
+ List<SingleClassPolicy> policies =
+ ImmutableList.of(
+ new NoAnnotationClasses(),
+ new NoDirectRuntimeTypeChecks(appView, mode),
+ new NoInterfaces(appView, mode),
+ new NoInnerClasses(),
+ new NoInstanceFieldAnnotations(),
+ new NoKotlinMetadata(),
+ new NoNativeMethods());
+ policies.stream().map(VerifySingleClassPolicyAlwaysSatisfied::new).forEach(builder::add);
return true;
}
@@ -194,6 +247,22 @@
return builder.add(new FinalizeMergeGroup(appView, mode)).build();
}
+ private static List<? extends Policy> getMultiClassPoliciesForD8(
+ AppView<AppInfo> appView, Mode mode) {
+ ImmutableList.Builder<MultiClassPolicy> builder = ImmutableList.builder();
+ builder.add(
+ new CheckAbstractClasses(appView),
+ new SameMainDexGroup(appView),
+ new SameNestHost(appView),
+ new SameParentClass(),
+ new SyntheticItemsPolicy(appView, mode),
+ new NoDifferentApiReferenceLevel(appView),
+ new LimitClassGroups(appView));
+ assert verifyMultiClassPoliciesIrrelevantForMergingSyntheticsInD8(appView, mode, builder);
+ builder.add(new FinalizeMergeGroup(appView, mode));
+ return builder.build();
+ }
+
private static void addRequiredMultiClassPolicies(
AppView<? extends AppInfoWithClassHierarchy> appView,
Mode mode,
@@ -234,6 +303,14 @@
new OnlyDirectlyConnectedOrUnrelatedInterfaces(appView, mode));
}
+ private static boolean verifyMultiClassPoliciesIrrelevantForMergingSyntheticsInD8(
+ AppView<AppInfo> appView, Mode mode, ImmutableList.Builder<MultiClassPolicy> builder) {
+ List<MultiClassPolicy> policies =
+ ImmutableList.of(new SyntheticItemsPolicy(appView, mode), new SameParentClass());
+ policies.stream().map(VerifyMultiClassPolicyAlwaysSatisfied::new).forEach(builder::add);
+ return true;
+ }
+
private static boolean verifyPolicyOrderingConstraints(List<Policy> policies) {
// No policies that may split interface groups are allowed to run after the
// OnlyDirectlyConnectedOrUnrelatedInterfaces policy. This policy ensures that interface merging
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java
index 183664a..31753bf 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java
@@ -5,7 +5,6 @@
package com.android.tools.r8.horizontalclassmerging;
import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DefaultInstanceInitializerCode;
import com.android.tools.r8.graph.DexEncodedField;
@@ -43,7 +42,7 @@
*/
class TreeFixer extends TreeFixerBase {
- private final AppView<? extends AppInfoWithClassHierarchy> appView;
+ private final AppView<?> appView;
private final HorizontallyMergedClasses mergedClasses;
private final Mode mode;
private final HorizontalClassMergerGraphLens.Builder lensBuilder;
@@ -55,7 +54,7 @@
HashBiMap.create();
public TreeFixer(
- AppView<? extends AppInfoWithClassHierarchy> appView,
+ AppView<?> appView,
HorizontallyMergedClasses mergedClasses,
HorizontalClassMergerGraphLens.Builder lensBuilder,
Mode mode,
@@ -123,17 +122,20 @@
* </ul>
*/
public HorizontalClassMergerGraphLens fixupTypeReferences() {
- Collection<DexProgramClass> classes = appView.appInfo().classesWithDeterministicOrder();
- Iterables.filter(classes, DexProgramClass::isInterface).forEach(this::fixupInterfaceClass);
- classes.forEach(this::fixupAttributes);
- classes.forEach(this::fixupProgramClassSuperTypes);
- SubtypingForrestForClasses subtypingForrest = new SubtypingForrestForClasses(appView);
- // TODO(b/170078037): parallelize this code segment.
- for (DexProgramClass root : subtypingForrest.getProgramRoots()) {
- subtypingForrest.traverseNodeDepthFirst(root, HashBiMap.create(), this::fixupProgramClass);
- }
HorizontalClassMergerGraphLens lens = lensBuilder.build(appView, mergedClasses);
- new AnnotationFixer(lens).run(appView.appInfo().classes());
+ if (appView.enableWholeProgramOptimizations()) {
+ Collection<DexProgramClass> classes = appView.appInfo().classesWithDeterministicOrder();
+ Iterables.filter(classes, DexProgramClass::isInterface).forEach(this::fixupInterfaceClass);
+ classes.forEach(this::fixupAttributes);
+ classes.forEach(this::fixupProgramClassSuperTypes);
+ SubtypingForrestForClasses subtypingForrest =
+ new SubtypingForrestForClasses(appView.withClassHierarchy());
+ // TODO(b/170078037): parallelize this code segment.
+ for (DexProgramClass root : subtypingForrest.getProgramRoots()) {
+ subtypingForrest.traverseNodeDepthFirst(root, HashBiMap.create(), this::fixupProgramClass);
+ }
+ new AnnotationFixer(lens).run(appView.appInfo().classes());
+ }
return lens;
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
index 080df47..1103c8f 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
@@ -60,7 +60,7 @@
SingleResolutionResult resolutionResult =
appView
.appInfo()
- .resolveMethodOnClass(template, group.getSuperType())
+ .resolveMethodOnClass(group.getSuperType(), template)
.asSingleResolution();
if (resolutionResult == null || resolutionResult.getResolvedMethod().isAbstract()) {
// If there is no super method or the method is abstract it should not be called.
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 fcae6d5..9787686 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
@@ -34,6 +34,7 @@
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.Position.SyntheticPosition;
import com.android.tools.r8.ir.code.Return;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.CfVersionUtils;
@@ -193,7 +194,11 @@
}
@Override
- public IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
+ public IRCode buildIR(
+ ProgramMethod method,
+ AppView<?> appView,
+ Origin origin,
+ MutableMethodConversionOptions conversionOptions) {
assert !classInitializers.isEmpty();
Position callerPosition =
@@ -227,7 +232,8 @@
valueNumberGenerator,
blockNumberGenerator,
metadata,
- origin);
+ origin,
+ conversionOptions);
ListIterator<BasicBlock> blockIterator = code.listIterator();
InstructionListIterator instructionIterator = blockIterator.next().listIterator(code);
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/SyntheticInitializerConverter.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/SyntheticInitializerConverter.java
index 446d245..7912f4c 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/SyntheticInitializerConverter.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/SyntheticInitializerConverter.java
@@ -5,7 +5,6 @@
package com.android.tools.r8.horizontalclassmerging.code;
import com.android.tools.r8.graph.AppInfo;
-import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.horizontalclassmerging.IRCodeProvider;
@@ -25,13 +24,13 @@
*/
public class SyntheticInitializerConverter {
- private final AppView<? extends AppInfoWithClassHierarchy> appView;
+ private final AppView<?> appView;
private final IRCodeProvider codeProvider;
private final List<ProgramMethod> classInitializers;
private final List<ProgramMethod> instanceInitializers;
private SyntheticInitializerConverter(
- AppView<? extends AppInfoWithClassHierarchy> appView,
+ AppView<?> appView,
IRCodeProvider codeProvider,
List<ProgramMethod> classInitializers,
List<ProgramMethod> instanceInitializers) {
@@ -41,8 +40,7 @@
this.instanceInitializers = instanceInitializers;
}
- public static Builder builder(
- AppView<? extends AppInfoWithClassHierarchy> appView, IRCodeProvider codeProvider) {
+ public static Builder builder(AppView<?> appView, IRCodeProvider codeProvider) {
return new Builder(appView, codeProvider);
}
@@ -88,13 +86,12 @@
public static class Builder {
- private final AppView<? extends AppInfoWithClassHierarchy> appView;
+ private final AppView<?> appView;
private final IRCodeProvider codeProvider;
private final List<ProgramMethod> classInitializers = new ArrayList<>();
private final List<ProgramMethod> instanceInitializers = new ArrayList<>();
- private Builder(
- AppView<? extends AppInfoWithClassHierarchy> appView, IRCodeProvider codeProvider) {
+ private Builder(AppView<?> appView, IRCodeProvider codeProvider) {
this.appView = appView;
this.codeProvider = codeProvider;
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/CheckAbstractClasses.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/CheckAbstractClasses.java
index 41fba55..06874f0 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/CheckAbstractClasses.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/CheckAbstractClasses.java
@@ -4,7 +4,6 @@
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.MultiClassSameReferencePolicy;
@@ -20,7 +19,7 @@
private final InternalOptions options;
- public CheckAbstractClasses(AppView<? extends AppInfoWithClassHierarchy> appView) {
+ public CheckAbstractClasses(AppView<?> appView) {
this.options = appView.options();
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/CheckSyntheticClasses.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/CheckSyntheticClasses.java
index 8c08712..4d2554a 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/CheckSyntheticClasses.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/CheckSyntheticClasses.java
@@ -4,7 +4,6 @@
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;
@@ -16,7 +15,7 @@
private final HorizontalClassMergerOptions options;
private final SyntheticItems syntheticItems;
- public CheckSyntheticClasses(AppView<? extends AppInfoWithClassHierarchy> appView) {
+ public CheckSyntheticClasses(AppView<?> appView) {
this.options = appView.options().horizontalClassMergerOptions();
this.syntheticItems = appView.getSyntheticItems();
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/FinalizeMergeGroup.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/FinalizeMergeGroup.java
index 705c8cd..b9c4c3c 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/FinalizeMergeGroup.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/FinalizeMergeGroup.java
@@ -4,7 +4,6 @@
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.DexType;
import com.android.tools.r8.horizontalclassmerging.HorizontalClassMerger.Mode;
@@ -12,6 +11,7 @@
import com.android.tools.r8.horizontalclassmerging.MultiClassPolicy;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.SetUtils;
+import com.android.tools.r8.utils.collections.EmptyBidirectionalOneToOneMap;
import java.util.Collection;
import java.util.Set;
@@ -25,23 +25,30 @@
*/
public class FinalizeMergeGroup extends MultiClassPolicy {
- private final AppView<? extends AppInfoWithClassHierarchy> appView;
+ private final AppView<?> appView;
private final Mode mode;
- public FinalizeMergeGroup(AppView<? extends AppInfoWithClassHierarchy> appView, Mode mode) {
+ public FinalizeMergeGroup(AppView<?> appView, Mode mode) {
this.appView = appView;
this.mode = mode;
}
@Override
public Collection<MergeGroup> apply(MergeGroup group) {
- if (mode.isInitial() || group.isInterfaceGroup()) {
- group.selectTarget(appView);
- group.selectInstanceFieldMap(appView);
+ if (appView.enableWholeProgramOptimizations()) {
+ if (mode.isInitial() || group.isInterfaceGroup()) {
+ group.selectTarget(appView);
+ group.selectInstanceFieldMap(appView.withClassHierarchy());
+ } else {
+ // In the final round of merging each group should be finalized by the
+ // NoInstanceInitializerMerging policy.
+ assert verifyAlreadyFinalized(group);
+ }
} else {
- // In the final round of merging each group should be finalized by the
- // NoInstanceInitializerMerging policy.
- assert verifyAlreadyFinalized(group);
+ assert !group.hasTarget();
+ assert !group.hasInstanceFieldMap();
+ group.selectTarget(appView);
+ group.setInstanceFieldMap(new EmptyBidirectionalOneToOneMap<>());
}
return ListUtils.newLinkedList(group);
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/LimitClassGroups.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/LimitClassGroups.java
index 2752544..55d0472 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/LimitClassGroups.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/LimitClassGroups.java
@@ -4,7 +4,6 @@
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.MergeGroup;
@@ -17,8 +16,11 @@
private final int maxGroupSize;
- public LimitClassGroups(AppView<? extends AppInfoWithClassHierarchy> appView) {
- maxGroupSize = appView.options().horizontalClassMergerOptions().getMaxClassGroupSize();
+ public LimitClassGroups(AppView<?> appView) {
+ maxGroupSize =
+ appView.enableWholeProgramOptimizations()
+ ? appView.options().horizontalClassMergerOptions().getMaxClassGroupSizeInR8()
+ : appView.options().horizontalClassMergerOptions().getMaxClassGroupSizeInD8();
assert maxGroupSize >= 2;
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassInitializerCycles.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassInitializerCycles.java
index 79d2a51..fa9bbde 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassInitializerCycles.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassInitializerCycles.java
@@ -487,7 +487,7 @@
DexMethod rewrittenMethod =
appView.graphLens().lookupInvokeDirect(method, getContext()).getReference();
MethodResolutionResult resolutionResult =
- appView.appInfo().resolveMethodOnClass(rewrittenMethod);
+ appView.appInfo().resolveMethodOnClassHolder(rewrittenMethod);
if (resolutionResult.isSingleResolution()
&& resolutionResult.getResolvedHolder().isProgramClass()) {
enqueueMethod(resolutionResult.getResolvedProgramMethod());
@@ -499,7 +499,7 @@
DexMethod rewrittenMethod =
appView.graphLens().lookupInvokeInterface(method, getContext()).getReference();
DexClassAndMethod resolvedMethod =
- appView.appInfo().resolveMethodOnInterface(rewrittenMethod).getResolutionPair();
+ appView.appInfo().resolveMethodOnInterfaceHolder(rewrittenMethod).getResolutionPair();
if (resolvedMethod != null) {
fail();
}
@@ -537,7 +537,7 @@
DexMethod rewrittenMethod =
appView.graphLens().lookupInvokeVirtual(method, getContext()).getReference();
DexClassAndMethod resolvedMethod =
- appView.appInfo().resolveMethodOnClass(rewrittenMethod).getResolutionPair();
+ appView.appInfo().resolveMethodOnClassHolder(rewrittenMethod).getResolutionPair();
if (resolvedMethod != null) {
if (!resolvedMethod.getHolder().isEffectivelyFinal(appView)) {
fail();
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoInterfaces.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoInterfaces.java
index 79b6601..feabe1c 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoInterfaces.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoInterfaces.java
@@ -4,7 +4,6 @@
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.HorizontalClassMerger.Mode;
@@ -16,7 +15,7 @@
private final Mode mode;
private final HorizontalClassMergerOptions options;
- public NoInterfaces(AppView<? extends AppInfoWithClassHierarchy> appView, Mode mode) {
+ public NoInterfaces(AppView<?> appView, Mode mode) {
this.mode = mode;
this.options = appView.options().horizontalClassMergerOptions();
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoVirtualMethodMerging.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoVirtualMethodMerging.java
index 54868a8..a914cf9 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoVirtualMethodMerging.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoVirtualMethodMerging.java
@@ -108,7 +108,7 @@
SingleResolutionResult resolutionResult =
appView
.appInfo()
- .resolveMethodOnClass(method.getReference(), superType)
+ .resolveMethodOnClass(superType, method.getReference())
.asSingleResolution();
return resolutionResult != null && !resolutionResult.getResolvedMethod().isAbstract();
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/OnlyClassesWithStaticDefinitions.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/OnlyClassesWithStaticDefinitions.java
new file mode 100644
index 0000000..736ede0
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/OnlyClassesWithStaticDefinitions.java
@@ -0,0 +1,23 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.horizontalclassmerging.policies;
+
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.horizontalclassmerging.SingleClassPolicy;
+import com.google.common.collect.Iterables;
+
+/** Prevent merging of classes that has non-static methods or fields. */
+public class OnlyClassesWithStaticDefinitions extends SingleClassPolicy {
+
+ @Override
+ public boolean canMerge(DexProgramClass program) {
+ return !Iterables.any(program.members(), member -> !member.isStatic());
+ }
+
+ @Override
+ public String getName() {
+ return "OnlyStaticDefinitions";
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/PreventClassMethodAndDefaultMethodCollisions.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/PreventClassMethodAndDefaultMethodCollisions.java
index d25c21d..54bcf57 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/PreventClassMethodAndDefaultMethodCollisions.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/PreventClassMethodAndDefaultMethodCollisions.java
@@ -171,7 +171,7 @@
if (clazzReserved.contains(signature)) {
DexMethod template = signature.withHolder(clazz, appView.dexItemFactory());
SingleResolutionResult result =
- appView.appInfo().resolveMethodOnClass(template, clazz).asSingleResolution();
+ appView.appInfo().resolveMethodOnClass(clazz, template).asSingleResolution();
if (result == null || result.getResolvedHolder().isInterface()) {
category = MethodCategory.KEEP_ABSENT;
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameMainDexGroup.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameMainDexGroup.java
index 6df343a..82dcbed 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameMainDexGroup.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameMainDexGroup.java
@@ -4,7 +4,6 @@
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.MultiClassSameReferencePolicy;
@@ -17,7 +16,7 @@
private final MainDexInfo mainDexInfo;
private final SyntheticItems synthetics;
- public SameMainDexGroup(AppView<? extends AppInfoWithClassHierarchy> appView) {
+ public SameMainDexGroup(AppView<?> appView) {
mainDexInfo = appView.appInfo().getMainDexInfo();
synthetics = appView.getSyntheticItems();
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameNestHost.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameNestHost.java
index a4ba653..0f6e5ae 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameNestHost.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameNestHost.java
@@ -4,7 +4,6 @@
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.DexItemFactory;
import com.android.tools.r8.graph.DexProgramClass;
@@ -15,7 +14,7 @@
private final DexItemFactory dexItemFactory;
- public SameNestHost(AppView<? extends AppInfoWithClassHierarchy> appView) {
+ public SameNestHost(AppView<?> appView) {
this.dexItemFactory = appView.dexItemFactory();
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SyntheticItemsPolicy.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SyntheticItemsPolicy.java
index f40b722..95764f9 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SyntheticItemsPolicy.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SyntheticItemsPolicy.java
@@ -4,7 +4,6 @@
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.HorizontalClassMerger.Mode;
@@ -22,7 +21,7 @@
private final Mode mode;
private final SyntheticItems syntheticItems;
- public SyntheticItemsPolicy(AppView<? extends AppInfoWithClassHierarchy> appView, Mode mode) {
+ public SyntheticItemsPolicy(AppView<?> appView, Mode mode) {
this.mode = mode;
this.syntheticItems = appView.getSyntheticItems();
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/VerifyMultiClassPolicyAlwaysSatisfied.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/VerifyMultiClassPolicyAlwaysSatisfied.java
new file mode 100644
index 0000000..7ad1e60
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/VerifyMultiClassPolicyAlwaysSatisfied.java
@@ -0,0 +1,44 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.horizontalclassmerging.policies;
+
+import com.android.tools.r8.horizontalclassmerging.MergeGroup;
+import com.android.tools.r8.horizontalclassmerging.MultiClassPolicy;
+import com.android.tools.r8.utils.InternalOptions;
+import java.util.Collection;
+import java.util.Collections;
+
+public class VerifyMultiClassPolicyAlwaysSatisfied extends MultiClassPolicy {
+
+ private final MultiClassPolicy policy;
+
+ public VerifyMultiClassPolicyAlwaysSatisfied(MultiClassPolicy policy) {
+ this.policy = policy;
+ }
+
+ @Override
+ public String getName() {
+ return "VerifyMultiClassPolicyAlwaysSatisfied(" + policy.getName() + ")";
+ }
+
+ @Override
+ public boolean shouldSkipPolicy() {
+ return !InternalOptions.assertionsEnabled() || policy.shouldSkipPolicy();
+ }
+
+ @Override
+ public Collection<MergeGroup> apply(MergeGroup group) {
+ assert verifySameAppliedGroup(group);
+ return Collections.singletonList(group);
+ }
+
+ private boolean verifySameAppliedGroup(MergeGroup group) {
+ Collection<MergeGroup> applied = policy.apply(group);
+ assert applied.size() == 1;
+ MergeGroup appliedGroup = applied.iterator().next();
+ assert appliedGroup.size() == group.size() && group.containsAll(appliedGroup);
+ return true;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/VerifyPolicyAlwaysSatisfied.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/VerifySingleClassPolicyAlwaysSatisfied.java
similarity index 65%
rename from src/main/java/com/android/tools/r8/horizontalclassmerging/policies/VerifyPolicyAlwaysSatisfied.java
rename to src/main/java/com/android/tools/r8/horizontalclassmerging/policies/VerifySingleClassPolicyAlwaysSatisfied.java
index 1fc559c..51d33b7 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/VerifyPolicyAlwaysSatisfied.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/VerifySingleClassPolicyAlwaysSatisfied.java
@@ -6,12 +6,13 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.horizontalclassmerging.SingleClassPolicy;
+import com.android.tools.r8.utils.InternalOptions;
-public class VerifyPolicyAlwaysSatisfied extends SingleClassPolicy {
+public class VerifySingleClassPolicyAlwaysSatisfied extends SingleClassPolicy {
private final SingleClassPolicy policy;
- public VerifyPolicyAlwaysSatisfied(SingleClassPolicy policy) {
+ public VerifySingleClassPolicyAlwaysSatisfied(SingleClassPolicy policy) {
this.policy = policy;
}
@@ -23,11 +24,11 @@
@Override
public String getName() {
- return "VerifyAlwaysSatisfied(" + policy.getName() + ")";
+ return "VerifySingleClassPolicyAlwaysSatisfied(" + policy.getName() + ")";
}
@Override
public boolean shouldSkipPolicy() {
- return policy.shouldSkipPolicy();
+ return !InternalOptions.assertionsEnabled() || policy.shouldSkipPolicy();
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/ClassInitializationAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/ClassInitializationAnalysis.java
index a46b2e0..670f74a 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/ClassInitializationAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/ClassInitializationAnalysis.java
@@ -431,7 +431,7 @@
}
DexMethod method = instruction.getInvokedMethod();
MethodResolutionResult resolutionResult =
- appView.appInfo().resolveMethodOnClass(method, method.holder);
+ appView.appInfo().resolveMethodOnClass(method.holder, method);
if (!resolutionResult.isSingleResolution()) {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/constant/SparseConditionalConstantPropagation.java b/src/main/java/com/android/tools/r8/ir/analysis/constant/SparseConditionalConstantPropagation.java
index cf531ff..0ac3c7e 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/constant/SparseConditionalConstantPropagation.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/constant/SparseConditionalConstantPropagation.java
@@ -78,7 +78,7 @@
}
}
rewriteCode();
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
}
private void rewriteCode() {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java
index bbee604..d05ea55 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java
@@ -203,12 +203,10 @@
}
assert fieldType.isClassType();
DynamicType dynamicType =
- fieldType.isArrayType()
- ? DynamicType.unknown()
- : WideningUtils.widenDynamicNonReceiverType(
- appView,
- value.getDynamicType(appView).withNullability(Nullability.maybeNull()),
- field.getType());
+ WideningUtils.widenDynamicNonReceiverType(
+ appView,
+ value.getDynamicType(appView).withNullability(Nullability.maybeNull()),
+ field.getType());
return ConcreteClassTypeFieldState.create(abstractValue, dynamicType);
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java
index 04b738c..d6ca793 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java
@@ -6,6 +6,7 @@
import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import static com.android.tools.r8.ir.optimize.info.OptimizationFeedback.getSimpleFeedback;
+import static com.android.tools.r8.shaking.ObjectAllocationInfoCollectionUtils.mayHaveFinalizeMethodDirectlyOrIndirectly;
import static com.android.tools.r8.utils.MapUtils.ignoreKey;
import com.android.tools.r8.code.CfOrDexInstanceFieldRead;
@@ -105,6 +106,9 @@
constantFields.forEach(this::markFieldAsDead);
readFields.keySet().forEach(this::markFieldAsDead);
writtenFields.keySet().forEach(this::markWriteOnlyFieldAsDead);
+
+ // Ensure determinism of method-to-reprocess set.
+ appView.testing().checkDeterminism(postMethodProcessorBuilder::dump);
}
private void markWriteOnlyFieldAsDead(DexEncodedField field) {
@@ -286,8 +290,7 @@
ClassTypeElement classType =
(fieldType.isArrayType() ? fieldType.asArrayType().getBaseType() : fieldType)
.asClassType();
- if (classType != null
- && appView.appInfo().mayHaveFinalizeMethodDirectlyOrIndirectly(classType)) {
+ if (classType != null && mayHaveFinalizeMethodDirectlyOrIndirectly(appView, classType)) {
return false;
}
}
@@ -329,7 +332,8 @@
if (definition.isStatic() != isStatic
|| appView.isCfByteCodePassThrough(getContext().getDefinition())
|| resolutionResult.isAccessibleFrom(getContext(), appView).isPossiblyFalse()
- || !resolutionResult.isSingleProgramFieldResolutionResult()) {
+ || !resolutionResult.isSingleProgramFieldResolutionResult()
+ || appView.appInfo().isNeverReprocessMethod(getContext())) {
recordAccessThatCannotBeOptimized(field, definition);
return;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/state/ConcreteClassTypeFieldState.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/state/ConcreteClassTypeFieldState.java
index 7cd6f2e..3f51c25 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/state/ConcreteClassTypeFieldState.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/state/ConcreteClassTypeFieldState.java
@@ -46,13 +46,12 @@
AbstractValue abstractValue,
DynamicType dynamicType,
ProgramField field) {
+ assert field.getType().isClassType();
this.abstractValue =
this.abstractValue.joinReference(abstractValue, appView.abstractValueFactory());
this.dynamicType =
- field.getType().isArrayType()
- ? DynamicType.unknown()
- : WideningUtils.widenDynamicNonReceiverType(
- appView, this.dynamicType.join(appView, dynamicType), field.getType());
+ WideningUtils.widenDynamicNonReceiverType(
+ appView, this.dynamicType.join(appView, dynamicType), field.getType());
return isEffectivelyUnknown() ? unknown() : this;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/EnumLiteProtoShrinker.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/EnumLiteProtoShrinker.java
index 6accb73..e527832 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/EnumLiteProtoShrinker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/EnumLiteProtoShrinker.java
@@ -86,9 +86,14 @@
if (enumLite != null) {
DexEncodedField field =
enumLite.lookupField(createInternalValueMapField(enumLite.getType()));
- return field != null
- && appView.appInfo().isStaticFieldWrittenOnlyInEnclosingStaticInitializer(field)
- && !appView.appInfo().isFieldRead(field);
+ if (field == null) {
+ return false;
+ }
+ if (appView.appInfo().isFieldRead(field)) {
+ return false;
+ }
+ return !appView.appInfo().isFieldWritten(field)
+ || appView.appInfo().isStaticFieldWrittenOnlyInEnclosingStaticInitializer(field);
}
}
return false;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedExtensionRegistryShrinker.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedExtensionRegistryShrinker.java
index 88d1c47..66d04da 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedExtensionRegistryShrinker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedExtensionRegistryShrinker.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.FieldAccessInfo;
import com.android.tools.r8.graph.FieldAccessInfoCollection;
+import com.android.tools.r8.graph.FieldResolutionResult;
import com.android.tools.r8.graph.ProgramField;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.IRCode;
@@ -231,10 +232,18 @@
public boolean isDeadProtoExtensionField(DexField fieldReference) {
AppInfoWithLiveness appInfo = appView.appInfo();
- ProgramField field = appInfo.resolveField(fieldReference).getSingleProgramField();
- return field != null
- && isDeadProtoExtensionField(
- field, appInfo.getFieldAccessInfoCollection(), appInfo.getKeepInfo());
+ return isDeadProtoExtensionField(
+ appInfo.resolveField(fieldReference),
+ appInfo.getFieldAccessInfoCollection(),
+ appInfo.getKeepInfo());
+ }
+
+ public boolean isDeadProtoExtensionField(
+ FieldResolutionResult resolutionResult,
+ FieldAccessInfoCollection<?> fieldAccessInfoCollection,
+ KeepInfoCollection keepInfo) {
+ ProgramField field = resolutionResult.getSingleProgramField();
+ return field != null && isDeadProtoExtensionField(field, fieldAccessInfoCollection, keepInfo);
}
public boolean isDeadProtoExtensionField(
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/LiveProtoFieldObject.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/LiveProtoFieldObject.java
index 4727869..4d10e4f 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/LiveProtoFieldObject.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/LiveProtoFieldObject.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.ir.analysis.type.Nullability;
import com.android.tools.r8.ir.analysis.type.TypeElement;
-import com.android.tools.r8.ir.code.BasicBlock.ThrowingInfo;
import com.android.tools.r8.ir.code.ConstString;
import com.android.tools.r8.ir.code.DexItemBasedConstString;
import com.android.tools.r8.ir.code.IRCode;
@@ -32,7 +31,6 @@
public Instruction buildIR(AppView<?> appView, IRCode code) {
Value value =
code.createValue(TypeElement.stringClassType(appView, Nullability.definitelyNotNull()));
- ThrowingInfo throwingInfo = ThrowingInfo.defaultForConstString(appView.options());
if (appView.options().isMinifying()) {
return new DexItemBasedConstString(value, field, FieldNameComputationInfo.forFieldName());
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java
index b3976c7..e84fc5a 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java
@@ -384,7 +384,7 @@
}
boolean valueStorageIsLive;
- if (enqueuer.isFieldLive(valueStorage)) {
+ if (enqueuer.isFieldReferenced(valueStorage)) {
if (enqueuer.isFieldRead(valueStorage)
|| enqueuer.isFieldWrittenOutsideDefaultConstructor(valueStorage)
|| reachesMapOrRequiredField(protoFieldInfo)) {
@@ -392,15 +392,13 @@
// (i) optimize field reads into loading the default value of the field or (ii) remove
// field writes to proto fields that could be read using reflection by the proto
// library.
- enqueuer.registerReflectiveFieldAccess(valueStorage.getReference(), dynamicMethod);
+ worklist.enqueueTraceReflectiveFieldAccessAction(valueStorage, dynamicMethod);
}
valueStorageIsLive = true;
} else if (reachesMapOrRequiredField(protoFieldInfo)) {
// Map/required fields cannot be removed. Therefore, we mark such fields as both read and
// written such that we cannot optimize any field reads or writes.
- enqueuer.registerReflectiveFieldAccess(valueStorage.getReference(), dynamicMethod);
- worklist.enqueueMarkFieldAsReachableAction(
- valueStorage, dynamicMethod, KeepReason.reflectiveUseIn(dynamicMethod));
+ worklist.enqueueTraceReflectiveFieldAccessAction(valueStorage, dynamicMethod);
valueStorageIsLive = true;
} else {
valueStorageIsLive = false;
@@ -414,7 +412,7 @@
newlyLiveField = protoFieldInfo.getOneOfCaseField(appView, protoMessageInfo);
} else if (protoFieldInfo.hasHazzerBitField(protoMessageInfo)) {
newlyLiveField = protoFieldInfo.getHazzerBitField(appView, protoMessageInfo);
- enqueuer.registerReflectiveFieldAccess(valueStorage.getReference(), dynamicMethod);
+ worklist.enqueueTraceReflectiveFieldAccessAction(valueStorage, dynamicMethod);
}
} else {
// For one-of fields, mark the one-of field as live if the one-of-case field is live, and
@@ -423,13 +421,13 @@
if (protoFieldInfo.getType().isOneOf()) {
ProgramField oneOfCaseField =
protoFieldInfo.getOneOfCaseField(appView, protoMessageInfo);
- if (oneOfCaseField != null && enqueuer.isFieldLive(oneOfCaseField)) {
+ if (oneOfCaseField != null && enqueuer.isFieldReferenced(oneOfCaseField)) {
newlyLiveField = valueStorage;
}
} else if (protoFieldInfo.hasHazzerBitField(protoMessageInfo)) {
ProgramField hazzerBitField =
protoFieldInfo.getHazzerBitField(appView, protoMessageInfo);
- if (hazzerBitField == null || !enqueuer.isFieldLive(hazzerBitField)) {
+ if (hazzerBitField == null || !enqueuer.isFieldReferenced(hazzerBitField)) {
continue;
}
@@ -458,15 +456,12 @@
&& !writer.isStructurallyEqualTo(dynamicMethod);
if (enqueuer.isFieldWrittenInMethodSatisfying(
newlyLiveField, neitherDefaultConstructorNorDynamicMethod)) {
- enqueuer.registerReflectiveFieldRead(newlyLiveField.getReference(), dynamicMethod);
+ worklist.enqueueTraceReflectiveFieldReadAction(newlyLiveField, dynamicMethod);
}
// Unconditionally register the hazzer and one-of proto fields as written from
// dynamicMethod().
- if (enqueuer.registerReflectiveFieldWrite(newlyLiveField.getReference(), dynamicMethod)) {
- worklist.enqueueMarkFieldAsReachableAction(
- newlyLiveField, dynamicMethod, KeepReason.reflectiveUseIn(dynamicMethod));
- }
+ worklist.enqueueTraceReflectiveFieldWriteAction(newlyLiveField, dynamicMethod);
}
}
@@ -497,7 +492,7 @@
// schema, and therefore we do need to trace the const-class instructions that will be
// emitted for it.
ProgramField valueStorage = protoFieldInfo.getValueStorage(appView, protoMessageInfo);
- if (valueStorage != null && enqueuer.isFieldLive(valueStorage)) {
+ if (valueStorage != null && enqueuer.isFieldReferenced(valueStorage)) {
for (ProtoObject object : objects) {
if (object.isProtoObjectFromStaticGet()) {
worklist.enqueueTraceStaticFieldRead(
@@ -554,7 +549,7 @@
return;
}
- if (!enqueuer.isFieldLive(oneOfCaseField)) {
+ if (!enqueuer.isFieldReferenced(oneOfCaseField)) {
return;
}
@@ -578,10 +573,7 @@
return;
}
- if (enqueuer.registerReflectiveFieldWrite(oneOfField.getReference(), dynamicMethod)) {
- worklist.enqueueMarkFieldAsReachableAction(
- oneOfField, dynamicMethod, KeepReason.reflectiveUseIn(dynamicMethod));
- }
+ worklist.enqueueTraceReflectiveFieldWriteAction(oneOfField, dynamicMethod);
}
/**
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/ArrayTypeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/ArrayTypeElement.java
index 78332d5..72cbe7d 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/ArrayTypeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/ArrayTypeElement.java
@@ -3,8 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.analysis.type;
-import static com.android.tools.r8.ir.analysis.type.Nullability.maybeNull;
-
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexItemFactory;
@@ -85,12 +83,10 @@
}
@Override
- public ReferenceTypeElement getOrCreateVariant(Nullability nullability) {
- ArrayTypeElement variant = variants.get(nullability);
- if (variant != null) {
- return variant;
- }
- return variants.getOrCreateElement(nullability, this::createVariant);
+ public ArrayTypeElement getOrCreateVariant(Nullability nullability) {
+ return nullability.equals(nullability())
+ ? this
+ : variants.getOrCreateElement(nullability, this::createVariant);
}
@Override
@@ -151,20 +147,36 @@
ReferenceTypeElement join(ArrayTypeElement other, AppView<?> appView) {
Nullability nullability = nullability().join(other.nullability());
ReferenceTypeElement join =
- joinMember(this.memberTypeLattice, other.memberTypeLattice, appView, nullability);
+ joinMember(getMemberType(), other.getMemberType(), appView, nullability);
if (join == null) {
// Check if other has the right nullability before creating it.
- if (other.nullability == nullability) {
+ if (other.nullability() == nullability) {
return other;
} else {
return getOrCreateVariant(nullability);
}
} else {
- assert join.nullability == nullability;
+ assert join.nullability() == nullability;
return join;
}
}
+ ReferenceTypeElement join(ClassTypeElement other, AppView<?> appView) {
+ return other.join(this, appView);
+ }
+
+ @Override
+ public ReferenceTypeElement join(ReferenceTypeElement other, AppView<?> appView) {
+ if (other.isArrayType()) {
+ return join(other.asArrayType(), appView);
+ }
+ if (other.isClassType()) {
+ return join(other.asClassType(), appView);
+ }
+ assert other.isNullType();
+ return joinNullability(other.nullability());
+ }
+
private static ReferenceTypeElement joinMember(
TypeElement aMember, TypeElement bMember, AppView<?> appView, Nullability nullability) {
if (aMember.equals(bMember)) {
@@ -172,12 +184,14 @@
return null;
}
if (aMember.isArrayType() && bMember.isArrayType()) {
+ TypeElement aMemberMember = aMember.asArrayType().getMemberType();
+ TypeElement bMemberMember = bMember.asArrayType().getMemberType();
TypeElement join =
joinMember(
- aMember.asArrayType().memberTypeLattice,
- bMember.asArrayType().memberTypeLattice,
+ aMemberMember,
+ bMemberMember,
appView,
- maybeNull());
+ aMemberMember.nullability().join(bMemberMember.nullability()));
return join == null ? null : ArrayTypeElement.create(join, nullability);
}
if (aMember.isClassType() && bMember.isClassType()) {
@@ -185,6 +199,20 @@
return ArrayTypeElement.create(join, nullability);
}
if (aMember.isPrimitiveType() || bMember.isPrimitiveType()) {
+ if (appView.enableWholeProgramOptimizations()) {
+ assert appView.hasClassHierarchy();
+ DexItemFactory dexItemFactory = appView.dexItemFactory();
+ InterfaceCollection interfaceCollection =
+ InterfaceCollection.builder()
+ .addKnownInterface(dexItemFactory.cloneableType)
+ .addKnownInterface(dexItemFactory.serializableType)
+ .build();
+ return ClassTypeElement.create(
+ dexItemFactory.objectType,
+ nullability,
+ appView.withClassHierarchy(),
+ interfaceCollection);
+ }
return objectClassType(appView, nullability);
}
return objectArrayType(appView, nullability);
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/ClassTypeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/ClassTypeElement.java
index 7e54571..3298b8e 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/ClassTypeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/ClassTypeElement.java
@@ -111,11 +111,9 @@
@Override
public ClassTypeElement getOrCreateVariant(Nullability nullability) {
- ClassTypeElement variant = variants.get(nullability);
- if (variant != null) {
- return variant;
- }
- return variants.getOrCreateElement(nullability, this::createVariant);
+ return nullability.equals(nullability())
+ ? this
+ : variants.getOrCreateElement(nullability, this::createVariant);
}
@Override
@@ -259,18 +257,39 @@
}
ClassTypeElement join(ClassTypeElement other, AppView<?> appView) {
- if (!appView.enableWholeProgramOptimizations()) {
- assert lazyInterfaces != null;
- assert lazyInterfaces.isEmpty();
- assert other.lazyInterfaces != null;
- assert other.lazyInterfaces.isEmpty();
- return ClassTypeElement.createForD8(
- getClassType() == other.getClassType()
- ? getClassType()
- : appView.dexItemFactory().objectType,
- nullability().join(other.nullability()));
+ if (appView.enableWholeProgramOptimizations()) {
+ return joinWithClassHierarchy(other);
+ } else {
+ return joinWithoutClassHierarchy(other.getClassType(), other.nullability(), appView);
}
- return joinWithClassHierarchy(other);
+ }
+
+ ReferenceTypeElement join(ArrayTypeElement other, AppView<?> appView) {
+ DexItemFactory dexItemFactory = appView.dexItemFactory();
+ if (appView.enableWholeProgramOptimizations()) {
+ DexType lubType = appView.dexItemFactory().objectType;
+ return joinWithClassHierarchy(
+ lubType,
+ InterfaceCollection.builder()
+ .addKnownInterface(dexItemFactory.cloneableType)
+ .addKnownInterface(dexItemFactory.serializableType)
+ .build(),
+ other.nullability());
+ } else {
+ return joinWithoutClassHierarchy(dexItemFactory.objectType, other.nullability(), appView);
+ }
+ }
+
+ @Override
+ public ReferenceTypeElement join(ReferenceTypeElement other, AppView<?> appView) {
+ if (other.isArrayType()) {
+ return join(other.asArrayType(), appView);
+ }
+ if (other.isClassType()) {
+ return join(other.asClassType(), appView);
+ }
+ assert other.isNullType();
+ return joinNullability(other.nullability());
}
private ClassTypeElement joinWithClassHierarchy(ClassTypeElement other) {
@@ -278,17 +297,23 @@
assert appView.enableWholeProgramOptimizations();
DexType lubType =
computeLeastUpperBoundOfClasses(appView.appInfo(), getClassType(), other.getClassType());
- InterfaceCollection c1lubItfs = getInterfaces();
- InterfaceCollection c2lubItfs = other.getInterfaces();
- InterfaceCollection lubItfs =
- c1lubItfs.equals(c2lubItfs)
- ? c1lubItfs
- : computeLeastUpperBoundOfInterfaces(appView, c1lubItfs, c2lubItfs);
- InterfaceCollection lubItfsDefault =
+ return joinWithClassHierarchy(lubType, other.getInterfaces(), other.nullability());
+ }
+
+ private ClassTypeElement joinWithClassHierarchy(
+ DexType lubType, InterfaceCollection otherInterfaces, Nullability nullability) {
+ assert appView != null;
+ assert appView.enableWholeProgramOptimizations();
+ InterfaceCollection interfaces = getInterfaces();
+ InterfaceCollection lubInterfaces =
+ interfaces.equals(otherInterfaces)
+ ? interfaces
+ : computeLeastUpperBoundOfInterfaces(appView, interfaces, otherInterfaces);
+ InterfaceCollection lubInterfacesDefault =
appView
.dexItemFactory()
.getOrComputeLeastUpperBoundOfImplementedInterfaces(lubType, appView);
- Nullability lubNullability = nullability().join(other.nullability());
+ Nullability lubNullability = nullability().join(nullability);
// If the computed interfaces are identical to the interfaces of `lubType`, then do not include
// the interfaces in the ClassTypeElement. This canonicalization of interfaces reduces memory,
@@ -296,9 +321,19 @@
// element does not require any rewriting).
//
// From a correctness point of view, both solutions should work.
- return lubItfs.equals(lubItfsDefault)
+ return lubInterfaces.equals(lubInterfacesDefault)
? create(lubType, lubNullability, appView)
- : create(lubType, lubNullability, appView, lubItfs);
+ : create(lubType, lubNullability, appView, lubInterfaces);
+ }
+
+ ClassTypeElement joinWithoutClassHierarchy(
+ DexType other, Nullability nullability, AppView<?> appView) {
+ assert !appView.enableWholeProgramOptimizations();
+ assert lazyInterfaces != null;
+ assert lazyInterfaces.isEmpty();
+ return createForD8(
+ getClassType() == other ? getClassType() : appView.dexItemFactory().objectType,
+ nullability().join(nullability));
}
/**
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicTypeWithLowerBound.java b/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicTypeWithLowerBound.java
index 9448ebb..1b1a557 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicTypeWithLowerBound.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicTypeWithLowerBound.java
@@ -65,6 +65,15 @@
}
@Override
+ public String toString() {
+ return "DynamicTypeWithLowerBound(upperBound="
+ + getDynamicUpperBoundType()
+ + ", lowerBound="
+ + getDynamicLowerBoundType()
+ + ")";
+ }
+
+ @Override
public DynamicTypeWithLowerBound withNullability(Nullability nullability) {
if (getDynamicUpperBoundType().nullability() == nullability) {
return this;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicTypeWithUpperBound.java b/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicTypeWithUpperBound.java
index 754fb43..5784e9e 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicTypeWithUpperBound.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicTypeWithUpperBound.java
@@ -266,6 +266,11 @@
return dynamicUpperBoundType.hashCode();
}
+ @Override
+ public String toString() {
+ return "DynamicTypeWithUpperBound(upperBound=" + getDynamicUpperBoundType() + ")";
+ }
+
private static boolean verifyNotEffectivelyFinalClassType(
AppView<AppInfoWithLiveness> appView, TypeElement type) {
if (type.isClassType()) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/ExactDynamicType.java b/src/main/java/com/android/tools/r8/ir/analysis/type/ExactDynamicType.java
index 8d2db28..0cd29f2 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/ExactDynamicType.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/ExactDynamicType.java
@@ -73,4 +73,9 @@
public int hashCode() {
return getExactClassType().hashCode();
}
+
+ @Override
+ public String toString() {
+ return "ExactDynamicType(type=" + getExactClassType() + ")";
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/InterfaceCollection.java b/src/main/java/com/android/tools/r8/ir/analysis/type/InterfaceCollection.java
index 02c35fd..7f4e28a 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/InterfaceCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/InterfaceCollection.java
@@ -56,6 +56,10 @@
return this;
}
+ public Builder addKnownInterface(DexType type) {
+ return addInterface(type, true);
+ }
+
public InterfaceCollection build() {
if (interfaces.isEmpty()) {
return InterfaceCollection.empty();
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/NotNullDynamicType.java b/src/main/java/com/android/tools/r8/ir/analysis/type/NotNullDynamicType.java
index 37ed14a..a9830ff 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/NotNullDynamicType.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/NotNullDynamicType.java
@@ -70,4 +70,9 @@
public int hashCode() {
return System.identityHashCode(this);
}
+
+ @Override
+ public String toString() {
+ return "NotNullDynamicType";
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/ReferenceTypeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/ReferenceTypeElement.java
index 3577c72..4aa2116 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/ReferenceTypeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/ReferenceTypeElement.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.ir.analysis.type;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexItemFactory;
public abstract class ReferenceTypeElement extends TypeElement {
@@ -15,7 +16,7 @@
}
@Override
- public ReferenceTypeElement getOrCreateVariant(Nullability nullability) {
+ public NullElement getOrCreateVariant(Nullability nullability) {
return nullability.isNullable() ? NULL_INSTANCE : NULL_BOTTOM_INSTANCE;
}
@@ -33,6 +34,11 @@
}
@Override
+ public ReferenceTypeElement join(ReferenceTypeElement other, AppView<?> appView) {
+ return other.joinNullability(nullability());
+ }
+
+ @Override
public String toString() {
return nullability.toString() + " " + DexItemFactory.nullValueType.toString();
}
@@ -54,8 +60,8 @@
}
}
- private static final ReferenceTypeElement NULL_INSTANCE = NullElement.create();
- private static final ReferenceTypeElement NULL_BOTTOM_INSTANCE = NullElement.createBottom();
+ private static final NullElement NULL_INSTANCE = NullElement.create();
+ private static final NullElement NULL_BOTTOM_INSTANCE = NullElement.createBottom();
final Nullability nullability;
@@ -90,6 +96,8 @@
return getOrCreateVariant(Nullability.maybeNull());
}
+ public abstract ReferenceTypeElement join(ReferenceTypeElement other, AppView<?> appView);
+
public ReferenceTypeElement joinNullability(Nullability nullability) {
return getOrCreateVariant(nullability().join(nullability));
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/TypeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/TypeElement.java
index 6451a1c..ef0e76e 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/TypeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/TypeElement.java
@@ -5,7 +5,6 @@
import static java.util.Collections.emptySet;
-import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexDefinitionSupplier;
@@ -119,48 +118,24 @@
* @return {@link TypeElement}, a least upper bound of {@param this} and {@param other}.
*/
public TypeElement join(TypeElement other, AppView<?> appView) {
- if (this == other) {
+ if (this == other || other.isBottom()) {
return this;
}
if (isBottom()) {
return other;
}
- if (other.isBottom()) {
- return this;
- }
- if (isTop() || other.isTop()) {
+ if (isTop() || other.isTop() || isPrimitiveType() != other.isPrimitiveType()) {
return getTop();
}
if (isPrimitiveType()) {
- return other.isPrimitiveType() ? asPrimitiveType().join(other.asPrimitiveType()) : getTop();
- }
- if (other.isPrimitiveType()) {
- // By the above case, !(isPrimitive())
- return getTop();
+ return asPrimitiveType().join(other.asPrimitiveType());
}
// From now on, this and other are precise reference types, i.e., either ArrayType or ClassType.
- assert isReferenceType() && other.isReferenceType();
- assert isPreciseType() && other.isPreciseType();
- Nullability nullabilityJoin = nullability().join(other.nullability());
- if (isNullType()) {
- return other.asReferenceType().getOrCreateVariant(nullabilityJoin);
- }
- if (other.isNullType()) {
- return this.asReferenceType().getOrCreateVariant(nullabilityJoin);
- }
- if (getClass() != other.getClass()) {
- return objectClassType(appView, nullabilityJoin);
- }
- // From now on, getClass() == other.getClass()
- if (isArrayType()) {
- assert other.isArrayType();
- return asArrayType().join(other.asArrayType(), appView);
- }
- if (isClassType()) {
- assert other.isClassType();
- return asClassType().join(other.asClassType(), appView);
- }
- throw new Unreachable("unless a new type lattice is introduced.");
+ assert isReferenceType();
+ assert isPreciseType();
+ assert other.isReferenceType();
+ assert other.isPreciseType();
+ return asReferenceType().join(other.asReferenceType(), appView);
}
public static TypeElement join(Iterable<TypeElement> typeLattices, AppView<?> appView) {
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 19af1c7..1c50dd7 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
@@ -29,6 +29,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.shaking.ObjectAllocationInfoCollectionUtils;
import com.android.tools.r8.synthesis.SyntheticItems;
public abstract class SingleFieldValue extends SingleValue {
@@ -59,7 +60,8 @@
if (fieldType.isClassType()) {
ClassTypeElement fieldClassType =
TypeElement.fromDexType(fieldType, maybeNull(), appView).asClassType();
- return appView.appInfo().mayHaveFinalizeMethodDirectlyOrIndirectly(fieldClassType);
+ return ObjectAllocationInfoCollectionUtils.mayHaveFinalizeMethodDirectlyOrIndirectly(
+ appView, fieldClassType);
}
assert fieldType.isArrayType() || fieldType.isPrimitiveType();
return false;
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java b/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java
index d51e318..82a2ef7 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java
@@ -25,6 +25,7 @@
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.ir.conversion.TypeConstraintResolver;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
@@ -113,7 +114,8 @@
}
@Override
- public boolean identicalAfterRegisterAllocation(Instruction other, RegisterAllocator allocator) {
+ public boolean identicalAfterRegisterAllocation(
+ Instruction other, RegisterAllocator allocator, MethodConversionOptions conversionOptions) {
// We cannot share ArrayGet instructions without knowledge of the type of the array input.
// If multiple primitive array types flow to the same ArrayGet instruction the art verifier
// gets confused.
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java b/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java
index 3835b3d..a0bf286 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.ir.regalloc.RegisterAllocator;
@@ -84,8 +85,9 @@
}
@Override
- public boolean identicalAfterRegisterAllocation(Instruction other, RegisterAllocator allocator) {
- if (super.identicalAfterRegisterAllocation(other, allocator)) {
+ public boolean identicalAfterRegisterAllocation(
+ Instruction other, RegisterAllocator allocator, MethodConversionOptions conversionOptions) {
+ if (super.identicalAfterRegisterAllocation(other, allocator, conversionOptions)) {
// The array length instruction doesn't carry the element type. The art verifier doesn't
// allow an array length instruction into which arrays of two different base types can
// flow. Therefore, as a safe approximation we only consider array length instructions
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java b/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java
index 9994dde..aa70b4f 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java
@@ -20,6 +20,7 @@
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.ir.conversion.TypeConstraintResolver;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
@@ -173,7 +174,8 @@
}
@Override
- public boolean identicalAfterRegisterAllocation(Instruction other, RegisterAllocator allocator) {
+ public boolean identicalAfterRegisterAllocation(
+ Instruction other, RegisterAllocator allocator, MethodConversionOptions conversionOptions) {
// We cannot share ArrayPut instructions without knowledge of the type of the array input.
// If multiple primitive array types flow to the same ArrayPut instruction the art verifier
// gets confused.
diff --git a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
index e5f15bd..b664c13 100644
--- a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
+++ b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
@@ -120,14 +120,6 @@
public enum ThrowingInfo {
NO_THROW,
CAN_THROW;
-
- public static ThrowingInfo defaultForConstString(InternalOptions options) {
- return options.isGeneratingClassFiles() ? NO_THROW : CAN_THROW;
- }
-
- public static ThrowingInfo defaultForInstruction(Instruction instruction) {
- return instruction.instructionTypeCanThrow() ? CAN_THROW : NO_THROW;
- }
}
public enum EdgeType {
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 60d87b7..f7a77af 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
@@ -9,7 +9,6 @@
import static com.android.tools.r8.ir.analysis.type.Nullability.maybeNull;
import static com.android.tools.r8.ir.code.DominatorTree.Assumption.MAY_HAVE_UNREACHABLE_BLOCKS;
-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.DexField;
@@ -326,8 +325,7 @@
removeOrReplaceByDebugLocalRead();
return true;
}
- DexMethod getClassMethod = appView.dexItemFactory().objectMembers.getClass;
- replaceCurrentInstruction(new InvokeVirtual(getClassMethod, null, ImmutableList.of(receiver)));
+ replaceCurrentInstructionWithNullCheck(appView, receiver);
return true;
}
@@ -408,6 +406,20 @@
}
@Override
+ public void replaceCurrentInstructionWithNullCheck(AppView<?> appView, Value object) {
+ if (current == null) {
+ throw new IllegalStateException();
+ }
+
+ assert current.hasUnusedOutValue();
+ assert !block.hasCatchHandlers() || current.instructionTypeCanThrow();
+
+ DexMethod getClassMethod = appView.dexItemFactory().objectMembers.getClass;
+ replaceCurrentInstruction(
+ InvokeVirtual.builder().setMethod(getClassMethod).setSingleArgument(object).build());
+ }
+
+ @Override
public void replaceCurrentInstructionWithStaticGet(
AppView<?> appView, IRCode code, DexField field, Set<Value> affectedValues) {
if (current == null) {
@@ -492,7 +504,7 @@
@Override
public void replaceCurrentInstructionWithThrowNull(
- AppView<? extends AppInfoWithClassHierarchy> appView,
+ AppView<?> appView,
IRCode code,
ListIterator<BasicBlock> blockIterator,
Set<BasicBlock> blocksToRemove,
@@ -574,7 +586,7 @@
// target.
return;
}
- if (!appView.appInfo().isSubtype(appView.dexItemFactory().npeType, guard)) {
+ if (appView.isSubtype(appView.dexItemFactory().npeType, guard).isFalse()) {
// TODO(christofferqa): Consider updating previous dominator tree instead of
// rebuilding it from scratch.
DominatorTree dominatorTree = new DominatorTree(code, MAY_HAVE_UNREACHABLE_BLOCKS);
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstClass.java b/src/main/java/com/android/tools/r8/ir/code/ConstClass.java
index 716396d..05869bb 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstClass.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstClass.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.cf.code.CfConstClass;
import com.android.tools.r8.dex.Constants;
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.DexClass;
import com.android.tools.r8.graph.DexType;
@@ -21,7 +22,6 @@
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
public class ConstClass extends ConstInstruction {
@@ -34,6 +34,7 @@
public ConstClass(Value dest, DexType clazz, boolean ignoreCompatRules) {
super(dest);
+ assert !clazz.isPrimitiveType();
this.clazz = clazz;
this.ignoreCompatRules = ignoreCompatRules;
}
@@ -133,8 +134,9 @@
return true;
}
- assert appView.appInfo().hasLiveness();
- AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
+ assert appView.appInfo().hasClassHierarchy();
+ AppView<? extends AppInfoWithClassHierarchy> appViewWithClassHierarchy =
+ appView.withClassHierarchy();
DexClass clazz = appView.definitionFor(baseType);
// * Check that the class and its super types are present.
@@ -142,7 +144,8 @@
return true;
}
// * Check that the class is accessible.
- if (AccessControl.isClassAccessible(clazz, context, appViewWithLiveness).isPossiblyFalse()) {
+ if (AccessControl.isClassAccessible(clazz, context, appViewWithClassHierarchy)
+ .isPossiblyFalse()) {
return true;
}
return false;
@@ -202,7 +205,7 @@
@Override
public AbstractValue getAbstractValue(
- AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
+ AppView<? extends AppInfoWithClassHierarchy> appView, ProgramMethod context) {
if (!instructionMayHaveSideEffects(appView, context)) {
return appView.abstractValueFactory().createSingleConstClassValue(clazz);
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java b/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java
index 4111b17..958816b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java
@@ -16,6 +16,7 @@
import com.android.tools.r8.code.ConstWide32;
import com.android.tools.r8.code.ConstWideHigh16;
import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
@@ -27,7 +28,6 @@
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.InternalOutputMode;
import com.android.tools.r8.utils.NumberUtils;
import java.util.Set;
@@ -340,7 +340,7 @@
@Override
public AbstractValue getAbstractValue(
- AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
+ AppView<? extends AppInfoWithClassHierarchy> appView, ProgramMethod context) {
return appView.abstractValueFactory().createSingleNumberValue(value);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstString.java b/src/main/java/com/android/tools/r8/ir/code/ConstString.java
index a3efba8..3df5d13 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstString.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstString.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.cf.TypeVerificationHelper;
import com.android.tools.r8.cf.code.CfConstString;
import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
@@ -20,7 +21,6 @@
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.ir.optimize.DeadCodeRemover.DeadInstructionResult;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
import java.io.UTFDataFormatException;
public class ConstString extends ConstInstruction {
@@ -164,7 +164,7 @@
@Override
public AbstractValue getAbstractValue(
- AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
+ AppView<? extends AppInfoWithClassHierarchy> appView, ProgramMethod context) {
if (!instructionInstanceCanThrow()) {
return appView.abstractValueFactory().createSingleStringValue(value);
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/DexItemBasedConstString.java b/src/main/java/com/android/tools/r8/ir/code/DexItemBasedConstString.java
index 4dc3985..b7820c1 100644
--- a/src/main/java/com/android/tools/r8/ir/code/DexItemBasedConstString.java
+++ b/src/main/java/com/android/tools/r8/ir/code/DexItemBasedConstString.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.cf.TypeVerificationHelper;
import com.android.tools.r8.cf.code.CfDexItemBasedConstString;
import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexType;
@@ -20,7 +21,6 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.dexitembasedstring.NameComputationInfo;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
public class DexItemBasedConstString extends ConstInstruction {
@@ -165,7 +165,7 @@
@Override
public AbstractValue getAbstractValue(
- AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
+ AppView<? extends AppInfoWithClassHierarchy> appView, ProgramMethod context) {
return appView
.abstractValueFactory()
.createSingleDexItemBasedStringValue(item, nameComputationInfo);
diff --git a/src/main/java/com/android/tools/r8/ir/code/FieldGet.java b/src/main/java/com/android/tools/r8/ir/code/FieldGet.java
index aecb3eb..ec663fb 100644
--- a/src/main/java/com/android/tools/r8/ir/code/FieldGet.java
+++ b/src/main/java/com/android/tools/r8/ir/code/FieldGet.java
@@ -5,10 +5,15 @@
package com.android.tools.r8.ir.code;
import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.ir.analysis.type.TypeElement;
public interface FieldGet {
DexField getField();
+ TypeElement getOutType();
+
+ boolean hasUsedOutValue();
+
Value outValue();
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java b/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
index c65bccc..b8eb09d 100644
--- a/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
@@ -3,6 +3,9 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.code;
+import static com.android.tools.r8.shaking.ObjectAllocationInfoCollectionUtils.mayHaveFinalizeMethodDirectlyOrIndirectly;
+
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedField;
@@ -199,17 +202,17 @@
DexItemFactory dexItemFactory = appView.dexItemFactory();
DexEncodedMethod resolutionResult =
appInfo
- .resolveMethodOnClass(dexItemFactory.objectMembers.finalize, clazz)
+ .resolveMethodOnClass(clazz, dexItemFactory.objectMembers.finalize)
.getSingleTarget();
return resolutionResult != null && resolutionResult.isProgramMethod(appView);
}
- return appInfo.mayHaveFinalizeMethodDirectlyOrIndirectly(baseType.asClassType());
+ return mayHaveFinalizeMethodDirectlyOrIndirectly(appView, baseType.asClassType());
}
@Override
public AbstractValue getAbstractValue(
- AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
+ AppView<? extends AppInfoWithClassHierarchy> appView, ProgramMethod context) {
assert isFieldGet();
DexEncodedField field = appView.appInfo().resolveField(getField()).getResolvedField();
if (field != null) {
diff --git a/src/main/java/com/android/tools/r8/ir/code/IRCode.java b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
index 6a237d0..01b08a8 100644
--- a/src/main/java/com/android/tools/r8/ir/code/IRCode.java
+++ b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
@@ -21,6 +21,8 @@
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.Phi.RegisterReadType;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.CfgPrinter;
@@ -110,6 +112,7 @@
public static final int INSTRUCTION_NUMBER_DELTA = 2;
private final ProgramMethod method;
+ private final MutableMethodConversionOptions conversionOptions;
public LinkedList<BasicBlock> blocks;
public final NumberGenerator valueNumberGenerator;
@@ -135,11 +138,13 @@
NumberGenerator valueNumberGenerator,
NumberGenerator basicBlockNumberGenerator,
IRMetadata metadata,
- Origin origin) {
+ Origin origin,
+ MutableMethodConversionOptions conversionOptions) {
assert metadata != null;
assert options != null;
assert blocks.size() == basicBlockNumberGenerator.peek();
this.options = options;
+ this.conversionOptions = conversionOptions;
this.method = method;
this.blocks = blocks;
this.valueNumberGenerator = valueNumberGenerator;
@@ -167,6 +172,14 @@
return blocks.getFirst();
}
+ public MethodConversionOptions getConversionOptions() {
+ return conversionOptions;
+ }
+
+ public void mutateConversionOptions(Consumer<MutableMethodConversionOptions> mutator) {
+ mutator.accept(conversionOptions);
+ }
+
/**
* Compute the set of live values at the entry to each block using a backwards data-flow analysis.
*/
@@ -574,15 +587,15 @@
}
}
- public boolean isConsistentSSA() {
- isConsistentSSABeforeTypesAreCorrect();
+ public boolean isConsistentSSA(AppView<?> appView) {
+ isConsistentSSABeforeTypesAreCorrect(appView);
assert verifyNoImpreciseOrBottomTypes();
return true;
}
- public boolean isConsistentSSABeforeTypesAreCorrect() {
- assert isConsistentGraph(true);
- assert consistentBlockInstructions(true);
+ public boolean isConsistentSSABeforeTypesAreCorrect(AppView<?> appView) {
+ assert isConsistentGraph(appView, true);
+ assert consistentBlockInstructions(appView, true);
assert consistentDefUseChains();
assert validThrowingInstructions();
assert noCriticalEdges();
@@ -615,16 +628,16 @@
return true;
}
- public boolean isConsistentGraph() {
- return isConsistentGraph(false);
+ public boolean isConsistentGraph(AppView<?> appView) {
+ return isConsistentGraph(appView, false);
}
- public boolean isConsistentGraph(boolean ssa) {
+ public boolean isConsistentGraph(AppView<?> appView, boolean ssa) {
assert noColorsInUse();
assert consistentBlockNumbering();
assert consistentPredecessorSuccessors();
assert consistentCatchHandlers();
- assert consistentBlockInstructions(ssa);
+ assert consistentBlockInstructions(appView, ssa);
assert consistentMetadata();
assert !allThrowingInstructionsHavePositions || computeAllThrowingInstructionsHavePositions();
return true;
@@ -816,12 +829,12 @@
return true;
}
- private boolean consistentBlockInstructions(boolean ssa) {
+ private boolean consistentBlockInstructions(AppView<?> appView, boolean ssa) {
boolean argumentsAllowed = true;
for (BasicBlock block : blocks) {
assert block.consistentBlockInstructions(
argumentsAllowed,
- options.debug || method().getOptimizationInfo().isReachabilitySensitive(),
+ options.debug || context().getOrComputeReachabilitySensitive(appView),
ssa);
argumentsAllowed = false;
}
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 21b9df5..9125869 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
@@ -5,7 +5,6 @@
package com.android.tools.r8.ir.code;
import com.android.tools.r8.errors.Unimplemented;
-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.DexField;
@@ -90,6 +89,11 @@
}
@Override
+ public void replaceCurrentInstructionWithNullCheck(AppView<?> appView, Value object) {
+ instructionIterator.replaceCurrentInstructionWithNullCheck(appView, object);
+ }
+
+ @Override
public void replaceCurrentInstructionWithStaticGet(
AppView<?> appView, IRCode code, DexField field, Set<Value> affectedValues) {
instructionIterator.replaceCurrentInstructionWithStaticGet(
@@ -114,7 +118,7 @@
@Override
public void replaceCurrentInstructionWithThrowNull(
- AppView<? extends AppInfoWithClassHierarchy> appView,
+ AppView<?> appView,
IRCode code,
ListIterator<BasicBlock> blockIterator,
Set<BasicBlock> blocksToRemove,
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 e0ca6cd..68d7ffc 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
@@ -26,6 +26,7 @@
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.Query;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.ir.regalloc.RegisterAllocator;
@@ -153,8 +154,9 @@
}
@Override
- public boolean identicalAfterRegisterAllocation(Instruction other, RegisterAllocator allocator) {
- if (!super.identicalAfterRegisterAllocation(other, allocator)) {
+ public boolean identicalAfterRegisterAllocation(
+ Instruction other, RegisterAllocator allocator, MethodConversionOptions conversionOptions) {
+ if (!super.identicalAfterRegisterAllocation(other, allocator, conversionOptions)) {
return false;
}
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 ec25297..feaca12 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
@@ -7,6 +7,7 @@
import com.android.tools.r8.cf.TypeVerificationHelper;
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DebugLocalInfo;
import com.android.tools.r8.graph.DexItemFactory;
@@ -26,12 +27,14 @@
import com.android.tools.r8.ir.analysis.value.UnknownValue;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.ir.optimize.DeadCodeRemover.DeadInstructionResult;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.ir.regalloc.RegisterAllocator;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.CfgPrinter;
+import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.StringUtils.BraceType;
import com.google.common.collect.ImmutableSet;
@@ -178,7 +181,7 @@
}
public AbstractValue getAbstractValue(
- AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
+ AppView<? extends AppInfoWithClassHierarchy> appView, ProgramMethod context) {
assert hasOutValue();
return UnknownValue.getInstance();
}
@@ -501,7 +504,8 @@
return a.outType() == b.outType();
}
- public boolean identicalAfterRegisterAllocation(Instruction other, RegisterAllocator allocator) {
+ public boolean identicalAfterRegisterAllocation(
+ Instruction other, RegisterAllocator allocator, MethodConversionOptions conversionOptions) {
if (other.getClass() != getClass()) {
return false;
}
@@ -541,8 +545,10 @@
}
}
// Finally check that the dex instructions for the generated code actually are the same.
- if (allocator.options().isGeneratingDex()
- && !DexBuilder.identicalInstructionsAfterBuildingDexCode(this, other, allocator)) {
+ InternalOptions options = allocator.options();
+ if (conversionOptions.isGeneratingDex()
+ && !DexBuilder.identicalInstructionsAfterBuildingDexCode(
+ this, other, allocator, conversionOptions)) {
return false;
}
return true;
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 f1eab89..5055072 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
@@ -5,7 +5,6 @@
package com.android.tools.r8.ir.code;
import com.android.tools.r8.errors.Unimplemented;
-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.DexField;
@@ -144,6 +143,8 @@
appView, code, appView.dexItemFactory().createString(value));
}
+ void replaceCurrentInstructionWithNullCheck(AppView<?> appView, Value object);
+
void replaceCurrentInstructionWithStaticGet(
AppView<?> appView, IRCode code, DexField field, Set<Value> affectedValues);
@@ -170,7 +171,7 @@
* @param affectedValues set passed where values depending on detached blocks will be added.
*/
void replaceCurrentInstructionWithThrowNull(
- AppView<? extends AppInfoWithClassHierarchy> appView,
+ AppView<?> appView,
IRCode code,
ListIterator<BasicBlock> blockIterator,
Set<BasicBlock> blocksToRemove,
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 06173d4..1d259f6 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
@@ -9,6 +9,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.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -26,6 +27,7 @@
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.analysis.value.UnknownValue;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.ir.optimize.DefaultInliningOracle;
import com.android.tools.r8.ir.optimize.Inliner.InlineAction;
import com.android.tools.r8.ir.optimize.Inliner.Reason;
@@ -187,8 +189,9 @@
WhyAreYouNotInliningReporter whyAreYouNotInliningReporter);
@Override
- public boolean identicalAfterRegisterAllocation(Instruction other, RegisterAllocator allocator) {
- if (!super.identicalAfterRegisterAllocation(other, allocator)) {
+ public boolean identicalAfterRegisterAllocation(
+ Instruction other, RegisterAllocator allocator, MethodConversionOptions conversionOptions) {
+ if (!super.identicalAfterRegisterAllocation(other, allocator, conversionOptions)) {
return false;
}
@@ -245,7 +248,7 @@
@Override
public AbstractValue getAbstractValue(
- AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
+ AppView<? extends AppInfoWithClassHierarchy> appView, ProgramMethod context) {
assert hasOutValue();
DexClassAndMethod method = lookupSingleTarget(appView, context);
if (method != null) {
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeMethodWithReceiver.java b/src/main/java/com/android/tools/r8/ir/code/InvokeMethodWithReceiver.java
index d01bcaa..cdf992b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeMethodWithReceiver.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeMethodWithReceiver.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.code;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexClassAndMethod;
@@ -192,11 +193,12 @@
return true;
}
- assert appView.appInfo().hasLiveness();
- AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
+ assert appView.appInfo().hasClassHierarchy();
+ AppView<? extends AppInfoWithClassHierarchy> appViewWithClassHierarchy =
+ appView.withClassHierarchy();
SingleResolutionResult resolutionResult =
- appViewWithLiveness
+ appViewWithClassHierarchy
.appInfo()
.resolveMethod(getInvokedMethod(), getInterfaceBit())
.asSingleResolution();
@@ -205,9 +207,7 @@
}
// Verify that the target method is accessible in the current context.
- if (resolutionResult
- .isAccessibleFrom(context, appViewWithLiveness.appInfo())
- .isPossiblyFalse()) {
+ if (resolutionResult.isAccessibleFrom(context, appViewWithClassHierarchy).isPossiblyFalse()) {
return true;
}
@@ -215,14 +215,16 @@
return false;
}
- DexEncodedMethod resolvedMethod = resolutionResult.getResolvedMethod();
- if (appViewWithLiveness.appInfo().noSideEffects.containsKey(getInvokedMethod())
- || appViewWithLiveness.appInfo().noSideEffects.containsKey(resolvedMethod.getReference())) {
- return false;
+ DexClassAndMethod resolvedMethod = resolutionResult.getResolutionPair();
+ if (appView.hasLiveness()) {
+ if (appView.appInfoWithLiveness().isAssumeNoSideEffectsMethod(getInvokedMethod())
+ || appView.appInfoWithLiveness().isAssumeNoSideEffectsMethod(resolvedMethod)) {
+ return false;
+ }
}
// Find the target and check if the invoke may have side effects.
- DexClassAndMethod singleTarget = lookupSingleTarget(appViewWithLiveness, context);
+ DexClassAndMethod singleTarget = lookupSingleTarget(appView, context);
if (singleTarget == null) {
return true;
}
@@ -235,8 +237,10 @@
}
// Verify that the target method does not have side-effects.
- if (appViewWithLiveness.appInfo().noSideEffects.containsKey(singleTarget.getReference())) {
- return false;
+ if (appView.hasLiveness()) {
+ if (appView.appInfoWithLiveness().isAssumeNoSideEffectsMethod(singleTarget)) {
+ return false;
+ }
}
DexEncodedMethod singleTargetDefinition = singleTarget.getDefinition();
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeMultiNewArray.java b/src/main/java/com/android/tools/r8/ir/code/InvokeMultiNewArray.java
index 63df06a..e750ab3 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeMultiNewArray.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeMultiNewArray.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.cf.code.CfMultiANewArray;
import com.android.tools.r8.errors.Unreachable;
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.DexClass;
import com.android.tools.r8.graph.DexType;
@@ -18,7 +19,6 @@
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.LongInterval;
import java.util.List;
@@ -134,8 +134,9 @@
return true;
}
- assert appView.appInfo().hasLiveness();
- AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
+ assert appView.appInfo().hasClassHierarchy();
+ AppView<? extends AppInfoWithClassHierarchy> appViewWithClassHierarchy =
+ appView.withClassHierarchy();
// Check if the type is guaranteed to be present.
DexClass clazz = appView.definitionFor(baseType);
@@ -149,7 +150,8 @@
}
// Check if the type is guaranteed to be accessible.
- if (AccessControl.isClassAccessible(clazz, context, appViewWithLiveness).isPossiblyFalse()) {
+ if (AccessControl.isClassAccessible(clazz, context, appViewWithClassHierarchy)
+ .isPossiblyFalse()) {
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java b/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java
index 636468c..1b356e3 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.code.FilledNewArrayRange;
import com.android.tools.r8.errors.Unreachable;
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.DexClass;
import com.android.tools.r8.graph.DexType;
@@ -22,7 +23,6 @@
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
import java.util.List;
public class InvokeNewArray extends Invoke {
@@ -144,7 +144,7 @@
@Override
public AbstractValue getAbstractValue(
- AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
+ AppView<? extends AppInfoWithClassHierarchy> appView, ProgramMethod context) {
if (!instructionMayHaveSideEffects(appView, context)) {
int size = inValues.size();
return StatefulObjectValue.create(
@@ -175,8 +175,9 @@
return true;
}
- assert appView.appInfo().hasLiveness();
- AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
+ assert appView.appInfo().hasClassHierarchy();
+ AppView<? extends AppInfoWithClassHierarchy> appViewWithClassHierarchy =
+ appView.withClassHierarchy();
// Check if the type is guaranteed to be present.
DexClass clazz = appView.definitionFor(baseType);
@@ -191,7 +192,8 @@
}
// Check if the type is guaranteed to be accessible.
- if (AccessControl.isClassAccessible(clazz, context, appViewWithLiveness).isPossiblyFalse()) {
+ if (AccessControl.isClassAccessible(clazz, context, appViewWithClassHierarchy)
+ .isPossiblyFalse()) {
return true;
}
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 ffb5d2b..093faf1 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
@@ -4,7 +4,6 @@
package com.android.tools.r8.ir.code;
-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.DexField;
@@ -114,6 +113,11 @@
}
@Override
+ public void replaceCurrentInstructionWithNullCheck(AppView<?> appView, Value object) {
+ currentBlockIterator.replaceCurrentInstructionWithNullCheck(appView, object);
+ }
+
+ @Override
public void replaceCurrentInstructionWithStaticGet(
AppView<?> appView, IRCode code, DexField field, Set<Value> affectedValues) {
currentBlockIterator.replaceCurrentInstructionWithStaticGet(
@@ -134,7 +138,7 @@
@Override
public void replaceCurrentInstructionWithThrowNull(
- AppView<? extends AppInfoWithClassHierarchy> appView,
+ AppView<?> appView,
IRCode code,
ListIterator<BasicBlock> blockIterator,
Set<BasicBlock> blocksToRemove,
diff --git a/src/main/java/com/android/tools/r8/ir/code/MoveException.java b/src/main/java/com/android/tools/r8/ir/code/MoveException.java
index dd74687..efec2dd 100644
--- a/src/main/java/com/android/tools/r8/ir/code/MoveException.java
+++ b/src/main/java/com/android/tools/r8/ir/code/MoveException.java
@@ -84,8 +84,8 @@
public DeadInstructionResult canBeDeadCode(AppView<?> appView, IRCode code) {
InternalOptions options = appView.options();
if (options.debug
- || code.context().getDefinition().getOptimizationInfo().isReachabilitySensitive()
- || options.isGeneratingClassFiles()) {
+ || code.context().getOrComputeReachabilitySensitive(appView)
+ || code.getConversionOptions().isGeneratingClassFiles()) {
return DeadInstructionResult.notDead();
}
return DeadInstructionResult.deadIfOutValueIsDead();
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java b/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java
index 3d6fb7d..500766c 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.cf.code.CfNewArray;
import com.android.tools.r8.code.NewArray;
import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
@@ -21,7 +22,6 @@
import com.android.tools.r8.ir.optimize.DeadCodeRemover.DeadInstructionResult;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
public class NewArrayEmpty extends Instruction {
@@ -88,7 +88,7 @@
@Override
public AbstractValue getAbstractValue(
- AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
+ AppView<? extends AppInfoWithClassHierarchy> appView, ProgramMethod context) {
if (!instructionMayHaveSideEffects(appView, context) && size().getType().isInt()) {
assert !instructionInstanceCanThrow();
return StatefulObjectValue.create(
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java b/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java
index fb04f03..260689f 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.code.FillArrayDataPayload;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
@@ -17,7 +18,6 @@
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
import java.util.Arrays;
public class NewArrayFilledData extends Instruction {
@@ -125,7 +125,7 @@
@Override
public AbstractValue getAbstractValue(
- AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
+ AppView<? extends AppInfoWithClassHierarchy> appView, ProgramMethod context) {
if (!instructionMayHaveSideEffects(appView, context) && size <= Integer.MAX_VALUE) {
assert !instructionInstanceCanThrow();
return StatefulObjectValue.create(
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewInstance.java b/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
index 3aff847..baae8e5 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.cf.code.CfNew;
import com.android.tools.r8.dex.Constants;
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.DexClass;
import com.android.tools.r8.graph.DexItemFactory;
@@ -158,8 +159,9 @@
&& dexItemFactory.libraryClassesWithoutStaticInitialization.contains(clazz));
}
- assert appView.appInfo().hasLiveness();
- AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
+ assert appView.appInfo().hasClassHierarchy();
+ AppView<? extends AppInfoWithClassHierarchy> appViewWithClassHierarchy =
+ appView.withClassHierarchy();
if (clazz.isPrimitiveType() || clazz.isArrayType()) {
assert false : "Unexpected new-instance instruction with primitive or array type";
@@ -177,21 +179,22 @@
}
// Verify that the instruction does not lead to an IllegalAccessError.
- if (AccessControl.isClassAccessible(definition, context, appViewWithLiveness)
+ if (AccessControl.isClassAccessible(definition, context, appViewWithClassHierarchy)
.isPossiblyFalse()) {
return true;
}
// Verify that the new-instance instruction won't lead to class initialization.
- if (definition.classInitializationMayHaveSideEffectsInContext(appViewWithLiveness, context)) {
+ if (definition.classInitializationMayHaveSideEffectsInContext(
+ appViewWithClassHierarchy, context)) {
return true;
}
// Verify that the object does not have a finalizer.
MethodResolutionResult finalizeResolutionResult =
- appViewWithLiveness
+ appViewWithClassHierarchy
.appInfo()
- .resolveMethodOnClass(dexItemFactory.objectMembers.finalize, clazz);
+ .resolveMethodOnClass(clazz, dexItemFactory.objectMembers.finalize);
if (finalizeResolutionResult.isSingleResolution()) {
DexMethod finalizeMethod = finalizeResolutionResult.getSingleTarget().getReference();
if (finalizeMethod != dexItemFactory.enumMembers.finalize
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 b32a651..b28f281 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
@@ -25,6 +25,7 @@
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.Query;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.ir.regalloc.RegisterAllocator;
@@ -149,8 +150,9 @@
}
@Override
- public boolean identicalAfterRegisterAllocation(Instruction other, RegisterAllocator allocator) {
- if (!super.identicalAfterRegisterAllocation(other, allocator)) {
+ public boolean identicalAfterRegisterAllocation(
+ Instruction other, RegisterAllocator allocator, MethodConversionOptions conversionOptions) {
+ if (!super.identicalAfterRegisterAllocation(other, allocator, conversionOptions)) {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Value.java b/src/main/java/com/android/tools/r8/ir/code/Value.java
index cc59793..bb83120 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Value.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Value.java
@@ -846,7 +846,7 @@
return UnknownValue.getInstance();
}
- return root.definition.getAbstractValue(appView.withLiveness(), context);
+ return root.definition.getAbstractValue(appView.withClassHierarchy(), context);
}
public boolean isDefinedByInstructionSatisfying(Predicate<Instruction> predicate) {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
index e95d612..4039c58 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
@@ -144,7 +144,8 @@
this.bytecodeMetadataBuilder = BytecodeMetadata.builder(bytecodeMetadataProvider);
}
- public CfCode build(DeadCodeRemover deadCodeRemover, MethodConversionOptions conversionOptions) {
+ public CfCode build(DeadCodeRemover deadCodeRemover) {
+ code.traceBlocks();
computeInitializers();
TypeVerificationHelper typeVerificationHelper = new TypeVerificationHelper(appView, code);
typeVerificationHelper.computeVerificationTypes();
@@ -162,7 +163,7 @@
reachedFixpoint = !phiOptimizations.optimize(code);
}
}
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
// Insert reads for uninitialized read blocks to ensure correct stack maps.
Set<UninitializedThisLocalRead> uninitializedThisLocalReads =
insertUninitializedThisLocalReads();
@@ -178,9 +179,9 @@
loadStoreHelper.insertPhiMoves(registerAllocator);
- if (conversionOptions.isPeepholeOptimizationsEnabled()) {
+ if (code.getConversionOptions().isPeepholeOptimizationsEnabled()) {
for (int i = 0; i < PEEPHOLE_OPTIMIZATION_PASSES; i++) {
- CodeRewriter.collapseTrivialGotos(code);
+ CodeRewriter.collapseTrivialGotos(appView, code);
PeepholeOptimizer.removeIdenticalPredecessorBlocks(code, registerAllocator);
PeepholeOptimizer.shareIdenticalBlockSuffix(
code, registerAllocator, SUFFIX_SHARING_OVERHEAD);
@@ -189,7 +190,7 @@
rewriteIincPatterns();
- CodeRewriter.collapseTrivialGotos(code);
+ CodeRewriter.collapseTrivialGotos(appView, code);
DexBuilder.removeRedundantDebugPositions(code);
CfCode code = buildCfCode();
assert verifyInvokeInterface(code, appView);
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java
index c4ac3ff..2bd4cfa 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java
@@ -93,6 +93,7 @@
private final RegisterAllocator registerAllocator;
private final InternalOptions options;
+ private final MethodConversionOptions conversionOptions;
// List of information about switch payloads that have to be created at the end of the
// dex code.
@@ -128,20 +129,23 @@
public DexBuilder(
IRCode ir,
BytecodeMetadataProvider bytecodeMetadataProvider,
- RegisterAllocator registerAllocator) {
- this(ir, bytecodeMetadataProvider, registerAllocator, registerAllocator.options());
- assert ir != null;
+ RegisterAllocator registerAllocator,
+ InternalOptions options) {
+ this(ir, bytecodeMetadataProvider, registerAllocator, options, ir.getConversionOptions());
}
- private DexBuilder(
+ public DexBuilder(
IRCode ir,
BytecodeMetadataProvider bytecodeMetadataProvider,
RegisterAllocator registerAllocator,
- InternalOptions options) {
+ InternalOptions options,
+ MethodConversionOptions conversionOptions) {
+ assert ir == null || conversionOptions == ir.getConversionOptions();
this.ir = ir;
this.bytecodeMetadataBuilder = BytecodeMetadata.builder(bytecodeMetadataProvider);
this.registerAllocator = registerAllocator;
this.options = options;
+ this.conversionOptions = conversionOptions;
if (isBuildingForComparison()) {
instructionToInfo = new Info[1];
}
@@ -150,9 +154,15 @@
public static boolean identicalInstructionsAfterBuildingDexCode(
com.android.tools.r8.ir.code.Instruction a,
com.android.tools.r8.ir.code.Instruction b,
- RegisterAllocator allocator) {
+ RegisterAllocator allocator,
+ MethodConversionOptions conversionOptions) {
DexBuilder builder =
- new DexBuilder(null, BytecodeMetadataProvider.empty(), allocator, allocator.options());
+ new DexBuilder(
+ null,
+ BytecodeMetadataProvider.empty(),
+ allocator,
+ allocator.options(),
+ conversionOptions);
Info infoA = buildInfoForComparison(a, builder);
Info infoB = buildInfoForComparison(b, builder);
return infoA.identicalInstructions(infoB, builder);
@@ -647,7 +657,8 @@
public void addReturn(Return ret, Instruction dex) {
if (nextBlock != null
- && ret.identicalAfterRegisterAllocation(nextBlock.entry(), registerAllocator)) {
+ && ret.identicalAfterRegisterAllocation(
+ nextBlock.entry(), registerAllocator, conversionOptions)) {
addNothing(ret);
} else {
add(ret, dex);
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
index 6dec27c..a8d0ccd 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
@@ -44,7 +44,6 @@
import com.android.tools.r8.ir.code.CanonicalPositions;
import com.android.tools.r8.ir.code.CatchHandlers;
import com.android.tools.r8.ir.code.Position;
-import com.android.tools.r8.ir.code.Position.SourcePosition;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -262,14 +261,8 @@
// If this instruction has already been inlined then this.method must be the outermost caller.
assert entry.callerPosition == null
|| entry.callerPosition.getOutermostCaller().getMethod() == originalMethod;
-
return canonicalPositions.getCanonical(
- SourcePosition.builder()
- .setLine(entry.line)
- .setFile(entry.sourceFile)
- .setMethod(entry.method)
- .setCallerPosition(canonicalPositions.canonicalizeCallerPosition(entry.callerPosition))
- .build());
+ entry.toPosition(canonicalPositions::canonicalizeCallerPosition));
}
@Override
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 4d1cfc2..b46ebad 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
@@ -118,6 +118,7 @@
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.code.ValueTypeConstraint;
import com.android.tools.r8.ir.code.Xor;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.naming.dexitembasedstring.NameComputationInfo;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApiLevel;
@@ -500,7 +501,7 @@
}
public boolean isDebugMode() {
- return appView.options().debug || getMethod().getOptimizationInfo().isReachabilitySensitive();
+ return appView.options().debug || getProgramMethod().getOrComputeReachabilitySensitive(appView);
}
public Int2ReferenceSortedMap<BlockInfo> getCFG() {
@@ -606,7 +607,7 @@
* @param context Under what context this IRCode is built. Either the current method or caller.
* @return The list of basic blocks. First block is the main entry.
*/
- public IRCode build(ProgramMethod context) {
+ public IRCode build(ProgramMethod context, MutableMethodConversionOptions conversionOptions) {
assert source != null;
source.setUp();
@@ -706,7 +707,8 @@
valueNumberGenerator,
basicBlockNumberGenerator,
metadata,
- origin);
+ origin,
+ conversionOptions);
// Verify critical edges are split so we have a place to insert phi moves if necessary.
assert ir.verifySplitCriticalEdges();
@@ -733,11 +735,11 @@
new TypeAnalysis(appView).narrowing(ir);
}
- if (appView.options().isStringSwitchConversionEnabled()) {
+ if (conversionOptions.isStringSwitchConversionEnabled()) {
StringSwitchConverter.convertToStringSwitchInstructions(ir, appView.dexItemFactory());
}
- assert ir.isConsistentSSA();
+ assert ir.isConsistentSSA(appView);
// Clear the code so we don't build multiple times.
source.clear();
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 3da2a7e..acadf11 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
@@ -11,16 +11,13 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexApplication.Builder;
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.DexString;
-import com.android.tools.r8.graph.DexTypeList;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.PrunedItems;
@@ -33,18 +30,8 @@
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.InstanceFieldValueAnalysis;
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.StaticFieldValueAnalysis;
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.StaticFieldValues;
-import com.android.tools.r8.ir.analysis.type.TypeElement;
-import com.android.tools.r8.ir.code.AlwaysMaterializingDefinition;
-import com.android.tools.r8.ir.code.AlwaysMaterializingUser;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.IRCode;
-import com.android.tools.r8.ir.code.Instruction;
-import com.android.tools.r8.ir.code.InstructionListIterator;
-import com.android.tools.r8.ir.code.InvokeStatic;
-import com.android.tools.r8.ir.code.NumericType;
-import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.ir.conversion.MethodConversionOptions.DefaultMethodConversionOptions;
-import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.ir.desugar.CfClassSynthesizerDesugaringCollection;
import com.android.tools.r8.ir.desugar.CfClassSynthesizerDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringCollection;
@@ -75,7 +62,6 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.MemberValuePropagation;
import com.android.tools.r8.ir.optimize.NaturalIntLoopRemover;
-import com.android.tools.r8.ir.optimize.PeepholeOptimizer;
import com.android.tools.r8.ir.optimize.RedundantFieldLoadAndStoreElimination;
import com.android.tools.r8.ir.optimize.ReflectionOptimizer;
import com.android.tools.r8.ir.optimize.ServiceLoaderRewriter;
@@ -92,8 +78,6 @@
import com.android.tools.r8.ir.optimize.outliner.Outliner;
import com.android.tools.r8.ir.optimize.string.StringBuilderOptimizer;
import com.android.tools.r8.ir.optimize.string.StringOptimizer;
-import com.android.tools.r8.ir.regalloc.LinearScanRegisterAllocator;
-import com.android.tools.r8.ir.regalloc.RegisterAllocator;
import com.android.tools.r8.logging.Log;
import com.android.tools.r8.naming.IdentifierNameStringMarker;
import com.android.tools.r8.optimize.argumentpropagation.ArgumentPropagator;
@@ -123,13 +107,10 @@
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.function.Supplier;
import java.util.stream.Collectors;
public class IRConverter {
- private static final int PEEPHOLE_OPTIMIZATION_PASSES = 2;
-
public final AppView<?> appView;
private final Timing timing;
@@ -487,7 +468,6 @@
D8CfInstructionDesugaringEventConsumer desugaringEventConsumer,
D8MethodProcessor methodProcessor,
InterfaceProcessor interfaceProcessor) {
- boolean isReachabilitySensitive = clazz.hasReachabilitySensitiveAnnotation(options.itemFactory);
// When converting all methods on a class always convert <clinit> first.
ProgramMethod classInitializer = clazz.getProgramClassInitializer();
@@ -498,17 +478,12 @@
// the need to copy the method list.
List<ProgramMethod> methods = ListUtils.newArrayList(clazz::forEachProgramMethod);
if (classInitializer != null) {
- classInitializer
- .getDefinition()
- .getMutableOptimizationInfo()
- .setReachabilitySensitive(isReachabilitySensitive);
methodProcessor.processMethod(classInitializer, desugaringEventConsumer);
}
for (ProgramMethod method : methods) {
if (!method.getDefinition().isClassInitializer()) {
DexEncodedMethod definition = method.getDefinition();
- definition.getMutableOptimizationInfo().setReachabilitySensitive(isReachabilitySensitive);
methodProcessor.processMethod(method, desugaringEventConsumer);
if (interfaceProcessor != null) {
interfaceProcessor.processMethod(method, desugaringEventConsumer);
@@ -642,9 +617,6 @@
// Desugaring happens in the enqueuer.
assert instructionDesugaring.isEmpty();
- DexApplication application = appView.appInfo().app();
-
- computeReachabilitySensitivity(application);
workaroundAbstractMethodOnNonAbstractClassVerificationBug(executorService);
// The process is in two phases in general.
@@ -849,6 +821,9 @@
inliner.onLastWaveDone(postMethodProcessorBuilder, executorService, timing);
}
openClosedInterfacesAnalysis.onPrimaryOptimizationPassComplete();
+
+ // Ensure determinism of method-to-reprocess set.
+ appView.testing().checkDeterminism(postMethodProcessorBuilder::dump);
}
public void addWaveDoneAction(com.android.tools.r8.utils.Action action) {
@@ -865,18 +840,6 @@
return onWaveDoneActions != null;
}
- private void computeReachabilitySensitivity(DexApplication application) {
- application
- .classes()
- .forEach(
- c -> {
- if (c.hasReachabilitySensitiveAnnotation(options.itemFactory)) {
- c.methods()
- .forEach(m -> m.getMutableOptimizationInfo().setReachabilitySensitive(true));
- }
- });
- }
-
private void processSynthesizedServiceLoaderMethods(
List<ProgramMethod> serviceLoadMethods, ExecutorService executorService)
throws ExecutionException {
@@ -901,28 +864,28 @@
/**
* This will replace the Dex code in the method with the Dex code generated from the provided IR.
- * <p>
- * This method is *only* intended for testing, where tests manipulate the IR and need runnable Dex
- * code.
*
- * @param method the method to replace code for
+ * <p>This method is *only* intended for testing, where tests manipulate the IR and need runnable
+ * Dex code.
+ *
* @param code the IR code for the method
*/
- public void replaceCodeForTesting(DexEncodedMethod method, IRCode code) {
- if (Log.ENABLED) {
- Log.debug(getClass(), "Initial (SSA) flow graph for %s:\n%s", method.toSourceString(), code);
- }
- assert code.isConsistentSSA();
+ public void replaceCodeForTesting(IRCode code) {
+ ProgramMethod method = code.context();
+ DexEncodedMethod definition = method.getDefinition();
+ assert code.isConsistentSSA(appView);
Timing timing = Timing.empty();
deadCodeRemover.run(code, timing);
- code.traceBlocks();
- RegisterAllocator registerAllocator =
- performRegisterAllocation(
- code, method, DefaultMethodConversionOptions.getInstance(), timing);
- method.setCode(code, BytecodeMetadataProvider.empty(), registerAllocator, appView);
+ method.setCode(
+ new IRToDexFinalizer(appView, deadCodeRemover)
+ .finalizeCode(code, BytecodeMetadataProvider.empty(), timing),
+ appView);
if (Log.ENABLED) {
- Log.debug(getClass(), "Resulting dex code for %s:\n%s",
- method.toSourceString(), logCode(options, method));
+ Log.debug(
+ getClass(),
+ "Resulting dex code for %s:\n%s",
+ method.toSourceString(),
+ logCode(options, definition));
}
}
@@ -1094,8 +1057,6 @@
ProgramMethod context = code.context();
DexEncodedMethod method = context.getDefinition();
DexProgramClass holder = context.getHolder();
- MutableMethodConversionOptions conversionOptions =
- new MutableMethodConversionOptions(methodProcessor);
assert holder != null;
Timing timing = Timing.create(context.toSourceString(), options);
@@ -1123,7 +1084,7 @@
timing.end();
}
- boolean isDebugMode = options.debug || method.getOptimizationInfo().isReachabilitySensitive();
+ boolean isDebugMode = options.debug || context.getOrComputeReachabilitySensitive(appView);
if (isDebugMode) {
codeRewriter.simplifyDebugLocals(code);
@@ -1164,7 +1125,7 @@
// check. In the latter case, the type checker should be extended to detect the issue such that
// we will return with a throw-null method above.
assert code.verifyTypes(appView);
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
openClosedInterfacesAnalysis.analyze(context, code);
@@ -1178,7 +1139,6 @@
ClassInitializerDefaultsResult.empty(),
feedback,
methodProcessor,
- conversionOptions,
BytecodeMetadataProvider.builder(),
timing);
timing.end();
@@ -1199,7 +1159,7 @@
timing.begin("Decouple identifier-name strings");
identifierNameStringMarker.decoupleIdentifierNameStringsInMethod(code);
timing.end();
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
}
if (memberValuePropagation != null) {
@@ -1282,7 +1242,7 @@
.optimize(code, feedback, methodProcessor, methodProcessingContext);
timing.end();
previous = printMethod(code, "IR after class library method optimizer (SSA)", previous);
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
}
assert code.verifyTypes(appView);
@@ -1389,7 +1349,7 @@
// as a result of those simplifications. The following optimizations could reveal more
// dead code which is removed right before register allocation in performRegisterAllocation.
deadCodeRemover.run(code, timing);
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
previous = printMethod(code, "IR after dead code removal (SSA)", previous);
@@ -1422,7 +1382,7 @@
// always uses a force inlining oracle for inlining.
-1)));
timing.end();
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
assert code.verifyTypes(appView);
}
@@ -1440,7 +1400,7 @@
previous = printMethod(code, "IR after outline handler (SSA)", previous);
- if (stringSwitchRemover != null) {
+ if (code.getConversionOptions().isStringSwitchConversionEnabled()) {
// Remove string switches prior to canonicalization to ensure that the constants that are
// being introduced will be canonicalized if possible.
timing.begin("Remove string switch");
@@ -1474,7 +1434,7 @@
// Insert code to log arguments if requested.
if (options.methodMatchesLogArgumentsFilter(method) && !method.isProcessed()) {
codeRewriter.logArgumentTypes(method, code);
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
}
previous = printMethod(code, "IR after argument type logging (SSA)", previous);
@@ -1493,7 +1453,6 @@
classInitializerDefaultsResult,
feedback,
methodProcessor,
- conversionOptions,
bytecodeMetadataProviderBuilder,
timing);
timing.end();
@@ -1503,7 +1462,7 @@
timing.begin("Remove assume instructions");
CodeRewriter.removeAssumeInstructions(appView, code);
timing.end();
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
// TODO(b/214496607): Remove when dynamic types are safe w.r.t. interface assignment rules.
codeRewriter.rewriteMoveResult(code);
@@ -1517,19 +1476,11 @@
previous =
printMethod(code, "IR after computation of optimization info summary (SSA)", previous);
- if (options.canHaveNumberConversionRegisterAllocationBug()) {
- timing.begin("Check number conversion issue");
- codeRewriter.workaroundNumberConversionRegisterAllocationBug(code);
- timing.end();
- }
-
printMethod(code, "Optimized IR (SSA)", previous);
timing.begin("Finalize IR");
finalizeIR(
- context,
code,
feedback,
- conversionOptions,
bytecodeMetadataProviderBuilder.build(),
timing);
timing.end();
@@ -1553,14 +1504,13 @@
ClassInitializerDefaultsResult classInitializerDefaultsResult,
OptimizationFeedback feedback,
MethodProcessor methodProcessor,
- MutableMethodConversionOptions conversionOptions,
BytecodeMetadataProvider.Builder bytecodeMetadataProviderBuilder,
Timing timing) {
appView.withArgumentPropagator(
argumentPropagator -> argumentPropagator.scan(method, code, methodProcessor, timing));
if (methodProcessor.isPrimaryMethodProcessor()) {
- enumUnboxer.analyzeEnums(code, conversionOptions);
+ enumUnboxer.analyzeEnums(code, methodProcessor);
}
if (inliner != null) {
@@ -1624,69 +1574,51 @@
}
deadCodeRemover.run(code, timing);
finalizeIR(
- code.context(),
code,
feedback,
- DefaultMethodConversionOptions.getInstance(),
BytecodeMetadataProvider.empty(),
timing);
}
public void finalizeIR(
- ProgramMethod method,
IRCode code,
OptimizationFeedback feedback,
- MethodConversionOptions conversionOptions,
BytecodeMetadataProvider bytecodeMetadataProvider,
Timing timing) {
- code.traceBlocks();
if (options.isGeneratingClassFiles()) {
- finalizeToCf(code, feedback, conversionOptions, bytecodeMetadataProvider);
+ finalizeToCf(code, feedback, bytecodeMetadataProvider, timing);
} else {
assert options.isGeneratingDex();
- finalizeToDex(code, feedback, conversionOptions, bytecodeMetadataProvider, timing);
+ finalizeToDex(code, feedback, bytecodeMetadataProvider, timing);
}
}
private void finalizeToCf(
IRCode code,
OptimizationFeedback feedback,
- MethodConversionOptions conversionOptions,
- BytecodeMetadataProvider bytecodeMetadataProvider) {
+ BytecodeMetadataProvider bytecodeMetadataProvider,
+ Timing timing) {
ProgramMethod method = code.context();
- assert !method.getDefinition().getCode().isDexCode();
- CfBuilder builder = new CfBuilder(appView, method, code, bytecodeMetadataProvider);
- CfCode result = builder.build(deadCodeRemover, conversionOptions);
- method.getDefinition().setCode(result, appView);
+ method.setCode(
+ new IRToCfFinalizer(appView, deadCodeRemover)
+ .finalizeCode(code, bytecodeMetadataProvider, timing),
+ appView);
markProcessed(code, feedback);
}
private void finalizeToDex(
IRCode code,
OptimizationFeedback feedback,
- MethodConversionOptions conversionOptions,
BytecodeMetadataProvider bytecodeMetadataProvider,
Timing timing) {
- DexEncodedMethod method = code.method();
- // Workaround massive dex2oat memory use for self-recursive methods.
- CodeRewriter.disableDex2OatInliningForSelfRecursiveMethods(appView, code);
- // Workaround MAX_INT switch issue.
- codeRewriter.rewriteSwitchForMaxInt(code);
- // Perform register allocation.
- RegisterAllocator registerAllocator =
- performRegisterAllocation(code, method, conversionOptions, timing);
- timing.begin("Build DEX code");
- method.setCode(code, bytecodeMetadataProvider, registerAllocator, appView);
- timing.end();
- updateHighestSortingStrings(method);
- if (Log.ENABLED) {
- Log.debug(getClass(), "Resulting dex code for %s:\n%s",
- method.toSourceString(), logCode(options, method));
- }
- printMethod(code, "Final IR (non-SSA)", null);
- timing.begin("Marking processed");
+ ProgramMethod method = code.context();
+ DexEncodedMethod definition = method.getDefinition();
+ method.setCode(
+ new IRToDexFinalizer(appView, deadCodeRemover)
+ .finalizeCode(code, bytecodeMetadataProvider, timing),
+ appView);
markProcessed(code, feedback);
- timing.end();
+ updateHighestSortingStrings(definition);
}
public void markProcessed(IRCode code, OptimizationFeedback feedback) {
@@ -1704,8 +1636,7 @@
return false;
}
DexEncodedMethod definition = method.getDefinition();
- if (definition.isClassInitializer()
- || definition.getOptimizationInfo().isReachabilitySensitive()) {
+ if (definition.isClassInitializer() || method.getOrComputeReachabilitySensitive(appView)) {
return false;
}
KeepMethodInfo keepInfo = appView.getKeepInfo(method);
@@ -1727,209 +1658,6 @@
}
}
- private RegisterAllocator performRegisterAllocation(
- IRCode code,
- DexEncodedMethod method,
- MethodConversionOptions conversionOptions,
- Timing timing) {
- // Always perform dead code elimination before register allocation. The register allocator
- // does not allow dead code (to make sure that we do not waste registers for unneeded values).
- assert deadCodeRemover.verifyNoDeadCode(code);
- materializeInstructionBeforeLongOperationsWorkaround(code);
- workaroundForwardingInitializerBug(code);
- timing.begin("Allocate registers");
- LinearScanRegisterAllocator registerAllocator = new LinearScanRegisterAllocator(appView, code);
- registerAllocator.allocateRegisters();
- timing.end();
- if (options.canHaveExceptionTargetingLoopHeaderBug()) {
- codeRewriter.workaroundExceptionTargetingLoopHeaderBug(code);
- }
- printMethod(code, "After register allocation (non-SSA)", null);
- if (conversionOptions.isPeepholeOptimizationsEnabled()) {
- timing.begin("Peephole optimize");
- for (int i = 0; i < PEEPHOLE_OPTIMIZATION_PASSES; i++) {
- CodeRewriter.collapseTrivialGotos(code);
- PeepholeOptimizer.optimize(code, registerAllocator);
- }
- timing.end();
- }
- timing.begin("Clean up");
- CodeRewriter.removeUnneededMovesOnExitingPaths(code, registerAllocator);
- CodeRewriter.collapseTrivialGotos(code);
- timing.end();
- if (Log.ENABLED) {
- Log.debug(getClass(), "Final (non-SSA) flow graph for %s:\n%s",
- method.toSourceString(), code);
- }
- return registerAllocator;
- }
-
- private void workaroundForwardingInitializerBug(IRCode code) {
- if (!options.canHaveForwardingInitInliningBug()) {
- return;
- }
- // Only constructors.
- if (!code.method().isInstanceInitializer()) {
- return;
- }
- // Only constructors with certain signatures.
- DexTypeList paramTypes = code.method().getReference().proto.parameters;
- if (paramTypes.size() != 3 ||
- paramTypes.values[0] != options.itemFactory.doubleType ||
- paramTypes.values[1] != options.itemFactory.doubleType ||
- !paramTypes.values[2].isClassType()) {
- return;
- }
- // Only if the constructor contains a super constructor call taking only parameters as
- // inputs.
- for (BasicBlock block : code.blocks) {
- InstructionListIterator it = block.listIterator(code);
- Instruction superConstructorCall =
- it.nextUntil(
- (i) ->
- i.isInvokeDirect()
- && i.asInvokeDirect().getInvokedMethod().name
- == options.itemFactory.constructorMethodName
- && i.asInvokeDirect().arguments().size() == 4
- && i.asInvokeDirect().arguments().stream().allMatch(Value::isArgument));
- if (superConstructorCall != null) {
- // We force a materializing const instruction in front of the super call to make
- // sure that there is at least one temporary register in the method. That disables
- // the inlining that is crashing on these devices.
- ensureInstructionBefore(code, superConstructorCall, it);
- break;
- }
- }
- }
-
- /**
- * For each block, we look to see if the header matches:
- *
- * <pre>
- * pseudo-instructions*
- * v2 <- long-{mul,div} v0 v1
- * pseudo-instructions*
- * v5 <- long-{add,sub} v3 v4
- * </pre>
- *
- * where v2 ~=~ v3 or v2 ~=~ v4 (with ~=~ being equal or an alias of) and the block is not a
- * fallthrough target.
- */
- private void materializeInstructionBeforeLongOperationsWorkaround(IRCode code) {
- if (!options.canHaveDex2OatLinkedListBug()) {
- return;
- }
- DexItemFactory factory = options.itemFactory;
- final Supplier<DexMethod> javaLangLangSignum =
- Suppliers.memoize(
- () ->
- factory.createMethod(
- factory.createString("Ljava/lang/Long;"),
- factory.createString("signum"),
- factory.intDescriptor,
- new DexString[] {factory.longDescriptor}));
- for (BasicBlock block : code.blocks) {
- InstructionListIterator it = block.listIterator(code);
- Instruction firstMaterializing = it.nextUntil(IRConverter::isNotPseudoInstruction);
- if (!isLongMul(firstMaterializing)) {
- continue;
- }
- Instruction secondMaterializing = it.nextUntil(IRConverter::isNotPseudoInstruction);
- if (!isLongAddOrSub(secondMaterializing)) {
- continue;
- }
- if (isFallthoughTarget(block)) {
- continue;
- }
- Value outOfMul = firstMaterializing.outValue();
- for (Value inOfAddOrSub : secondMaterializing.inValues()) {
- if (isAliasOf(inOfAddOrSub, outOfMul)) {
- it = block.listIterator(code);
- it.nextUntil(i -> i == firstMaterializing);
- Value longValue = firstMaterializing.inValues().get(0);
- InvokeStatic invokeLongSignum =
- new InvokeStatic(
- javaLangLangSignum.get(), null, Collections.singletonList(longValue));
- ensureThrowingInstructionBefore(code, firstMaterializing, it, invokeLongSignum);
- return;
- }
- }
- }
- }
-
- private static boolean isAliasOf(Value usedValue, Value definingValue) {
- while (true) {
- if (usedValue == definingValue) {
- return true;
- }
- Instruction definition = usedValue.definition;
- if (definition == null || !definition.isMove()) {
- return false;
- }
- usedValue = definition.asMove().src();
- }
- }
-
- private static boolean isNotPseudoInstruction(Instruction instruction) {
- return !(instruction.isDebugInstruction() || instruction.isMove());
- }
-
- private static boolean isLongMul(Instruction instruction) {
- return instruction != null
- && instruction.isMul()
- && instruction.asBinop().getNumericType() == NumericType.LONG
- && instruction.outValue() != null;
- }
-
- private static boolean isLongAddOrSub(Instruction instruction) {
- return instruction != null
- && (instruction.isAdd() || instruction.isSub())
- && instruction.asBinop().getNumericType() == NumericType.LONG;
- }
-
- private static boolean isFallthoughTarget(BasicBlock block) {
- for (BasicBlock pred : block.getPredecessors()) {
- if (pred.exit().fallthroughBlock() == block) {
- return true;
- }
- }
- return false;
- }
-
- private void ensureThrowingInstructionBefore(
- IRCode code, Instruction addBefore, InstructionListIterator it, Instruction instruction) {
- Instruction check = it.previous();
- assert addBefore == check;
- BasicBlock block = check.getBlock();
- if (block.hasCatchHandlers()) {
- // Split so the existing instructions retain their handlers and the new instruction has none.
- BasicBlock split = it.split(code);
- assert split.hasCatchHandlers();
- assert !block.hasCatchHandlers();
- it = block.listIterator(code, block.getInstructions().size() - 1);
- }
- instruction.setPosition(addBefore.getPosition());
- it.add(instruction);
- }
-
- private static void ensureInstructionBefore(
- IRCode code, Instruction addBefore, InstructionListIterator it) {
- // Force materialize a constant-zero before the long operation.
- Instruction check = it.previous();
- assert addBefore == check;
- // Forced definition of const-zero
- Value fixitValue = code.createValue(TypeElement.getInt());
- Instruction fixitDefinition = new AlwaysMaterializingDefinition(fixitValue);
- fixitDefinition.setBlock(addBefore.getBlock());
- fixitDefinition.setPosition(addBefore.getPosition());
- it.add(fixitDefinition);
- // Forced user of the forced definition to ensure it has a user and thus live range.
- Instruction fixitUser = new AlwaysMaterializingUser(fixitValue);
- fixitUser.setBlock(addBefore.getBlock());
- fixitUser.setPosition(addBefore.getPosition());
- it.add(fixitUser);
- }
-
private void printC1VisualizerHeader(DexEncodedMethod method) {
if (printer != null) {
printer.begin("compilation");
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRFinalizer.java b/src/main/java/com/android/tools/r8/ir/conversion/IRFinalizer.java
new file mode 100644
index 0000000..c0c6808
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRFinalizer.java
@@ -0,0 +1,26 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.conversion;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.Code;
+import com.android.tools.r8.graph.bytecodemetadata.BytecodeMetadataProvider;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.optimize.DeadCodeRemover;
+import com.android.tools.r8.utils.Timing;
+
+public abstract class IRFinalizer<C extends Code> {
+
+ protected final AppView<?> appView;
+ protected final DeadCodeRemover deadCodeRemover;
+
+ public IRFinalizer(AppView<?> appView, DeadCodeRemover deadCodeRemover) {
+ this.appView = appView;
+ this.deadCodeRemover = deadCodeRemover;
+ }
+
+ public abstract C finalizeCode(
+ IRCode code, BytecodeMetadataProvider bytecodeMetadataProvider, Timing timing);
+}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRToCfFinalizer.java b/src/main/java/com/android/tools/r8/ir/conversion/IRToCfFinalizer.java
new file mode 100644
index 0000000..74d0376
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRToCfFinalizer.java
@@ -0,0 +1,27 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.conversion;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.CfCode;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.bytecodemetadata.BytecodeMetadataProvider;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.optimize.DeadCodeRemover;
+import com.android.tools.r8.utils.Timing;
+
+public class IRToCfFinalizer extends IRFinalizer<CfCode> {
+
+ public IRToCfFinalizer(AppView<?> appView, DeadCodeRemover deadCodeRemover) {
+ super(appView, deadCodeRemover);
+ }
+
+ @Override
+ public CfCode finalizeCode(
+ IRCode code, BytecodeMetadataProvider bytecodeMetadataProvider, Timing timing) {
+ ProgramMethod method = code.context();
+ return new CfBuilder(appView, method, code, bytecodeMetadataProvider).build(deadCodeRemover);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRToDexFinalizer.java b/src/main/java/com/android/tools/r8/ir/conversion/IRToDexFinalizer.java
new file mode 100644
index 0000000..4155003
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRToDexFinalizer.java
@@ -0,0 +1,80 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.conversion;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexCode;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.bytecodemetadata.BytecodeMetadataProvider;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.optimize.CodeRewriter;
+import com.android.tools.r8.ir.optimize.DeadCodeRemover;
+import com.android.tools.r8.ir.optimize.PeepholeOptimizer;
+import com.android.tools.r8.ir.optimize.RuntimeWorkaroundCodeRewriter;
+import com.android.tools.r8.ir.regalloc.LinearScanRegisterAllocator;
+import com.android.tools.r8.ir.regalloc.RegisterAllocator;
+import com.android.tools.r8.logging.Log;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.Timing;
+
+public class IRToDexFinalizer extends IRFinalizer<DexCode> {
+
+ private static final int PEEPHOLE_OPTIMIZATION_PASSES = 2;
+
+ private final CodeRewriter codeRewriter;
+ private final InternalOptions options;
+
+ public IRToDexFinalizer(AppView<?> appView, DeadCodeRemover deadCodeRemover) {
+ super(appView, deadCodeRemover);
+ this.codeRewriter = deadCodeRemover.getCodeRewriter();
+ this.options = appView.options();
+ }
+
+ @Override
+ public DexCode finalizeCode(
+ IRCode code, BytecodeMetadataProvider bytecodeMetadataProvider, Timing timing) {
+ DexEncodedMethod method = code.method();
+ code.traceBlocks();
+ RuntimeWorkaroundCodeRewriter.workaroundNumberConversionRegisterAllocationBug(code, options);
+ // Workaround massive dex2oat memory use for self-recursive methods.
+ RuntimeWorkaroundCodeRewriter.workaroundDex2OatInliningIssue(appView, code);
+ // Workaround MAX_INT switch issue.
+ RuntimeWorkaroundCodeRewriter.workaroundSwitchMaxIntBug(code, codeRewriter, options);
+ RuntimeWorkaroundCodeRewriter.workaroundDex2OatLinkedListBug(code, options);
+ RuntimeWorkaroundCodeRewriter.workaroundForwardingInitializerBug(code, options);
+ RuntimeWorkaroundCodeRewriter.workaroundExceptionTargetingLoopHeaderBug(code, options);
+ // Perform register allocation.
+ RegisterAllocator registerAllocator = performRegisterAllocation(code, method, timing);
+ return new DexBuilder(code, bytecodeMetadataProvider, registerAllocator, options).build();
+ }
+
+ private RegisterAllocator performRegisterAllocation(
+ IRCode code, DexEncodedMethod method, Timing timing) {
+ // Always perform dead code elimination before register allocation. The register allocator
+ // does not allow dead code (to make sure that we do not waste registers for unneeded values).
+ assert deadCodeRemover.verifyNoDeadCode(code);
+ timing.begin("Allocate registers");
+ LinearScanRegisterAllocator registerAllocator = new LinearScanRegisterAllocator(appView, code);
+ registerAllocator.allocateRegisters();
+ timing.end();
+ if (code.getConversionOptions().isPeepholeOptimizationsEnabled()) {
+ timing.begin("Peephole optimize");
+ for (int i = 0; i < PEEPHOLE_OPTIMIZATION_PASSES; i++) {
+ CodeRewriter.collapseTrivialGotos(appView, code);
+ PeepholeOptimizer.optimize(appView, code, registerAllocator);
+ }
+ timing.end();
+ }
+ timing.begin("Clean up");
+ CodeRewriter.removeUnneededMovesOnExitingPaths(code, registerAllocator);
+ CodeRewriter.collapseTrivialGotos(appView, code);
+ timing.end();
+ if (Log.ENABLED) {
+ Log.debug(
+ getClass(), "Final (non-SSA) flow graph for %s:\n%s", method.toSourceString(), code);
+ }
+ return registerAllocator;
+ }
+}
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 309cf22..2154c8c 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
@@ -667,7 +667,19 @@
ConstClass constClass = current.asConstClass();
new InstructionReplacer(code, current, iterator, affectedPhis)
.replaceInstructionIfTypeChanged(
- constClass.getValue(), (t, v) -> new ConstClass(v, t), graphLens, codeLens);
+ constClass.getValue(),
+ (t, v) ->
+ t.isPrimitiveType() || t.isVoidType()
+ ? StaticGet.builder()
+ .setField(
+ factory
+ .getBoxedMembersForPrimitiveOrVoidType(t)
+ .getTypeField())
+ .setOutValue(v)
+ .build()
+ : new ConstClass(v, t),
+ graphLens,
+ codeLens);
}
break;
@@ -809,7 +821,7 @@
// Finalize cast and null check insertion.
interfaceTypeToClassTypeRewriterHelper.processWorklist();
- assert code.isConsistentSSABeforeTypesAreCorrect();
+ assert code.isConsistentSSABeforeTypesAreCorrect(appView);
}
// Applies the prototype changes of the current method to the argument instructions:
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/MethodConversionOptions.java b/src/main/java/com/android/tools/r8/ir/conversion/MethodConversionOptions.java
index 1dd9510..038a277 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/MethodConversionOptions.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/MethodConversionOptions.java
@@ -4,45 +4,77 @@
package com.android.tools.r8.ir.conversion;
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.utils.InternalOptions;
+
public abstract class MethodConversionOptions {
+ public abstract boolean isGeneratingClassFiles();
+
+ public final boolean isGeneratingDex() {
+ return !isGeneratingClassFiles();
+ }
+
public abstract boolean isPeepholeOptimizationsEnabled();
+ public abstract boolean isStringSwitchConversionEnabled();
+
public static class MutableMethodConversionOptions extends MethodConversionOptions {
- private final MethodProcessor methodProcessor;
private boolean enablePeepholeOptimizations = true;
+ private boolean enableStringSwitchConversion;
+ private boolean isGeneratingClassFiles;
- public MutableMethodConversionOptions(MethodProcessor methodProcessor) {
- this.methodProcessor = methodProcessor;
+ public MutableMethodConversionOptions(InternalOptions options) {
+ this.enableStringSwitchConversion = options.isStringSwitchConversionEnabled();
+ this.isGeneratingClassFiles = options.isGeneratingClassFiles();
}
- public void disablePeepholeOptimizations() {
+ public void disablePeepholeOptimizations(MethodProcessor methodProcessor) {
assert methodProcessor.isPrimaryMethodProcessor();
enablePeepholeOptimizations = false;
}
+ public void disableStringSwitchConversion() {
+ enableStringSwitchConversion = false;
+ }
+
+ public MutableMethodConversionOptions setIsGeneratingClassFiles(
+ boolean isGeneratingClassFiles) {
+ this.isGeneratingClassFiles = isGeneratingClassFiles;
+ return this;
+ }
+
+ @Override
+ public boolean isGeneratingClassFiles() {
+ return isGeneratingClassFiles;
+ }
+
@Override
public boolean isPeepholeOptimizationsEnabled() {
- assert enablePeepholeOptimizations || methodProcessor.isPrimaryMethodProcessor();
return enablePeepholeOptimizations;
}
+
+ @Override
+ public boolean isStringSwitchConversionEnabled() {
+ return enableStringSwitchConversion;
+ }
}
- public static class DefaultMethodConversionOptions extends MethodConversionOptions {
+ public static class ThrowingMethodConversionOptions extends MutableMethodConversionOptions {
- private static final DefaultMethodConversionOptions INSTANCE =
- new DefaultMethodConversionOptions();
+ public ThrowingMethodConversionOptions(InternalOptions options) {
+ super(options);
+ }
- private DefaultMethodConversionOptions() {}
-
- public static DefaultMethodConversionOptions getInstance() {
- return INSTANCE;
+ @Override
+ public boolean isGeneratingClassFiles() {
+ throw new Unreachable();
}
@Override
public boolean isPeepholeOptimizationsEnabled() {
- return true;
+ throw new Unreachable();
}
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java b/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java
index 8ad701f..c1a7b55 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java
@@ -109,8 +109,6 @@
void unsetNonNullParamOrThrow(ProgramMethod method);
- void unsetReachabilitySensitive(ProgramMethod method);
-
void unsetReturnedArgument(ProgramMethod method);
void unsetReturnValueOnlyDependsOnArguments(ProgramMethod method);
@@ -135,7 +133,6 @@
unsetNeverReturnsNormally(method);
unsetNonNullParamOnNormalExits(method);
unsetNonNullParamOrThrow(method);
- unsetReachabilitySensitive(method);
unsetReturnedArgument(method);
unsetReturnValueOnlyDependsOnArguments(method);
unsetSimpleInliningConstraint(method);
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java b/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java
index ecee91f..780f5d4 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java
@@ -20,11 +20,13 @@
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackDelayed;
import com.android.tools.r8.logging.Log;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.DeterminismChecker;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
import com.android.tools.r8.utils.Timing.TimingMerger;
import com.android.tools.r8.utils.collections.LongLivedProgramMethodSetBuilder;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
+import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Deque;
@@ -142,6 +144,10 @@
new PartialCallGraphBuilder(appView, methodsToReprocess).build(executorService, timing);
return new PostMethodProcessor(appView, callGraph);
}
+
+ public void dump(DeterminismChecker determinismChecker) throws IOException {
+ determinismChecker.accept(methodsToReprocessBuilder::dump);
+ }
}
private Deque<ProgramMethodSet> createWaves(CallGraph callGraph) {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/StringSwitchRemover.java b/src/main/java/com/android/tools/r8/ir/conversion/StringSwitchRemover.java
index 845793f..ab6e97d 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/StringSwitchRemover.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/StringSwitchRemover.java
@@ -56,7 +56,7 @@
this.stringType = TypeElement.stringClassType(appView, definitelyNotNull());
}
- void run(IRCode code) {
+ public void run(IRCode code) {
if (!code.metadata().mayHaveStringSwitch()) {
assert Streams.stream(code.instructions()).noneMatch(Instruction::isStringSwitch);
return;
@@ -97,7 +97,7 @@
identifierNameStringMarker.decoupleIdentifierNameStringsInBlocks(code, newBlocksWithStrings);
}
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
}
// Returns true if minification is enabled and the switch value is guaranteed to be a class name.
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 9aada99..6c0c957 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
@@ -13,6 +13,7 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.ClassConverterResult;
import com.android.tools.r8.ir.conversion.D8MethodProcessor;
+import com.android.tools.r8.ir.desugar.apimodel.ApiInvokeOutlinerDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.backports.BackportedMethodDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.constantdynamic.ConstantDynamicClass;
import com.android.tools.r8.ir.desugar.constantdynamic.ConstantDynamicDesugaringEventConsumer;
@@ -57,7 +58,8 @@
InterfaceMethodDesugaringEventConsumer,
DesugaredLibraryRetargeterInstructionEventConsumer,
DesugaredLibraryAPIConverterEventConsumer,
- ClasspathEmulatedInterfaceSynthesizerEventConsumer {
+ ClasspathEmulatedInterfaceSynthesizerEventConsumer,
+ ApiInvokeOutlinerDesugaringEventConsumer {
public static D8CfInstructionDesugaringEventConsumer createForD8(
D8MethodProcessor methodProcessor) {
@@ -221,7 +223,6 @@
info -> {
ProgramMethod newDirectMethod = info.getNewDirectMethod();
newDirectMethod
- .getDefinition()
.setCode(info.getVirtualMethod().getDefinition().getCode(), appView);
});
@@ -232,7 +233,6 @@
.forEach(
info -> {
info.getVirtualMethod()
- .getDefinition()
.setCode(info.getVirtualMethodCode(), appView);
needsProcessing.accept(info.getVirtualMethod());
});
@@ -268,6 +268,11 @@
assert synthesizedConstantDynamicClasses.isEmpty();
return true;
}
+
+ @Override
+ public void acceptOutlinedMethod(ProgramMethod outlinedMethod, ProgramMethod context) {
+ methodProcessor.scheduleDesugaredMethodForProcessing(outlinedMethod);
+ }
}
public static class R8CfInstructionDesugaringEventConsumer
@@ -433,7 +438,6 @@
pendingInvokeSpecialBridges.forEach(
info ->
info.getVirtualMethod()
- .getDefinition()
.setCode(info.getVirtualMethodCode(), appView));
}
@@ -462,5 +466,10 @@
// Remove all '$deserializeLambda$' methods which are not supported by desugaring.
LambdaDeserializationMethodRemover.run(appView, classesWithSerializableLambdas);
}
+
+ @Override
+ public void acceptOutlinedMethod(ProgramMethod outlinedMethod, ProgramMethod context) {
+ // Intentionally empty. The method will be hit by tracing if required.
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
index 27298a9..d01f7fc 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
@@ -72,6 +72,7 @@
public LambdaDescriptor descriptor;
public final DexMethod constructor;
final DexMethod classConstructor;
+ private final DexMethod factoryMethod;
public final DexField lambdaField;
public final Target target;
@@ -108,6 +109,13 @@
statelessSingleton
? factory.createField(type, type, factory.lambdaInstanceFieldName)
: null;
+ this.factoryMethod =
+ appView.options().testing.alwaysGenerateLambdaFactoryMethods
+ ? factory.createMethod(
+ type,
+ factory.createProto(type, descriptor.captures.values),
+ factory.createString("create"))
+ : null;
// Synthesize the program class once all fields are set.
synthesizeLambdaClass(builder, desugarInvoke);
@@ -151,6 +159,15 @@
return appView.options().createSingletonsForStatelessLambdas && descriptor.isStateless();
}
+ public boolean hasFactoryMethod() {
+ return factoryMethod != null;
+ }
+
+ public DexMethod getFactoryMethod() {
+ assert hasFactoryMethod();
+ return factoryMethod;
+ }
+
// Synthesize virtual methods.
private void synthesizeVirtualMethods(
SyntheticProgramClassBuilder builder, DesugarInvoke desugarInvoke) {
@@ -227,6 +244,17 @@
.build());
feedback.classInitializerMayBePostponed(methods.get(1));
}
+ if (hasFactoryMethod()) {
+ methods.add(
+ DexEncodedMethod.syntheticBuilder()
+ .setMethod(factoryMethod)
+ .setAccessFlags(
+ MethodAccessFlags.fromSharedAccessFlags(
+ Constants.ACC_STATIC | Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+ .setCode(LambdaClassFactorySourceCode.build(this))
+ .disableAndroidApiLevelCheck()
+ .build());
+ }
builder.setDirectMethods(methods);
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClassFactorySourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClassFactorySourceCode.java
new file mode 100644
index 0000000..0ca21cf
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClassFactorySourceCode.java
@@ -0,0 +1,40 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.ir.desugar;
+
+import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.cf.code.CfLoad;
+import com.android.tools.r8.cf.code.CfNew;
+import com.android.tools.r8.cf.code.CfReturn;
+import com.android.tools.r8.cf.code.CfStackInstruction;
+import com.android.tools.r8.cf.code.CfStackInstruction.Opcode;
+import com.android.tools.r8.graph.CfCode;
+import com.android.tools.r8.ir.code.ValueType;
+import com.google.common.collect.ImmutableList;
+import org.objectweb.asm.Opcodes;
+
+// Source code representing lambda factory method.
+final class LambdaClassFactorySourceCode {
+
+ public static CfCode build(LambdaClass lambda) {
+ int maxStack = 0;
+ int maxLocals = 0;
+ ImmutableList.Builder<CfInstruction> builder = ImmutableList.builder();
+ builder.add(new CfNew(lambda.type)).add(new CfStackInstruction(Opcode.Dup));
+ maxStack += 2;
+ int local = 0;
+ for (int i = 0; i < lambda.constructor.proto.getParameters().size(); i++) {
+ ValueType parameterType = ValueType.fromDexType(lambda.constructor.proto.getParameter(i));
+ builder.add(new CfLoad(parameterType, local));
+ maxStack += parameterType.requiredRegisters();
+ local += parameterType.requiredRegisters();
+ maxLocals = local;
+ }
+ builder
+ .add(new CfInvoke(Opcodes.INVOKESPECIAL, lambda.constructor, false))
+ .add(new CfReturn(ValueType.fromDexType(lambda.type)));
+ return new CfCode(lambda.type, maxStack, maxLocals, builder.build());
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java
index e642655..06fadd9 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java
@@ -63,7 +63,9 @@
methodProcessingContext.createUniqueContext(),
instruction.asInvoke(),
computedApiLevel,
- dexItemFactory);
+ dexItemFactory,
+ eventConsumer,
+ context);
}
return null;
}
@@ -146,14 +148,17 @@
}
private Collection<CfInstruction> desugarLibraryCall(
- UniqueContext context,
+ UniqueContext uniqueContext,
CfInvoke invoke,
ComputedApiLevel computedApiLevel,
- DexItemFactory factory) {
+ DexItemFactory factory,
+ ApiInvokeOutlinerDesugaringEventConsumer eventConsumer,
+ ProgramMethod context) {
DexMethod method = invoke.getMethod();
- ProgramMethod programMethod =
- ensureOutlineMethod(context, method, computedApiLevel, factory, invoke);
- return ImmutableList.of(new CfInvoke(INVOKESTATIC, programMethod.getReference(), false));
+ ProgramMethod outlinedMethod =
+ ensureOutlineMethod(uniqueContext, method, computedApiLevel, factory, invoke);
+ eventConsumer.acceptOutlinedMethod(outlinedMethod, context);
+ return ImmutableList.of(new CfInvoke(INVOKESTATIC, outlinedMethod.getReference(), false));
}
private ProgramMethod ensureOutlineMethod(
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaringEventConsumer.java
new file mode 100644
index 0000000..873d5e5
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaringEventConsumer.java
@@ -0,0 +1,12 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.desugar.apimodel;
+
+import com.android.tools.r8.graph.ProgramMethod;
+
+public interface ApiInvokeOutlinerDesugaringEventConsumer {
+
+ void acceptOutlinedMethod(ProgramMethod outlinedMethod, ProgramMethod context);
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPICallbackSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPICallbackSynthesizer.java
index 450cdb5..a0f8961 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPICallbackSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPICallbackSynthesizer.java
@@ -209,7 +209,7 @@
() -> context.createUniqueContext(clazz))
.generateCfCode();
DexEncodedMethod newMethod = wrapperSynthesizor.newSynthesizedMethod(methodToInstall, cfCode);
- newMethod.setCode(cfCode, appView);
+ newMethod.setCode(cfCode, DexEncodedMethod.NO_PARAMETER_INFO);
if (originalMethod.isLibraryMethodOverride().isTrue()) {
newMethod.setLibraryMethodOverride(OptionalBool.TRUE);
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
index 2eb550b..5499ffb 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
@@ -48,6 +48,7 @@
static final String WRAPPER_CONVERSION_EXCLUDING_KEY = "wrapper_conversion_excluding";
static final String CUSTOM_CONVERSION_KEY = "custom_conversion";
static final String REWRITE_PREFIX_KEY = "rewrite_prefix";
+ static final String MAINTAIN_PREFIX_KEY = "maintain_prefix";
static final String RETARGET_METHOD_KEY = "retarget_method";
static final String RETARGET_METHOD_EMULATED_DISPATCH_KEY =
"retarget_method_with_emulated_dispatch";
@@ -235,6 +236,11 @@
builder.putRewritePrefix(rewritePrefix.getKey(), rewritePrefix.getValue().getAsString());
}
}
+ if (jsonFlagSet.has(MAINTAIN_PREFIX_KEY)) {
+ for (JsonElement maintainPrefix : jsonFlagSet.get(MAINTAIN_PREFIX_KEY).getAsJsonArray()) {
+ builder.putMaintainPrefix(maintainPrefix.getAsString());
+ }
+ }
if (jsonFlagSet.has(REWRITE_DERIVED_PREFIX_KEY)) {
for (Map.Entry<String, JsonElement> prefixToMatch :
jsonFlagSet.get(REWRITE_DERIVED_PREFIX_KEY).getAsJsonObject().entrySet()) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java
index 9eb3ed7..8f4c435 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java
@@ -24,6 +24,7 @@
public class HumanRewritingFlags {
private final Map<String, String> rewritePrefix;
+ private final Set<String> maintainPrefix;
private final Map<String, Map<String, String>> rewriteDerivedPrefix;
private final Map<DexType, DexType> emulatedInterfaces;
private final Map<DexMethod, DexType> retargetMethod;
@@ -37,6 +38,7 @@
HumanRewritingFlags(
Map<String, String> rewritePrefix,
+ Set<String> maintainPrefix,
Map<String, Map<String, String>> rewriteDerivedPrefix,
Map<DexType, DexType> emulateLibraryInterface,
Map<DexMethod, DexType> retargetMethod,
@@ -48,6 +50,7 @@
Map<DexType, Set<DexMethod>> wrapperConversion,
Map<DexMethod, MethodAccessFlags> amendLibraryMethod) {
this.rewritePrefix = rewritePrefix;
+ this.maintainPrefix = maintainPrefix;
this.rewriteDerivedPrefix = rewriteDerivedPrefix;
this.emulatedInterfaces = emulateLibraryInterface;
this.retargetMethod = retargetMethod;
@@ -63,6 +66,7 @@
public static HumanRewritingFlags empty() {
return new HumanRewritingFlags(
ImmutableMap.of(),
+ ImmutableSet.of(),
ImmutableMap.of(),
ImmutableMap.of(),
ImmutableMap.of(),
@@ -84,6 +88,7 @@
reporter,
origin,
rewritePrefix,
+ maintainPrefix,
rewriteDerivedPrefix,
emulatedInterfaces,
retargetMethod,
@@ -100,6 +105,10 @@
return rewritePrefix;
}
+ public Set<String> getMaintainPrefix() {
+ return maintainPrefix;
+ }
+
public Map<String, Map<String, String>> getRewriteDerivedPrefix() {
return rewriteDerivedPrefix;
}
@@ -153,6 +162,7 @@
private final Origin origin;
private final Map<String, String> rewritePrefix;
+ private final Set<String> maintainPrefix;
private final Map<String, Map<String, String>> rewriteDerivedPrefix;
private final Map<DexType, DexType> emulatedInterfaces;
private final Map<DexMethod, DexType> retargetMethod;
@@ -169,6 +179,7 @@
reporter,
origin,
new HashMap<>(),
+ Sets.newIdentityHashSet(),
new HashMap<>(),
new IdentityHashMap<>(),
new IdentityHashMap<>(),
@@ -185,6 +196,7 @@
Reporter reporter,
Origin origin,
Map<String, String> rewritePrefix,
+ Set<String> maintainPrefix,
Map<String, Map<String, String>> rewriteDerivedPrefix,
Map<DexType, DexType> emulateLibraryInterface,
Map<DexMethod, DexType> retargetMethod,
@@ -198,6 +210,7 @@
this.reporter = reporter;
this.origin = origin;
this.rewritePrefix = new HashMap<>(rewritePrefix);
+ this.maintainPrefix = Sets.newHashSet(maintainPrefix);
this.rewriteDerivedPrefix = new HashMap<>(rewriteDerivedPrefix);
this.emulatedInterfaces = new IdentityHashMap<>(emulateLibraryInterface);
this.retargetMethod = new IdentityHashMap<>(retargetMethod);
@@ -237,6 +250,11 @@
return this;
}
+ public Builder putMaintainPrefix(String prefix) {
+ maintainPrefix.add(prefix);
+ return this;
+ }
+
public Builder putRewriteDerivedPrefix(
String prefixToMatch, String prefixToRewrite, String rewrittenPrefix) {
Map<String, String> map =
@@ -322,6 +340,7 @@
validate();
return new HumanRewritingFlags(
ImmutableMap.copyOf(rewritePrefix),
+ ImmutableSet.copyOf(maintainPrefix),
ImmutableMap.copyOf(rewriteDerivedPrefix),
ImmutableMap.copyOf(emulatedInterfaces),
ImmutableMap.copyOf(retargetMethod),
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java
index 1f52b3d..735d4f0 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java
@@ -82,6 +82,10 @@
return rewritingFlags.getRewriteType();
}
+ public Set<DexType> getMaintainType() {
+ return rewritingFlags.getMaintainType();
+ }
+
public Map<DexType, DexType> getRewriteDerivedTypeOnly() {
return rewritingFlags.getRewriteDerivedTypeOnly();
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java
index 00a4747..0f1aef3 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java
@@ -25,6 +25,7 @@
MachineRewritingFlags(
Map<DexType, DexType> rewriteType,
+ Set<DexType> maintainType,
Map<DexType, DexType> rewriteDerivedTypeOnly,
Map<DexMethod, DexMethod> staticRetarget,
Map<DexMethod, DexMethod> nonEmulatedVirtualRetarget,
@@ -37,6 +38,7 @@
Map<DexType, CustomConversionDescriptor> customConversions,
Map<DexMethod, MethodAccessFlags> amendLibraryMethods) {
this.rewriteType = rewriteType;
+ this.maintainType = maintainType;
this.rewriteDerivedTypeOnly = rewriteDerivedTypeOnly;
this.staticRetarget = staticRetarget;
this.nonEmulatedVirtualRetarget = nonEmulatedVirtualRetarget;
@@ -53,6 +55,8 @@
// Rewrites all the references to the keys as well as synthetic types derived from any key.
private final Map<DexType, DexType> rewriteType;
+ // Maintains the references in the desugared library dex file.
+ private final Set<DexType> maintainType;
// Rewrites only synthetic types derived from any key.
private final Map<DexType, DexType> rewriteDerivedTypeOnly;
@@ -88,6 +92,10 @@
return rewriteType;
}
+ public Set<DexType> getMaintainType() {
+ return maintainType;
+ }
+
public Map<DexType, DexType> getRewriteDerivedTypeOnly() {
return rewriteDerivedTypeOnly;
}
@@ -174,6 +182,7 @@
Builder() {}
private final Map<DexType, DexType> rewriteType = new IdentityHashMap<>();
+ private final ImmutableSet.Builder<DexType> maintainType = ImmutableSet.builder();
private final Map<DexType, DexType> rewriteDerivedTypeOnly = new IdentityHashMap<>();
private final ImmutableMap.Builder<DexMethod, DexMethod> staticRetarget =
ImmutableMap.builder();
@@ -201,6 +210,11 @@
rewriteType.put(src, target);
}
+ public void maintainType(DexType type) {
+ assert type != null;
+ maintainType.add(type);
+ }
+
public void rewriteDerivedTypeOnly(DexType src, DexType target) {
rewriteDerivedTypeOnly.put(src, target);
}
@@ -252,6 +266,7 @@
public MachineRewritingFlags build() {
return new MachineRewritingFlags(
rewriteType,
+ maintainType.build(),
rewriteDerivedTypeOnly,
staticRetarget.build(),
nonEmulatedVirtualRetarget.build(),
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java
index 87c03e3..78fc59f 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineRewritingFlags;
import com.android.tools.r8.utils.DescriptorUtils;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import java.util.Map;
import java.util.Set;
@@ -25,6 +26,7 @@
private final String synthesizedPrefix;
private final boolean libraryCompilation;
private final Map<DexString, DexString> descriptorPrefix;
+ private final Set<DexString> descriptorMaintainPrefix;
private final Map<DexString, Map<DexString, DexString>> descriptorDifferentPrefix;
private final Set<DexString> usedPrefix = Sets.newIdentityHashSet();
@@ -38,6 +40,7 @@
this.synthesizedPrefix = humanSpec.getSynthesizedLibraryClassesPackagePrefix();
this.libraryCompilation = humanSpec.isLibraryCompilation();
this.descriptorPrefix = convertRewritePrefix(rewritingFlags.getRewritePrefix());
+ this.descriptorMaintainPrefix = convertMaintainPrefix(rewritingFlags.getMaintainPrefix());
this.descriptorDifferentPrefix =
convertRewriteDifferentPrefix(rewritingFlags.getRewriteDerivedPrefix());
}
@@ -56,6 +59,7 @@
private void warnIfUnusedPrefix(BiConsumer<String, Set<DexString>> warnConsumer) {
Set<DexString> prefixes = Sets.newIdentityHashSet();
prefixes.addAll(descriptorPrefix.keySet());
+ prefixes.addAll(descriptorMaintainPrefix);
prefixes.addAll(descriptorDifferentPrefix.keySet());
prefixes.removeAll(usedPrefix);
warnConsumer.accept("The following prefixes do not match any type: ", prefixes);
@@ -99,6 +103,7 @@
private void registerClassType(DexType type) {
registerType(type);
+ registerMaintainType(type);
registerDifferentType(type);
}
@@ -109,6 +114,15 @@
}
}
+ private void registerMaintainType(DexType type) {
+ DexString prefix = prefixMatching(type, descriptorMaintainPrefix);
+ if (prefix == null) {
+ return;
+ }
+ builder.maintainType(type);
+ usedPrefix.add(prefix);
+ }
+
private void registerDifferentType(DexType type) {
DexString prefix = prefixMatching(type, descriptorDifferentPrefix.keySet());
if (prefix == null) {
@@ -160,6 +174,14 @@
return mapBuilder.build();
}
+ private ImmutableSet<DexString> convertMaintainPrefix(Set<String> maintainPrefix) {
+ ImmutableSet.Builder<DexString> builder = ImmutableSet.builder();
+ for (String prefix : maintainPrefix) {
+ builder.add(toDescriptorPrefix(prefix));
+ }
+ return builder.build();
+ }
+
private ImmutableMap<DexString, DexString> convertRewritePrefix(
Map<String, String> rewritePrefix) {
ImmutableMap.Builder<DexString, DexString> mapBuilder = ImmutableMap.builder();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
index da7d679..b1c59bc 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
@@ -644,7 +644,7 @@
AppInfoWithClassHierarchy appInfo = appView.appInfoForDesugaring();
for (Wrapper<DexMethod> signature : emulatedInterfaceInfo.signatures.signatures) {
MethodResolutionResult resolutionResult =
- appInfo.resolveMethodOnClass(signature.get(), clazz);
+ appInfo.resolveMethodOnClass(clazz, signature.get());
if (resolutionResult.isFailedResolution()) {
return true;
}
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 dc739bb..3919202 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
@@ -98,6 +98,13 @@
if (isEmulatedInterface(clazz.type)) {
return true;
}
+ if (appView
+ .options()
+ .machineDesugaredLibrarySpecification
+ .getMaintainType()
+ .contains(clazz.type)) {
+ return true;
+ }
return appView.typeRewriter.hasRewrittenType(clazz.type, appView);
}
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 2ae7d7d..a9a33cb 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
@@ -713,7 +713,9 @@
DexClass clazz, DexMethod invokedMethod, ProgramMethod context) {
DexClassAndMethod superTarget =
appView.appInfoForDesugaring().lookupSuperTarget(invokedMethod, context);
- if (clazz.isInterface() && appView.typeRewriter.hasRewrittenType(clazz.type, appView)) {
+ if (clazz.isInterface()
+ && helper.isInDesugaredLibrary(clazz)
+ && !helper.isEmulatedInterface(clazz.type)) {
if (superTarget != null && superTarget.getDefinition().isDefaultMethod()) {
DexClass holder = superTarget.getHolder();
if (holder.isLibraryClass() && holder.isInterface()) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
index 5d14741..f963a21 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
@@ -175,8 +175,8 @@
DexEncodedMethod.setDebugInfoWithFakeThisParameter(
code, companion.getReference().getArity(), appView);
}
- companion.getDefinition().setCode(code, appView);
- definition.setCode(InvalidCode.getInstance(), appView);
+ companion.setCode(code, appView);
+ method.setCode(InvalidCode.getInstance(), appView);
}
private void clearDirectMethods(DexProgramClass iface) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/lambda/LambdaInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/lambda/LambdaInstructionDesugaring.java
index d336a16..532909b 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/lambda/LambdaInstructionDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/lambda/LambdaInstructionDesugaring.java
@@ -120,6 +120,11 @@
eventConsumer.acceptLambdaClass(lambdaClass, context);
+ if (lambdaClass.hasFactoryMethod()) {
+ return ImmutableList.of(
+ new CfInvoke(Opcodes.INVOKESTATIC, lambdaClass.getFactoryMethod(), false));
+ }
+
if (lambdaClass.isStatelessSingleton()) {
return ImmutableList.of(
new CfStaticFieldRead(lambdaClass.lambdaField, lambdaClass.lambdaField));
@@ -143,7 +148,6 @@
// elements on the stack, we load all the N arguments back onto the stack. At this point, we
// have the original N arguments on the stack plus the 2 new stack elements.
localStackAllocator.allocateLocalStack(2);
-
return replacement;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordDesugaring.java
index 3f17800..6a84f09 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordDesugaring.java
@@ -22,6 +22,7 @@
import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.errors.MissingGlobalSyntheticsConsumerDiagnostic;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
@@ -239,8 +240,9 @@
// Will be traced by the enqueuer.
.disableAndroidApiLevelCheck()
.build();
- encodedMethod.setCode(provider.generateCfCode(), appView);
- return new ProgramMethod(clazz, encodedMethod);
+ ProgramMethod result = new ProgramMethod(clazz, encodedMethod);
+ result.setCode(provider.generateCfCode(), appView);
+ return result;
}
private DexMethod ensureEqualsRecord(
@@ -372,7 +374,8 @@
checkRecordTagNotPresent(factory);
appView
.getSyntheticItems()
- .ensureFixedClassFromType(
+ .ensureGlobalClass(
+ () -> new MissingGlobalSyntheticsConsumerDiagnostic("Record desugaring"),
kinds -> kinds.RECORD_TAG,
factory.recordType,
appView,
@@ -462,17 +465,13 @@
MethodAccessFlags methodAccessFlags =
MethodAccessFlags.fromSharedAccessFlags(
Constants.ACC_SYNTHETIC | Constants.ACC_PROTECTED, true);
- DexEncodedMethod init =
- DexEncodedMethod.syntheticBuilder()
- .setMethod(factory.recordMembers.constructor)
- .setAccessFlags(methodAccessFlags)
- .setCode(null)
- // Will be traced by the enqueuer.
- .disableAndroidApiLevelCheck()
- .build();
- init.setCode(
- new CallObjectInitCfCodeProvider(appView, factory.recordTagType).generateCfCode(), appView);
- return init;
+ return DexEncodedMethod.syntheticBuilder()
+ .setMethod(factory.recordMembers.constructor)
+ .setAccessFlags(methodAccessFlags)
+ .setCode(new CallObjectInitCfCodeProvider(appView, factory.recordTagType).generateCfCode())
+ // Will be traced by the enqueuer.
+ .disableAndroidApiLevelCheck()
+ .build();
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/AssertionsRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/AssertionsRewriter.java
index 0da7886..72b8d6a 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/AssertionsRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/AssertionsRewriter.java
@@ -340,7 +340,7 @@
if (enabled) {
timing.begin("Rewrite assertions");
runInternal(method, code);
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
timing.end();
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/BasicBlockInstructionsEquivalence.java b/src/main/java/com/android/tools/r8/ir/optimize/BasicBlockInstructionsEquivalence.java
index b7909df..5373a30 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/BasicBlockInstructionsEquivalence.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/BasicBlockInstructionsEquivalence.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.ir.regalloc.RegisterAllocator;
import com.google.common.base.Equivalence;
import java.util.Arrays;
@@ -17,10 +18,12 @@
private static final int UNKNOW_HASH = -1;
private static final int MAX_HASH_INSTRUCTIONS = 5;
private final RegisterAllocator allocator;
+ private final MethodConversionOptions conversionOptions;
private final int[] hashes;
BasicBlockInstructionsEquivalence(IRCode code, RegisterAllocator allocator) {
this.allocator = allocator;
+ this.conversionOptions = code.getConversionOptions();
hashes = new int[code.getCurrentBlockNumber() + 1];
Arrays.fill(hashes, UNKNOW_HASH);
}
@@ -34,7 +37,7 @@
for (int i = 0; i < instructions0.size(); i++) {
Instruction i0 = instructions0.get(i);
Instruction i1 = instructions1.get(i);
- if (!i0.identicalAfterRegisterAllocation(i1, allocator)) {
+ if (!i0.identicalAfterRegisterAllocation(i1, allocator, conversionOptions)) {
return false;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java b/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java
index 3551295..ef1b959 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java
@@ -137,7 +137,7 @@
}
ProgramMethod context = code.context();
- if (context.getDefinition().getOptimizationInfo().isReachabilitySensitive()) {
+ if (context.getOrComputeReachabilitySensitive(appView)) {
return ClassInitializerDefaultsResult.empty();
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index 204b1a6..e011479 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -39,7 +39,6 @@
import com.android.tools.r8.ir.analysis.value.ConstantOrNonConstantNumberValue;
import com.android.tools.r8.ir.analysis.value.SingleConstClassValue;
import com.android.tools.r8.ir.analysis.value.SingleFieldValue;
-import com.android.tools.r8.ir.code.AlwaysMaterializingNop;
import com.android.tools.r8.ir.code.ArrayLength;
import com.android.tools.r8.ir.code.ArrayPut;
import com.android.tools.r8.ir.code.Assume;
@@ -158,7 +157,6 @@
private static final int MAX_FILL_ARRAY_SIZE = 8 * Constants.KILOBYTE;
// This constant was determined by experimentation.
private static final int STOP_SHARED_CONSTANT_THRESHOLD = 50;
- private static final int SELF_RECURSION_LIMIT = 4;
private final AppView<?> appView;
private final DexItemFactory dexItemFactory;
@@ -387,7 +385,7 @@
new TypeAnalysis(appView).narrowing(affectedValues);
}
}
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
}
public static boolean isFallthroughBlock(BasicBlock block) {
@@ -489,41 +487,6 @@
}
}
- // For method with many self-recursive calls, insert a try-catch to disable inlining.
- // Marshmallow dex2oat aggressively inlines and eats up all the memory on devices.
- public static void disableDex2OatInliningForSelfRecursiveMethods(
- AppView<?> appView, IRCode code) {
- if (!appView.options().canHaveDex2OatInliningIssue() || code.hasCatchHandlers()) {
- // Catch handlers disables inlining, so if the method already has catch handlers
- // there is nothing to do.
- return;
- }
- int selfRecursionFanOut = 0;
- Instruction lastSelfRecursiveCall = null;
- for (Instruction i : code.instructions()) {
- if (i.isInvokeMethod()
- && i.asInvokeMethod().getInvokedMethod() == code.method().getReference()) {
- selfRecursionFanOut++;
- lastSelfRecursiveCall = i;
- }
- }
- if (selfRecursionFanOut > SELF_RECURSION_LIMIT) {
- assert lastSelfRecursiveCall != null;
- // Split out the last recursive call in its own block.
- InstructionListIterator splitIterator =
- lastSelfRecursiveCall.getBlock().listIterator(code, lastSelfRecursiveCall);
- splitIterator.previous();
- BasicBlock newBlock = splitIterator.split(code, 1);
- // Generate rethrow block.
- DexType guard = appView.dexItemFactory().throwableType;
- BasicBlock rethrowBlock =
- BasicBlock.createRethrowBlock(code, lastSelfRecursiveCall.getPosition(), guard, appView);
- code.blocks.add(rethrowBlock);
- // Add catch handler to the block containing the last recursive call.
- newBlock.appendCatchHandler(rethrowBlock, guard);
- }
- }
-
// TODO(sgjesse); Move this somewhere else, and reuse it for some of the other switch rewritings.
public abstract static class InstructionBuilder<T> {
protected int blockNumber;
@@ -663,7 +626,7 @@
* Covert the switch instruction to a sequence of if instructions checking for a specified set of
* keys, followed by a new switch with the remaining keys.
*/
- private void convertSwitchToSwitchAndIfs(
+ void convertSwitchToSwitchAndIfs(
IRCode code,
ListIterator<BasicBlock> blocksIterator,
BasicBlock originalBlock,
@@ -945,57 +908,6 @@
return rewriteSwitchFull(code, switchCaseAnalyzer);
}
- public void rewriteSwitchForMaxInt(IRCode code) {
- if (options.canHaveSwitchMaxIntBug() && code.metadata().mayHaveSwitch()) {
- // Always rewrite for workaround switch bug.
- rewriteSwitchForMaxIntOnly(code);
- }
- }
-
- private void rewriteSwitchForMaxIntOnly(IRCode code) {
- boolean needToSplitCriticalEdges = false;
- ListIterator<BasicBlock> blocksIterator = code.listIterator();
- while (blocksIterator.hasNext()) {
- BasicBlock block = blocksIterator.next();
- InstructionListIterator iterator = block.listIterator(code);
- while (iterator.hasNext()) {
- Instruction instruction = iterator.next();
- assert !instruction.isStringSwitch();
- if (instruction.isIntSwitch()) {
- IntSwitch intSwitch = instruction.asIntSwitch();
- if (intSwitch.getKey(intSwitch.numberOfKeys() - 1) == Integer.MAX_VALUE) {
- if (intSwitch.numberOfKeys() == 1) {
- rewriteSingleKeySwitchToIf(code, block, iterator, intSwitch);
- } else {
- IntList newSwitchSequences = new IntArrayList(intSwitch.numberOfKeys() - 1);
- for (int i = 0; i < intSwitch.numberOfKeys() - 1; i++) {
- newSwitchSequences.add(intSwitch.getKey(i));
- }
- IntList outliers = new IntArrayList(1);
- outliers.add(Integer.MAX_VALUE);
- convertSwitchToSwitchAndIfs(
- code,
- blocksIterator,
- block,
- iterator,
- intSwitch,
- ImmutableList.of(newSwitchSequences),
- outliers);
- }
- needToSplitCriticalEdges = true;
- }
- }
- }
- }
-
- // Rewriting of switches introduces new branching structure. It relies on critical edges
- // being split on the way in but does not maintain this property. We therefore split
- // critical edges at exit.
- if (needToSplitCriticalEdges) {
- code.splitCriticalEdges();
- }
- }
-
private boolean rewriteSwitchFull(IRCode code, SwitchCaseAnalyzer switchCaseAnalyzer) {
boolean needToRemoveUnreachableBlocks = false;
ListIterator<BasicBlock> blocksIterator = code.listIterator();
@@ -1041,11 +953,11 @@
if (!affectedValues.isEmpty()) {
new TypeAnalysis(appView).narrowing(affectedValues);
}
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
return !affectedValues.isEmpty();
}
- private void rewriteSingleKeySwitchToIf(
+ void rewriteSingleKeySwitchToIf(
IRCode code, BasicBlock block, InstructionListIterator iterator, IntSwitch theSwitch) {
// Rewrite the switch to an if.
int fallthroughBlockIndex = theSwitch.getFallthroughBlockIndex();
@@ -1247,8 +1159,8 @@
* rewrite fallthrough targets as that would require block reordering and the transformation only
* makes sense after SSA destruction where there are no phis.
*/
- public static void collapseTrivialGotos(IRCode code) {
- assert code.isConsistentGraph();
+ public static void collapseTrivialGotos(AppView<?> appView, IRCode code) {
+ assert code.isConsistentGraph(appView);
List<BasicBlock> blocksToRemove = new ArrayList<>();
// Rewrite all non-fallthrough targets to the end of trivial goto chains and remove
// first round of trivial goto blocks.
@@ -1286,7 +1198,7 @@
code.removeBlocks(blocksToRemove);
}
assert removedTrivialGotos(code);
- assert code.isConsistentGraph();
+ assert code.isConsistentGraph(appView);
}
private boolean checkArgumentType(InvokeMethod invoke, int argumentIndex) {
@@ -1375,7 +1287,7 @@
if (!affectedValues.isEmpty()) {
new TypeAnalysis(appView).narrowing(affectedValues);
}
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
return changed;
}
@@ -1466,7 +1378,7 @@
typeAnalysis.narrowing(affectedValues);
}
}
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
}
// Returns true if the given check-cast instruction was removed.
@@ -1744,7 +1656,7 @@
}
}
}
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
}
/**
@@ -1823,7 +1735,7 @@
}
}
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
}
// Check if a binop can be represented in the binop/lit8 or binop/lit16 form.
@@ -2006,7 +1918,7 @@
}
}
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
}
private void forEachUse(Instruction instruction, Consumer<Value> fn) {
@@ -2331,7 +2243,7 @@
} while (block != null);
}
}
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
}
// TODO(mikaelpeltier) Manage that from and to instruction do not belong to the same block.
@@ -2556,7 +2468,7 @@
}
}
code.returnMarkingColor(noCandidate);
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
}
static class ControlFlowSimplificationResult {
@@ -2632,7 +2544,7 @@
if (!affectedValues.isEmpty()) {
new TypeAnalysis(appView).narrowing(affectedValues);
}
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
return new ControlFlowSimplificationResult(!affectedValues.isEmpty(), simplified);
}
@@ -2988,7 +2900,7 @@
if (changed) {
code.removeAllDeadAndTrivialPhis();
}
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
}
private static Long2ReferenceMap<List<ConstNumber>> getConstantsByValue(IRCode code) {
@@ -3099,11 +3011,6 @@
// it with a block throwing a null value (which should result in NPE). Note that this throw is not
// expected to be ever reached, but is intended to satisfy verifier.
public void optimizeAlwaysThrowingInstructions(IRCode code) {
- if (!appView.appInfo().hasLiveness()) {
- return;
- }
-
- AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
Set<Value> affectedValues = Sets.newIdentityHashSet();
Set<BasicBlock> blocksToRemove = Sets.newIdentityHashSet();
ListIterator<BasicBlock> blockIterator = code.listIterator();
@@ -3153,7 +3060,7 @@
}
}
instructionIterator.replaceCurrentInstructionWithThrowNull(
- appViewWithLiveness, code, blockIterator, blocksToRemove, affectedValues);
+ appView, code, blockIterator, blocksToRemove, affectedValues);
continue;
}
}
@@ -3163,8 +3070,7 @@
}
InvokeMethod invoke = instruction.asInvokeMethod();
- DexClassAndMethod singleTarget =
- invoke.lookupSingleTarget(appView.withLiveness(), code.context());
+ DexClassAndMethod singleTarget = invoke.lookupSingleTarget(appView, code.context());
if (singleTarget == null) {
continue;
}
@@ -3190,7 +3096,7 @@
instructionIterator.setInsertionPosition(invoke.getPosition());
instructionIterator.next();
instructionIterator.replaceCurrentInstructionWithThrowNull(
- appViewWithLiveness, code, blockIterator, blocksToRemove, affectedValues);
+ appView, code, blockIterator, blocksToRemove, affectedValues);
instructionIterator.unsetInsertionPosition();
}
}
@@ -3203,7 +3109,7 @@
if (!affectedValues.isEmpty()) {
new TypeAnalysis(appView).narrowing(affectedValues);
}
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
}
/* Identify simple diamond shapes converting boolean true/false to 1/0. We consider the forms:
@@ -3465,7 +3371,7 @@
phiUsers.forEach(Phi::removeTrivialPhi);
}
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
}
public void rewriteAssertionErrorTwoArgumentConstructor(IRCode code, InternalOptions options) {
@@ -3514,7 +3420,7 @@
}
}
}
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
}
/**
@@ -3870,78 +3776,4 @@
}
}
}
-
- // See comment for InternalOptions.canHaveNumberConversionRegisterAllocationBug().
- public void workaroundNumberConversionRegisterAllocationBug(IRCode code) {
- ListIterator<BasicBlock> blocks = code.listIterator();
- while (blocks.hasNext()) {
- BasicBlock block = blocks.next();
- InstructionListIterator it = block.listIterator(code);
- while (it.hasNext()) {
- Instruction instruction = it.next();
- if (instruction.isArithmeticBinop() || instruction.isNeg()) {
- for (Value value : instruction.inValues()) {
- // Insert a call to Double.isNaN on each value which come from a number conversion
- // to double and flows into an arithmetic instruction. This seems to break the traces
- // in the Dalvik JIT and avoid the bug where the generated ARM code can clobber float
- // values in a single-precision registers with double values written to
- // double-precision registers. See b/77496850 for examples.
- if (!value.isPhi()
- && value.definition.isNumberConversion()
- && value.definition.asNumberConversion().to == NumericType.DOUBLE) {
- InvokeStatic invokeIsNaN =
- new InvokeStatic(
- dexItemFactory.doubleMembers.isNaN, null, ImmutableList.of(value));
- invokeIsNaN.setPosition(instruction.getPosition());
-
- // Insert the invoke before the current instruction.
- it.previous();
- BasicBlock blockWithInvokeNaN =
- block.hasCatchHandlers() ? it.split(code, blocks) : block;
- if (blockWithInvokeNaN != block) {
- // If we split, add the invoke at the end of the original block.
- it = block.listIterator(code, block.getInstructions().size());
- it.previous();
- it.add(invokeIsNaN);
- // Continue iteration in the split block.
- block = blockWithInvokeNaN;
- it = block.listIterator(code);
- } else {
- // Otherwise, add it to the current block.
- it.add(invokeIsNaN);
- }
- // Skip over the instruction causing the invoke to be inserted.
- Instruction temp = it.next();
- assert temp == instruction;
- }
- }
- }
- }
- }
- }
-
- // If an exceptional edge could target a conditional-loop header ensure that we have a
- // materializing instruction on that path to work around a bug in some L x86_64 non-emulator VMs.
- // See b/111337896.
- public void workaroundExceptionTargetingLoopHeaderBug(IRCode code) {
- for (BasicBlock block : code.blocks) {
- if (block.hasCatchHandlers()) {
- for (BasicBlock handler : block.getCatchHandlers().getUniqueTargets()) {
- // We conservatively assume that a block with at least two normal predecessors is a loop
- // header. If we ever end up computing exact loop headers, use that here instead.
- // The loop is conditional if it has at least two normal successors.
- BasicBlock target = handler.endOfGotoChain();
- if (target != null
- && target.getPredecessors().size() > 1
- && target.getNormalPredecessors().size() > 1
- && target.getNormalSuccessors().size() > 1) {
- Instruction fixit = new AlwaysMaterializingNop();
- fixit.setBlock(handler);
- fixit.setPosition(handler.getPosition());
- handler.getInstructions().addFirst(fixit);
- }
- }
- }
- }
- }
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ConstantCanonicalizer.java b/src/main/java/com/android/tools/r8/ir/optimize/ConstantCanonicalizer.java
index 912a030..8839c13 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ConstantCanonicalizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ConstantCanonicalizer.java
@@ -270,7 +270,7 @@
codeRewriter.simplifyIf(code);
}
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
}
private static void insertCanonicalizedConstant(IRCode code, Instruction canonicalizedConstant) {
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 5dbfaba..92e653d 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
@@ -40,6 +40,10 @@
this.codeRewriter = codeRewriter;
}
+ public CodeRewriter getCodeRewriter() {
+ return codeRewriter;
+ }
+
public void run(IRCode code, Timing timing) {
timing.begin("Remove dead code");
@@ -58,7 +62,7 @@
}
} while (codeRewriter.simplifyIf(code).anySimplifications()
|| removeUnneededCatchHandlers(code));
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
timing.end();
}
@@ -210,7 +214,7 @@
if (mayHaveIntroducedUnreachableBlocks) {
code.removeUnreachableBlocks();
}
- assert code.isConsistentGraph();
+ assert code.isConsistentGraph(appView);
return mayHaveIntroducedUnreachableBlocks;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java b/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
index 2ef8dd2..cd5b8b2 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
@@ -315,7 +315,7 @@
if (!affectedValues.isEmpty()) {
new TypeAnalysis(appView).narrowing(affectedValues);
}
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
}
/** This rebinds invoke-super instructions to their most specific target. */
@@ -369,7 +369,7 @@
}
SingleResolutionResult resolutionResult =
- appView.appInfo().resolveMethodOnClass(target).asSingleResolution();
+ appView.appInfo().resolveMethodOnClass(target.getHolderType(), target).asSingleResolution();
if (resolutionResult == null
|| resolutionResult
.isAccessibleForVirtualDispatchFrom(context, appView.appInfo())
@@ -385,7 +385,7 @@
}
SingleResolutionResult newResolutionResult =
- appView.appInfo().resolveMethodOnClass(target, receiverType).asSingleResolution();
+ appView.appInfo().resolveMethodOnClass(receiverType, target).asSingleResolution();
if (newResolutionResult == null
|| newResolutionResult
.isAccessibleForVirtualDispatchFrom(context, appView.appInfo())
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/IdempotentFunctionCallCanonicalizer.java b/src/main/java/com/android/tools/r8/ir/optimize/IdempotentFunctionCallCanonicalizer.java
index 28530d3..4b3bb6f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/IdempotentFunctionCallCanonicalizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/IdempotentFunctionCallCanonicalizer.java
@@ -271,7 +271,7 @@
}
code.removeAllDeadAndTrivialPhis();
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
}
private boolean isIdempotentLibraryMethodInvoke(InvokeMethod invoke) {
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 c458574..577dbf2 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
@@ -704,7 +704,7 @@
if (options.testing.inlineeIrModifier != null) {
options.testing.inlineeIrModifier.accept(code);
}
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
return new InlineeWithReason(code, reason);
}
@@ -959,11 +959,11 @@
if (current.isInvokeMethod()) {
InvokeMethod invoke = current.asInvokeMethod();
// TODO(b/142116551): This should be equivalent to invoke.lookupSingleTarget()!
-
+ DexMethod invokedMethod = invoke.getInvokedMethod();
SingleResolutionResult resolutionResult =
appView
.appInfo()
- .resolveMethod(invoke.getInvokedMethod(), invoke.getInterfaceBit())
+ .resolveMethod(invokedMethod, invoke.getInterfaceBit())
.asSingleResolution();
if (resolutionResult == null
|| resolutionResult.isAccessibleFrom(context, appView).isPossiblyFalse()) {
@@ -1105,7 +1105,7 @@
classInitializationAnalysis.finish();
code.removeBlocks(blocksToRemove);
code.removeAllDeadAndTrivialPhis();
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
}
private boolean tryInlineMethodWithoutSideEffects(
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InstructionEquivalence.java b/src/main/java/com/android/tools/r8/ir/optimize/InstructionEquivalence.java
index 2f2523d..68207cd 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/InstructionEquivalence.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/InstructionEquivalence.java
@@ -3,21 +3,25 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.optimize;
+import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.ir.regalloc.RegisterAllocator;
import com.google.common.base.Equivalence;
public class InstructionEquivalence extends Equivalence<Instruction> {
private final RegisterAllocator allocator;
+ private final MethodConversionOptions conversionOptions;
- InstructionEquivalence(RegisterAllocator allocator) {
+ InstructionEquivalence(RegisterAllocator allocator, IRCode code) {
this.allocator = allocator;
+ this.conversionOptions = code.getConversionOptions();
}
@Override
protected boolean doEquivalent(Instruction a, Instruction b) {
- return a.identicalAfterRegisterAllocation(b, allocator)
+ return a.identicalAfterRegisterAllocation(b, allocator, conversionOptions)
&& a.getBlock().getCatchHandlers().equals(b.getBlock().getCatchHandlers());
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
index 08edc70..7e494f3 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
@@ -382,6 +382,13 @@
return;
}
+ if (current.isStaticGet() && current.hasUnusedOutValue()) {
+ // Replace by initclass.
+ iterator.removeOrReplaceCurrentInstructionByInitClassIfPossible(
+ appView, code, field.getHolderType());
+ return;
+ }
+
if (!mayPropagateValueFor(target)) {
return;
}
@@ -510,7 +517,7 @@
if (!affectedValues.isEmpty()) {
new TypeAnalysis(appView).narrowing(affectedValues);
}
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
assert code.verifyTypes(appView);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/NaturalIntLoopRemover.java b/src/main/java/com/android/tools/r8/ir/optimize/NaturalIntLoopRemover.java
index 0951ff9..c82a122 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/NaturalIntLoopRemover.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/NaturalIntLoopRemover.java
@@ -41,7 +41,7 @@
}
if (loopRemoved) {
code.removeAllDeadAndTrivialPhis();
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/OutlinerImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/OutlinerImpl.java
index f04e328..fa902a6 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/OutlinerImpl.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/OutlinerImpl.java
@@ -59,6 +59,7 @@
import com.android.tools.r8.ir.code.ValueTypeConstraint;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.IRConverter;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.ir.conversion.SourceCode;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackDelayed;
@@ -1794,9 +1795,13 @@
}
@Override
- public IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
+ public IRCode buildIR(
+ ProgramMethod method,
+ AppView<?> appView,
+ Origin origin,
+ MutableMethodConversionOptions conversionOptions) {
OutlineSourceCode source = new OutlineSourceCode(outline, method.getReference());
- return IRBuilder.create(method, appView, source, origin).build(method);
+ return IRBuilder.create(method, appView, source, origin).build(method, conversionOptions);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/PeepholeOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/PeepholeOptimizer.java
index a8cd620..0b199bc 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/PeepholeOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/PeepholeOptimizer.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.optimize;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DebugLocalInfo;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.ConstNumber;
@@ -36,17 +37,18 @@
/**
* Perform optimizations of the code with register assignments provided by the register allocator.
*/
- public static void optimize(IRCode code, LinearScanRegisterAllocator allocator) {
+ public static void optimize(
+ AppView<?> appView, IRCode code, LinearScanRegisterAllocator allocator) {
removeIdenticalPredecessorBlocks(code, allocator);
removeRedundantInstructions(code, allocator);
shareIdenticalBlockPrefix(code, allocator);
shareIdenticalBlockSuffix(code, allocator, 0);
- assert code.isConsistentGraph();
+ assert code.isConsistentGraph(appView);
}
/** Identify common prefixes in successor blocks and share them. */
private static void shareIdenticalBlockPrefix(IRCode code, RegisterAllocator allocator) {
- InstructionEquivalence equivalence = new InstructionEquivalence(allocator);
+ InstructionEquivalence equivalence = new InstructionEquivalence(allocator, code);
Set<BasicBlock> blocksToBeRemoved = Sets.newIdentityHashSet();
for (BasicBlock block : code.blocks) {
shareIdenticalBlockPrefixFromNormalSuccessors(
@@ -244,7 +246,7 @@
do {
Map<BasicBlock, BasicBlock> newBlocks = new IdentityHashMap<>();
for (BasicBlock block : blocks) {
- InstructionEquivalence equivalence = new InstructionEquivalence(allocator);
+ InstructionEquivalence equivalence = new InstructionEquivalence(allocator, code);
// Group interesting predecessor blocks by their last instruction.
Map<Wrapper<Instruction>, List<BasicBlock>> lastInstructionToBlocks = new HashMap<>();
for (BasicBlock pred : block.getPredecessors()) {
@@ -284,7 +286,7 @@
BasicBlock pred = predsWithSameLastInstruction.get(i);
assert pred.exit().isGoto() || pred.exit().isReturn();
commonSuffixSize =
- Math.min(commonSuffixSize, sharedSuffixSize(firstPred, pred, allocator));
+ Math.min(commonSuffixSize, sharedSuffixSize(firstPred, pred, allocator, code));
}
int sizeDelta = overhead - (predsWithSameLastInstruction.size() - 1) * commonSuffixSize;
@@ -403,7 +405,7 @@
}
private static int sharedSuffixSize(
- BasicBlock block0, BasicBlock block1, RegisterAllocator allocator) {
+ BasicBlock block0, BasicBlock block1, RegisterAllocator allocator, IRCode code) {
assert block0.exit().isGoto() || block0.exit().isReturn();
// If the blocks do not agree on locals at exit then they don't have any shared suffix.
if (!Objects.equals(localsAtBlockExit(block0), localsAtBlockExit(block1))) {
@@ -415,7 +417,7 @@
while (it0.hasPrevious() && it1.hasPrevious()) {
Instruction i0 = it0.previous();
Instruction i1 = it1.previous();
- if (!i0.identicalAfterRegisterAllocation(i1, allocator)) {
+ if (!i0.identicalAfterRegisterAllocation(i1, allocator, code.getConversionOptions())) {
return suffixSize;
}
suffixSize++;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
index d758988..5966a8c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
@@ -413,7 +413,7 @@
}
processInstructionsToRemove();
assumeRemover.removeMarkedInstructions().finish();
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
}
private void processInstructionsToRemove() {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
index 683cf92..879646e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
@@ -74,7 +74,7 @@
if (!affectedValues.isEmpty()) {
new TypeAnalysis(appView).narrowing(affectedValues);
}
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
}
private static BiConsumer<DexType, DexClass> rewriteSingleGetClassOrForNameToConstClass(
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/RuntimeWorkaroundCodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/RuntimeWorkaroundCodeRewriter.java
new file mode 100644
index 0000000..20b26b0
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/RuntimeWorkaroundCodeRewriter.java
@@ -0,0 +1,375 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.optimize;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DexTypeList;
+import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.ir.code.AlwaysMaterializingDefinition;
+import com.android.tools.r8.ir.code.AlwaysMaterializingNop;
+import com.android.tools.r8.ir.code.AlwaysMaterializingUser;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.InstructionListIterator;
+import com.android.tools.r8.ir.code.IntSwitch;
+import com.android.tools.r8.ir.code.InvokeStatic;
+import com.android.tools.r8.ir.code.NumericType;
+import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.utils.InternalOptions;
+import com.google.common.base.Suppliers;
+import com.google.common.collect.ImmutableList;
+import it.unimi.dsi.fastutil.ints.IntArrayList;
+import it.unimi.dsi.fastutil.ints.IntList;
+import java.util.Collections;
+import java.util.ListIterator;
+import java.util.function.Supplier;
+
+public class RuntimeWorkaroundCodeRewriter {
+
+ private static final int SELF_RECURSION_LIMIT = 4;
+
+ // For method with many self-recursive calls, insert a try-catch to disable inlining.
+ // Marshmallow dex2oat aggressively inlines and eats up all the memory on devices.
+ public static void workaroundDex2OatInliningIssue(AppView<?> appView, IRCode code) {
+ if (!appView.options().canHaveDex2OatInliningIssue() || code.hasCatchHandlers()) {
+ // Catch handlers disables inlining, so if the method already has catch handlers
+ // there is nothing to do.
+ return;
+ }
+ int selfRecursionFanOut = 0;
+ Instruction lastSelfRecursiveCall = null;
+ for (Instruction i : code.instructions()) {
+ if (i.isInvokeMethod()
+ && i.asInvokeMethod().getInvokedMethod() == code.method().getReference()) {
+ selfRecursionFanOut++;
+ lastSelfRecursiveCall = i;
+ }
+ }
+ if (selfRecursionFanOut > SELF_RECURSION_LIMIT) {
+ assert lastSelfRecursiveCall != null;
+ // Split out the last recursive call in its own block.
+ InstructionListIterator splitIterator =
+ lastSelfRecursiveCall.getBlock().listIterator(code, lastSelfRecursiveCall);
+ splitIterator.previous();
+ BasicBlock newBlock = splitIterator.split(code, 1);
+ // Generate rethrow block.
+ DexType guard = appView.dexItemFactory().throwableType;
+ BasicBlock rethrowBlock =
+ BasicBlock.createRethrowBlock(code, lastSelfRecursiveCall.getPosition(), guard, appView);
+ code.blocks.add(rethrowBlock);
+ // Add catch handler to the block containing the last recursive call.
+ newBlock.appendCatchHandler(rethrowBlock, guard);
+ }
+ }
+
+ /**
+ * For each block, we look to see if the header matches:
+ *
+ * <pre>
+ * pseudo-instructions*
+ * v2 <- long-{mul,div} v0 v1
+ * pseudo-instructions*
+ * v5 <- long-{add,sub} v3 v4
+ * </pre>
+ *
+ * where v2 ~=~ v3 or v2 ~=~ v4 (with ~=~ being equal or an alias of) and the block is not a
+ * fallthrough target.
+ */
+ public static void workaroundDex2OatLinkedListBug(IRCode code, InternalOptions options) {
+ if (!options.canHaveDex2OatLinkedListBug()) {
+ return;
+ }
+ DexItemFactory factory = options.itemFactory;
+ final Supplier<DexMethod> javaLangLangSignum =
+ Suppliers.memoize(
+ () ->
+ factory.createMethod(
+ factory.createString("Ljava/lang/Long;"),
+ factory.createString("signum"),
+ factory.intDescriptor,
+ new DexString[] {factory.longDescriptor}));
+ for (BasicBlock block : code.blocks) {
+ InstructionListIterator it = block.listIterator(code);
+ Instruction firstMaterializing =
+ it.nextUntil(RuntimeWorkaroundCodeRewriter::isNotPseudoInstruction);
+ if (!isLongMul(firstMaterializing)) {
+ continue;
+ }
+ Instruction secondMaterializing =
+ it.nextUntil(RuntimeWorkaroundCodeRewriter::isNotPseudoInstruction);
+ if (!isLongAddOrSub(secondMaterializing)) {
+ continue;
+ }
+ if (isFallthoughTarget(block)) {
+ continue;
+ }
+ Value outOfMul = firstMaterializing.outValue();
+ for (Value inOfAddOrSub : secondMaterializing.inValues()) {
+ if (isAliasOf(inOfAddOrSub, outOfMul)) {
+ it = block.listIterator(code);
+ it.nextUntil(i -> i == firstMaterializing);
+ Value longValue = firstMaterializing.inValues().get(0);
+ InvokeStatic invokeLongSignum =
+ new InvokeStatic(
+ javaLangLangSignum.get(), null, Collections.singletonList(longValue));
+ ensureThrowingInstructionBefore(code, firstMaterializing, it, invokeLongSignum);
+ return;
+ }
+ }
+ }
+ }
+
+ // If an exceptional edge could target a conditional-loop header ensure that we have a
+ // materializing instruction on that path to work around a bug in some L x86_64 non-emulator VMs.
+ // See b/111337896.
+ public static void workaroundExceptionTargetingLoopHeaderBug(
+ IRCode code, InternalOptions options) {
+ if (!options.canHaveExceptionTargetingLoopHeaderBug()) {
+ return;
+ }
+ for (BasicBlock block : code.blocks) {
+ if (block.hasCatchHandlers()) {
+ for (BasicBlock handler : block.getCatchHandlers().getUniqueTargets()) {
+ // We conservatively assume that a block with at least two normal predecessors is a loop
+ // header. If we ever end up computing exact loop headers, use that here instead.
+ // The loop is conditional if it has at least two normal successors.
+ BasicBlock target = handler.endOfGotoChain();
+ if (target != null
+ && target.getPredecessors().size() > 1
+ && target.getNormalPredecessors().size() > 1
+ && target.getNormalSuccessors().size() > 1) {
+ Instruction fixit = new AlwaysMaterializingNop();
+ fixit.setBlock(handler);
+ fixit.setPosition(handler.getPosition());
+ handler.getInstructions().addFirst(fixit);
+ }
+ }
+ }
+ }
+ }
+
+ public static void workaroundForwardingInitializerBug(IRCode code, InternalOptions options) {
+ if (!options.canHaveForwardingInitInliningBug()) {
+ return;
+ }
+ // Only constructors.
+ if (!code.method().isInstanceInitializer()) {
+ return;
+ }
+ // Only constructors with certain signatures.
+ DexTypeList paramTypes = code.method().getReference().proto.parameters;
+ if (paramTypes.size() != 3
+ || paramTypes.values[0] != options.itemFactory.doubleType
+ || paramTypes.values[1] != options.itemFactory.doubleType
+ || !paramTypes.values[2].isClassType()) {
+ return;
+ }
+ // Only if the constructor contains a super constructor call taking only parameters as
+ // inputs.
+ for (BasicBlock block : code.blocks) {
+ InstructionListIterator it = block.listIterator(code);
+ Instruction superConstructorCall =
+ it.nextUntil(
+ (i) ->
+ i.isInvokeDirect()
+ && i.asInvokeDirect().getInvokedMethod().name
+ == options.itemFactory.constructorMethodName
+ && i.asInvokeDirect().arguments().size() == 4
+ && i.asInvokeDirect().arguments().stream().allMatch(Value::isArgument));
+ if (superConstructorCall != null) {
+ // We force a materializing const instruction in front of the super call to make
+ // sure that there is at least one temporary register in the method. That disables
+ // the inlining that is crashing on these devices.
+ ensureInstructionBefore(code, superConstructorCall, it);
+ break;
+ }
+ }
+ }
+
+ public static void workaroundSwitchMaxIntBug(
+ IRCode code, CodeRewriter codeRewriter, InternalOptions options) {
+ if (options.canHaveSwitchMaxIntBug() && code.metadata().mayHaveSwitch()) {
+ // Always rewrite for workaround switch bug.
+ rewriteSwitchForMaxIntOnly(code, codeRewriter);
+ }
+ }
+
+ private static void rewriteSwitchForMaxIntOnly(IRCode code, CodeRewriter codeRewriter) {
+ boolean needToSplitCriticalEdges = false;
+ ListIterator<BasicBlock> blocksIterator = code.listIterator();
+ while (blocksIterator.hasNext()) {
+ BasicBlock block = blocksIterator.next();
+ InstructionListIterator iterator = block.listIterator(code);
+ while (iterator.hasNext()) {
+ Instruction instruction = iterator.next();
+ assert !instruction.isStringSwitch();
+ if (instruction.isIntSwitch()) {
+ IntSwitch intSwitch = instruction.asIntSwitch();
+ if (intSwitch.getKey(intSwitch.numberOfKeys() - 1) == Integer.MAX_VALUE) {
+ if (intSwitch.numberOfKeys() == 1) {
+ codeRewriter.rewriteSingleKeySwitchToIf(code, block, iterator, intSwitch);
+ } else {
+ IntList newSwitchSequences = new IntArrayList(intSwitch.numberOfKeys() - 1);
+ for (int i = 0; i < intSwitch.numberOfKeys() - 1; i++) {
+ newSwitchSequences.add(intSwitch.getKey(i));
+ }
+ IntList outliers = new IntArrayList(1);
+ outliers.add(Integer.MAX_VALUE);
+ codeRewriter.convertSwitchToSwitchAndIfs(
+ code,
+ blocksIterator,
+ block,
+ iterator,
+ intSwitch,
+ ImmutableList.of(newSwitchSequences),
+ outliers);
+ }
+ needToSplitCriticalEdges = true;
+ }
+ }
+ }
+ }
+
+ // Rewriting of switches introduces new branching structure. It relies on critical edges
+ // being split on the way in but does not maintain this property. We therefore split
+ // critical edges at exit.
+ if (needToSplitCriticalEdges) {
+ code.splitCriticalEdges();
+ }
+ }
+
+ // See comment for InternalOptions.canHaveNumberConversionRegisterAllocationBug().
+ public static void workaroundNumberConversionRegisterAllocationBug(
+ IRCode code, InternalOptions options) {
+ if (!options.canHaveNumberConversionRegisterAllocationBug()) {
+ return;
+ }
+
+ DexItemFactory dexItemFactory = options.dexItemFactory();
+ ListIterator<BasicBlock> blocks = code.listIterator();
+ while (blocks.hasNext()) {
+ BasicBlock block = blocks.next();
+ InstructionListIterator it = block.listIterator(code);
+ while (it.hasNext()) {
+ Instruction instruction = it.next();
+ if (instruction.isArithmeticBinop() || instruction.isNeg()) {
+ for (Value value : instruction.inValues()) {
+ // Insert a call to Double.isNaN on each value which come from a number conversion
+ // to double and flows into an arithmetic instruction. This seems to break the traces
+ // in the Dalvik JIT and avoid the bug where the generated ARM code can clobber float
+ // values in a single-precision registers with double values written to
+ // double-precision registers. See b/77496850 for examples.
+ if (!value.isPhi()
+ && value.definition.isNumberConversion()
+ && value.definition.asNumberConversion().to == NumericType.DOUBLE) {
+ InvokeStatic invokeIsNaN =
+ new InvokeStatic(
+ dexItemFactory.doubleMembers.isNaN, null, ImmutableList.of(value));
+ invokeIsNaN.setPosition(instruction.getPosition());
+
+ // Insert the invoke before the current instruction.
+ it.previous();
+ BasicBlock blockWithInvokeNaN =
+ block.hasCatchHandlers() ? it.split(code, blocks) : block;
+ if (blockWithInvokeNaN != block) {
+ // If we split, add the invoke at the end of the original block.
+ it = block.listIterator(code, block.getInstructions().size());
+ it.previous();
+ it.add(invokeIsNaN);
+ // Continue iteration in the split block.
+ block = blockWithInvokeNaN;
+ it = block.listIterator(code);
+ } else {
+ // Otherwise, add it to the current block.
+ it.add(invokeIsNaN);
+ }
+ // Skip over the instruction causing the invoke to be inserted.
+ Instruction temp = it.next();
+ assert temp == instruction;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private static void ensureInstructionBefore(
+ IRCode code, Instruction addBefore, InstructionListIterator it) {
+ // Force materialize a constant-zero before the long operation.
+ Instruction check = it.previous();
+ assert addBefore == check;
+ // Forced definition of const-zero
+ Value fixitValue = code.createValue(TypeElement.getInt());
+ Instruction fixitDefinition = new AlwaysMaterializingDefinition(fixitValue);
+ fixitDefinition.setBlock(addBefore.getBlock());
+ fixitDefinition.setPosition(addBefore.getPosition());
+ it.add(fixitDefinition);
+ // Forced user of the forced definition to ensure it has a user and thus live range.
+ Instruction fixitUser = new AlwaysMaterializingUser(fixitValue);
+ fixitUser.setBlock(addBefore.getBlock());
+ fixitUser.setPosition(addBefore.getPosition());
+ it.add(fixitUser);
+ }
+
+ private static void ensureThrowingInstructionBefore(
+ IRCode code, Instruction addBefore, InstructionListIterator it, Instruction instruction) {
+ Instruction check = it.previous();
+ assert addBefore == check;
+ BasicBlock block = check.getBlock();
+ if (block.hasCatchHandlers()) {
+ // Split so the existing instructions retain their handlers and the new instruction has none.
+ BasicBlock split = it.split(code);
+ assert split.hasCatchHandlers();
+ assert !block.hasCatchHandlers();
+ it = block.listIterator(code, block.getInstructions().size() - 1);
+ }
+ instruction.setPosition(addBefore.getPosition());
+ it.add(instruction);
+ }
+
+ private static boolean isNotPseudoInstruction(Instruction instruction) {
+ return !(instruction.isDebugInstruction() || instruction.isMove());
+ }
+
+ private static boolean isAliasOf(Value usedValue, Value definingValue) {
+ while (true) {
+ if (usedValue == definingValue) {
+ return true;
+ }
+ Instruction definition = usedValue.definition;
+ if (definition == null || !definition.isMove()) {
+ return false;
+ }
+ usedValue = definition.asMove().src();
+ }
+ }
+
+ private static boolean isLongMul(Instruction instruction) {
+ return instruction != null
+ && instruction.isMul()
+ && instruction.asBinop().getNumericType() == NumericType.LONG
+ && instruction.outValue() != null;
+ }
+
+ private static boolean isLongAddOrSub(Instruction instruction) {
+ return instruction != null
+ && (instruction.isAdd() || instruction.isSub())
+ && instruction.asBinop().getNumericType() == NumericType.LONG;
+ }
+
+ private static boolean isFallthoughTarget(BasicBlock block) {
+ for (BasicBlock pred : block.getPredecessors()) {
+ if (pred.exit().fallthroughBlock() == block) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
index 442cb96..ccbd132 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
@@ -229,7 +229,7 @@
assumeRemover.removeMarkedInstructions();
code.removeAllDeadAndTrivialPhis(affectedValues);
assumeRemover.finish();
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
rootsIterator.remove();
repeat = true;
}
@@ -253,8 +253,7 @@
codeRewriter.simplifyControlFlow(code);
// If a method was inlined we may see more trivial computation/conversion of String.
boolean isDebugMode =
- appView.options().debug
- || method.getDefinition().getOptimizationInfo().isReachabilitySensitive();
+ appView.options().debug || method.getOrComputeReachabilitySensitive(appView);
if (!isDebugMode) {
// Reflection/string optimization 3. trivial conversion/computation on const-string
stringOptimizer.computeTrivialOperationsOnConstString(code);
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 c3c21f1..974bedd 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
@@ -1028,7 +1028,7 @@
// signature of the invocation resolves to a private or static method.
// TODO(b/147212189): Why not inline private methods? If access is permitted it is valid.
MethodResolutionResult resolutionResult =
- appView.appInfo().resolveMethodOnClass(callee, eligibleClass);
+ appView.appInfo().resolveMethodOnClass(eligibleClass, callee);
if (resolutionResult.isSingleResolution()
&& !resolutionResult.getSingleTarget().isNonPrivateVirtualMethod()) {
return false;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/TransferFunction.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/TransferFunction.java
index 4d45a08..65c05e6 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/TransferFunction.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/TransferFunction.java
@@ -247,7 +247,10 @@
}
SingleResolutionResult resolutionResult =
- appView.appInfo().resolveMethodOnClass(invoke.getInvokedMethod()).asSingleResolution();
+ appView
+ .appInfo()
+ .resolveMethodOnClassHolder(invoke.getInvokedMethod())
+ .asSingleResolution();
if (resolutionResult == null) {
return state.abandonClassInliningInCurrentContexts(receiverRoot);
}
@@ -283,7 +286,10 @@
}
SingleResolutionResult resolutionResult =
- appView.appInfo().resolveMethodOnInterface(invoke.getInvokedMethod()).asSingleResolution();
+ appView
+ .appInfo()
+ .resolveMethodOnInterfaceHolder(invoke.getInvokedMethod())
+ .asSingleResolution();
if (resolutionResult == null) {
return state.abandonClassInliningInCurrentContexts(receiverRoot);
}
@@ -322,7 +328,10 @@
}
SingleResolutionResult resolutionResult =
- appView.appInfo().resolveMethodOnClass(invoke.getInvokedMethod()).asSingleResolution();
+ appView
+ .appInfo()
+ .resolveMethodOnClassHolder(invoke.getInvokedMethod())
+ .asSingleResolution();
if (resolutionResult == null) {
return state.abandonClassInliningInCurrentContexts(receiverRoot);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EmptyEnumUnboxer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EmptyEnumUnboxer.java
index 23ae546..bde3a44 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EmptyEnumUnboxer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EmptyEnumUnboxer.java
@@ -13,7 +13,6 @@
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Phi;
import com.android.tools.r8.ir.conversion.IRConverter;
-import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.ir.conversion.MethodProcessor;
import com.android.tools.r8.ir.conversion.PostMethodProcessor.Builder;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackDelayed;
@@ -38,7 +37,7 @@
}
@Override
- public void analyzeEnums(IRCode code, MutableMethodConversionOptions conversionOptions) {
+ public void analyzeEnums(IRCode code, MethodProcessor methodProcessor) {
// Intentionally empty.
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
index ae119f6..659d802 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
@@ -13,7 +13,6 @@
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Phi;
import com.android.tools.r8.ir.conversion.IRConverter;
-import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.ir.conversion.MethodProcessor;
import com.android.tools.r8.ir.conversion.PostMethodProcessor.Builder;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackDelayed;
@@ -35,7 +34,7 @@
public abstract void prepareForPrimaryOptimizationPass(
GraphLens graphLensForPrimaryOptimizationPass);
- public abstract void analyzeEnums(IRCode code, MutableMethodConversionOptions conversionOptions);
+ public abstract void analyzeEnums(IRCode code, MethodProcessor methodProcessor);
public abstract void onMethodPruned(ProgramMethod method);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
index 700c1d7..f455175 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
@@ -75,7 +75,6 @@
import com.android.tools.r8.ir.code.Return;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.conversion.IRConverter;
-import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.ir.conversion.MethodProcessor;
import com.android.tools.r8.ir.conversion.PostMethodProcessor.Builder;
import com.android.tools.r8.ir.desugar.LambdaDescriptor;
@@ -236,7 +235,7 @@
}
@Override
- public void analyzeEnums(IRCode code, MutableMethodConversionOptions conversionOptions) {
+ public void analyzeEnums(IRCode code, MethodProcessor methodProcessor) {
Set<DexType> eligibleEnums = Sets.newIdentityHashSet();
for (BasicBlock block : code.blocks) {
for (Instruction instruction : block.getInstructions()) {
@@ -307,7 +306,8 @@
}
}
if (methodsDependingOnLibraryModelisation.contains(code.context(), appView.graphLens())) {
- conversionOptions.disablePeepholeOptimizations();
+ code.mutateConversionOptions(
+ conversionOptions -> conversionOptions.disablePeepholeOptimizations(methodProcessor));
}
}
@@ -706,6 +706,9 @@
enumUnboxingLens,
enumDataMap,
utilityClasses);
+
+ // Ensure determinism of method-to-reprocess set.
+ appView.testing().checkDeterminism(postMethodProcessorBuilder::dump);
}
private void updateOptimizationInfos(
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
index f223300..bc981ea 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
@@ -120,7 +120,7 @@
if (unboxedEnumsData.isEmpty()) {
return Sets.newIdentityHashSet();
}
- assert code.isConsistentSSABeforeTypesAreCorrect();
+ assert code.isConsistentSSABeforeTypesAreCorrect(appView);
ProgramMethod context = code.context();
Map<Instruction, DexType> convertedEnums = createInitialConvertedEnums(code, prototypeChanges);
Set<Phi> affectedPhis = Sets.newIdentityHashSet();
@@ -351,7 +351,7 @@
}
}
}
- assert code.isConsistentSSABeforeTypesAreCorrect();
+ assert code.isConsistentSSABeforeTypesAreCorrect(appView);
return affectedPhis;
}
@@ -461,7 +461,7 @@
ProgramMethod checkNotZeroMethod =
appView
.appInfo()
- .resolveMethodOnClass(checkNotZeroMethodReference)
+ .resolveMethodOnClassHolder(checkNotZeroMethodReference)
.getResolvedProgramMethod();
if (checkNotZeroMethod != null) {
EnumUnboxerMethodClassification classification =
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java
index 293d93f..0d6fa85 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java
@@ -160,7 +160,7 @@
DexEncodedMethod singleTarget =
appView
.appInfo()
- .resolveMethodOnClass(factory.objectMembers.toString, enumFieldType.getClassType())
+ .resolveMethodOnClass(enumFieldType.getClassType(), factory.objectMembers.toString)
.getSingleTarget();
if (singleTarget != null && singleTarget.getReference() != factory.enumMembers.toString) {
continue;
@@ -175,7 +175,7 @@
if (!affectedValues.isEmpty()) {
new TypeAnalysis(appView).narrowing(affectedValues);
}
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
}
/**
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/code/CheckNotZeroCode.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/code/CheckNotZeroCode.java
index c2cbec9..dd73d7e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/code/CheckNotZeroCode.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/code/CheckNotZeroCode.java
@@ -17,6 +17,7 @@
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.Return;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.ir.optimize.enums.EnumUnboxerImpl;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
@@ -41,7 +42,11 @@
}
@Override
- public IRCode buildIR(ProgramMethod checkNotZeroMethod, AppView<?> appView, Origin origin) {
+ public IRCode buildIR(
+ ProgramMethod checkNotZeroMethod,
+ AppView<?> appView,
+ Origin origin,
+ MutableMethodConversionOptions conversionOptions) {
// Build IR from the checkNotNull() method.
IRCode code = checkNotNullMethod.buildIR(appView);
InstructionListIterator instructionIterator = code.instructionListIterator();
@@ -82,7 +87,8 @@
code.valueNumberGenerator,
code.basicBlockNumberGenerator,
code.metadata(),
- checkNotZeroMethod.getOrigin());
+ checkNotZeroMethod.getOrigin(),
+ conversionOptions);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
index 9faaebc..c9f6819 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
@@ -106,11 +106,6 @@
}
@Override
- public boolean isReachabilitySensitive() {
- return false;
- }
-
- @Override
public boolean returnsArgument() {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java
index ffcad46..c36ee4d 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java
@@ -54,8 +54,6 @@
public abstract boolean hasBeenInlinedIntoSingleCallSite();
- public abstract boolean isReachabilitySensitive();
-
public abstract boolean returnsArgument();
public abstract int getReturnedArgument();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
index 29a843b..8d2e339 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
@@ -965,7 +965,7 @@
MethodResolutionResult resolutionResult =
appView
.appInfo()
- .resolveMethodOnClass(appView.dexItemFactory().objectMembers.finalize, clazz);
+ .resolveMethodOnClass(clazz, appView.dexItemFactory().objectMembers.finalize);
DexEncodedMethod target = resolutionResult.getSingleTarget();
return target != null
&& target.getReference() != dexItemFactory.enumMembers.finalize
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
index b810885..df68f40 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
@@ -88,14 +88,9 @@
private static final int HAS_BEEN_INLINED_INTO_SINGLE_CALL_SITE_FLAG = 0x4;
private static final int MAY_HAVE_SIDE_EFFECT_FLAG = 0x8;
private static final int RETURN_VALUE_ONLY_DEPENDS_ON_ARGUMENTS_FLAG = 0x10;
- private static final int UNUSED_FLAG_1 = 0x20;
- private static final int NEVER_RETURNS_NORMALLY_FLAG = 0x40;
- private static final int UNUSED_FLAG_2 = 0x80;
- private static final int UNUSED_FLAG_3 = 0x100;
- private static final int UNUSED_FLAG_4 = 0x200;
- private static final int INITIALIZER_ENABLING_JAVA_ASSERTIONS_FLAG = 0x400;
- private static final int REACHABILITY_SENSITIVE_FLAG = 0x800;
- private static final int RETURN_VALUE_HAS_BEEN_PROPAGATED_FLAG = 0x1000;
+ private static final int NEVER_RETURNS_NORMALLY_FLAG = 0x20;
+ private static final int INITIALIZER_ENABLING_JAVA_ASSERTIONS_FLAG = 0x80;
+ private static final int RETURN_VALUE_HAS_BEEN_PROPAGATED_FLAG = 0x100;
private static final int DEFAULT_FLAGS;
@@ -114,19 +109,12 @@
defaultFlags |=
BooleanUtils.intValue(defaultOptInfo.returnValueOnlyDependsOnArguments())
* RETURN_VALUE_ONLY_DEPENDS_ON_ARGUMENTS_FLAG;
- defaultFlags |= 0 * UNUSED_FLAG_1;
defaultFlags |=
BooleanUtils.intValue(defaultOptInfo.neverReturnsNormally()) * NEVER_RETURNS_NORMALLY_FLAG;
- defaultFlags |= 0 * UNUSED_FLAG_2;
- defaultFlags |= 0 * UNUSED_FLAG_3;
- defaultFlags |= 0 * UNUSED_FLAG_4;
defaultFlags |=
BooleanUtils.intValue(defaultOptInfo.isInitializerEnablingJavaVmAssertions())
* INITIALIZER_ENABLING_JAVA_ASSERTIONS_FLAG;
defaultFlags |=
- BooleanUtils.intValue(defaultOptInfo.isReachabilitySensitive())
- * REACHABILITY_SENSITIVE_FLAG;
- defaultFlags |=
BooleanUtils.intValue(defaultOptInfo.returnValueHasBeenPropagated())
* RETURN_VALUE_HAS_BEEN_PROPAGATED_FLAG;
DEFAULT_FLAGS = defaultFlags;
@@ -381,11 +369,6 @@
}
@Override
- public boolean isReachabilitySensitive() {
- return isFlagSet(REACHABILITY_SENSITIVE_FLAG);
- }
-
- @Override
public boolean returnsArgument() {
return returnedArgument != -1;
}
@@ -515,14 +498,6 @@
return isFlagSet(RETURN_VALUE_ONLY_DEPENDS_ON_ARGUMENTS_FLAG);
}
- public void setReachabilitySensitive(boolean reachabilitySensitive) {
- setFlag(REACHABILITY_SENSITIVE_FLAG, reachabilitySensitive);
- }
-
- void unsetReachabilitySensitive() {
- clearFlag(REACHABILITY_SENSITIVE_FLAG);
- }
-
void setSimpleInliningConstraint(SimpleInliningConstraint constraint) {
this.simpleInliningConstraint = constraint;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
index 8853607..af6cf62 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
@@ -364,11 +364,6 @@
}
@Override
- public synchronized void unsetReachabilitySensitive(ProgramMethod method) {
- getMethodOptimizationInfoForUpdating(method).unsetReachabilitySensitive();
- }
-
- @Override
public synchronized void unsetReturnedArgument(ProgramMethod method) {
getMethodOptimizationInfoForUpdating(method).unsetReturnedArgument();
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java
index d15bb00..3f46ce1 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java
@@ -176,9 +176,6 @@
public void unsetNonNullParamOrThrow(ProgramMethod method) {}
@Override
- public void unsetReachabilitySensitive(ProgramMethod method) {}
-
- @Override
public void unsetReturnedArgument(ProgramMethod method) {}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
index 5b65a8a..7a6a3ce 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
@@ -305,12 +305,6 @@
}
@Override
- public void unsetReachabilitySensitive(ProgramMethod method) {
- withMutableMethodOptimizationInfo(
- method, MutableMethodOptimizationInfo::unsetReachabilitySensitive);
- }
-
- @Override
public void unsetReturnedArgument(ProgramMethod method) {
withMutableMethodOptimizationInfo(method, MutableMethodOptimizationInfo::unsetReturnedArgument);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/membervaluepropagation/assume/AssumeInfoLookup.java b/src/main/java/com/android/tools/r8/ir/optimize/membervaluepropagation/assume/AssumeInfoLookup.java
index 85fb76a..b28520c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/membervaluepropagation/assume/AssumeInfoLookup.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/membervaluepropagation/assume/AssumeInfoLookup.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.ir.optimize.membervaluepropagation.assume;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClassAndMember;
import com.android.tools.r8.graph.DexClassAndMethod;
@@ -31,10 +32,10 @@
}
public static AssumeInfo lookupAssumeInfo(
- AppView<AppInfoWithLiveness> appView, DexClassAndMember<?, ?> member) {
+ AppView<? extends AppInfoWithClassHierarchy> appView, DexClassAndMember<?, ?> member) {
DexMember<?, ?> reference = member.getReference();
- ProguardMemberRule assumeNoSideEffectsRule = appView.appInfo().noSideEffects.get(reference);
- ProguardMemberRule assumeValuesRule = appView.appInfo().assumedValues.get(reference);
+ ProguardMemberRule assumeNoSideEffectsRule = appView.rootSet().noSideEffects.get(reference);
+ ProguardMemberRule assumeValuesRule = appView.rootSet().assumedValues.get(reference);
if (assumeNoSideEffectsRule == null && assumeValuesRule == null) {
return null;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/string/StringBuilderOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/string/StringBuilderOptimizer.java
index a2ecba8..b851f1e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/string/StringBuilderOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/string/StringBuilderOptimizer.java
@@ -18,7 +18,6 @@
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.BasicBlock.ThrowingInfo;
import com.android.tools.r8.ir.code.ConstNumber;
import com.android.tools.r8.ir.code.ConstString;
import com.android.tools.r8.ir.code.DominatorTree;
@@ -85,7 +84,6 @@
private final AppView<?> appView;
private final DexItemFactory factory;
- private final ThrowingInfo throwingInfo;
@VisibleForTesting
StringConcatenationAnalysis analysis;
final StringBuilderOptimizationConfiguration optimizationConfiguration;
@@ -108,7 +106,6 @@
public StringBuilderOptimizer(AppView<? extends AppInfo> appView) {
this.appView = appView;
this.factory = appView.dexItemFactory();
- this.throwingInfo = ThrowingInfo.defaultForConstString(appView.options());
this.optimizationConfiguration = new DefaultStringBuilderOptimizationConfiguration();
if (Log.ENABLED && Log.isLoggingEnabledFor(StringBuilderOptimizer.class)) {
histogramOfLengthOfAppendChains = new Object2IntArrayMap<>();
@@ -819,7 +816,7 @@
if (!affectedValues.isEmpty()) {
new TypeAnalysis(appView).narrowing(affectedValues);
}
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/typechecks/CheckCastAndInstanceOfMethodSpecialization.java b/src/main/java/com/android/tools/r8/ir/optimize/typechecks/CheckCastAndInstanceOfMethodSpecialization.java
index 8c6a531..93f6242 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/typechecks/CheckCastAndInstanceOfMethodSpecialization.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/typechecks/CheckCastAndInstanceOfMethodSpecialization.java
@@ -133,7 +133,7 @@
if (abstractParentReturnValue == abstractReturnValue) {
// The parent method is already guaranteed to return the same value.
} else if (isClassAccessible(method.getHolder(), parentMethod, appView).isTrue()) {
- parentMethodDefinition.setCode(
+ parentMethod.setCode(
parentMethodDefinition.buildInstanceOfCode(
method.getHolderType(), abstractParentReturnValue.isTrue(), appView.options()),
appView);
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 827f316..af1ed03 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
@@ -207,7 +207,7 @@
public void allocateRegisters() {
// There are no linked values prior to register allocation.
assert noLinkedValues();
- assert code.isConsistentSSA();
+ assert code.isConsistentSSA(appView);
if (this.code.method().accessFlags.isBridge() && implementationIsBridge(this.code)) {
transformBridgeMethod();
}
@@ -216,7 +216,7 @@
insertRangeInvokeMoves();
ImmutableList<BasicBlock> blocks = computeLivenessInformation();
performAllocation();
- assert code.isConsistentGraph();
+ assert code.isConsistentGraph(appView);
if (Log.ENABLED) {
Log.debug(this.getClass(), toString());
}
@@ -227,7 +227,7 @@
// and we do not actually want locals information in the output.
if (options().debug) {
computeDebugInfo(code, blocks, liveIntervals, this, liveAtEntrySets);
- } else if (code.method().getOptimizationInfo().isReachabilitySensitive()) {
+ } else if (code.context().getOrComputeReachabilitySensitive(appView)) {
InstructionListIterator it = code.instructionListIterator();
while (it.hasNext()) {
Instruction instruction = it.next();
@@ -1642,7 +1642,7 @@
// Set all free positions for possible registers to max integer.
RegisterPositions freePositions = new RegisterPositionsImpl(registerConstraint + 1);
- if ((options().debug || code.method().getOptimizationInfo().isReachabilitySensitive())
+ if ((options().debug || code.context().getOrComputeReachabilitySensitive(appView))
&& !code.method().accessFlags.isStatic()) {
// If we are generating debug information or if the method is reachability sensitive,
// we pin the this value register. The debugger expects to always be able to find it in
@@ -2508,11 +2508,7 @@
}
private static void addLiveRange(
- Value value,
- BasicBlock block,
- int end,
- List<LiveIntervals> liveIntervals,
- InternalOptions options) {
+ Value value, BasicBlock block, int end, List<LiveIntervals> liveIntervals, IRCode code) {
int firstInstructionInBlock = block.entry().getNumber();
int instructionsSize = block.getInstructions().size() * INSTRUCTION_NUMBER_DELTA;
int lastInstructionInBlock =
@@ -2548,8 +2544,8 @@
instructionNumber--;
}
intervals.addRange(new LiveRange(instructionNumber, end));
- assert unconstrainedForCf(intervals.getRegisterLimit(), options);
- if (options.isGeneratingDex() && !value.isPhi()) {
+ assert unconstrainedForCf(intervals.getRegisterLimit(), code);
+ if (code.getConversionOptions().isGeneratingDex() && !value.isPhi()) {
int constraint = value.definition.maxOutValueRegister();
intervals.addUse(new LiveIntervalsUse(instructionNumber, constraint));
}
@@ -2559,7 +2555,7 @@
}
private void computeLiveRanges() {
- computeLiveRanges(options(), code, liveAtEntrySets, liveIntervals);
+ computeLiveRanges(appView, code, liveAtEntrySets, liveIntervals);
// Art VMs before Android M assume that the register for the receiver never changes its value.
// This assumption is used during verification. Allowing the receiver register to be
// overwritten can therefore lead to verification errors. If we could be targeting one of these
@@ -2583,7 +2579,7 @@
/** Compute live ranges based on liveAtEntry sets for all basic blocks. */
public static void computeLiveRanges(
- InternalOptions options,
+ AppView<?> appView,
IRCode code,
Map<BasicBlock, LiveAtEntrySets> liveAtEntrySets,
List<LiveIntervals> liveIntervals) {
@@ -2622,7 +2618,7 @@
if (phiOperands.contains(value)) {
end--;
}
- addLiveRange(value, block, end, liveIntervals, options);
+ addLiveRange(value, block, end, liveIntervals, code);
}
InstructionIterator iterator = block.iterator(block.getInstructions().size());
while (iterator.hasPrevious()) {
@@ -2642,20 +2638,20 @@
block,
instruction.getNumber() + INSTRUCTION_NUMBER_DELTA - 1,
liveIntervals,
- options);
- assert !options.isGeneratingClassFiles() || instruction.isArgument()
+ code);
+ assert !code.getConversionOptions().isGeneratingClassFiles() || instruction.isArgument()
: "Arguments should be the only potentially unused local in CF";
}
live.remove(definition);
}
for (Value use : instruction.inValues()) {
if (use.needsRegister()) {
- assert unconstrainedForCf(instruction.maxInValueRegister(), options);
+ assert unconstrainedForCf(instruction.maxInValueRegister(), code);
if (!live.contains(use)) {
live.add(use);
- addLiveRange(use, block, instruction.getNumber(), liveIntervals, options);
+ addLiveRange(use, block, instruction.getNumber(), liveIntervals, code);
}
- if (options.isGeneratingDex()) {
+ if (code.getConversionOptions().isGeneratingDex()) {
int inConstraint = instruction.maxInValueRegister();
LiveIntervals useIntervals = use.getLiveIntervals();
// Arguments are always kept in their original, incoming register. For every
@@ -2693,11 +2689,11 @@
block,
getLiveRangeEndOnExceptionalFlow(instruction, use),
liveIntervals,
- options);
+ code);
}
}
}
- if (options.debug || code.method().getOptimizationInfo().isReachabilitySensitive()) {
+ if (appView.options().debug || code.context().getOrComputeReachabilitySensitive(appView)) {
// In debug mode, or if the method is reachability sensitive, extend the live range
// to cover the full scope of a local variable (encoded as debug values).
int number = instruction.getNumber();
@@ -2707,7 +2703,7 @@
assert use.needsRegister();
if (!live.contains(use)) {
live.add(use);
- addLiveRange(use, block, number, liveIntervals, options);
+ addLiveRange(use, block, number, liveIntervals, code);
}
}
}
@@ -2723,8 +2719,8 @@
return end;
}
- private static boolean unconstrainedForCf(int constraint, InternalOptions options) {
- return !options.isGeneratingClassFiles() || constraint == Constants.U16BIT_MAX;
+ private static boolean unconstrainedForCf(int constraint, IRCode code) {
+ return code.getConversionOptions().isGeneratingDex() || constraint == Constants.U16BIT_MAX;
}
private void clearUserInfo() {
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java
index acf4d56..8c28b9e 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java
@@ -18,6 +18,8 @@
import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.ThrowingMethodConversionOptions;
import com.android.tools.r8.ir.conversion.SourceCode;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
@@ -39,9 +41,13 @@
}
@Override
- public final IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
+ public final IRCode buildIR(
+ ProgramMethod method,
+ AppView<?> appView,
+ Origin origin,
+ MutableMethodConversionOptions conversionOptions) {
return IRBuilder.create(method, appView, getSourceCodeProvider().get(method, null), origin)
- .build(method);
+ .build(method, conversionOptions);
}
@Override
@@ -62,7 +68,7 @@
origin,
valueNumberGenerator,
protoChanges)
- .build(context);
+ .build(context, new ThrowingMethodConversionOptions(appView.options()));
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java
index 5ef065a..6427f75 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java
@@ -54,9 +54,14 @@
assert returnType == appView.dexItemFactory().stringType;
instructions.add(new CfConstString(value.asSingleStringValue().getDexString()));
} else if (value.isSingleNumberValue()) {
- instructions.add(
- new CfConstNumber(
- value.asSingleNumberValue().getValue(), ValueType.fromDexType(returnType)));
+ if (returnType.isReferenceType()) {
+ assert value.isNull();
+ instructions.add(new CfConstNull());
+ } else {
+ instructions.add(
+ new CfConstNumber(
+ value.asSingleNumberValue().getValue(), ValueType.fromDexType(returnType)));
+ }
} else {
throw new Unreachable("Only Number and String fields in enums are supported.");
}
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 1332bf7..7f8d075 100644
--- a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
@@ -48,6 +48,7 @@
import com.android.tools.r8.utils.AsmUtils;
import com.android.tools.r8.utils.ComparatorUtils;
import com.android.tools.r8.utils.ExceptionUtils;
+import com.android.tools.r8.utils.InternalGlobalSyntheticsProgramConsumer.InternalGlobalSyntheticsCfConsumer;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.OriginalSourceFiles;
import com.android.tools.r8.utils.PredicateUtils;
@@ -57,6 +58,7 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
@@ -149,36 +151,67 @@
sourceFileEnvironment = ApplicationWriter.createSourceFileEnvironment(proguardMapId);
}
LensCodeRewriterUtils rewriter = new LensCodeRewriterUtils(appView);
- for (DexProgramClass clazz : application.classes()) {
- assert SyntheticNaming.verifyNotInternalSynthetic(clazz.getType());
- try {
- writeClass(clazz, consumer, rewriter, markerString, sourceFileEnvironment);
- } catch (ClassTooLargeException e) {
- throw appView
- .options()
- .reporter
- .fatalError(
- new ConstantPoolOverflowDiagnostic(
- clazz.getOrigin(),
- Reference.classFromBinaryName(e.getClassName()),
- e.getConstantPoolCount()));
- } catch (MethodTooLargeException e) {
- throw appView
- .options()
- .reporter
- .fatalError(
- new CodeSizeOverflowDiagnostic(
- clazz.getOrigin(),
- Reference.methodFromDescriptor(
- Reference.classFromBinaryName(e.getClassName()).getDescriptor(),
- e.getMethodName(),
- e.getDescriptor()),
- e.getCodeSize()));
+ Collection<DexProgramClass> classes = application.classes();
+ Collection<DexProgramClass> globalSyntheticClasses = new ArrayList<>();
+ if (options.intermediate && options.hasGlobalSyntheticsConsumer()) {
+ Collection<DexProgramClass> allClasses = classes;
+ classes = new ArrayList<>(allClasses.size());
+ for (DexProgramClass clazz : allClasses) {
+ if (appView.getSyntheticItems().isGlobalSyntheticClass(clazz)) {
+ globalSyntheticClasses.add(clazz);
+ } else {
+ classes.add(clazz);
+ }
}
}
+ for (DexProgramClass clazz : classes) {
+ writeClassCatchingErrors(clazz, consumer, rewriter, markerString, sourceFileEnvironment);
+ }
+ if (!globalSyntheticClasses.isEmpty()) {
+ InternalGlobalSyntheticsCfConsumer globalsConsumer =
+ new InternalGlobalSyntheticsCfConsumer(options.getGlobalSyntheticsConsumer());
+ for (DexProgramClass clazz : globalSyntheticClasses) {
+ writeClassCatchingErrors(
+ clazz, globalsConsumer, rewriter, markerString, sourceFileEnvironment);
+ }
+ globalsConsumer.finished(options.reporter);
+ }
ApplicationWriter.supplyAdditionalConsumers(application, appView, namingLens, options);
}
+ private void writeClassCatchingErrors(
+ DexProgramClass clazz,
+ ClassFileConsumer consumer,
+ LensCodeRewriterUtils rewriter,
+ Optional<String> markerString,
+ SourceFileEnvironment sourceFileEnvironment) {
+ assert SyntheticNaming.verifyNotInternalSynthetic(clazz.getType());
+ try {
+ writeClass(clazz, consumer, rewriter, markerString, sourceFileEnvironment);
+ } catch (ClassTooLargeException e) {
+ throw appView
+ .options()
+ .reporter
+ .fatalError(
+ new ConstantPoolOverflowDiagnostic(
+ clazz.getOrigin(),
+ Reference.classFromBinaryName(e.getClassName()),
+ e.getConstantPoolCount()));
+ } catch (MethodTooLargeException e) {
+ throw appView
+ .options()
+ .reporter
+ .fatalError(
+ new CodeSizeOverflowDiagnostic(
+ clazz.getOrigin(),
+ Reference.methodFromDescriptor(
+ Reference.classFromBinaryName(e.getClassName()).getDescriptor(),
+ e.getMethodName(),
+ e.getDescriptor()),
+ e.getCodeSize()));
+ }
+ }
+
private void writeClass(
DexProgramClass clazz,
ClassFileConsumer consumer,
@@ -594,6 +627,7 @@
MethodVisitor visitor) {
Code code = method.getDefinition().getCode();
assert code.isCfWritableCode();
+ assert code.estimatedDexCodeSizeUpperBoundInBytes() > 0;
code.asCfWritableCode()
.writeCf(method, classFileVersion, appView, namingLens, rewriter, visitor);
}
diff --git a/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java b/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java
index bc285b7..e50737d 100644
--- a/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java
+++ b/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java
@@ -38,6 +38,14 @@
this.contextBuilder = contextBuilder;
}
+ public void runForD8(Iterable<? extends DexProgramClass> classes, ExecutorService executorService)
+ throws ExecutionException {
+ if (namingLens.isIdentityLens()) {
+ return;
+ }
+ run(classes, executorService);
+ }
+
public void run(Iterable<? extends DexProgramClass> classes, ExecutorService executorService)
throws ExecutionException {
// Rewrite signature annotations for applications that are minified or if we have liveness
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
index b933b4d..e13e860 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
@@ -116,7 +116,7 @@
currentResolutionResult =
appView
.appInfo()
- .resolveMethodOnClass(original, currentResolvedHolder.getSuperType())
+ .resolveMethodOnClass(currentResolvedHolder.getSuperType(), original)
.asSingleResolution();
} else {
break;
@@ -244,7 +244,7 @@
}
private MethodResolutionResult resolveMethodOnClass(DexMethod method) {
- return appView.appInfo().resolveMethodOnClass(method, method.holder);
+ return appView.appInfo().resolveMethodOnClass(method.holder, method);
}
private MethodResolutionResult resolveMethodOnInterface(DexMethod method) {
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
index b7dd7ff..00be161 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
@@ -195,6 +195,9 @@
.fixupApplication(affectedClasses, executorService, timing);
timing.end();
+
+ // Ensure determinism of method-to-reprocess set.
+ appView.testing().checkDeterminism(postMethodProcessorBuilder::dump);
}
/**
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InterfaceMethodArgumentPropagator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InterfaceMethodArgumentPropagator.java
index b9d6fda..b41cdda 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InterfaceMethodArgumentPropagator.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InterfaceMethodArgumentPropagator.java
@@ -131,7 +131,7 @@
interfaceState.forEach(
(interfaceMethod, interfaceMethodState) -> {
MethodResolutionResult resolutionResult =
- appView.appInfo().resolveMethodOnClass(interfaceMethod, subclass);
+ appView.appInfo().resolveMethodOnClass(subclass, interfaceMethod);
if (resolutionResult.isFailedResolution()) {
// TODO(b/190154391): Do we need to propagate argument information to the first
// virtual method above the inaccessible method in the class hierarchy?
@@ -146,8 +146,7 @@
}
ProgramMethod resolvedMethod = resolutionResult.getResolvedProgramMethod();
- if (resolvedMethod == null
- || resolvedMethod.getHolder() == subclass) {
+ if (resolvedMethod == null || resolvedMethod.getHolder() == subclass) {
return;
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/VirtualDispatchMethodArgumentPropagator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/VirtualDispatchMethodArgumentPropagator.java
index 085d4a0..787ae13 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/VirtualDispatchMethodArgumentPropagator.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/VirtualDispatchMethodArgumentPropagator.java
@@ -112,7 +112,7 @@
appView
.appInfo()
.resolveMethodOnClass(
- signature, resolutionResult.getResolvedHolder().getSuperType())
+ resolutionResult.getResolvedHolder().getSuperType(), signature)
.asSingleResolution();
}
diff --git a/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java b/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java
index 5550d52..1bd92a3 100644
--- a/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java
+++ b/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java
@@ -166,7 +166,7 @@
DexEncodedMethod definition = subclass.lookupVirtualMethod(method);
if (definition == null) {
DexEncodedMethod resolutionTarget =
- appView.appInfo().resolveMethodOnClass(method, subclass).getSingleTarget();
+ appView.appInfo().resolveMethodOnClass(subclass, method).getSingleTarget();
if (resolutionTarget == null || resolutionTarget.isAbstract()) {
// The fact that this class does not declare the bridge (or the bridge is abstract) should
// not prevent us from hoisting the bridge.
@@ -228,14 +228,13 @@
// The targeted method must be present on the new holder class for this to be feasible.
MethodResolutionResult resolutionResult =
- appView.appInfo().resolveMethodOnClass(methodToInvoke, clazz);
+ appView.appInfo().resolveMethodOnClass(clazz, methodToInvoke);
if (!resolutionResult.isSingleResolution()) {
return;
}
// Now update the code of the bridge method chosen as representative.
representative
- .getDefinition()
.setCode(createCodeForVirtualBridge(representative, methodToInvoke), appView);
feedback.setBridgeInfo(representative.getDefinition(), new VirtualBridgeInfo(methodToInvoke));
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/collection/OpenClosedInterfacesCollection.java b/src/main/java/com/android/tools/r8/optimize/interfaces/collection/OpenClosedInterfacesCollection.java
index 5b009ba..755c319 100644
--- a/src/main/java/com/android/tools/r8/optimize/interfaces/collection/OpenClosedInterfacesCollection.java
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/collection/OpenClosedInterfacesCollection.java
@@ -76,6 +76,9 @@
return false;
}
TypeElement dynamicUpperBoundType = dynamicType.getDynamicUpperBoundType(staticType);
+ if (dynamicUpperBoundType.isArrayType()) {
+ return dynamicUpperBoundType.lessThanOrEqualUpToNullability(staticType, appView);
+ }
if (!dynamicUpperBoundType.isClassType()) {
// Should not happen, since the dynamic type should be assignable to the static type.
assert false;
diff --git a/src/main/java/com/android/tools/r8/optimize/proto/ProtoNormalizer.java b/src/main/java/com/android/tools/r8/optimize/proto/ProtoNormalizer.java
index 0213d86..a3f2d38 100644
--- a/src/main/java/com/android/tools/r8/optimize/proto/ProtoNormalizer.java
+++ b/src/main/java/com/android/tools/r8/optimize/proto/ProtoNormalizer.java
@@ -122,11 +122,42 @@
// Tracks the set of unoptimizable method signatures. These must remain as-is.
DexMethodSignatureSet unoptimizableSignatures = DexMethodSignatureSet.createConcurrent();
- ThreadUtils.processMethods(
- appView,
- method ->
- computeReservationsFromMethod(
- method, optimizableParameterLists, reservedParameterLists, unoptimizableSignatures),
+ ThreadUtils.processItems(
+ appView.appInfo().classes(),
+ clazz -> {
+ Map<DexMethodSignature, DexMethodSignatureSet> collisions = new HashMap<>();
+ clazz.forEachProgramMethod(
+ method -> {
+ DexTypeList methodParametersSorted = method.getParameters().getSorted();
+ computeReservationsFromMethod(
+ method,
+ methodParametersSorted,
+ optimizableParameterLists,
+ reservedParameterLists,
+ unoptimizableSignatures);
+
+ DexMethodSignature methodSignature = method.getMethodSignature();
+ DexMethodSignature methodSignatureWithSortedParameters =
+ methodSignature.withParameters(methodParametersSorted, dexItemFactory);
+ collisions
+ .computeIfAbsent(
+ methodSignatureWithSortedParameters,
+ ignoreKey(DexMethodSignatureSet::createLinked))
+ .add(methodSignature);
+ });
+ collisions.forEach(
+ (methodSignatureWithSortedParameters, methodSignatures) -> {
+ if (methodSignatures.size() > 1) {
+ methodSignatures.forEach(
+ methodSignature ->
+ addUnoptimizableMethod(
+ methodSignature,
+ methodSignatureWithSortedParameters.getParameters(),
+ reservedParameterLists,
+ unoptimizableSignatures));
+ }
+ });
+ },
executorService);
// Reserve parameter lists that won't lead to any sharing after normalization. Any method with
@@ -164,28 +195,39 @@
private void computeReservationsFromMethod(
ProgramMethod method,
+ DexTypeList methodParametersSorted,
Map<DexTypeList, Set<DexTypeList>> optimizableParameterLists,
Map<DexTypeList, Set<DexTypeList>> reservedParameterLists,
DexMethodSignatureSet unoptimizableSignatures) {
if (isUnoptimizable(method)) {
- // Record that other optimizable methods with the same set of parameter types should be
- // rewritten to have the same parameter list as this method.
- reservedParameterLists
- .computeIfAbsent(
- method.getParameters().getSorted(), ignoreKey(Sets::newConcurrentHashSet))
- .add(method.getParameters());
-
- // Mark signature as unoptimizable.
- unoptimizableSignatures.add(method);
+ addUnoptimizableMethod(
+ method.getMethodSignature(),
+ methodParametersSorted,
+ reservedParameterLists,
+ unoptimizableSignatures);
} else {
// Record that the method's parameter list can be rewritten into any permutation.
optimizableParameterLists
- .computeIfAbsent(
- method.getParameters().getSorted(), ignoreKey(Sets::newConcurrentHashSet))
+ .computeIfAbsent(methodParametersSorted, ignoreKey(Sets::newConcurrentHashSet))
.add(method.getParameters());
}
}
+ private void addUnoptimizableMethod(
+ DexMethodSignature method,
+ DexTypeList methodParametersSorted,
+ Map<DexTypeList, Set<DexTypeList>> reservedParameterLists,
+ DexMethodSignatureSet unoptimizableSignatures) {
+ // Record that other optimizable methods with the same set of parameter types should be
+ // rewritten to have the same parameter list as this method.
+ reservedParameterLists
+ .computeIfAbsent(methodParametersSorted, ignoreKey(Sets::newConcurrentHashSet))
+ .add(method.getParameters());
+
+ // Mark signature as unoptimizable.
+ unoptimizableSignatures.add(method);
+ }
+
private void computeExtraReservationsFromMethod(
ProgramMethod method,
Set<DexTypeList> unoptimizableParameterLists,
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/StackTraceRegularExpressionParser.java b/src/main/java/com/android/tools/r8/retrace/internal/StackTraceRegularExpressionParser.java
index 7877902..ff09bd7 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/StackTraceRegularExpressionParser.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/StackTraceRegularExpressionParser.java
@@ -275,9 +275,9 @@
private static class SourceFileGroup extends RegularExpressionGroup {
static String subExpressionInternal() {
- String anyNonDigitNonColonChar = "^\\d:";
+ String anyNonDigitNonColonNonWhitespaceChar = "^\\d:\\s";
String anyNonColonChar = "^:";
- String colonWithNonDigitSuffix = ":+[" + anyNonDigitNonColonChar + "]";
+ String colonWithNonDigitSuffix = ":+[" + anyNonDigitNonColonNonWhitespaceChar + "]";
return "((?:(?:(?:" + colonWithNonDigitSuffix + "))|(?:[" + anyNonColonChar + "]))+)?";
}
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index 7081da1..8b8e13b 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -1554,45 +1554,6 @@
public SubtypingInfo computeSubtypingInfo() {
return SubtypingInfo.create(this);
}
-
- public boolean mayHaveFinalizeMethodDirectlyOrIndirectly(ClassTypeElement type) {
- // Special case for java.lang.Object.
- if (type.getClassType() == dexItemFactory().objectType) {
- if (type.getInterfaces().isEmpty()) {
- // The type java.lang.Object could be any instantiated type. Assume a finalizer exists.
- return true;
- }
- return type.getInterfaces().anyMatch((iface, isKnown) -> mayHaveFinalizer(iface));
- }
- return mayHaveFinalizer(type.getClassType());
- }
-
- private boolean mayHaveFinalizer(DexType type) {
- // A type may have an active finalizer if any derived instance has a finalizer.
- return objectAllocationInfoCollection
- .traverseInstantiatedSubtypes(
- type,
- clazz -> {
- if (objectAllocationInfoCollection.isInterfaceWithUnknownSubtypeHierarchy(clazz)) {
- return TraversalContinuation.doBreak();
- } else {
- SingleResolutionResult resolution =
- resolveMethodOn(clazz, dexItemFactory().objectMembers.finalize)
- .asSingleResolution();
- if (resolution != null && resolution.getResolvedHolder().isProgramClass()) {
- return TraversalContinuation.doBreak();
- }
- }
- return TraversalContinuation.doContinue();
- },
- lambda -> {
- // Lambda classes do not have finalizers.
- return TraversalContinuation.doContinue();
- },
- this)
- .shouldBreak();
- }
-
/** Predicate on types that *must* never be merged horizontally. */
public boolean isNoHorizontalClassMergingOfType(DexType type) {
return noClassMerging.contains(type) || noHorizontalClassMerging.contains(type);
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 c3950c4..c7917ce 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -124,6 +124,10 @@
import com.android.tools.r8.shaking.EnqueuerEvent.LiveClassEnqueuerEvent;
import com.android.tools.r8.shaking.EnqueuerEvent.UnconditionalKeepInfoEvent;
import com.android.tools.r8.shaking.EnqueuerWorklist.EnqueuerAction;
+import com.android.tools.r8.shaking.EnqueuerWorklist.TraceInstanceFieldReadAction;
+import com.android.tools.r8.shaking.EnqueuerWorklist.TraceInstanceFieldWriteAction;
+import com.android.tools.r8.shaking.EnqueuerWorklist.TraceStaticFieldReadAction;
+import com.android.tools.r8.shaking.EnqueuerWorklist.TraceStaticFieldWriteAction;
import com.android.tools.r8.shaking.GraphReporter.KeepReasonWitness;
import com.android.tools.r8.shaking.KeepInfoCollection.MutableKeepInfoCollection;
import com.android.tools.r8.shaking.RootSetUtils.ConsequentRootSet;
@@ -461,7 +465,7 @@
InternalOptions options = appView.options();
this.appInfo = appView.appInfo();
this.appView = appView.withClassHierarchy();
- this.deferredTracing = new EnqueuerDeferredTracing();
+ this.deferredTracing = new EnqueuerDeferredTracing(appView, this, mode);
this.executorService = executorService;
this.subtypingInfo = subtypingInfo;
this.forceProguardCompatibility = options.forceProguardCompatibility;
@@ -684,6 +688,10 @@
return clazz;
}
+ public FieldAccessInfoCollectionImpl getFieldAccessInfoCollection() {
+ return fieldAccessInfoCollection;
+ }
+
public MutableKeepInfoCollection getKeepInfo() {
return keepInfo;
}
@@ -692,6 +700,18 @@
return keepInfo.getClassInfo(clazz);
}
+ public KeepFieldInfo getKeepInfo(ProgramField field) {
+ return keepInfo.getFieldInfo(field);
+ }
+
+ public ObjectAllocationInfoCollectionImpl getObjectAllocationInfoCollection() {
+ return objectAllocationInfoCollection;
+ }
+
+ public EnqueuerWorklist getWorklist() {
+ return workList;
+ }
+
private void addLiveNonProgramType(
ClasspathOrLibraryClass clazz,
// TODO(b/216576191): Remove when tracking live library members.
@@ -954,22 +974,39 @@
return registerFieldAccess(field, context, true, false);
}
- public boolean registerReflectiveFieldRead(DexField field, ProgramMethod context) {
- return registerFieldAccess(field, context, true, true);
+ public boolean registerReflectiveFieldRead(ProgramField field, ProgramMethod context) {
+ return registerFieldAccess(field.getReference(), context, true, true);
}
public boolean registerFieldWrite(DexField field, ProgramMethod context) {
return registerFieldAccess(field, context, false, false);
}
- public boolean registerReflectiveFieldWrite(DexField field, ProgramMethod context) {
- return registerFieldAccess(field, context, false, true);
+ public boolean registerReflectiveFieldWrite(ProgramField field, ProgramMethod context) {
+ return registerFieldAccess(field.getReference(), context, false, true);
}
- public boolean registerReflectiveFieldAccess(DexField field, ProgramMethod context) {
- boolean changed = registerFieldAccess(field, context, true, true);
- changed |= registerFieldAccess(field, context, false, true);
- return changed;
+ public void traceReflectiveFieldAccess(ProgramField field, ProgramMethod context) {
+ deferredTracing.notifyReflectiveFieldAccess(field, context);
+ boolean changed = registerReflectiveFieldRead(field, context);
+ changed |= registerReflectiveFieldWrite(field, context);
+ if (changed) {
+ markFieldAsReachable(field, context, KeepReason.reflectiveUseIn(context));
+ }
+ }
+
+ public void traceReflectiveFieldRead(ProgramField field, ProgramMethod context) {
+ deferredTracing.notifyReflectiveFieldAccess(field, context);
+ if (registerReflectiveFieldRead(field, context)) {
+ markFieldAsReachable(field, context, KeepReason.reflectiveUseIn(context));
+ }
+ }
+
+ public void traceReflectiveFieldWrite(ProgramField field, ProgramMethod context) {
+ deferredTracing.notifyReflectiveFieldAccess(field, context);
+ if (registerReflectiveFieldWrite(field, context)) {
+ markFieldAsReachable(field, context, KeepReason.reflectiveUseIn(context));
+ }
}
private boolean registerFieldAccess(
@@ -1003,7 +1040,18 @@
return false;
}
if (isReflective) {
- info.setHasReflectiveAccess();
+ if (isRead) {
+ if (!info.hasReflectiveRead()) {
+ info.setHasReflectiveRead();
+ return true;
+ }
+ } else {
+ if (!info.hasReflectiveWrite()) {
+ info.setHasReflectiveWrite();
+ return true;
+ }
+ }
+ return false;
}
return isRead ? info.recordRead(field, context) : info.recordWrite(field, context);
}
@@ -1188,7 +1236,7 @@
initClassReferences.put(
type, computeMinimumRequiredVisibilityForInitClassField(type, currentMethod.getHolder()));
- markTypeAsLive(type, currentMethod);
+ markTypeAsLive(clazz, currentMethod);
markDirectAndIndirectClassInitializersAsLive(clazz);
return;
}
@@ -1487,12 +1535,29 @@
boolean isWrite() {
return !isRead();
}
+
+ EnqueuerAction toEnqueuerAction(
+ DexField fieldReference, ProgramMethod context, FieldAccessMetadata metadata) {
+ switch (this) {
+ case INSTANCE_READ:
+ return new TraceInstanceFieldReadAction(fieldReference, context, metadata);
+ case INSTANCE_WRITE:
+ return new TraceInstanceFieldWriteAction(fieldReference, context, metadata);
+ case STATIC_READ:
+ return new TraceStaticFieldReadAction(fieldReference, context, metadata);
+ case STATIC_WRITE:
+ return new TraceStaticFieldWriteAction(fieldReference, context, metadata);
+ default:
+ throw new Unreachable();
+ }
+ }
}
static class FieldAccessMetadata {
- private static int FROM_METHOD_HANDLE_MASK = 1;
- private static int FROM_RECORD_METHOD_HANDLE_MASK = 2;
+ private static int DEFERRED_MASK = 1;
+ private static int FROM_METHOD_HANDLE_MASK = 2;
+ private static int FROM_RECORD_METHOD_HANDLE_MASK = 4;
static FieldAccessMetadata DEFAULT = new FieldAccessMetadata(0);
static FieldAccessMetadata FROM_METHOD_HANDLE =
@@ -1500,10 +1565,16 @@
static FieldAccessMetadata FROM_RECORD_METHOD_HANDLE =
new FieldAccessMetadata(FROM_RECORD_METHOD_HANDLE_MASK);
+ private final FieldAccessMetadata deferred;
private final int flags;
- FieldAccessMetadata(int flags) {
+ private FieldAccessMetadata(int flags) {
this.flags = flags;
+ this.deferred = isDeferred() ? this : new FieldAccessMetadata(flags | DEFERRED_MASK);
+ }
+
+ boolean isDeferred() {
+ return (flags & DEFERRED_MASK) != 0;
}
boolean isFromMethodHandle() {
@@ -1513,17 +1584,39 @@
boolean isFromRecordMethodHandle() {
return (flags & FROM_RECORD_METHOD_HANDLE_MASK) != 0;
}
+
+ public FieldAccessMetadata toDeferred() {
+ return deferred;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ FieldAccessMetadata metadata = (FieldAccessMetadata) obj;
+ return flags == metadata.flags;
+ }
+
+ @Override
+ public int hashCode() {
+ return flags;
+ }
}
- private void traceInstanceFieldRead(
+ void traceInstanceFieldRead(
DexField fieldReference, ProgramMethod currentMethod, FieldAccessMetadata metadata) {
- if (!registerFieldRead(fieldReference, currentMethod)) {
+ if (!metadata.isDeferred() && !registerFieldRead(fieldReference, currentMethod)) {
return;
}
FieldResolutionResult resolutionResult = resolveField(fieldReference, currentMethod);
if (deferredTracing.deferTracingOfFieldAccess(
fieldReference, resolutionResult, currentMethod, FieldAccessKind.INSTANCE_READ, metadata)) {
+ assert !metadata.isDeferred();
return;
}
@@ -1579,9 +1672,9 @@
traceInstanceFieldWrite(field, currentMethod, FieldAccessMetadata.FROM_METHOD_HANDLE);
}
- private void traceInstanceFieldWrite(
+ void traceInstanceFieldWrite(
DexField fieldReference, ProgramMethod currentMethod, FieldAccessMetadata metadata) {
- if (!registerFieldWrite(fieldReference, currentMethod)) {
+ if (!metadata.isDeferred() && !registerFieldWrite(fieldReference, currentMethod)) {
return;
}
@@ -1592,6 +1685,7 @@
currentMethod,
FieldAccessKind.INSTANCE_WRITE,
metadata)) {
+ assert !metadata.isDeferred();
return;
}
@@ -1645,15 +1739,31 @@
traceStaticFieldRead(field, currentMethod, FieldAccessMetadata.FROM_METHOD_HANDLE);
}
- private void traceStaticFieldRead(
+ void traceStaticFieldRead(
DexField fieldReference, ProgramMethod currentMethod, FieldAccessMetadata metadata) {
- if (!registerFieldRead(fieldReference, currentMethod)) {
+ if (!metadata.isDeferred() && !registerFieldRead(fieldReference, currentMethod)) {
return;
}
FieldResolutionResult resolutionResult = resolveField(fieldReference, currentMethod);
+
+ if (appView.options().protoShrinking().enableGeneratedExtensionRegistryShrinking) {
+ // If it is a dead proto extension field, don't trace onwards.
+ boolean skipTracing =
+ appView.withGeneratedExtensionRegistryShrinker(
+ shrinker ->
+ shrinker.isDeadProtoExtensionField(
+ resolutionResult, fieldAccessInfoCollection, keepInfo),
+ false);
+ if (skipTracing) {
+ addDeadProtoTypeCandidate(resolutionResult.getSingleProgramField().getHolder());
+ return;
+ }
+ }
+
if (deferredTracing.deferTracingOfFieldAccess(
fieldReference, resolutionResult, currentMethod, FieldAccessKind.STATIC_READ, metadata)) {
+ assert !metadata.isDeferred();
return;
}
@@ -1684,18 +1794,6 @@
Log.verbose(getClass(), "Register Sget `%s`.", fieldReference);
}
- // If it is a dead proto extension field, don't trace onwards.
- boolean skipTracing =
- appView.withGeneratedExtensionRegistryShrinker(
- shrinker ->
- shrinker.isDeadProtoExtensionField(
- field, fieldAccessInfoCollection, keepInfo),
- false);
- if (skipTracing) {
- addDeadProtoTypeCandidate(field.getHolder());
- return;
- }
-
if (field.getReference() != fieldReference) {
// Mark the initial resolution holder as live. Note that this should only be done if
// the field
@@ -1725,15 +1823,31 @@
traceStaticFieldWrite(field, currentMethod, FieldAccessMetadata.FROM_METHOD_HANDLE);
}
- private void traceStaticFieldWrite(
+ void traceStaticFieldWrite(
DexField fieldReference, ProgramMethod currentMethod, FieldAccessMetadata metadata) {
- if (!registerFieldWrite(fieldReference, currentMethod)) {
+ if (!metadata.isDeferred() && !registerFieldWrite(fieldReference, currentMethod)) {
return;
}
FieldResolutionResult resolutionResult = resolveField(fieldReference, currentMethod);
+
+ if (appView.options().protoShrinking().enableGeneratedExtensionRegistryShrinking) {
+ // If it is a dead proto extension field, don't trace onwards.
+ boolean skipTracing =
+ appView.withGeneratedExtensionRegistryShrinker(
+ shrinker ->
+ shrinker.isDeadProtoExtensionField(
+ resolutionResult, fieldAccessInfoCollection, keepInfo),
+ false);
+ if (skipTracing) {
+ addDeadProtoTypeCandidate(resolutionResult.getSingleProgramField().getHolder());
+ return;
+ }
+ }
+
if (deferredTracing.deferTracingOfFieldAccess(
fieldReference, resolutionResult, currentMethod, FieldAccessKind.STATIC_WRITE, metadata)) {
+ assert !metadata.isDeferred();
return;
}
@@ -1764,20 +1878,6 @@
Log.verbose(getClass(), "Register Sput `%s`.", fieldReference);
}
- if (appView.options().protoShrinking().enableGeneratedExtensionRegistryShrinking) {
- // If it is a dead proto extension field, don't trace onwards.
- boolean skipTracing =
- appView.withGeneratedExtensionRegistryShrinker(
- shrinker ->
- shrinker.isDeadProtoExtensionField(
- field, fieldAccessInfoCollection, keepInfo),
- false);
- if (skipTracing) {
- addDeadProtoTypeCandidate(field.getHolder());
- return;
- }
- }
-
if (field.getReference() != fieldReference) {
// Mark the initial resolution holder as live. Note that this should only be done if
// the field
@@ -1867,7 +1967,7 @@
markTypeAsLive(clazz, graphReporter.reportClassReferencedFrom(clazz, context));
}
- private void markTypeAsLive(DexProgramClass clazz, KeepReason reason) {
+ void markTypeAsLive(DexProgramClass clazz, KeepReason reason) {
assert clazz != null;
markTypeAsLive(
clazz,
@@ -2222,7 +2322,7 @@
}
}
- private void markDirectAndIndirectClassInitializersAsLive(DexProgramClass clazz) {
+ void markDirectAndIndirectClassInitializersAsLive(DexProgramClass clazz) {
if (clazz.isInterface()) {
// Accessing a static field or method on an interface does not trigger the class initializer
// of any parent interfaces.
diff --git a/src/main/java/com/android/tools/r8/shaking/EnqueuerDeferredTracing.java b/src/main/java/com/android/tools/r8/shaking/EnqueuerDeferredTracing.java
index a09a358..b0a03a2 100644
--- a/src/main/java/com/android/tools/r8/shaking/EnqueuerDeferredTracing.java
+++ b/src/main/java/com/android/tools/r8/shaking/EnqueuerDeferredTracing.java
@@ -4,16 +4,75 @@
package com.android.tools.r8.shaking;
+import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
+import static com.android.tools.r8.shaking.ObjectAllocationInfoCollectionUtils.mayHaveFinalizeMethodDirectlyOrIndirectly;
+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.Code;
import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.FieldAccessInfo;
+import com.android.tools.r8.graph.FieldAccessInfoCollectionImpl;
import com.android.tools.r8.graph.FieldResolutionResult;
+import com.android.tools.r8.graph.ProgramField;
import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.bytecodemetadata.BytecodeMetadataProvider;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.conversion.IRFinalizer;
+import com.android.tools.r8.ir.conversion.IRToCfFinalizer;
+import com.android.tools.r8.ir.conversion.IRToDexFinalizer;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
+import com.android.tools.r8.ir.optimize.membervaluepropagation.assume.AssumeInfo;
+import com.android.tools.r8.ir.optimize.membervaluepropagation.assume.AssumeInfoLookup;
import com.android.tools.r8.shaking.Enqueuer.FieldAccessKind;
import com.android.tools.r8.shaking.Enqueuer.FieldAccessMetadata;
+import com.android.tools.r8.shaking.Enqueuer.Mode;
+import com.android.tools.r8.shaking.EnqueuerWorklist.EnqueuerAction;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.ThreadUtils;
+import com.android.tools.r8.utils.Timing;
+import com.android.tools.r8.utils.collections.ProgramFieldMap;
+import com.android.tools.r8.utils.collections.ProgramFieldSet;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
+import java.util.IdentityHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
public class EnqueuerDeferredTracing {
+ private final AppView<? extends AppInfoWithClassHierarchy> appView;
+ private final Enqueuer enqueuer;
+ private final Mode mode;
+ private final InternalOptions options;
+
+ // Helper for rewriting code instances at the end of tree shaking.
+ private final EnqueuerDeferredTracingRewriter rewriter;
+
+ // Maps each field to the tracing actions that have been deferred for that field. This allows
+ // enqueuing previously deferred tracing actions into the worklist if a given field cannot be
+ // optimized after all.
+ private final ProgramFieldMap<Set<EnqueuerAction>> deferredEnqueuerActions =
+ ProgramFieldMap.create();
+
+ // A set of fields that are never eligible for pruning.
+ private final ProgramFieldSet ineligibleForPruning = ProgramFieldSet.create();
+
+ EnqueuerDeferredTracing(
+ AppView<? extends AppInfoWithClassHierarchy> appView, Enqueuer enqueuer, Mode mode) {
+ this.appView = appView;
+ this.enqueuer = enqueuer;
+ this.mode = mode;
+ this.options = appView.options();
+ this.rewriter = new EnqueuerDeferredTracingRewriter(appView);
+ }
+
/**
* Returns true if the {@link Enqueuer} should not trace the given field reference.
*
@@ -25,8 +84,123 @@
DexField fieldReference,
FieldResolutionResult resolutionResult,
ProgramMethod context,
- FieldAccessKind kind,
+ FieldAccessKind accessKind,
FieldAccessMetadata metadata) {
+ if (!enqueuer.getMode().isFinalTreeShaking()) {
+ return false;
+ }
+
+ ProgramField field = resolutionResult.getSingleProgramField();
+ if (field == null) {
+ return false;
+ }
+
+ // Check if field access is consistent with the field access flags.
+ if (field.getAccessFlags().isStatic() != accessKind.isStatic()) {
+ return enqueueDeferredEnqueuerActions(field);
+ }
+
+ // If the access is from a reachability sensitive method, then bail out.
+ if (context.getHolder().getOrComputeReachabilitySensitive(appView)) {
+ return enqueueDeferredEnqueuerActions(field);
+ }
+
+ if (accessKind.isRead()) {
+ // If the value of the field is not guaranteed to be the default value, even if it is never
+ // assigned, then give up.
+ // TODO(b/205810841): Allow this by handling this in the corresponding IR rewriter.
+ AssumeInfo assumeInfo = AssumeInfoLookup.lookupAssumeInfo(appView, field);
+ if (assumeInfo != null && assumeInfo.hasReturnInfo()) {
+ return enqueueDeferredEnqueuerActions(field);
+ }
+ if (field.getAccessFlags().isStatic() && field.getDefinition().hasExplicitStaticValue()) {
+ return enqueueDeferredEnqueuerActions(field);
+ }
+ }
+
+ if (!isEligibleForPruning(field)) {
+ return enqueueDeferredEnqueuerActions(field);
+ }
+
+ // Field can be removed unless some other field access that has not yet been seen prohibits it.
+ // Record an EnqueuerAction that must be traced if that should happen.
+ EnqueuerAction deferredEnqueuerAction =
+ accessKind.toEnqueuerAction(fieldReference, context, metadata.toDeferred());
+ deferredEnqueuerActions
+ .computeIfAbsent(field, ignoreKey(LinkedHashSet::new))
+ .add(deferredEnqueuerAction);
+
+ // If the field is static, then the field access will trigger the class initializer of the
+ // field's holder. Therefore, we unconditionally trace the class initializer in this case.
+ // The corresponding IR rewriter will rewrite the field access into an init-class instruction.
+ if (accessKind.isStatic()) {
+ KeepReason reason =
+ enqueuer.getGraphReporter().reportClassReferencedFrom(field.getHolder(), context);
+ enqueuer.getWorklist().enqueueTraceTypeReferenceAction(field.getHolder(), reason);
+ enqueuer.getWorklist().enqueueTraceDirectAndIndirectClassInitializers(field.getHolder());
+ }
+
+ return true;
+ }
+
+ public void notifyReflectiveFieldAccess(ProgramField field, ProgramMethod context) {
+ enqueueDeferredEnqueuerActions(field);
+ }
+
+ private boolean isEligibleForPruning(ProgramField field) {
+ FieldAccessInfo info = enqueuer.getFieldAccessInfoCollection().get(field.getReference());
+ if (info.hasReflectiveAccess()
+ || info.isAccessedFromMethodHandle()
+ || info.isReadFromAnnotation()
+ || info.isReadFromRecordInvokeDynamic()
+ || enqueuer.getKeepInfo(field).isPinned(options)) {
+ return false;
+ }
+
+ if (info.isWritten()) {
+ // If the assigned value may have an override of Object#finalize() then give up.
+ // Note that this check depends on the set of instantiated types, and must therefore be rerun
+ // when the enqueuer's fixpoint is reached.
+ if (field.getType().isReferenceType()) {
+ DexType fieldBaseType = field.getType().toBaseType(appView.dexItemFactory());
+ if (fieldBaseType.isClassType()
+ && mayHaveFinalizeMethodDirectlyOrIndirectly(
+ appView, fieldBaseType, enqueuer.getObjectAllocationInfoCollection())) {
+ return false;
+ }
+ }
+ }
+
+ // We always have precise knowledge of field accesses during tracing.
+ assert info.hasKnownReadContexts();
+ assert info.hasKnownWriteContexts();
+
+ DexType fieldType = field.getType();
+
+ // If the field is now both read and written, then we cannot optimize the field unless the field
+ // type is an uninstantiated class type.
+ if (info.getReadsWithContexts().hasAccesses() && info.getWritesWithContexts().hasAccesses()) {
+ if (!fieldType.isClassType()) {
+ return false;
+ }
+ DexProgramClass fieldTypeDefinition = asProgramClassOrNull(appView.definitionFor(fieldType));
+ if (fieldTypeDefinition == null
+ || enqueuer
+ .getObjectAllocationInfoCollection()
+ .isInstantiatedDirectlyOrHasInstantiatedSubtype(fieldTypeDefinition)) {
+ return false;
+ }
+ }
+
+ return !ineligibleForPruning.contains(field);
+ }
+
+ private boolean enqueueDeferredEnqueuerActions(ProgramField field) {
+ Set<EnqueuerAction> actions = deferredEnqueuerActions.remove(field);
+ if (actions != null) {
+ enqueuer.getWorklist().enqueueAll(actions);
+ }
+ ineligibleForPruning.add(field);
return false;
}
@@ -35,7 +209,14 @@
* tree shaking.
*/
public boolean enqueueWorklistActions(EnqueuerWorklist worklist) {
- return false;
+ return deferredEnqueuerActions.removeIf(
+ (field, worklistActions) -> {
+ if (isEligibleForPruning(field)) {
+ return false;
+ }
+ worklist.enqueueAll(worklistActions);
+ return true;
+ });
}
/**
@@ -43,6 +224,63 @@
* that has not been performed (e.g., rewriting of dead field instructions).
*/
public void rewriteApplication(ExecutorService executorService) throws ExecutionException {
- // Intentionally empty.
+ FieldAccessInfoCollectionImpl fieldAccessInfoCollection =
+ enqueuer.getFieldAccessInfoCollection();
+ ProgramMethodSet methodsToProcess = ProgramMethodSet.create();
+ Map<DexField, ProgramField> prunedFields = new IdentityHashMap<>();
+ deferredEnqueuerActions.forEach(
+ (field, ignore) -> {
+ FieldAccessInfo accessInfo = fieldAccessInfoCollection.get(field.getReference());
+ prunedFields.put(field.getReference(), field);
+ accessInfo.forEachAccessContext(methodsToProcess::add);
+ accessInfo.forEachIndirectAccess(reference -> prunedFields.put(reference, field));
+ });
+ deferredEnqueuerActions.clear();
+
+ // Rewrite application.
+ Map<DexProgramClass, ProgramMethodSet> initializedClassesWithContexts =
+ new ConcurrentHashMap<>();
+ ThreadUtils.processItems(
+ methodsToProcess,
+ method -> rewriteMethod(method, initializedClassesWithContexts, prunedFields),
+ executorService);
+
+ // Register new InitClass instructions.
+ initializedClassesWithContexts.forEach(
+ (clazz, contexts) ->
+ contexts.forEach(context -> enqueuer.traceInitClass(clazz.getType(), context)));
+ assert enqueuer.getWorklist().isEmpty();
+
+ // Prune field access info collection.
+ prunedFields.values().forEach(field -> fieldAccessInfoCollection.remove(field.getReference()));
+ }
+
+ private void rewriteMethod(
+ ProgramMethod method,
+ Map<DexProgramClass, ProgramMethodSet> initializedClassesWithContexts,
+ Map<DexField, ProgramField> prunedFields) {
+ // Build IR.
+ MutableMethodConversionOptions conversionOptions =
+ mode.isInitialTreeShaking()
+ ? new MutableMethodConversionOptions(options).setIsGeneratingClassFiles(true)
+ : new MutableMethodConversionOptions(options);
+ conversionOptions.disableStringSwitchConversion();
+
+ IRCode ir = method.buildIR(appView, conversionOptions);
+
+ // Rewrite the IR according to the tracing that has been deferred.
+ rewriter.rewriteCode(ir, initializedClassesWithContexts, prunedFields);
+
+ // Run dead code elimination.
+ rewriter.getCodeRewriter().optimizeAlwaysThrowingInstructions(ir);
+ rewriter.getDeadCodeRemover().run(ir, Timing.empty());
+
+ // Finalize to class files or dex.
+ IRFinalizer<?> finalizer =
+ conversionOptions.isGeneratingClassFiles()
+ ? new IRToCfFinalizer(appView, rewriter.getDeadCodeRemover())
+ : new IRToDexFinalizer(appView, rewriter.getDeadCodeRemover());
+ Code newCode = finalizer.finalizeCode(ir, BytecodeMetadataProvider.empty(), Timing.empty());
+ method.setCode(newCode, appView);
}
}
diff --git a/src/main/java/com/android/tools/r8/shaking/EnqueuerDeferredTracingRewriter.java b/src/main/java/com/android/tools/r8/shaking/EnqueuerDeferredTracingRewriter.java
new file mode 100644
index 0000000..79165d1
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/shaking/EnqueuerDeferredTracingRewriter.java
@@ -0,0 +1,228 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.shaking;
+
+import static com.android.tools.r8.ir.code.Opcodes.INSTANCE_GET;
+import static com.android.tools.r8.ir.code.Opcodes.INSTANCE_PUT;
+import static com.android.tools.r8.ir.code.Opcodes.STATIC_GET;
+import static com.android.tools.r8.ir.code.Opcodes.STATIC_PUT;
+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.DexField;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ProgramField;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
+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.FieldGet;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.InitClass;
+import com.android.tools.r8.ir.code.InstanceFieldInstruction;
+import com.android.tools.r8.ir.code.InstanceGet;
+import com.android.tools.r8.ir.code.InstancePut;
+import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.InstructionListIterator;
+import com.android.tools.r8.ir.code.StaticGet;
+import com.android.tools.r8.ir.code.StaticPut;
+import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.optimize.CodeRewriter;
+import com.android.tools.r8.ir.optimize.DeadCodeRemover;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
+import com.google.common.collect.Sets;
+import java.util.Map;
+import java.util.Set;
+
+public class EnqueuerDeferredTracingRewriter {
+
+ private final AppView<? extends AppInfoWithClassHierarchy> appView;
+ private final CodeRewriter codeRewriter;
+ private final DeadCodeRemover deadCodeRemover;
+
+ EnqueuerDeferredTracingRewriter(AppView<? extends AppInfoWithClassHierarchy> appView) {
+ this.appView = appView;
+ this.codeRewriter = new CodeRewriter(appView);
+ this.deadCodeRemover = new DeadCodeRemover(appView, codeRewriter);
+ }
+
+ public CodeRewriter getCodeRewriter() {
+ return codeRewriter;
+ }
+
+ public DeadCodeRemover getDeadCodeRemover() {
+ return deadCodeRemover;
+ }
+
+ public void rewriteCode(
+ IRCode code,
+ Map<DexProgramClass, ProgramMethodSet> initializedClassesWithContexts,
+ Map<DexField, ProgramField> prunedFields) {
+ // TODO(b/205810841): Consider inserting assume instructions to reduce number of null checks.
+ // TODO(b/205810841): Consider running constant canonicalizer.
+ ProgramMethod context = code.context();
+
+ // Rewrite field instructions that reference a pruned field.
+ Set<Value> affectedValues = Sets.newIdentityHashSet();
+ BasicBlockIterator blockIterator = code.listIterator();
+ while (blockIterator.hasNext()) {
+ BasicBlock block = blockIterator.next();
+ InstructionListIterator instructionIterator = block.listIterator(code);
+ while (instructionIterator.hasNext()) {
+ Instruction instruction = instructionIterator.next();
+ switch (instruction.opcode()) {
+ case INSTANCE_GET:
+ rewriteInstanceGet(
+ code,
+ instructionIterator,
+ instruction.asInstanceGet(),
+ affectedValues,
+ prunedFields);
+ break;
+ case INSTANCE_PUT:
+ rewriteInstancePut(instructionIterator, instruction.asInstancePut(), prunedFields);
+ break;
+ case STATIC_GET:
+ rewriteStaticGet(
+ code,
+ instructionIterator,
+ instruction.asStaticGet(),
+ affectedValues,
+ context,
+ initializedClassesWithContexts,
+ prunedFields);
+ break;
+ case STATIC_PUT:
+ rewriteStaticPut(
+ code,
+ instructionIterator,
+ instruction.asStaticPut(),
+ context,
+ initializedClassesWithContexts,
+ prunedFields);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ if (!affectedValues.isEmpty()) {
+ new TypeAnalysis(appView).narrowing(affectedValues);
+ }
+ }
+
+ private void rewriteInstanceGet(
+ IRCode code,
+ InstructionListIterator instructionIterator,
+ InstanceGet instanceGet,
+ Set<Value> affectedValues,
+ Map<DexField, ProgramField> prunedFields) {
+ ProgramField prunedField = prunedFields.get(instanceGet.getField());
+ if (prunedField == null) {
+ return;
+ }
+
+ insertDefaultValueForFieldGet(
+ code, instructionIterator, instanceGet, affectedValues, prunedField);
+ removeOrReplaceInstanceFieldInstructionWithNullCheck(instructionIterator, instanceGet);
+ }
+
+ private void rewriteInstancePut(
+ InstructionListIterator instructionIterator,
+ InstancePut instancePut,
+ Map<DexField, ProgramField> prunedFields) {
+ ProgramField prunedField = prunedFields.get(instancePut.getField());
+ if (prunedField == null) {
+ return;
+ }
+
+ removeOrReplaceInstanceFieldInstructionWithNullCheck(instructionIterator, instancePut);
+ }
+
+ private void rewriteStaticGet(
+ IRCode code,
+ InstructionListIterator instructionIterator,
+ StaticGet staticGet,
+ Set<Value> affectedValues,
+ ProgramMethod context,
+ Map<DexProgramClass, ProgramMethodSet> initializedClassesWithContexts,
+ Map<DexField, ProgramField> prunedFields) {
+ ProgramField prunedField = prunedFields.get(staticGet.getField());
+ if (prunedField == null) {
+ return;
+ }
+
+ insertDefaultValueForFieldGet(
+ code, instructionIterator, staticGet, affectedValues, prunedField);
+ removeOrReplaceStaticFieldInstructionByInitClass(
+ code, instructionIterator, context, initializedClassesWithContexts, prunedField);
+ }
+
+ private void rewriteStaticPut(
+ IRCode code,
+ InstructionListIterator instructionIterator,
+ StaticPut staticPut,
+ ProgramMethod context,
+ Map<DexProgramClass, ProgramMethodSet> initializedClassesWithContexts,
+ Map<DexField, ProgramField> prunedFields) {
+ ProgramField prunedField = prunedFields.get(staticPut.getField());
+ if (prunedField == null) {
+ return;
+ }
+
+ removeOrReplaceStaticFieldInstructionByInitClass(
+ code, instructionIterator, context, initializedClassesWithContexts, prunedField);
+ }
+
+ private void insertDefaultValueForFieldGet(
+ IRCode code,
+ InstructionListIterator instructionIterator,
+ FieldGet fieldGet,
+ Set<Value> affectedValues,
+ ProgramField prunedField) {
+ if (fieldGet.hasUsedOutValue()) {
+ instructionIterator.previous();
+ Value replacement =
+ prunedField.getType().isReferenceType()
+ ? instructionIterator.insertConstNullInstruction(code, appView.options())
+ : instructionIterator.insertConstNumberInstruction(
+ code, appView.options(), 0, fieldGet.getOutType());
+ fieldGet.outValue().replaceUsers(replacement, affectedValues);
+ instructionIterator.next();
+ }
+ }
+
+ private void removeOrReplaceInstanceFieldInstructionWithNullCheck(
+ InstructionListIterator instructionIterator, InstanceFieldInstruction fieldInstruction) {
+ if (fieldInstruction.object().isMaybeNull()) {
+ instructionIterator.replaceCurrentInstructionWithNullCheck(
+ appView, fieldInstruction.object());
+ } else {
+ instructionIterator.removeOrReplaceByDebugLocalRead();
+ }
+ }
+
+ private void removeOrReplaceStaticFieldInstructionByInitClass(
+ IRCode code,
+ InstructionListIterator instructionIterator,
+ ProgramMethod context,
+ Map<DexProgramClass, ProgramMethodSet> initializedClassesWithContexts,
+ ProgramField prunedField) {
+ if (prunedField.getHolder().classInitializationMayHaveSideEffectsInContext(appView, context)) {
+ instructionIterator.replaceCurrentInstruction(
+ InitClass.builder()
+ .setFreshOutValue(code, TypeElement.getInt())
+ .setType(prunedField.getHolderType())
+ .build());
+ initializedClassesWithContexts
+ .computeIfAbsent(prunedField.getHolder(), ignoreKey(ProgramMethodSet::createConcurrent))
+ .add(context);
+ } else {
+ instructionIterator.removeOrReplaceByDebugLocalRead();
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/shaking/EnqueuerWorklist.java b/src/main/java/com/android/tools/r8/shaking/EnqueuerWorklist.java
index 0efc4b5..a09efe6 100644
--- a/src/main/java/com/android/tools/r8/shaking/EnqueuerWorklist.java
+++ b/src/main/java/com/android/tools/r8/shaking/EnqueuerWorklist.java
@@ -11,12 +11,17 @@
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.FieldAccessInfo;
import com.android.tools.r8.graph.ProgramDefinition;
import com.android.tools.r8.graph.ProgramField;
import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.shaking.Enqueuer.FieldAccessKind;
+import com.android.tools.r8.shaking.Enqueuer.FieldAccessMetadata;
import com.android.tools.r8.shaking.GraphReporter.KeepReasonWitness;
import com.android.tools.r8.utils.Action;
import com.android.tools.r8.utils.InternalOptions;
+import java.util.Collection;
+import java.util.Objects;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
@@ -241,6 +246,19 @@
}
}
+ static class TraceDirectAndIndirectClassInitializers extends EnqueuerAction {
+ private final DexProgramClass clazz;
+
+ TraceDirectAndIndirectClassInitializers(DexProgramClass clazz) {
+ this.clazz = clazz;
+ }
+
+ @Override
+ public void run(Enqueuer enqueuer) {
+ enqueuer.markDirectAndIndirectClassInitializersAsLive(clazz);
+ }
+ }
+
static class TraceInvokeDirectAction extends EnqueuerAction {
private final DexMethod invokedMethod;
// TODO(b/175854431): Avoid pushing context on worklist.
@@ -302,19 +320,199 @@
}
}
- static class TraceStaticFieldReadAction extends EnqueuerAction {
- private final DexField field;
- // TODO(b/175854431): Avoid pushing context on worklist.
+ static class TraceReflectiveFieldAccessAction extends EnqueuerAction {
+ private final ProgramField field;
private final ProgramMethod context;
+ private final FieldAccessKind kind;
- TraceStaticFieldReadAction(DexField field, ProgramMethod context) {
+ TraceReflectiveFieldAccessAction(ProgramField field, ProgramMethod context) {
+ this(field, context, null);
+ }
+
+ TraceReflectiveFieldAccessAction(
+ ProgramField field, ProgramMethod context, FieldAccessKind kind) {
this.field = field;
this.context = context;
+ this.kind = kind;
}
@Override
public void run(Enqueuer enqueuer) {
- enqueuer.traceStaticFieldRead(field, context);
+ if (kind != null) {
+ if (kind.isRead()) {
+ enqueuer.traceReflectiveFieldRead(field, context);
+ } else {
+ enqueuer.traceReflectiveFieldWrite(field, context);
+ }
+ } else {
+ enqueuer.traceReflectiveFieldAccess(field, context);
+ }
+ }
+ }
+
+ static class TraceTypeReferenceAction extends EnqueuerAction {
+ private final DexProgramClass clazz;
+ private final KeepReason reason;
+
+ TraceTypeReferenceAction(DexProgramClass clazz, KeepReason reason) {
+ this.clazz = clazz;
+ this.reason = reason;
+ }
+
+ @Override
+ public void run(Enqueuer enqueuer) {
+ enqueuer.markTypeAsLive(clazz, reason);
+ }
+ }
+
+ abstract static class TraceFieldAccessAction extends EnqueuerAction {
+ protected final DexField field;
+ // TODO(b/175854431): Avoid pushing context on worklist.
+ protected final ProgramMethod context;
+ protected final FieldAccessMetadata metadata;
+
+ TraceFieldAccessAction(DexField field, ProgramMethod context, FieldAccessMetadata metadata) {
+ this.field = field;
+ this.context = context;
+ this.metadata = metadata;
+ }
+
+ protected boolean baseEquals(TraceFieldAccessAction action) {
+ return field == action.field
+ && context.isStructurallyEqualTo(action.context)
+ && metadata.equals(action.metadata);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ TraceFieldAccessAction action = (TraceFieldAccessAction) obj;
+ return baseEquals(action);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(field, context.getReference(), metadata);
+ }
+ }
+
+ static class TraceInstanceFieldReadAction extends TraceFieldAccessAction {
+
+ TraceInstanceFieldReadAction(
+ DexField field, ProgramMethod context, FieldAccessMetadata metadata) {
+ super(field, context, metadata);
+ }
+
+ @Override
+ public void run(Enqueuer enqueuer) {
+ enqueuer.traceInstanceFieldRead(field, context, metadata);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ TraceInstanceFieldReadAction action = (TraceInstanceFieldReadAction) obj;
+ return baseEquals(action);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(field, context.getReference(), metadata);
+ }
+ }
+
+ static class TraceInstanceFieldWriteAction extends TraceFieldAccessAction {
+
+ TraceInstanceFieldWriteAction(
+ DexField field, ProgramMethod context, FieldAccessMetadata metadata) {
+ super(field, context, metadata);
+ }
+
+ @Override
+ public void run(Enqueuer enqueuer) {
+ enqueuer.traceInstanceFieldWrite(field, context, metadata);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ TraceInstanceFieldWriteAction action = (TraceInstanceFieldWriteAction) obj;
+ return baseEquals(action);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(field, context.getReference(), metadata);
+ }
+ }
+
+ static class TraceStaticFieldReadAction extends TraceFieldAccessAction {
+
+ TraceStaticFieldReadAction(
+ DexField field, ProgramMethod context, FieldAccessMetadata metadata) {
+ super(field, context, metadata);
+ }
+
+ @Override
+ public void run(Enqueuer enqueuer) {
+ enqueuer.traceStaticFieldRead(field, context, metadata);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ TraceStaticFieldReadAction action = (TraceStaticFieldReadAction) obj;
+ return baseEquals(action);
+ }
+ }
+
+ static class TraceStaticFieldWriteAction extends TraceFieldAccessAction {
+
+ TraceStaticFieldWriteAction(
+ DexField field, ProgramMethod context, FieldAccessMetadata metadata) {
+ super(field, context, metadata);
+ }
+
+ @Override
+ public void run(Enqueuer enqueuer) {
+ enqueuer.traceStaticFieldWrite(field, context, metadata);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ TraceStaticFieldWriteAction action = (TraceStaticFieldWriteAction) obj;
+ return baseEquals(action);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(field, context.getReference(), metadata);
}
}
@@ -340,6 +538,12 @@
abstract EnqueuerWorklist nonPushable();
+ final void enqueueAll(Collection<? extends EnqueuerAction> actions) {
+ actions.forEach(this::enqueue);
+ }
+
+ abstract void enqueue(EnqueuerAction action);
+
abstract boolean enqueueAssertAction(Action assertion);
abstract void enqueueMarkReachableDirectAction(
@@ -377,6 +581,8 @@
public abstract void enqueueTraceConstClassAction(
DexType type, ProgramMethod context, boolean ignoreCompatRules);
+ public abstract void enqueueTraceDirectAndIndirectClassInitializers(DexProgramClass clazz);
+
public abstract void enqueueTraceInvokeDirectAction(
DexMethod invokedMethod, ProgramMethod context);
@@ -385,8 +591,19 @@
public abstract void enqueueTraceNewInstanceAction(DexType type, ProgramMethod context);
+ public abstract void enqueueTraceReflectiveFieldAccessAction(
+ ProgramField field, ProgramMethod context);
+
+ public abstract void enqueueTraceReflectiveFieldReadAction(
+ ProgramField field, ProgramMethod context);
+
+ public abstract void enqueueTraceReflectiveFieldWriteAction(
+ ProgramField field, ProgramMethod context);
+
public abstract void enqueueTraceStaticFieldRead(DexField field, ProgramMethod context);
+ public abstract void enqueueTraceTypeReferenceAction(DexProgramClass clazz, KeepReason reason);
+
static class PushableEnqueuerWorkList extends EnqueuerWorklist {
PushableEnqueuerWorkList(Enqueuer enqueuer) {
@@ -399,6 +616,11 @@
}
@Override
+ void enqueue(EnqueuerAction action) {
+ queue.add(action);
+ }
+
+ @Override
boolean enqueueAssertAction(Action assertion) {
if (InternalOptions.assertionsEnabled()) {
queue.add(new AssertAction(assertion));
@@ -492,6 +714,11 @@
}
@Override
+ public void enqueueTraceDirectAndIndirectClassInitializers(DexProgramClass clazz) {
+ queue.add(new TraceDirectAndIndirectClassInitializers(clazz));
+ }
+
+ @Override
public void enqueueTraceInvokeDirectAction(DexMethod invokedMethod, ProgramMethod context) {
queue.add(new TraceInvokeDirectAction(invokedMethod, context));
}
@@ -507,8 +734,49 @@
}
@Override
+ public void enqueueTraceReflectiveFieldAccessAction(ProgramField field, ProgramMethod context) {
+ FieldAccessInfo info = enqueuer.getFieldAccessInfoCollection().get(field.getReference());
+ if (info == null || !info.hasReflectiveAccess()) {
+ queue.add(new TraceReflectiveFieldAccessAction(field, context));
+ }
+ }
+
+ @Override
+ public void enqueueTraceReflectiveFieldReadAction(ProgramField field, ProgramMethod context) {
+ FieldAccessInfo info = enqueuer.getFieldAccessInfoCollection().get(field.getReference());
+ if (info == null || !info.hasReflectiveRead()) {
+ queue.add(
+ new TraceReflectiveFieldAccessAction(
+ field,
+ context,
+ field.getAccessFlags().isStatic()
+ ? FieldAccessKind.STATIC_READ
+ : FieldAccessKind.INSTANCE_READ));
+ }
+ }
+
+ @Override
+ public void enqueueTraceReflectiveFieldWriteAction(ProgramField field, ProgramMethod context) {
+ FieldAccessInfo info = enqueuer.getFieldAccessInfoCollection().get(field.getReference());
+ if (info == null || !info.hasReflectiveWrite()) {
+ queue.add(
+ new TraceReflectiveFieldAccessAction(
+ field,
+ context,
+ field.getAccessFlags().isStatic()
+ ? FieldAccessKind.STATIC_WRITE
+ : FieldAccessKind.INSTANCE_WRITE));
+ }
+ }
+
+ @Override
public void enqueueTraceStaticFieldRead(DexField field, ProgramMethod context) {
- queue.add(new TraceStaticFieldReadAction(field, context));
+ queue.add(new TraceStaticFieldReadAction(field, context, FieldAccessMetadata.DEFAULT));
+ }
+
+ @Override
+ public void enqueueTraceTypeReferenceAction(DexProgramClass clazz, KeepReason reason) {
+ queue.add(new TraceTypeReferenceAction(clazz, reason));
}
}
@@ -523,6 +791,11 @@
return this;
}
+ @Override
+ void enqueue(EnqueuerAction action) {
+ throw attemptToEnqueue();
+ }
+
private Unreachable attemptToEnqueue() {
throw new Unreachable("Attempt to enqueue an action in a non pushable enqueuer work list.");
}
@@ -614,6 +887,11 @@
}
@Override
+ public void enqueueTraceDirectAndIndirectClassInitializers(DexProgramClass clazz) {
+ throw attemptToEnqueue();
+ }
+
+ @Override
public void enqueueTraceInvokeDirectAction(DexMethod invokedMethod, ProgramMethod context) {
throw attemptToEnqueue();
}
@@ -629,8 +907,28 @@
}
@Override
+ public void enqueueTraceReflectiveFieldAccessAction(ProgramField field, ProgramMethod context) {
+ throw attemptToEnqueue();
+ }
+
+ @Override
+ public void enqueueTraceReflectiveFieldReadAction(ProgramField field, ProgramMethod context) {
+ throw attemptToEnqueue();
+ }
+
+ @Override
+ public void enqueueTraceReflectiveFieldWriteAction(ProgramField field, ProgramMethod context) {
+ throw attemptToEnqueue();
+ }
+
+ @Override
public void enqueueTraceStaticFieldRead(DexField field, ProgramMethod context) {
throw attemptToEnqueue();
}
+
+ @Override
+ public void enqueueTraceTypeReferenceAction(DexProgramClass clazz, KeepReason reason) {
+ throw attemptToEnqueue();
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/shaking/L8TreePruner.java b/src/main/java/com/android/tools/r8/shaking/L8TreePruner.java
index 46e77e8..d462818 100644
--- a/src/main/java/com/android/tools/r8/shaking/L8TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/L8TreePruner.java
@@ -9,7 +9,6 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.desugar.TypeRewriter;
import com.android.tools.r8.utils.InternalOptions;
-import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.List;
@@ -22,25 +21,24 @@
public class L8TreePruner {
private final InternalOptions options;
- private final Set<DexType> emulatedInterfaces = Sets.newIdentityHashSet();
- private final Set<DexType> backports = Sets.newIdentityHashSet();
private final List<DexType> pruned = new ArrayList<>();
public L8TreePruner(InternalOptions options) {
this.options = options;
- backports.addAll(options.machineDesugaredLibrarySpecification.getLegacyBackport().keySet());
- emulatedInterfaces.addAll(
- options.machineDesugaredLibrarySpecification.getEmulatedInterfaces().keySet());
}
public DexApplication prune(DexApplication app, TypeRewriter typeRewriter) {
+ Set<DexType> maintainType = options.machineDesugaredLibrarySpecification.getMaintainType();
+ Set<DexType> emulatedInterfaces =
+ options.machineDesugaredLibrarySpecification.getEmulatedInterfaces().keySet();
Map<DexType, DexProgramClass> typeMap = new IdentityHashMap<>();
List<DexProgramClass> toKeep = new ArrayList<>();
boolean pruneNestMember = false;
for (DexProgramClass aClass : app.classes()) {
typeMap.put(aClass.type, aClass);
if (typeRewriter.hasRewrittenType(aClass.type, null)
- || emulatedInterfaces.contains(aClass.type)) {
+ || emulatedInterfaces.contains(aClass.type)
+ || maintainType.contains(aClass.type)) {
toKeep.add(aClass);
} else {
pruneNestMember |= aClass.isInANest();
diff --git a/src/main/java/com/android/tools/r8/shaking/ObjectAllocationInfoCollectionUtils.java b/src/main/java/com/android/tools/r8/shaking/ObjectAllocationInfoCollectionUtils.java
new file mode 100644
index 0000000..b7b2513
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/shaking/ObjectAllocationInfoCollectionUtils.java
@@ -0,0 +1,80 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.shaking;
+
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+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.ObjectAllocationInfoCollection;
+import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
+import com.android.tools.r8.utils.TraversalContinuation;
+
+public class ObjectAllocationInfoCollectionUtils {
+
+ public static boolean mayHaveFinalizeMethodDirectlyOrIndirectly(
+ AppView<AppInfoWithLiveness> appView, ClassTypeElement type) {
+ return mayHaveFinalizeMethodDirectlyOrIndirectly(
+ appView, type, appView.appInfo().getObjectAllocationInfoCollection());
+ }
+
+ public static boolean mayHaveFinalizeMethodDirectlyOrIndirectly(
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ ClassTypeElement type,
+ ObjectAllocationInfoCollection objectAllocationInfoCollection) {
+ // Special case for java.lang.Object.
+ if (type.getClassType() == appView.dexItemFactory().objectType
+ && !type.getInterfaces().isEmpty()) {
+ return type.getInterfaces()
+ .anyMatch(
+ (iface, isKnown) -> mayHaveFinalizer(appView, objectAllocationInfoCollection, iface));
+ }
+ return mayHaveFinalizeMethodDirectlyOrIndirectly(
+ appView, type.getClassType(), objectAllocationInfoCollection);
+ }
+
+ public static boolean mayHaveFinalizeMethodDirectlyOrIndirectly(
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ DexType type,
+ ObjectAllocationInfoCollection objectAllocationInfoCollection) {
+ // Special case for java.lang.Object.
+ if (type == appView.dexItemFactory().objectType) {
+ // The type java.lang.Object could be any instantiated type. Assume a finalizer exists.
+ return true;
+ }
+ return mayHaveFinalizer(appView, objectAllocationInfoCollection, type);
+ }
+
+ private static boolean mayHaveFinalizer(
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ ObjectAllocationInfoCollection objectAllocationInfoCollection,
+ DexType type) {
+ // A type may have an active finalizer if any derived instance has a finalizer.
+ return objectAllocationInfoCollection
+ .traverseInstantiatedSubtypes(
+ type,
+ clazz -> {
+ if (objectAllocationInfoCollection.isInterfaceWithUnknownSubtypeHierarchy(clazz)) {
+ return TraversalContinuation.doBreak();
+ } else {
+ SingleResolutionResult resolution =
+ appView
+ .appInfo()
+ .resolveMethodOn(clazz, appView.dexItemFactory().objectMembers.finalize)
+ .asSingleResolution();
+ if (resolution != null && resolution.getResolvedHolder().isProgramClass()) {
+ return TraversalContinuation.doBreak();
+ }
+ }
+ return TraversalContinuation.doContinue();
+ },
+ lambda -> {
+ // Lambda classes do not have finalizers.
+ return TraversalContinuation.doContinue();
+ },
+ appView.appInfo())
+ .isBreak();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
index 07f65be..ef3cdbd 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
@@ -315,7 +315,7 @@
// Check that the prefix of each synthetic is never itself synthetic.
committed.forEachNonLegacyItem(
item -> {
- if (item.getKind().allowSyntheticContext()) {
+ if (item.getKind().isGlobal()) {
return;
}
String prefix =
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 48ff52a..cee58c4 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.FeatureSplit;
import com.android.tools.r8.contexts.CompilationContext.UniqueContext;
+import com.android.tools.r8.errors.MissingGlobalSyntheticsConsumerDiagnostic;
import com.android.tools.r8.features.ClassToFeatureSplitMap;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppView;
@@ -278,6 +279,32 @@
return isSyntheticClass(clazz.type);
}
+ public boolean isGlobalSyntheticClass(DexProgramClass clazz) {
+ SyntheticDefinition<?, ?, ?> definition = pending.nonLegacyDefinitions.get(clazz.type);
+ if (definition != null) {
+ return definition.getKind().isGlobal();
+ }
+ return isGlobalReferences(committed.getNonLegacyClasses().get(clazz.type));
+ }
+
+ private static boolean isGlobalReferences(List<SyntheticProgramClassReference> references) {
+ if (references == null) {
+ return false;
+ }
+ if (references.size() == 1 && references.get(0).getKind().isGlobal()) {
+ return true;
+ }
+ assert verifyNoGlobals(references);
+ return false;
+ }
+
+ private static boolean verifyNoGlobals(List<SyntheticProgramClassReference> references) {
+ for (SyntheticProgramClassReference reference : references) {
+ assert !reference.getKind().isGlobal();
+ }
+ return true;
+ }
+
public boolean isSyntheticOfKind(DexType type, SyntheticKindSelector kindSelector) {
SyntheticKind kind = kindSelector.select(naming);
return pending.containsTypeOfKind(type, kind) || committed.containsTypeOfKind(type, kind);
@@ -769,14 +796,20 @@
}
}
- public DexProgramClass ensureFixedClassFromType(
+ public DexProgramClass ensureGlobalClass(
+ Supplier<MissingGlobalSyntheticsConsumerDiagnostic> diagnosticSupplier,
SyntheticKindSelector kindSelector,
- DexType contextType,
+ DexType globalType,
AppView<?> appView,
Consumer<SyntheticProgramClassBuilder> fn,
Consumer<DexProgramClass> onCreationConsumer) {
SyntheticKind kind = kindSelector.select(naming);
- SynthesizingContext outerContext = SynthesizingContext.fromType(contextType);
+ assert kind.isGlobal();
+ if (appView.options().intermediate && !appView.options().hasGlobalSyntheticsConsumer()) {
+ appView.reporter().fatalError(diagnosticSupplier.get());
+ }
+ // A global type is its own context.
+ SynthesizingContext outerContext = SynthesizingContext.fromType(globalType);
return internalEnsureFixedProgramClass(kind, fn, onCreationConsumer, outerContext, appView);
}
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticMarker.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticMarker.java
index c21954b..ceb9a37 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticMarker.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticMarker.java
@@ -147,6 +147,9 @@
private static DexType getSyntheticContextType(
DexType type, SyntheticKind kind, DexItemFactory factory) {
+ if (kind.isGlobal()) {
+ return type;
+ }
String prefix = SyntheticNaming.getPrefixForExternalSyntheticType(kind, type);
return factory.createType(DescriptorUtils.getDescriptorFromClassBinaryName(prefix));
}
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
index e95c6a1..37e327f 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
@@ -122,15 +122,15 @@
}
SyntheticKind forFixedClass(String descriptor) {
- return register(new SyntheticFixedClassKind(getNextId(), descriptor, false, false));
+ return register(new SyntheticFixedClassKind(getNextId(), descriptor, false));
}
SyntheticKind forGlobalClass() {
- return register(new SyntheticFixedClassKind(getNextId(), "", true, true));
+ return register(new SyntheticFixedClassKind(getNextId(), "", true));
}
SyntheticKind forGlobalClasspathClass() {
- return register(new SyntheticFixedClassKind(getNextId(), "", false, false));
+ return register(new SyntheticFixedClassKind(getNextId(), "", false));
}
List<SyntheticKind> getAllKinds() {
@@ -192,7 +192,6 @@
public abstract boolean isMayOverridesNonProgramType();
- public abstract boolean allowSyntheticContext();
}
private static class SyntheticMethodKind extends SyntheticKind {
@@ -227,10 +226,6 @@
return false;
}
- @Override
- public boolean allowSyntheticContext() {
- return false;
- }
}
private static class SyntheticClassKind extends SyntheticKind {
@@ -268,24 +263,14 @@
return false;
}
- @Override
- public boolean allowSyntheticContext() {
- return false;
- }
}
private static class SyntheticFixedClassKind extends SyntheticClassKind {
private final boolean mayOverridesNonProgramType;
- private final boolean allowSyntheticContext;
- private SyntheticFixedClassKind(
- int id,
- String descriptor,
- boolean mayOverridesNonProgramType,
- boolean allowSyntheticContext) {
+ private SyntheticFixedClassKind(int id, String descriptor, boolean mayOverridesNonProgramType) {
super(id, descriptor, false);
this.mayOverridesNonProgramType = mayOverridesNonProgramType;
- this.allowSyntheticContext = allowSyntheticContext;
}
@Override
@@ -308,10 +293,6 @@
return mayOverridesNonProgramType;
}
- @Override
- public boolean allowSyntheticContext() {
- return allowSyntheticContext;
- }
}
private static final String SYNTHETIC_CLASS_SEPARATOR = "$$";
@@ -333,6 +314,9 @@
static String getPrefixForExternalSyntheticType(SyntheticKind kind, DexType type) {
String binaryName = type.toBinaryName();
+ if (kind.isGlobal()) {
+ return binaryName;
+ }
int index =
binaryName.lastIndexOf(
kind.isFixedSuffixSynthetic() ? kind.descriptor : SYNTHETIC_CLASS_SEPARATOR);
diff --git a/src/main/java/com/android/tools/r8/tracereferences/Tracer.java b/src/main/java/com/android/tools/r8/tracereferences/Tracer.java
index 97b2621..c5ffc7a 100644
--- a/src/main/java/com/android/tools/r8/tracereferences/Tracer.java
+++ b/src/main/java/com/android/tools/r8/tracereferences/Tracer.java
@@ -349,8 +349,8 @@
handleRewrittenMethodResolution(
method,
lookupResult.getType().isInterface()
- ? appInfo().resolveMethodOnInterface(method)
- : appInfo().resolveMethodOnClass(method));
+ ? appInfo().resolveMethodOnInterfaceHolder(method)
+ : appInfo().resolveMethodOnClassHolder(method));
}
private void handleRewrittenMethodResolution(
diff --git a/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java b/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java
index bfd8334..7cce06b 100644
--- a/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java
@@ -229,6 +229,14 @@
|| c == 'D';
}
+ public static boolean isVoidDescriptor(String descriptor) {
+ return descriptor.length() == 1 && isVoidType(descriptor.charAt(0));
+ }
+
+ public static boolean isVoidType(char c) {
+ return c == 'V';
+ }
+
public static boolean isArrayDescriptor(String descriptor) {
if (descriptor.length() < 2) {
return false;
@@ -270,6 +278,31 @@
}
}
+ public static String primitiveDescriptorToBoxedInternalName(char primitive) {
+ switch (primitive) {
+ case 'V':
+ return "java/lang/Void";
+ case 'Z':
+ return "java/lang/Boolean";
+ case 'B':
+ return "java/lang/Byte";
+ case 'S':
+ return "java/lang/Short";
+ case 'C':
+ return "java/lang/Character";
+ case 'I':
+ return "java/lang/Integer";
+ case 'J':
+ return "java/lang/Long";
+ case 'F':
+ return "java/lang/Float";
+ case 'D':
+ return "java/lang/Double";
+ default:
+ throw new Unreachable("Unknown type " + primitive);
+ }
+ }
+
/**
* Get unqualified class name from its descriptor.
*
@@ -327,7 +360,7 @@
return Integer.max(classDescriptor.lastIndexOf("/"), 0) + 1;
}
- /**
+ /**
* Get canonical class name from its descriptor.
*
* @param classDescriptor a class descriptor i.e. "La/b/C$D;"
diff --git a/src/main/java/com/android/tools/r8/utils/DeterminismChecker.java b/src/main/java/com/android/tools/r8/utils/DeterminismChecker.java
index 4871186..2f95428 100644
--- a/src/main/java/com/android/tools/r8/utils/DeterminismChecker.java
+++ b/src/main/java/com/android/tools/r8/utils/DeterminismChecker.java
@@ -10,12 +10,13 @@
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.Closeable;
+import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
@@ -44,12 +45,14 @@
return new LineCallbackChecker(Files.newBufferedReader(log, StandardCharsets.UTF_8));
} else {
System.out.println("Writing determinism log: " + log);
+ // Note that Files.newBufferedWriter will cause issues in presence of malformed input
+ // and unmappable character errors, since Files.newBufferedWriter uses the
+ // java.nio.charset.CharsetDecoder default action, which is to report such errors,
+ // instead of dealing with them in java.nio.charset.CharsetDecoder#onMalformedInput.
BufferedWriter bufferedWriter =
- Files.newBufferedWriter(
- log,
- StandardCharsets.UTF_8,
- StandardOpenOption.CREATE,
- StandardOpenOption.TRUNCATE_EXISTING);
+ new BufferedWriter(
+ new OutputStreamWriter(
+ new FileOutputStream(log.toFile()), StandardCharsets.UTF_8));
return new LineCallbackWriter(bufferedWriter);
}
}
@@ -82,6 +85,13 @@
return method.getReference().toSourceString();
}
+ public <E extends Exception> void accept(ThrowingConsumer<LineCallback, E> consumer)
+ throws E, IOException {
+ try (LineCallback callback = callbackFactory.createCallback()) {
+ consumer.accept(callback);
+ }
+ }
+
public void check(AppView<?> appView) {
try (LineCallback callback = callbackFactory.createCallback()) {
List<DexProgramClass> classes = new ArrayList<>(appView.appInfo().classes());
diff --git a/src/main/java/com/android/tools/r8/utils/FileUtils.java b/src/main/java/com/android/tools/r8/utils/FileUtils.java
index 20bde1a..ef26890 100644
--- a/src/main/java/com/android/tools/r8/utils/FileUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/FileUtils.java
@@ -31,6 +31,7 @@
public static final String KT_EXTENSION = ".kt";
public static final String MODULE_INFO_CLASS = "module-info.class";
public static final String MODULES_PREFIX = "/modules";
+ public static final String GLOBAL_SYNTHETIC_EXTENSION = ".global";
public static final boolean isAndroid =
System.getProperty("java.vm.name").equalsIgnoreCase("Dalvik");
diff --git a/src/main/java/com/android/tools/r8/utils/InternalGlobalSyntheticsProgramConsumer.java b/src/main/java/com/android/tools/r8/utils/InternalGlobalSyntheticsProgramConsumer.java
new file mode 100644
index 0000000..3945a6e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/InternalGlobalSyntheticsProgramConsumer.java
@@ -0,0 +1,125 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.utils;
+
+import static com.android.tools.r8.utils.FileUtils.GLOBAL_SYNTHETIC_EXTENSION;
+
+import com.android.tools.r8.ByteDataView;
+import com.android.tools.r8.ClassFileConsumer;
+import com.android.tools.r8.DexFilePerClassFileConsumer;
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.GlobalSyntheticsConsumer;
+import com.android.tools.r8.ProgramResource.Kind;
+import com.android.tools.r8.Version;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+public abstract class InternalGlobalSyntheticsProgramConsumer {
+
+ public static final String COMPILER_INFO_ENTRY_NAME = "compilerinfo";
+ public static final String OUTPUT_KIND_ENTRY_NAME = "kind";
+
+ private final GlobalSyntheticsConsumer consumer;
+ private final List<Pair<String, byte[]>> content = new ArrayList<>();
+
+ public InternalGlobalSyntheticsProgramConsumer(GlobalSyntheticsConsumer consumer) {
+ this.consumer = consumer;
+ }
+
+ public abstract Kind getKind();
+
+ synchronized void addGlobalSynthetic(String descriptor, byte[] data) {
+ add(getGlobalSyntheticFileName(descriptor), data);
+ }
+
+ private void add(String entryName, byte[] data) {
+ content.add(new Pair<>(entryName, data));
+ }
+
+ public void finished(DiagnosticsHandler handler) {
+ // Add meta information.
+ add(COMPILER_INFO_ENTRY_NAME, Version.getVersionString().getBytes(StandardCharsets.UTF_8));
+ add(OUTPUT_KIND_ENTRY_NAME, getKind().toString().getBytes(StandardCharsets.UTF_8));
+
+ // Size estimate to avoid reallocation of the byte output array.
+ final int zipHeaderOverhead = 500;
+ final int zipEntryOverhead = 200;
+ int estimatedZipSize =
+ zipHeaderOverhead
+ + ListUtils.fold(
+ content,
+ 0,
+ (acc, pair) ->
+ acc + pair.getFirst().length() + pair.getSecond().length + zipEntryOverhead);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(estimatedZipSize);
+ try (ZipOutputStream stream = new ZipOutputStream(baos)) {
+ for (Pair<String, byte[]> pair : content) {
+ ZipUtils.writeToZipStream(stream, pair.getFirst(), pair.getSecond(), ZipEntry.STORED);
+ // Clear out the bytes to avoid three copies when converting the boas.
+ pair.setSecond(null);
+ }
+ } catch (IOException e) {
+ handler.error(new ExceptionDiagnostic(e));
+ }
+ byte[] bytes = baos.toByteArray();
+ consumer.accept(bytes);
+ }
+
+ private static String getGlobalSyntheticFileName(String descriptor) {
+ assert descriptor != null && DescriptorUtils.isClassDescriptor(descriptor);
+ return DescriptorUtils.getClassBinaryNameFromDescriptor(descriptor)
+ + GLOBAL_SYNTHETIC_EXTENSION;
+ }
+
+ public static class InternalGlobalSyntheticsDexConsumer
+ extends InternalGlobalSyntheticsProgramConsumer implements DexFilePerClassFileConsumer {
+
+ public InternalGlobalSyntheticsDexConsumer(GlobalSyntheticsConsumer consumer) {
+ super(consumer);
+ }
+
+ @Override
+ public Kind getKind() {
+ return Kind.DEX;
+ }
+
+ @Override
+ public void accept(
+ String primaryClassDescriptor,
+ ByteDataView data,
+ Set<String> descriptors,
+ DiagnosticsHandler handler) {
+ addGlobalSynthetic(primaryClassDescriptor, data.copyByteData());
+ }
+
+ @Override
+ public boolean combineSyntheticClassesWithPrimaryClass() {
+ return false;
+ }
+ }
+
+ public static class InternalGlobalSyntheticsCfConsumer
+ extends InternalGlobalSyntheticsProgramConsumer implements ClassFileConsumer {
+
+ public InternalGlobalSyntheticsCfConsumer(GlobalSyntheticsConsumer consumer) {
+ super(consumer);
+ }
+
+ @Override
+ public Kind getKind() {
+ return Kind.CF;
+ }
+
+ @Override
+ public void accept(ByteDataView data, String descriptor, DiagnosticsHandler handler) {
+ addGlobalSynthetic(descriptor, data.copyByteData());
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/InternalGlobalSyntheticsProgramProvider.java b/src/main/java/com/android/tools/r8/utils/InternalGlobalSyntheticsProgramProvider.java
new file mode 100644
index 0000000..6b2d828
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/InternalGlobalSyntheticsProgramProvider.java
@@ -0,0 +1,100 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.utils;
+
+import com.android.tools.r8.GlobalSyntheticsResourceProvider;
+import com.android.tools.r8.ProgramResource;
+import com.android.tools.r8.ProgramResource.Kind;
+import com.android.tools.r8.ProgramResourceProvider;
+import com.android.tools.r8.ResourceException;
+import com.android.tools.r8.Version;
+import com.android.tools.r8.origin.ArchiveEntryOrigin;
+import com.google.common.io.ByteStreams;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+public class InternalGlobalSyntheticsProgramProvider implements ProgramResourceProvider {
+
+ private final List<GlobalSyntheticsResourceProvider> providers;
+ private List<ProgramResource> resources = null;
+
+ public InternalGlobalSyntheticsProgramProvider(List<GlobalSyntheticsResourceProvider> providers) {
+ this.providers = providers;
+ }
+
+ @Override
+ public Collection<ProgramResource> getProgramResources() throws ResourceException {
+ if (resources == null) {
+ ensureResources();
+ }
+ return resources;
+ }
+
+ private synchronized void ensureResources() throws ResourceException {
+ if (resources != null) {
+ return;
+ }
+ List<ProgramResource> resources = new ArrayList<>();
+ Set<String> seen = new HashSet<>();
+ for (GlobalSyntheticsResourceProvider provider : providers) {
+ List<Function<Kind, ProgramResource>> delayedResouces = new ArrayList<>();
+ Kind providerKind = null;
+ try (ZipInputStream stream = new ZipInputStream(provider.getByteStream())) {
+ ZipEntry entry;
+ while (null != (entry = stream.getNextEntry())) {
+ String name = entry.getName();
+ if (name.equals(InternalGlobalSyntheticsProgramConsumer.OUTPUT_KIND_ENTRY_NAME)) {
+ providerKind =
+ Kind.valueOf(new String(ByteStreams.toByteArray(stream), StandardCharsets.UTF_8));
+ } else if (name.equals(
+ InternalGlobalSyntheticsProgramConsumer.COMPILER_INFO_ENTRY_NAME)) {
+ String version = new String(ByteStreams.toByteArray(stream), StandardCharsets.UTF_8);
+ if (!Version.getVersionString().equals(version)) {
+ throw new ResourceException(
+ provider.getOrigin(),
+ "Outdated or inconsistent global synthetics information."
+ + "\nGlobal synthetics information version: "
+ + version
+ + "\nCompiler version: "
+ + Version.getVersionString());
+ }
+ } else if (name.endsWith(FileUtils.GLOBAL_SYNTHETIC_EXTENSION) && seen.add(name)) {
+ ArchiveEntryOrigin origin = new ArchiveEntryOrigin(name, provider.getOrigin());
+ String descriptor = guessTypeDescriptor(name);
+ byte[] bytes = ByteStreams.toByteArray(stream);
+ Set<String> descriptors = Collections.singleton(descriptor);
+ delayedResouces.add(
+ kind -> OneShotByteResource.create(kind, origin, bytes, descriptors));
+ }
+ }
+ } catch (IOException e) {
+ throw new ResourceException(provider.getOrigin(), e);
+ }
+ if (providerKind == null) {
+ throw new ResourceException(
+ provider.getOrigin(),
+ "Invalid global synthetics provider does not specify its content kind.");
+ }
+ for (Function<Kind, ProgramResource> fn : delayedResouces) {
+ resources.add(fn.apply(providerKind));
+ }
+ }
+ this.resources = resources;
+ }
+
+ private String guessTypeDescriptor(String name) {
+ String noExt = name.substring(0, name.length() - FileUtils.GLOBAL_SYNTHETIC_EXTENSION.length());
+ String classExt = noExt + FileUtils.CLASS_EXTENSION;
+ return DescriptorUtils.guessTypeDescriptor(classExt);
+ }
+}
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 dcf8dbd..133f721 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.DexFilePerClassFileConsumer;
import com.android.tools.r8.DexIndexedConsumer;
import com.android.tools.r8.FeatureSplit;
+import com.android.tools.r8.GlobalSyntheticsConsumer;
import com.android.tools.r8.MapIdProvider;
import com.android.tools.r8.ProgramConsumer;
import com.android.tools.r8.SourceFileProvider;
@@ -137,7 +138,7 @@
}
public static final CfVersion SUPPORTED_CF_VERSION = CfVersion.V17;
- public static final CfVersion EXPERIMENTAL_CF_VERSION = CfVersion.V12;
+ public static final CfVersion EXPERIMENTAL_CF_VERSION = CfVersion.V14;
public static final int SUPPORTED_DEX_VERSION =
AndroidApiLevel.LATEST.getDexVersion().getIntValue();
@@ -164,6 +165,8 @@
// TODO(zerny): Make this private-final once we have full program-consumer support.
public ProgramConsumer programConsumer = null;
+ private GlobalSyntheticsConsumer globalSyntheticsConsumer = null;
+
public DataResourceConsumer dataResourceConsumer;
public FeatureSplitConfiguration featureSplitConfiguration;
public StartupConfiguration startupConfiguration;
@@ -271,6 +274,7 @@
// Flag to toggle if the prefix based merge restriction should be enforced.
public boolean enableNeverMergePrefixes = true;
+ // TODO(b/227277105): Control merging with desugared library and maintain prefix.
public Set<String> neverMergePrefixes = ImmutableSet.of("j$.");
public boolean classpathInterfacesMayHaveStaticInitialization = false;
@@ -444,6 +448,18 @@
throw new UnsupportedOperationException("Cannot find internal output mode.");
}
+ public boolean hasGlobalSyntheticsConsumer() {
+ return globalSyntheticsConsumer != null;
+ }
+
+ public GlobalSyntheticsConsumer getGlobalSyntheticsConsumer() {
+ return globalSyntheticsConsumer;
+ }
+
+ public void setGlobalSyntheticsConsumer(GlobalSyntheticsConsumer globalSyntheticsConsumer) {
+ this.globalSyntheticsConsumer = globalSyntheticsConsumer;
+ }
+
public boolean isAndroidPlatform() {
return minApiLevel == ANDROID_PLATFORM;
}
@@ -922,6 +938,10 @@
}
timing.begin("Load machine specification");
loadMachineDesugaredLibrarySpecification.accept(timing, app);
+ if (!machineDesugaredLibrarySpecification.getMaintainType().isEmpty()) {
+ // TODO(b/227277105): Control merging with desugared library and maintain prefix.
+ neverMergePrefixes = ImmutableSet.of();
+ }
timing.end();
}
@@ -1449,10 +1469,14 @@
this.enable = enable;
}
- public int getMaxClassGroupSize() {
+ public int getMaxClassGroupSizeInR8() {
return 30;
}
+ public int getMaxClassGroupSizeInD8() {
+ return 100;
+ }
+
public int getMaxInterfaceGroupSize() {
return 100;
}
@@ -1672,24 +1696,37 @@
private boolean hasReadCheckDeterminism = false;
private DeterminismChecker determinismChecker = null;
- public void setDeterminismChecker(DeterminismChecker checker) {
- determinismChecker = checker;
- }
-
- public void checkDeterminism(AppView<?> appView) {
+ private DeterminismChecker getDeterminismChecker() {
// Lazily read the env-var so that it can be set after options init.
if (determinismChecker == null && !hasReadCheckDeterminism) {
hasReadCheckDeterminism = true;
String dir = System.getProperty("com.android.tools.r8.checkdeterminism");
if (dir != null) {
- determinismChecker = DeterminismChecker.createWithFileBacking(Paths.get(dir));
+ setDeterminismChecker(DeterminismChecker.createWithFileBacking(Paths.get(dir)));
}
}
+ return determinismChecker;
+ }
+
+ public void setDeterminismChecker(DeterminismChecker checker) {
+ determinismChecker = checker;
+ }
+
+ public void checkDeterminism(AppView<?> appView) {
+ DeterminismChecker determinismChecker = getDeterminismChecker();
if (determinismChecker != null) {
determinismChecker.check(appView);
}
}
+ public <E extends Exception> void checkDeterminism(
+ ThrowingConsumer<DeterminismChecker, E> consumer) {
+ DeterminismChecker determinismChecker = getDeterminismChecker();
+ if (determinismChecker != null) {
+ consumer.acceptWithRuntimeException(determinismChecker);
+ }
+ }
+
public static void allowExperimentClassFileVersion(InternalOptions options) {
options.reportedExperimentClassFileVersion.set(true);
}
@@ -1760,6 +1797,7 @@
public boolean enableCheckCastAndInstanceOfRemoval = true;
public boolean enableDeadSwitchCaseElimination = true;
public boolean enableInvokeSuperToInvokeVirtualRewriting = true;
+ public boolean enableMultiANewArrayDesugaringForClassFiles = false;
public boolean enableSwitchToIfRewriting = true;
public boolean enableEnumUnboxingDebugLogs = false;
public boolean forceRedundantConstNumberRemoval = false;
@@ -1867,6 +1905,8 @@
public Predicate<DexMethod> cfByteCodePassThrough = null;
public boolean enableExperimentalMapFileVersion = false;
+
+ public boolean alwaysGenerateLambdaFactoryMethods = false;
}
public MapVersion getMapFileVersion() {
@@ -2077,8 +2117,7 @@
// and the first register of the result could lead to the wrong exception
// being thrown on out of bounds.
public boolean canUseSameArrayAndResultRegisterInArrayGetWide() {
- assert isGeneratingDex();
- return getMinApiLevel().isGreaterThan(AndroidApiLevel.O_MR1);
+ return isGeneratingClassFiles() || getMinApiLevel().isGreaterThan(AndroidApiLevel.O_MR1);
}
// Some Lollipop versions of Art found in the wild perform invalid bounds
@@ -2309,8 +2348,7 @@
//
// Fixed in Android Q, see b/120985556.
public boolean canHaveArtInstanceOfVerifierBug() {
- assert isGeneratingDex();
- return getMinApiLevel().isLessThan(AndroidApiLevel.Q);
+ return isGeneratingDex() && getMinApiLevel().isLessThan(AndroidApiLevel.Q);
}
// Some Art Lollipop version do not deal correctly with long-to-int conversions.
diff --git a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
index 22932f6..78f612a 100644
--- a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
+++ b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
@@ -40,6 +40,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexValue.DexValueString;
import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.Position.OutlineCallerPosition;
import com.android.tools.r8.ir.code.Position.OutlineCallerPosition.OutlineCallerPositionBuilder;
@@ -493,7 +494,7 @@
for (DexProgramClass clazz : application.classes()) {
boolean isSyntheticClass = appView.getSyntheticItems().isSyntheticClass(clazz);
- IdentityHashMap<DexString, List<DexEncodedMethod>> methodsByRenamedName =
+ IdentityHashMap<DexString, List<ProgramMethod>> methodsByRenamedName =
groupMethodsByRenamedName(appView.graphLens(), namingLens, clazz);
// At this point we don't know if we really need to add this class to the builder.
@@ -538,7 +539,7 @@
List<DexString> renamedMethodNames = new ArrayList<>(methodsByRenamedName.keySet());
renamedMethodNames.sort(DexString::compareTo);
for (DexString methodName : renamedMethodNames) {
- List<DexEncodedMethod> methods = methodsByRenamedName.get(methodName);
+ List<ProgramMethod> methods = methodsByRenamedName.get(methodName);
if (methods.size() > 1) {
// If there are multiple methods with the same name (overloaded) then sort them for
// deterministic behaviour: the algorithm will assign new line numbers in this order.
@@ -566,26 +567,27 @@
new KotlinInlineFunctionPositionRemapper(
appView, positionRemapper, cfLineToMethodMapper);
- for (DexEncodedMethod method : methods) {
- kotlinRemapper.currentMethod = method;
+ for (ProgramMethod method : methods) {
+ DexEncodedMethod definition = method.getDefinition();
+ kotlinRemapper.currentMethod = definition;
List<MappedPosition> mappedPositions;
- Code code = method.getCode();
+ Code code = definition.getCode();
boolean canUseDexPc =
- methods.size() == 1 && representation.useDexPcEncoding(clazz, method);
+ methods.size() == 1 && representation.useDexPcEncoding(clazz, definition);
if (code != null) {
if (code.isDexCode() && doesContainPositions(code.asDexCode())) {
if (canUseDexPc) {
mappedPositions =
optimizeDexCodePositionsForPc(
- method, appView, kotlinRemapper, pcBasedDebugInfo);
+ definition, appView, kotlinRemapper, pcBasedDebugInfo);
} else {
mappedPositions =
optimizeDexCodePositions(
- method, appView, kotlinRemapper, identityMapping, methods.size() != 1);
+ definition, appView, kotlinRemapper, identityMapping, methods.size() != 1);
}
} else if (code.isCfCode()
&& doesContainPositions(code.asCfCode())
- && !appView.isCfByteCodePassThrough(method)) {
+ && !appView.isCfByteCodePassThrough(definition)) {
mappedPositions = optimizeCfCodePositions(method, kotlinRemapper, appView);
} else {
mappedPositions = new ArrayList<>();
@@ -603,7 +605,7 @@
String obfuscatedName = obfuscatedNameDexString.toString();
List<MappingInformation> methodMappingInfo = new ArrayList<>();
- if (method.isD8R8Synthesized()) {
+ if (definition.isD8R8Synthesized()) {
methodMappingInfo.add(CompilerSynthesizedMappingInformation.builder().build());
}
@@ -613,8 +615,8 @@
&& obfuscatedNameDexString == originalMethod.name
&& originalMethod.holder == originalType) {
assert appView.options().lineNumberOptimization == LineNumberOptimization.OFF
- || !doesContainPositions(method)
- || appView.isCfByteCodePassThrough(method);
+ || !doesContainPositions(definition)
+ || appView.isCfByteCodePassThrough(definition);
continue;
}
@@ -691,8 +693,8 @@
}
}
Range obfuscatedRange;
- if (method.getCode().isDexCode()
- && method.getCode().asDexCode().getDebugInfo()
+ if (definition.getCode().isDexCode()
+ && definition.getCode().asDexCode().getDebugInfo()
== DexDebugInfoForSingleLineMethod.getInstance()) {
assert firstPosition.originalLine == lastPosition.originalLine;
obfuscatedRange = new Range(0, MAX_LINE_NUMBER);
@@ -745,11 +747,11 @@
}
i = j;
}
- if (method.getCode().isDexCode()
- && method.getCode().asDexCode().getDebugInfo()
+ if (definition.getCode().isDexCode()
+ && definition.getCode().asDexCode().getDebugInfo()
== DexDebugInfoForSingleLineMethod.getInstance()) {
pcBasedDebugInfo.recordSingleLineFor(
- method.getCode().asDexCode(), method.getParameters().size());
+ definition.getCode().asDexCode(), method.getParameters().size());
}
} // for each method of the group
} // for each method group, grouped by name
@@ -815,7 +817,7 @@
}
private static boolean verifyMethodsAreKeptDirectlyOrIndirectly(
- AppView<?> appView, List<DexEncodedMethod> methods) {
+ AppView<?> appView, List<ProgramMethod> methods) {
if (appView.options().isGeneratingClassFiles() || !appView.appInfo().hasClassHierarchy()) {
return true;
}
@@ -823,9 +825,9 @@
KeepInfoCollection keepInfo = appView.getKeepInfo();
boolean allSeenAreInstanceInitializers = true;
DexString originalName = null;
- for (DexEncodedMethod method : methods) {
+ for (ProgramMethod method : methods) {
// We cannot rename instance initializers.
- if (method.isInstanceInitializer()) {
+ if (method.getDefinition().isInstanceInitializer()) {
assert allSeenAreInstanceInitializers;
continue;
}
@@ -835,7 +837,7 @@
continue;
}
// With desugared library, call-backs names are reserved here.
- if (method.isLibraryMethodOverride().isTrue()) {
+ if (method.getDefinition().isLibraryMethodOverride().isTrue()) {
continue;
}
// We use the same name for interface names even if it has different types.
@@ -856,8 +858,8 @@
return true;
}
- private static int getMethodStartLine(DexEncodedMethod method) {
- Code code = method.getCode();
+ private static int getMethodStartLine(ProgramMethod method) {
+ Code code = method.getDefinition().getCode();
if (code == null) {
return 0;
}
@@ -878,14 +880,14 @@
// Sort by startline, then DexEncodedMethod.slowCompare.
// Use startLine = 0 if no debuginfo.
- private static void sortMethods(List<DexEncodedMethod> methods) {
+ private static void sortMethods(List<ProgramMethod> methods) {
methods.sort(
(lhs, rhs) -> {
int lhsStartLine = getMethodStartLine(lhs);
int rhsStartLine = getMethodStartLine(rhs);
int startLineDiff = lhsStartLine - rhsStartLine;
if (startLineDiff != 0) return startLineDiff;
- return DexEncodedMethod.slowCompare(lhs, rhs);
+ return DexEncodedMethod.slowCompare(lhs.getDefinition(), rhs.getDefinition());
});
}
@@ -921,21 +923,22 @@
});
}
- public static IdentityHashMap<DexString, List<DexEncodedMethod>> groupMethodsByRenamedName(
+ public static IdentityHashMap<DexString, List<ProgramMethod>> groupMethodsByRenamedName(
GraphLens graphLens, NamingLens namingLens, DexProgramClass clazz) {
- IdentityHashMap<DexString, List<DexEncodedMethod>> methodsByRenamedName =
+ IdentityHashMap<DexString, List<ProgramMethod>> methodsByRenamedName =
new IdentityHashMap<>(clazz.getMethodCollection().size());
- for (DexEncodedMethod encodedMethod : clazz.methods()) {
+ for (ProgramMethod programMethod : clazz.programMethods()) {
// Add method only if renamed, moved, or contains positions.
- DexMethod method = encodedMethod.getReference();
+ DexEncodedMethod definition = programMethod.getDefinition();
+ DexMethod method = programMethod.getReference();
DexString renamedName = namingLens.lookupName(method);
if (renamedName != method.name
|| graphLens.getOriginalMethodSignature(method) != method
- || doesContainPositions(encodedMethod)
- || encodedMethod.isD8R8Synthesized()) {
+ || doesContainPositions(definition)
+ || definition.isD8R8Synthesized()) {
methodsByRenamedName
.computeIfAbsent(renamedName, key -> new ArrayList<>())
- .add(encodedMethod);
+ .add(programMethod);
}
}
return methodsByRenamedName;
@@ -1117,7 +1120,7 @@
} else if (state.isOutline()) {
positionBuilder = OutlinePosition.builder();
} else {
- positionBuilder = SourcePosition.builder();
+ positionBuilder = SourcePosition.builder().setFile(state.getCurrentFile());
}
return positionBuilder
.setLine(state.getCurrentLine())
@@ -1206,10 +1209,10 @@
}
private static List<MappedPosition> optimizeCfCodePositions(
- DexEncodedMethod method, PositionRemapper positionRemapper, AppView<?> appView) {
+ ProgramMethod method, PositionRemapper positionRemapper, AppView<?> appView) {
List<MappedPosition> mappedPositions = new ArrayList<>();
// Do the actual processing for each method.
- CfCode oldCode = method.getCode().asCfCode();
+ CfCode oldCode = method.getDefinition().getCode().asCfCode();
List<CfInstruction> oldInstructions = oldCode.getInstructions();
List<CfInstruction> newInstructions = new ArrayList<>(oldInstructions.size());
for (CfInstruction oldInstruction : oldInstructions) {
diff --git a/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java b/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
index 8c3e592..a5bbfcb 100644
--- a/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
+++ b/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
@@ -79,8 +79,7 @@
private static DexProgramClass mergeClasses(
Reporter reporter, DexProgramClass a, DexProgramClass b) {
- if (a.type.isLegacySynthesizedTypeAllowedDuplication()
- || a.type.isSynthesizedTypeAllowedDuplication()) {
+ if (a.type.isLegacySynthesizedTypeAllowedDuplication()) {
assert assertEqualClasses(a, b);
return a;
}
diff --git a/src/main/java/com/android/tools/r8/utils/classhierarchy/MethodOverridesCollector.java b/src/main/java/com/android/tools/r8/utils/classhierarchy/MethodOverridesCollector.java
index bd63c2a..7407b59 100644
--- a/src/main/java/com/android/tools/r8/utils/classhierarchy/MethodOverridesCollector.java
+++ b/src/main/java/com/android/tools/r8/utils/classhierarchy/MethodOverridesCollector.java
@@ -111,7 +111,7 @@
SingleResolutionResult resolutionResult =
appView
.appInfo()
- .resolveMethodOnClass(interfaceMethod, implementer)
+ .resolveMethodOnClass(implementer, interfaceMethod)
.asSingleResolution();
if (resolutionResult == null || !resolutionResult.getResolvedHolder().isProgramClass()) {
continue;
diff --git a/src/main/java/com/android/tools/r8/utils/collections/LongLivedProgramMethodSetBuilder.java b/src/main/java/com/android/tools/r8/utils/collections/LongLivedProgramMethodSetBuilder.java
index ce4399b..735146a 100644
--- a/src/main/java/com/android/tools/r8/utils/collections/LongLivedProgramMethodSetBuilder.java
+++ b/src/main/java/com/android/tools/r8/utils/collections/LongLivedProgramMethodSetBuilder.java
@@ -13,7 +13,11 @@
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.DeterminismChecker.LineCallback;
import com.android.tools.r8.utils.SetUtils;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Set;
import java.util.function.IntFunction;
import java.util.function.Predicate;
@@ -184,4 +188,12 @@
!= null;
return true;
}
+
+ public void dump(LineCallback lineCallback) throws IOException {
+ List<DexMethod> sortedMethods = new ArrayList<>(methods);
+ sortedMethods.sort(DexMethod::compareTo);
+ for (DexMethod method : sortedMethods) {
+ lineCallback.onLine(method.toSourceString());
+ }
+ }
}
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 b14dd86..8292f14 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
@@ -71,8 +71,10 @@
return backing.remove(wrap(member));
}
- public void removeIf(BiPredicate<K, V> predicate) {
- backing.entrySet().removeIf(entry -> predicate.test(entry.getKey().get(), entry.getValue()));
+ public boolean removeIf(BiPredicate<K, V> predicate) {
+ return backing
+ .entrySet()
+ .removeIf(entry -> predicate.test(entry.getKey().get(), entry.getValue()));
}
abstract Wrapper<K> wrap(K member);
diff --git a/src/test/java/com/android/tools/r8/BackportedMethodListTest.java b/src/test/java/com/android/tools/r8/BackportedMethodListTest.java
index 6ed9d46..b2b78d1 100644
--- a/src/test/java/com/android/tools/r8/BackportedMethodListTest.java
+++ b/src/test/java/com/android/tools/r8/BackportedMethodListTest.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8;
+import static com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase.isJDK11DesugaredLibrary;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -68,21 +69,27 @@
backports.contains("java/lang/Short#toUnsignedLong(S)J"));
// Java 9, 10 and 11 Optional methods which require Android N or library desugaring.
+ // The methods are not backported in desugared library JDK 11 (already present).
assertEquals(
- mode == Mode.LIBRARY_DESUGAR || apiLevel >= AndroidApiLevel.N.getLevel(),
+ (mode == Mode.LIBRARY_DESUGAR && !isJDK11DesugaredLibrary())
+ || apiLevel >= AndroidApiLevel.N.getLevel(),
backports.contains(
"java/util/Optional#or(Ljava/util/function/Supplier;)Ljava/util/Optional;"));
assertEquals(
- mode == Mode.LIBRARY_DESUGAR || apiLevel >= AndroidApiLevel.N.getLevel(),
+ (mode == Mode.LIBRARY_DESUGAR && !isJDK11DesugaredLibrary())
+ || apiLevel >= AndroidApiLevel.N.getLevel(),
backports.contains("java/util/OptionalInt#orElseThrow()I"));
assertEquals(
- mode == Mode.LIBRARY_DESUGAR || apiLevel >= AndroidApiLevel.N.getLevel(),
+ (mode == Mode.LIBRARY_DESUGAR && !isJDK11DesugaredLibrary())
+ || apiLevel >= AndroidApiLevel.N.getLevel(),
backports.contains("java/util/OptionalLong#isEmpty()Z"));
- // Java 9, 10 and 11 methods added at API level S.
+ // Java 9, 10 and 11 method added at API level S.
assertEquals(
apiLevel < AndroidApiLevel.S.getLevel(),
backports.contains("java/lang/StrictMath#multiplyExact(JI)J"));
+ // Java 9, 10 and 11 method added at API level S.
+ // The method is not backported in desugared library JDK 11 (already present).
assertEquals(
apiLevel < AndroidApiLevel.S.getLevel(),
backports.contains("java/util/List#copyOf(Ljava/util/Collection;)Ljava/util/List;"));
@@ -97,7 +104,7 @@
builder
.addDesugaredLibraryConfiguration(
StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
- .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P.getLevel()));
+ .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.R.getLevel()));
}
@Test
diff --git a/src/test/java/com/android/tools/r8/JctfTestSpecifications.java b/src/test/java/com/android/tools/r8/JctfTestSpecifications.java
deleted file mode 100644
index 118f3b1..0000000
--- a/src/test/java/com/android/tools/r8/JctfTestSpecifications.java
+++ /dev/null
@@ -1,2027 +0,0 @@
-// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8;
-
-import static com.android.tools.r8.TestCondition.JAVA_RUNTIME;
-import static com.android.tools.r8.TestCondition.R8DEX_COMPILER;
-import static com.android.tools.r8.TestCondition.R8_COMPILER;
-import static com.android.tools.r8.TestCondition.and;
-import static com.android.tools.r8.TestCondition.any;
-import static com.android.tools.r8.TestCondition.anyDexVm;
-import static com.android.tools.r8.TestCondition.artRuntimesFrom;
-import static com.android.tools.r8.TestCondition.artRuntimesFromAndJava;
-import static com.android.tools.r8.TestCondition.artRuntimesUpTo;
-import static com.android.tools.r8.TestCondition.artRuntimesUpToAndJava;
-import static com.android.tools.r8.TestCondition.cf;
-import static com.android.tools.r8.TestCondition.match;
-import static com.android.tools.r8.TestCondition.runtimes;
-
-import com.android.tools.r8.R8RunArtTestsTest.CompilerUnderTest;
-import com.android.tools.r8.R8RunArtTestsTest.DexTool;
-import com.android.tools.r8.TestCondition.Runtime;
-import com.google.common.collect.ImmutableListMultimap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Multimap;
-import java.util.Collection;
-import java.util.Set;
-import java.util.function.BiFunction;
-
-public class JctfTestSpecifications {
-
- public enum Outcome {
- PASSES,
- FAILS_WHEN_RUN,
- TIMEOUTS_WHEN_RUN,
- FLAKY_WHEN_RUN
- }
-
- public static final Multimap<String, TestCondition> failuresToTriage =
- new ImmutableListMultimap.Builder<String, TestCondition>()
- .put("math.BigInteger.nextProbablePrime.BigInteger_nextProbablePrime_A02", anyDexVm())
- .put("math.BigInteger.ConstructorLjava_lang_String.BigInteger_Constructor_A02", any())
- .put(
- "lang.StringBuffer.insertILjava_lang_Object.StringBuffer_insert_A01",
- match(
- runtimes(
- Runtime.ART_DEFAULT, Runtime.ART_V9_0_0, Runtime.ART_V8_1_0, Runtime.JAVA)))
- .put("lang.StringBuffer.serialization.StringBuffer_serialization_A01", anyDexVm())
- .put(
- "lang.CloneNotSupportedException.serialization.CloneNotSupportedException_serialization_A01",
- anyDexVm())
- .put(
- "lang.NumberFormatException.serialization.NumberFormatException_serialization_A01",
- anyDexVm())
- .put(
- "lang.StrictMath.roundF.StrictMath_round_A01",
- match(
- runtimes(
- Runtime.ART_DEFAULT,
- Runtime.ART_V9_0_0,
- Runtime.ART_V8_1_0,
- Runtime.ART_V7_0_0,
- Runtime.JAVA)))
- .put(
- "lang.StrictMath.roundD.StrictMath_round_A01",
- match(
- runtimes(
- Runtime.ART_DEFAULT,
- Runtime.ART_V9_0_0,
- Runtime.ART_V8_1_0,
- Runtime.ART_V7_0_0,
- Runtime.JAVA)))
- .put("lang.StrictMath.atan2DD.StrictMath_atan2_A01", any())
- .put("lang.Thread.stop.Thread_stop_A05", any())
- .put("lang.Thread.resume.Thread_resume_A02", anyDexVm())
- .put("lang.Thread.suspend.Thread_suspend_A02", anyDexVm())
- .put("lang.Thread.stop.Thread_stop_A03", any())
- .put("lang.Thread.interrupt.Thread_interrupt_A03", any())
- .put("lang.Thread.stop.Thread_stop_A04", any())
- .put(
- "lang.Thread.ConstructorLjava_lang_ThreadGroupLjava_lang_RunnableLjava_lang_StringJ.Thread_Constructor_A01",
- match(
- runtimes(
- Runtime.ART_DEFAULT,
- Runtime.ART_V9_0_0,
- Runtime.ART_V8_1_0,
- Runtime.ART_V7_0_0,
- Runtime.ART_V6_0_1)))
- .put(
- "lang.Thread.getUncaughtExceptionHandler.Thread_getUncaughtExceptionHandler_A01",
- anyDexVm())
- .put("lang.Thread.getStackTrace.Thread_getStackTrace_A02", anyDexVm())
- .put("lang.Thread.enumerate_Ljava_lang_Thread.Thread_enumerate_A02", anyDexVm())
- .put("lang.Thread.countStackFrames.Thread_countStackFrames_A01", any())
- .put(
- "lang.Thread.getAllStackTraces.Thread_getAllStackTraces_A01",
- match(runtimes(Runtime.ART_V7_0_0)))
- .put("lang.Thread.destroy.Thread_destroy_A01", match(artRuntimesFrom(Runtime.ART_V4_4_4)))
- .put("lang.Thread.isAlive.Thread_isAlive_A01", anyDexVm())
- .put("lang.Thread.stopLjava_lang_Throwable.Thread_stop_A04", any())
- .put("lang.Thread.stopLjava_lang_Throwable.Thread_stop_A03", any())
- .put("lang.Thread.stopLjava_lang_Throwable.Thread_stop_A05", any())
- .put("lang.Thread.getPriority.Thread_getPriority_A01", anyDexVm())
- .put(
- "lang.Thread.getContextClassLoader.Thread_getContextClassLoader_A03",
- match(runtimes(Runtime.ART_V7_0_0)))
- .put("lang.OutOfMemoryError.serialization.OutOfMemoryError_serialization_A01", anyDexVm())
- .put(
- "lang.RuntimePermission.ConstructorLjava_lang_StringLjava_lang_String.RuntimePermission_Constructor_A01",
- anyDexVm())
- .put(
- "lang.RuntimePermission.serialization.RuntimePermission_serialization_A01",
- anyDexVm())
- .put(
- "lang.RuntimePermission.ConstructorLjava_lang_StringLjava_lang_String.RuntimePermission_Constructor_A02",
- anyDexVm())
- .put(
- "lang.RuntimePermission.ConstructorLjava_lang_StringLjava_lang_String.RuntimePermission_Constructor_A03",
- anyDexVm())
- .put("lang.RuntimePermission.Class.RuntimePermission_class_A17", any())
- .put(
- "lang.RuntimePermission.ConstructorLjava_lang_String.RuntimePermission_Constructor_A02",
- anyDexVm())
- .put(
- "lang.RuntimePermission.ConstructorLjava_lang_String.RuntimePermission_Constructor_A03",
- anyDexVm())
- .put(
- "lang.RuntimePermission.ConstructorLjava_lang_String.RuntimePermission_Constructor_A01",
- anyDexVm())
- .put("lang.RuntimePermission.Class.RuntimePermission_class_A26", any())
- .put("lang.RuntimePermission.Class.RuntimePermission_class_A04", any())
- .put("lang.RuntimePermission.Class.RuntimePermission_class_A03", any())
- .put("lang.RuntimePermission.Class.RuntimePermission_class_A25", any())
- .put("lang.RuntimePermission.Class.RuntimePermission_class_A06", any())
- .put("lang.RuntimePermission.Class.RuntimePermission_class_A21", any())
- .put("lang.RuntimePermission.Class.RuntimePermission_class_A22", any())
- .put("lang.RuntimePermission.Class.RuntimePermission_class_A11", any())
- .put("lang.RuntimePermission.Class.RuntimePermission_class_A08", any())
- .put("lang.RuntimePermission.Class.RuntimePermission_class_A16", any())
- .put("lang.RuntimePermission.Class.RuntimePermission_class_A12", any())
- .put("lang.RuntimePermission.Class.RuntimePermission_class_A24", any())
- .put("lang.RuntimePermission.Class.RuntimePermission_class_A23", any())
- .put("lang.RuntimePermission.Class.RuntimePermission_class_A18", any())
- .put("lang.RuntimePermission.Class.RuntimePermission_class_A19", any())
- .put("lang.RuntimePermission.Class.RuntimePermission_class_A07", any())
- .put("lang.RuntimePermission.Class.RuntimePermission_class_A20", any())
- .put("lang.RuntimePermission.Class.RuntimePermission_class_A15", any())
- .put("lang.RuntimePermission.Class.RuntimePermission_class_A05", any())
- .put("lang.RuntimePermission.Class.RuntimePermission_class_A09", any())
- .put("lang.RuntimePermission.Class.RuntimePermission_class_A10", any())
- .put("lang.RuntimePermission.Class.RuntimePermission_class_A01", any())
- .put(
- "lang.ClassLoader.defineClassLjava_lang_String_BII.ClassLoader_defineClass_A06",
- anyDexVm())
- .put("lang.RuntimePermission.Class.RuntimePermission_class_A14", any())
- .put(
- "lang.ClassLoader.defineClassLjava_lang_String_BII.ClassLoader_defineClass_A05",
- anyDexVm())
- .put(
- "lang.ClassLoader.defineClassLjava_lang_String_BII.ClassLoader_defineClass_A02",
- anyDexVm())
- .put(
- "lang.ClassLoader.defineClassLjava_lang_String_BII.ClassLoader_defineClass_A04",
- anyDexVm())
- .put(
- "lang.ClassLoader.defineClassLjava_lang_String_BII.ClassLoader_defineClass_A03",
- anyDexVm())
- .put(
- "lang.ClassLoader.defineClassLjava_lang_String_BII.ClassLoader_defineClass_A01",
- anyDexVm())
- .put(
- "lang.ClassLoader.defineClassLjava_lang_String_BII.ClassLoader_defineClass_A07",
- anyDexVm())
- .put(
- "lang.ClassLoader.setPackageAssertionStatusLjava_lang_StringZ.ClassLoader_setPackageAssertionStatus_A02",
- anyDexVm())
- .put(
- "lang.ClassLoader.setPackageAssertionStatusLjava_lang_StringZ.ClassLoader_setPackageAssertionStatus_A01",
- anyDexVm())
- .put(
- "lang.ClassLoader.setPackageAssertionStatusLjava_lang_StringZ.ClassLoader_setPackageAssertionStatus_A03",
- anyDexVm())
- .put("lang.ClassLoader.loadClassLjava_lang_StringZ.ClassLoader_loadClass_A03", anyDexVm())
- .put("lang.ClassLoader.loadClassLjava_lang_StringZ.ClassLoader_loadClass_A01", anyDexVm())
- .put("lang.ClassLoader.loadClassLjava_lang_StringZ.ClassLoader_loadClass_A04", anyDexVm())
- .put(
- "lang.ClassLoader.definePackageLjava_lang_String6Ljava_net_URL.ClassLoader_definePackage_A02",
- anyDexVm())
- .put(
- "lang.ClassLoader.definePackageLjava_lang_String6Ljava_net_URL.ClassLoader_definePackage_A01",
- anyDexVm())
- .put(
- "lang.ClassLoader.definePackageLjava_lang_String6Ljava_net_URL.ClassLoader_definePackage_A03",
- anyDexVm())
- .put(
- "lang.ClassLoader.defineClassLjava_lang_StringLjava_nio_ByteBufferLjava_security_ProtectionDomain.ClassLoader_defineClass_A05",
- anyDexVm())
- .put(
- "lang.ClassLoader.getResourceLjava_lang_String.ClassLoader_getResource_A01",
- anyDexVm())
- .put(
- "lang.ClassLoader.defineClassLjava_lang_StringLjava_nio_ByteBufferLjava_security_ProtectionDomain.ClassLoader_defineClass_A01",
- anyDexVm())
- .put(
- "lang.ClassLoader.defineClassLjava_lang_StringLjava_nio_ByteBufferLjava_security_ProtectionDomain.ClassLoader_defineClass_A02",
- anyDexVm())
- .put(
- "lang.ClassLoader.defineClassLjava_lang_StringLjava_nio_ByteBufferLjava_security_ProtectionDomain.ClassLoader_defineClass_A06",
- anyDexVm())
- .put(
- "lang.ClassLoader.defineClassLjava_lang_StringLjava_nio_ByteBufferLjava_security_ProtectionDomain.ClassLoader_defineClass_A03",
- anyDexVm())
- .put(
- "lang.ClassLoader.defineClassLjava_lang_StringLjava_nio_ByteBufferLjava_security_ProtectionDomain.ClassLoader_defineClass_A07",
- match(
- runtimes(
- Runtime.ART_DEFAULT,
- Runtime.ART_V9_0_0,
- Runtime.ART_V8_1_0,
- Runtime.ART_V7_0_0)))
- .put(
- "lang.ClassLoader.defineClassLjava_lang_StringLjava_nio_ByteBufferLjava_security_ProtectionDomain.ClassLoader_defineClass_A04",
- anyDexVm())
- .put(
- "lang.ClassLoader.setSignersLjava_lang_Class_Ljava_lang_Object.ClassLoader_setSigners_A01",
- anyDexVm())
- .put(
- "lang.ClassLoader.clearAssertionStatus.ClassLoader_clearAssertionStatus_A01",
- anyDexVm())
- .put("lang.ClassLoader.Constructor.ClassLoader_Constructor_A02", anyDexVm())
- .put(
- "lang.ClassLoader.getSystemResourceLjava_lang_String.ClassLoader_getSystemResource_A01",
- anyDexVm())
- .put(
- "lang.ClassLoader.getResourcesLjava_lang_String.ClassLoader_getResources_A01",
- anyDexVm())
- .put(
- "lang.ClassLoader.resolveClassLjava_lang_Class.ClassLoader_resolveClass_A02",
- anyDexVm())
- .put(
- "lang.ClassLoader.getResourceAsStreamLjava_lang_String.ClassLoader_getResourceAsStream_A01",
- anyDexVm())
- .put(
- "lang.ClassLoader.findLoadedClassLjava_lang_String.ClassLoader_findLoadedClass_A01",
- anyDexVm())
- .put(
- "lang.ClassLoader.defineClassLjava_lang_String_BIILjava_security_ProtectionDomain.ClassLoader_defineClass_A02",
- anyDexVm())
- .put(
- "lang.ClassLoader.resolveClassLjava_lang_Class.ClassLoader_resolveClass_A01",
- anyDexVm())
- .put(
- "lang.ClassLoader.setDefaultAssertionStatusZ.ClassLoader_setDefaultAssertionStatus_A01",
- anyDexVm())
- .put(
- "lang.ClassLoader.defineClassLjava_lang_String_BIILjava_security_ProtectionDomain.ClassLoader_defineClass_A05",
- anyDexVm())
- .put(
- "lang.ClassLoader.defineClassLjava_lang_String_BIILjava_security_ProtectionDomain.ClassLoader_defineClass_A01",
- anyDexVm())
- .put(
- "lang.ClassLoader.defineClassLjava_lang_String_BIILjava_security_ProtectionDomain.ClassLoader_defineClass_A06",
- anyDexVm())
- .put(
- "lang.ClassLoader.defineClassLjava_lang_String_BIILjava_security_ProtectionDomain.ClassLoader_defineClass_A08",
- anyDexVm())
- .put(
- "lang.ClassLoader.defineClassLjava_lang_String_BIILjava_security_ProtectionDomain.ClassLoader_defineClass_A03",
- anyDexVm())
- .put(
- "lang.ClassLoader.getSystemResourcesLjava_lang_String.ClassLoader_getSystemResources_A01",
- anyDexVm())
- .put(
- "lang.ClassLoader.defineClassLjava_lang_String_BIILjava_security_ProtectionDomain.ClassLoader_defineClass_A07",
- anyDexVm())
- .put(
- "lang.ClassLoader.defineClassLjava_lang_String_BIILjava_security_ProtectionDomain.ClassLoader_defineClass_A09",
- anyDexVm())
- .put(
- "lang.ClassLoader.defineClassLjava_lang_String_BIILjava_security_ProtectionDomain.ClassLoader_defineClass_A04",
- anyDexVm())
- .put("lang.ClassLoader.defineClass_BII.ClassLoader_defineClass_A02", anyDexVm())
- .put(
- "lang.ClassLoader.getSystemResourceAsStreamLjava_lang_String.ClassLoader_getSystemResourceAsStream_A01",
- anyDexVm())
- .put("lang.ClassLoader.getPackages.ClassLoader_getPackages_A01", anyDexVm())
- .put(
- "lang.ClassLoader.setClassAssertionStatusLjava_lang_StringZ.ClassLoader_setClassAssertionStatus_A01",
- any())
- .put("lang.ClassLoader.defineClass_BII.ClassLoader_defineClass_A03", anyDexVm())
- .put("lang.ClassLoader.defineClass_BII.ClassLoader_defineClass_A01", anyDexVm())
- .put("lang.ClassLoader.defineClass_BII.ClassLoader_defineClass_A04", anyDexVm())
- .put("lang.ClassLoader.getParent.ClassLoader_getParent_A01", anyDexVm())
- .put(
- "lang.ClassLoader.setClassAssertionStatusLjava_lang_StringZ.ClassLoader_setClassAssertionStatus_A04",
- any())
- .put(
- "lang.ClassLoader.setClassAssertionStatusLjava_lang_StringZ.ClassLoader_setClassAssertionStatus_A02",
- anyDexVm())
- .put("lang.ClassLoader.getParent.ClassLoader_getParent_A02", anyDexVm())
- .put(
- "lang.ClassLoader.getSystemClassLoader.ClassLoader_getSystemClassLoader_A02",
- anyDexVm())
- .put(
- "lang.ClassLoader.ConstructorLjava_lang_ClassLoader.ClassLoader_Constructor_A02",
- anyDexVm())
- .put(
- "lang.ClassLoader.findSystemClassLjava_lang_String.ClassLoader_findSystemClass_A04",
- anyDexVm())
- .put(
- "lang.ClassLoader.getPackageLjava_lang_String.ClassLoader_getPackage_A01", anyDexVm())
- .put(
- "lang.NoClassDefFoundError.serialization.NoClassDefFoundError_serialization_A01",
- anyDexVm())
- .put(
- "lang.TypeNotPresentException.serialization.TypeNotPresentException_serialization_A01",
- anyDexVm())
- .put(
- "lang.IndexOutOfBoundsException.serialization.IndexOutOfBoundsException_serialization_A01",
- anyDexVm())
- .put("lang.Enum.serialization.Enum_serialization_A01", anyDexVm())
- .put("lang.Enum.ConstructorLjava_lang_StringI.Enum_Constructor_A01", anyDexVm())
- .put("lang.InternalError.serialization.InternalError_serialization_A01", anyDexVm())
- .put("lang.Error.serialization.Error_serialization_A01", anyDexVm())
- .put("lang.Runtime.loadLjava_lang_String.Runtime_load_A02", any())
- .put("lang.Runtime.loadLjava_lang_String.Runtime_load_A05", any())
- .put("lang.Runtime.loadLjava_lang_String.Runtime_load_A03", any())
- .put("lang.Runtime.loadLjava_lang_String.Runtime_load_A04", any())
- .put("lang.Runtime.exec_Ljava_lang_String.Runtime_exec_A02", anyDexVm())
- .put("lang.Runtime.exec_Ljava_lang_String.Runtime_exec_A03", anyDexVm())
- .put("lang.Runtime.exec_Ljava_lang_String.Runtime_exec_A01", anyDexVm())
- .put("lang.Runtime.loadLibraryLjava_lang_String.Runtime_loadLibrary_A04", any())
- .put("lang.Runtime.loadLibraryLjava_lang_String.Runtime_loadLibrary_A05", any())
- .put("lang.Runtime.loadLibraryLjava_lang_String.Runtime_loadLibrary_A03", any())
- .put("lang.Runtime.execLjava_lang_String.Runtime_exec_A02", anyDexVm())
- .put("lang.Runtime.execLjava_lang_String.Runtime_exec_A03", anyDexVm())
- .put("lang.Runtime.loadLibraryLjava_lang_String.Runtime_loadLibrary_A02", any())
- .put("lang.Runtime.traceMethodCallsZ.Runtime_traceMethodCalls_A01", anyDexVm())
- .put(
- "lang.Runtime.addShutdownHookLjava_lang_Thread.Runtime_addShutdownHook_A01",
- anyDexVm())
- .put(
- "lang.Runtime.addShutdownHookLjava_lang_Thread.Runtime_addShutdownHook_A08",
- anyDexVm())
- .put("lang.Runtime.execLjava_lang_String.Runtime_exec_A01", anyDexVm())
- .put(
- "lang.Runtime.addShutdownHookLjava_lang_Thread.Runtime_addShutdownHook_A03",
- anyDexVm())
- .put(
- "lang.Runtime.addShutdownHookLjava_lang_Thread.Runtime_addShutdownHook_A07",
- anyDexVm())
- .put(
- "lang.Runtime.addShutdownHookLjava_lang_Thread.Runtime_addShutdownHook_A05",
- anyDexVm())
- .put(
- "lang.Runtime.addShutdownHookLjava_lang_Thread.Runtime_addShutdownHook_A06",
- anyDexVm())
- .put("lang.Runtime.execLjava_lang_String_Ljava_lang_String.Runtime_exec_A03", anyDexVm())
- .put("lang.Runtime.execLjava_lang_String_Ljava_lang_String.Runtime_exec_A02", anyDexVm())
- .put("lang.Runtime.execLjava_lang_String_Ljava_lang_String.Runtime_exec_A01", anyDexVm())
- .put(
- "lang.Runtime.removeShutdownHookLjava_lang_Thread.Runtime_removeShutdownHook_A02",
- anyDexVm())
- .put("lang.Runtime.exec_Ljava_lang_String_Ljava_lang_String.Runtime_exec_A01", anyDexVm())
- .put(
- "lang.Runtime.removeShutdownHookLjava_lang_Thread.Runtime_removeShutdownHook_A01",
- anyDexVm())
- .put("lang.Runtime.exec_Ljava_lang_String_Ljava_lang_String.Runtime_exec_A02", anyDexVm())
- .put(
- "lang.Runtime.removeShutdownHookLjava_lang_Thread.Runtime_removeShutdownHook_A03",
- anyDexVm())
- .put(
- "lang.Runtime.exec_Ljava_lang_String_Ljava_lang_StringLjava_io_File.Runtime_exec_A01",
- anyDexVm())
- .put("lang.Runtime.exec_Ljava_lang_String_Ljava_lang_String.Runtime_exec_A03", anyDexVm())
- .put(
- "lang.Runtime.exec_Ljava_lang_String_Ljava_lang_StringLjava_io_File.Runtime_exec_A02",
- anyDexVm())
- .put("lang.Runtime.haltI.Runtime_halt_A02", any())
- .put(
- "lang.Runtime.exec_Ljava_lang_String_Ljava_lang_StringLjava_io_File.Runtime_exec_A03",
- anyDexVm())
- .put("lang.Runtime.haltI.Runtime_halt_A03", any())
- .put("lang.Runtime.runFinalizersOnExitZ.Runtime_runFinalizersOnExit_A01", anyDexVm())
- .put("lang.Runtime.haltI.Runtime_halt_A01", any())
- .put("lang.Runtime.runFinalizersOnExitZ.Runtime_runFinalizersOnExit_A03", anyDexVm())
- .put(
- "lang.Runtime.execLjava_lang_String_Ljava_lang_StringLjava_io_File.Runtime_exec_A03",
- anyDexVm())
- .put(
- "lang.Runtime.execLjava_lang_String_Ljava_lang_StringLjava_io_File.Runtime_exec_A01",
- anyDexVm())
- .put("lang.Runtime.runFinalizersOnExitZ.Runtime_runFinalizersOnExit_A02", anyDexVm())
- .put("lang.Runtime.exitI.Runtime_exit_A03", any())
- .put(
- "lang.Runtime.execLjava_lang_String_Ljava_lang_StringLjava_io_File.Runtime_exec_A02",
- anyDexVm())
- .put("lang.Runtime.exitI.Runtime_exit_A04", any())
- .put(
- "lang.NoSuchMethodException.serialization.NoSuchMethodException_serialization_A01",
- anyDexVm())
- .put("lang.Runtime.exitI.Runtime_exit_A01", any())
- .put("lang.Runtime.exitI.Runtime_exit_A02", any())
- .put(
- "lang.InstantiationException.serialization.InstantiationException_serialization_A01",
- anyDexVm())
- .put("lang.Exception.serialization.Exception_serialization_A01", anyDexVm())
- .put(
- "lang.StackOverflowError.serialization.StackOverflowError_serialization_A01",
- anyDexVm())
- .put(
- "lang.NoSuchFieldException.serialization.NoSuchFieldException_serialization_A01",
- anyDexVm())
- .put(
- "lang.NegativeArraySizeException.serialization.NegativeArraySizeException_serialization_A01",
- anyDexVm())
- .put(
- "lang.ArrayIndexOutOfBoundsException.serialization.ArrayIndexOutOfBoundsException_serialization_A01",
- anyDexVm())
- .put("lang.VerifyError.serialization.VerifyError_serialization_A01", anyDexVm())
- .put(
- "lang.IllegalArgumentException.serialization.IllegalArgumentException_serialization_A01",
- anyDexVm())
- .put(
- "lang.IllegalStateException.serialization.IllegalStateException_serialization_A01",
- anyDexVm())
- .put("lang.Double.serialization.Double_serialization_A01", anyDexVm())
- .put("lang.Double.toStringD.Double_toString_A05", any())
- .put(
- "lang.ArithmeticException.serialization.ArithmeticException_serialization_A01",
- anyDexVm())
- .put(
- "lang.ExceptionInInitializerError.serialization.ExceptionInInitializerError_serialization_A01",
- anyDexVm())
- .put("lang.ThreadLocal.Class.ThreadLocal_class_A01", anyDexVm())
- .put("lang.Byte.serialization.Byte_serialization_A01", anyDexVm())
- .put(
- "lang.Byte.parseByteLjava_lang_StringI.Byte_parseByte_A02",
- match(
- runtimes(
- Runtime.ART_DEFAULT,
- Runtime.ART_V9_0_0,
- Runtime.ART_V8_1_0,
- Runtime.ART_V7_0_0,
- Runtime.ART_V6_0_1,
- Runtime.ART_V5_1_1,
- Runtime.JAVA)))
- .put(
- "lang.Byte.valueOfLjava_lang_StringI.Byte_valueOf_A02",
- match(
- runtimes(
- Runtime.ART_DEFAULT,
- Runtime.ART_V9_0_0,
- Runtime.ART_V8_1_0,
- Runtime.ART_V7_0_0,
- Runtime.ART_V6_0_1,
- Runtime.ART_V5_1_1,
- Runtime.JAVA)))
- .put(
- "lang.Byte.valueOfLjava_lang_String.Byte_ValueOf_A02",
- match(
- runtimes(
- Runtime.ART_DEFAULT,
- Runtime.ART_V9_0_0,
- Runtime.ART_V8_1_0,
- Runtime.ART_V7_0_0,
- Runtime.ART_V6_0_1,
- Runtime.ART_V5_1_1,
- Runtime.JAVA)))
- .put(
- "lang.Byte.decodeLjava_lang_String.Byte_decode_A04",
- match(
- runtimes(
- Runtime.ART_DEFAULT,
- Runtime.ART_V9_0_0,
- Runtime.ART_V8_1_0,
- Runtime.ART_V7_0_0,
- Runtime.ART_V6_0_1,
- Runtime.ART_V5_1_1,
- Runtime.JAVA)))
- .put("lang.LinkageError.serialization.LinkageError_serialization_A01", anyDexVm())
- .put(
- "lang.ClassCastException.serialization.ClassCastException_serialization_A01",
- anyDexVm())
- .put(
- "lang.Byte.ConstructorLjava_lang_String.Byte_Constructor_A02",
- match(
- runtimes(
- Runtime.ART_DEFAULT,
- Runtime.ART_V9_0_0,
- Runtime.ART_V8_1_0,
- Runtime.ART_V7_0_0,
- Runtime.ART_V6_0_1,
- Runtime.ART_V5_1_1,
- Runtime.JAVA)))
- .put(
- "lang.Byte.parseByteLjava_lang_String.Byte_parseByte_A02",
- match(
- runtimes(
- Runtime.ART_DEFAULT,
- Runtime.ART_V9_0_0,
- Runtime.ART_V8_1_0,
- Runtime.ART_V7_0_0,
- Runtime.ART_V6_0_1,
- Runtime.ART_V5_1_1,
- Runtime.JAVA)))
- .put("lang.NoSuchFieldError.serialization.NoSuchFieldError_serialization_A01", anyDexVm())
- .put(
- "lang.UnsupportedOperationException.serialization.UnsupportedOperationException_serialization_A01",
- anyDexVm())
- .put(
- "lang.NoSuchMethodError.serialization.NoSuchMethodError_serialization_A01",
- anyDexVm())
- .put(
- "lang.IllegalMonitorStateException.serialization.IllegalMonitorStateException_serialization_A01",
- anyDexVm())
- .put(
- "lang.StringIndexOutOfBoundsException.serialization.StringIndexOutOfBoundsException_serialization_A01",
- anyDexVm())
- .put(
- "lang.SecurityException.serialization.SecurityException_serialization_A01",
- anyDexVm())
- .put(
- "lang.IllegalAccessError.serialization.IllegalAccessError_serialization_A01",
- anyDexVm())
- .put(
- "lang.ArrayStoreException.serialization.ArrayStoreException_serialization_A01",
- anyDexVm())
- .put("lang.UnknownError.serialization.UnknownError_serialization_A01", anyDexVm())
- .put("lang.Boolean.serialization.Boolean_serialization_A01", anyDexVm())
- .put(
- "lang.Integer.valueOfLjava_lang_StringI.Integer_valueOf_A02",
- match(
- runtimes(
- Runtime.ART_DEFAULT,
- Runtime.ART_V9_0_0,
- Runtime.ART_V8_1_0,
- Runtime.ART_V7_0_0,
- Runtime.ART_V6_0_1,
- Runtime.ART_V5_1_1,
- Runtime.JAVA)))
- .put("lang.Integer.serialization.Integer_serialization_A01", anyDexVm())
- .put(
- "lang.Integer.parseIntLjava_lang_String.Integer_parseInt_A02",
- match(
- runtimes(
- Runtime.ART_DEFAULT,
- Runtime.ART_V9_0_0,
- Runtime.ART_V8_1_0,
- Runtime.ART_V7_0_0,
- Runtime.ART_V6_0_1,
- Runtime.ART_V5_1_1,
- Runtime.JAVA)))
- .put(
- "lang.Integer.getIntegerLjava_lang_StringI.Integer_getInteger_A02",
- match(
- runtimes(
- Runtime.ART_DEFAULT,
- Runtime.ART_V9_0_0,
- Runtime.ART_V8_1_0,
- Runtime.ART_V7_0_0,
- Runtime.ART_V6_0_1,
- Runtime.ART_V5_1_1,
- Runtime.JAVA)))
- .put(
- "lang.Integer.valueOfLjava_lang_String.Integer_valueOf_A02",
- match(
- runtimes(
- Runtime.ART_DEFAULT,
- Runtime.ART_V9_0_0,
- Runtime.ART_V8_1_0,
- Runtime.ART_V7_0_0,
- Runtime.ART_V6_0_1,
- Runtime.ART_V5_1_1,
- Runtime.JAVA)))
- .put(
- "lang.Integer.decodeLjava_lang_String.Integer_decode_A04",
- match(
- runtimes(
- Runtime.ART_DEFAULT,
- Runtime.ART_V9_0_0,
- Runtime.ART_V8_1_0,
- Runtime.ART_V7_0_0,
- Runtime.ART_V6_0_1,
- Runtime.ART_V5_1_1,
- Runtime.JAVA)))
- .put(
- "lang.Integer.parseIntLjava_lang_StringI.Integer_parseInt_A02",
- match(
- runtimes(
- Runtime.ART_DEFAULT,
- Runtime.ART_V9_0_0,
- Runtime.ART_V8_1_0,
- Runtime.ART_V7_0_0,
- Runtime.ART_V6_0_1,
- Runtime.ART_V5_1_1,
- Runtime.JAVA)))
- .put(
- "lang.Integer.getIntegerLjava_lang_StringLjava_lang_Integer.Integer_getInteger_A02",
- match(
- runtimes(
- Runtime.ART_DEFAULT,
- Runtime.ART_V9_0_0,
- Runtime.ART_V8_1_0,
- Runtime.ART_V7_0_0,
- Runtime.ART_V6_0_1,
- Runtime.ART_V5_1_1,
- Runtime.JAVA)))
- .put(
- "lang.Integer.ConstructorLjava_lang_String.Integer_Constructor_A02",
- match(
- runtimes(
- Runtime.ART_DEFAULT,
- Runtime.ART_V9_0_0,
- Runtime.ART_V8_1_0,
- Runtime.ART_V7_0_0,
- Runtime.ART_V6_0_1,
- Runtime.ART_V5_1_1,
- Runtime.JAVA)))
- .put(
- "lang.Integer.getIntegerLjava_lang_String.Integer_getInteger_A02",
- match(
- runtimes(
- Runtime.ART_DEFAULT,
- Runtime.ART_V9_0_0,
- Runtime.ART_V8_1_0,
- Runtime.ART_V7_0_0,
- Runtime.ART_V6_0_1,
- Runtime.ART_V5_1_1,
- Runtime.JAVA)))
- .put(
- "lang.ref.PhantomReference.isEnqueued.PhantomReference_isEnqueued_A01",
- match(
- runtimes(
- Runtime.ART_DEFAULT,
- Runtime.ART_V7_0_0,
- Runtime.ART_V6_0_1,
- Runtime.ART_V5_1_1)))
- .put(
- "lang.ref.SoftReference.isEnqueued.SoftReference_isEnqueued_A01",
- match(
- runtimes(
- Runtime.ART_DEFAULT,
- Runtime.ART_V7_0_0,
- Runtime.ART_V6_0_1,
- Runtime.ART_V5_1_1)))
- .put("lang.ref.SoftReference.get.SoftReference_get_A01", anyDexVm())
- .put("lang.ref.SoftReference.clear.SoftReference_clear_A01", cf())
- .put(
- "lang.ref.ReferenceQueue.poll.ReferenceQueue_poll_A01",
- match(
- runtimes(
- Runtime.ART_DEFAULT,
- Runtime.ART_V9_0_0,
- Runtime.ART_V8_1_0,
- Runtime.ART_V7_0_0,
- Runtime.ART_V6_0_1,
- Runtime.ART_V5_1_1)))
- .put(
- "lang.StackTraceElement.serialization.StackTraceElement_serialization_A01",
- anyDexVm())
- .put("lang.ref.WeakReference.get.WeakReference_get_A01", anyDexVm())
- .put(
- "lang.StackTraceElement.toString.StackTraceElement_toString_A01",
- match(runtimes(Runtime.ART_DEFAULT, Runtime.ART_V9_0_0, Runtime.ART_V8_1_0)))
- .put(
- "lang.NullPointerException.serialization.NullPointerException_serialization_A01",
- anyDexVm())
- .put(
- "lang.VirtualMachineError.serialization.VirtualMachineError_serialization_A01",
- anyDexVm())
- .put(
- "lang.ClassCircularityError.serialization.ClassCircularityError_serialization_A01",
- anyDexVm())
- .put("lang.ThreadDeath.serialization.ThreadDeath_serialization_A01", anyDexVm())
- .put(
- "lang.InstantiationError.serialization.InstantiationError_serialization_A01",
- anyDexVm())
- .put(
- "lang.IllegalThreadStateException.serialization.IllegalThreadStateException_serialization_A01",
- anyDexVm())
- .put("lang.ProcessBuilder.environment.ProcessBuilder_environment_A05", anyDexVm())
- .put("lang.ProcessBuilder.environment.ProcessBuilder_environment_A06", anyDexVm())
- .put("lang.ProcessBuilder.start.ProcessBuilder_start_A05", anyDexVm())
- .put("lang.ProcessBuilder.start.ProcessBuilder_start_A06", anyDexVm())
- .put("lang.ClassFormatError.serialization.ClassFormatError_serialization_A01", anyDexVm())
- .put("lang.Math.cbrtD.Math_cbrt_A01", match(artRuntimesFrom(Runtime.ART_V6_0_1)))
- .put("lang.Math.powDD.Math_pow_A08", anyDexVm())
- .put(
- "lang.IncompatibleClassChangeError.serialization.IncompatibleClassChangeError_serialization_A01",
- anyDexVm())
- .put("lang.Float.serialization.Float_serialization_A01", anyDexVm())
- .put("lang.Float.toStringF.Float_toString_A02", any())
- .put(
- "lang.Short.valueOfLjava_lang_StringI.Short_valueOf_A02",
- match(artRuntimesFromAndJava(Runtime.ART_V5_1_1)))
- .put(
- "lang.Short.valueOfLjava_lang_String.Short_valueOf_A02",
- match(artRuntimesFromAndJava(Runtime.ART_V5_1_1)))
- .put("lang.Short.serialization.Short_serialization_A01", anyDexVm())
- .put(
- "lang.Short.parseShortLjava_lang_String.Short_parseShort_A02",
- match(artRuntimesFromAndJava(Runtime.ART_V5_1_1)))
- .put(
- "lang.Short.decodeLjava_lang_String.Short_decode_A04",
- match(artRuntimesFromAndJava(Runtime.ART_V5_1_1)))
- .put(
- "lang.Short.ConstructorLjava_lang_String.Short_Constructor_A02",
- match(artRuntimesFromAndJava(Runtime.ART_V5_1_1)))
- .put(
- "lang.ClassNotFoundException.serialization.ClassNotFoundException_serialization_A01",
- anyDexVm())
- .put(
- "lang.annotation.AnnotationFormatError.serialization.AnnotationFormatError_serialization_A01",
- anyDexVm())
- .put(
- "lang.Short.parseShortLjava_lang_StringI.Short_parseShort_A02",
- match(artRuntimesFromAndJava(Runtime.ART_V5_1_1)))
- .put(
- "lang.annotation.IncompleteAnnotationException.ConstructorLjava_lang_ClassLjava_lang_String.IncompleteAnnotationException_Constructor_A01",
- match(
- runtimes(
- Runtime.ART_DEFAULT, Runtime.ART_V9_0_0, Runtime.ART_V8_1_0, Runtime.JAVA)))
- .put(
- "lang.InterruptedException.serialization.InterruptedException_serialization_A01",
- anyDexVm())
- .put(
- "lang.annotation.IncompleteAnnotationException.Class.IncompleteAnnotationException_class_A01",
- any())
- .put("lang.annotation.Annotation.Class.Annotation_class_A03", anyDexVm())
- .put("lang.annotation.Annotation.serialization.Annotation_serialization_A01", anyDexVm())
- .put(
- "lang.annotation.Annotation.annotationType.Annotation_annotationType_A01", anyDexVm())
- .put(
- "lang.annotation.IncompleteAnnotationException.serialization.IncompleteAnnotationException_serialization_A01",
- anyDexVm())
- .put("lang.annotation.Annotation.Class.Annotation_class_A02", any())
- .put("lang.annotation.Retention.Retention_class_A01", anyDexVm())
- .put(
- "lang.annotation.AnnotationTypeMismatchException.Class.AnnotationTypeMismatchException_class_A01",
- any())
- .put("lang.Long.serialization.Long_serialization_A01", anyDexVm())
- .put("lang.ThreadGroup.resume.ThreadGroup_resume_A01", anyDexVm())
- .put(
- "lang.AbstractMethodError.serialization.AbstractMethodError_serialization_A01",
- anyDexVm())
- .put("lang.RuntimeException.serialization.RuntimeException_serialization_A01", anyDexVm())
- .put("lang.ThreadGroup.suspend.ThreadGroup_suspend_A01", anyDexVm())
- .put(
- "lang.ThreadGroup.ConstructorLjava_lang_ThreadGroupLjava_lang_String.ThreadGroup_Constructor_A03",
- anyDexVm())
- .put("lang.ThreadGroup.stop.ThreadGroup_stop_A01", anyDexVm())
- .put("lang.ThreadGroup.enumerate_Thread.ThreadGroup_enumerate_A01", anyDexVm())
- .put(
- "lang.ThreadGroup.ConstructorLjava_lang_ThreadGroupLjava_lang_String.ThreadGroup_Constructor_A04",
- anyDexVm())
- .put(
- "lang.ThreadGroup.parentOfLjava_lang_ThreadGroup.ThreadGroup_parentOf_A01",
- anyDexVm())
- .put("lang.ThreadGroup.getMaxPriority.ThreadGroup_getMaxPriority_A02", anyDexVm())
- .put("lang.ThreadGroup.checkAccess.ThreadGroup_checkAccess_A03", anyDexVm())
- .put("lang.ThreadGroup.enumerate_ThreadZ.ThreadGroup_enumerate_A01", anyDexVm())
- .put(
- "lang.ThreadGroup.uncaughtExceptionLjava_lang_ThreadLjava_lang_Throwable.ThreadGroup_uncaughtException_A01",
- anyDexVm())
- .put("lang.ThreadGroup.checkAccess.ThreadGroup_checkAccess_A02", anyDexVm())
- .put(
- "lang.ThreadGroup.ConstructorLjava_lang_String.ThreadGroup_Constructor_A04",
- anyDexVm())
- .put("lang.ThreadGroup.activeCount.ThreadGroup_activeCount_A01", anyDexVm())
- .put("lang.ThreadGroup.setMaxPriorityI.ThreadGroup_setMaxPriority_A03", anyDexVm())
- .put(
- "lang.ThreadGroup.ConstructorLjava_lang_String.ThreadGroup_Constructor_A03",
- anyDexVm())
- .put("lang.ThreadGroup.getParent.ThreadGroup_getParent_A03", anyDexVm())
- .put("lang.Class.getDeclaredConstructors.Class_getDeclaredConstructors_A02", any())
- .put("lang.AssertionError.serialization.AssertionError_serialization_A01", anyDexVm())
- .put("lang.Class.getClassLoader.Class_getClassLoader_A01", anyDexVm())
- .put("lang.Class.getDeclaringClass.Class_getDeclaringClass_A01", anyDexVm())
- .put(
- "lang.Class.getDeclaredFields.Class_getDeclaredFields_A01",
- match(artRuntimesFrom(Runtime.ART_V5_1_1)))
- .put("lang.Class.getClassLoader.Class_getClassLoader_A02", anyDexVm())
- .put("lang.Class.getClassLoader.Class_getClassLoader_A03", anyDexVm())
- .put("lang.Class.getDeclaredFields.Class_getDeclaredFields_A02", any())
- .put("lang.Class.getResourceLjava_lang_String.Class_getResource_A01", anyDexVm())
- .put("lang.Class.getConstructor_Ljava_lang_Class.Class_getConstructor_A03", anyDexVm())
- .put(
- "lang.Class.forNameLjava_lang_StringZLjava_lang_ClassLoader.Class_forName_A03", any())
- .put(
- "lang.Class.forNameLjava_lang_StringZLjava_lang_ClassLoader.Class_forName_A07",
- anyDexVm())
- .put(
- "lang.Class.forNameLjava_lang_StringZLjava_lang_ClassLoader.Class_forName_A01",
- anyDexVm())
- .put("lang.Class.getConstructor_Ljava_lang_Class.Class_getConstructor_A04", any())
- .put("lang.Class.serialization.Class_serialization_A01", anyDexVm())
- .put("lang.Class.getMethods.Class_getMethods_A02", any())
- .put(
- "lang.Class.getDeclaredMethodLjava_lang_String_Ljava_lang_Class.Class_getDeclaredMethod_A05",
- any())
- .put("lang.Class.getClasses.Class_getClasses_A02", any())
- .put(
- "lang.Class.getDeclaredMethodLjava_lang_String_Ljava_lang_Class.Class_getDeclaredMethod_A03",
- anyDexVm())
- .put(
- "lang.Class.getClasses.Class_getClasses_A01",
- match(
- runtimes(
- Runtime.ART_DEFAULT,
- Runtime.ART_V9_0_0,
- Runtime.ART_V8_1_0,
- Runtime.ART_V7_0_0,
- Runtime.ART_V4_4_4,
- Runtime.ART_V4_0_4,
- Runtime.JAVA)))
- .put("lang.Class.getProtectionDomain.Class_getProtectionDomain_A01", any())
- .put("lang.Class.getProtectionDomain.Class_getProtectionDomain_A02", anyDexVm())
- .put(
- "lang.Class.getDeclaredMethods.Class_getDeclaredMethods_A01",
- match(artRuntimesFromAndJava(Runtime.ART_V7_0_0)))
- .put(
- "lang.Class.getMethods.Class_getMethods_A01",
- match(artRuntimesFromAndJava(Runtime.ART_V7_0_0)))
- .put("lang.Class.getGenericInterfaces.Class_getGenericInterfaces_A04", any())
- .put("lang.Class.getDeclaredFieldLjava_lang_String.Class_getDeclaredField_A04", any())
- .put("lang.Class.getDeclaredMethods.Class_getDeclaredMethods_A02", any())
- .put(
- "lang.Class.getResourceAsStreamLjava_lang_String.Class_getResourceAsStream_A01",
- anyDexVm())
- .put("lang.Class.getGenericInterfaces.Class_getGenericInterfaces_A05", any())
- .put("lang.Class.getAnnotationLjava_lang_Class.Class_getAnnotation_A01", any())
- .put("lang.Class.getGenericInterfaces.Class_getGenericInterfaces_A03", any())
- .put("lang.Class.getDeclaredClasses.Class_getDeclaredClasses_A02", any())
- .put("lang.Class.desiredAssertionStatus.Class_desiredAssertionStatus_A01", anyDexVm())
- .put("lang.Class.getPackage.Class_getPackage_A01", anyDexVm())
- .put("lang.Class.getFieldLjava_lang_String.Class_getField_A04", any())
- .put("lang.Class.getTypeParameters.Class_getTypeParameters_A02", any())
- .put("lang.Class.getDeclaredAnnotations.Class_getDeclaredAnnotations_A01", any())
- .put("lang.Class.getConstructors.Class_getConstructors_A02", any())
- .put(
- "lang.Class.isAnnotationPresentLjava_lang_Class.Class_isAnnotationPresent_A01", any())
- .put("lang.Class.getFields.Class_getFields_A02", any())
- .put("lang.Class.getGenericSuperclass.Class_getGenericSuperclass_A03", any())
- .put("lang.Class.getGenericSuperclass.Class_getGenericSuperclass_A04", any())
- .put("lang.Class.getSigners.Class_getSigners_A01", anyDexVm())
- .put(
- "lang.Class.getMethodLjava_lang_String_Ljava_lang_Class.Class_getMethod_A01",
- match(
- runtimes(
- Runtime.ART_DEFAULT,
- Runtime.ART_V9_0_0,
- Runtime.ART_V8_1_0,
- Runtime.ART_V7_0_0,
- Runtime.ART_V4_4_4,
- Runtime.ART_V4_0_4)))
- .put(
- "lang.Class.getModifiers.Class_getModifiers_A03", match(runtimes(Runtime.ART_V4_0_4)))
- .put("lang.Class.newInstance.Class_newInstance_A06", match(runtimes(Runtime.ART_V4_0_4)))
- .put("lang.Class.getGenericSuperclass.Class_getGenericSuperclass_A01", any())
- .put("lang.Class.getGenericSuperclass.Class_getGenericSuperclass_A02", any())
- .put("lang.Class.newInstance.Class_newInstance_A07", any())
- .put(
- "lang.Class.getDeclaredConstructor_Ljava_lang_Class.Class_getDeclaredConstructor_A02",
- anyDexVm())
- .put("lang.Class.getMethodLjava_lang_String_Ljava_lang_Class.Class_getMethod_A05", any())
- .put("lang.Class.forNameLjava_lang_String.Class_forName_A01", anyDexVm())
- .put(
- "lang.Class.getDeclaredConstructor_Ljava_lang_Class.Class_getDeclaredConstructor_A03",
- any())
- .put(
- "lang.Class.getMethodLjava_lang_String_Ljava_lang_Class.Class_getMethod_A03",
- anyDexVm())
- .put("lang.Class.forNameLjava_lang_String.Class_forName_A02", any())
- .put(
- "lang.UnsatisfiedLinkError.serialization.UnsatisfiedLinkError_serialization_A01",
- anyDexVm())
- .put("lang.Class.getAnnotations.Class_getAnnotations_A01", any())
- .put(
- "lang.EnumConstantNotPresentException.serialization.EnumConstantNotPresentException_serialization_A01",
- anyDexVm())
- .put("lang.String.toLowerCase.String_toLowerCase_A01", any())
- .put("lang.String.splitLjava_lang_StringI.String_split_A01", any())
- .put("lang.String.serialization.String_serialization_A01", anyDexVm())
- .put("lang.String.regionMatchesZILjava_lang_StringII.String_regionMatches_A01", any())
- .put("lang.String.valueOfF.String_valueOf_A01", any())
- .put("lang.String.Constructor_BLjava_nio_charset_Charset.String_Constructor_A01", any())
- .put("lang.String.concatLjava_lang_String.String_concat_A01", anyDexVm())
- .put("lang.String.matchesLjava_lang_String.String_matches_A01", anyDexVm())
- .put(
- "lang.String.CASE_INSENSITIVE_ORDER.serialization.String_serialization_A01",
- anyDexVm())
- .put(
- "lang.String.getBytesLjava_lang_String.String_getBytes_A14",
- match(artRuntimesUpTo(Runtime.ART_V7_0_0)))
- .put("lang.String.splitLjava_lang_String.String_split_A01", any())
- .put("lang.String.getBytesII_BI.String_getBytes_A03", anyDexVm())
- .put("lang.String.getBytesII_BI.String_getBytes_A02", anyDexVm())
- .put("lang.String.toLowerCaseLjava_util_Locale.String_toLowerCase_A01", any())
- .put("lang.String.Constructor_BIILjava_nio_charset_Charset.String_Constructor_A01", any())
- .put("lang.String.getBytesLjava_nio_charset_Charset.String_getBytes_A01", anyDexVm())
- .put("lang.String.valueOfD.String_valueOf_A01", any())
- .put(
- "lang.String.getBytesLjava_nio_charset_Charset.String_getBytes_A14",
- match(artRuntimesUpTo(Runtime.ART_V7_0_0)))
- .put("lang.Package.isSealed.Package_isSealed_A01", anyDexVm())
- .put(
- "lang.Package.getSpecificationVersion.Package_getSpecificationVersion_A01",
- anyDexVm())
- .put("lang.Package.getAnnotationLjava_lang_Class.Package_getAnnotation_A01", any())
- .put(
- "lang.Package.isAnnotationPresentLjava_lang_Class.Package_isAnnotationPresent_A02",
- match(and(runtimes(Runtime.ART_V4_0_4), artRuntimesFrom(Runtime.ART_V7_0_0))))
- .put("lang.Package.getName.Package_getName_A01", anyDexVm())
- .put(
- "lang.Package.getImplementationVersion.Package_getImplementationVersion_A01",
- anyDexVm())
- .put("lang.Package.getDeclaredAnnotations.Package_getDeclaredAnnotations_A01", any())
- .put("lang.Package.getSpecificationVendor.Package_getSpecificationVendor_A01", anyDexVm())
- .put(
- "lang.Package.getAnnotationLjava_lang_Class.Package_getAnnotation_A02",
- match(and(artRuntimesFrom(Runtime.ART_V7_0_0), runtimes(Runtime.ART_V4_0_4))))
- .put(
- "lang.Package.isCompatibleWithLjava_lang_String.Package_isCompatibleWith_A01",
- anyDexVm())
- .put("lang.Package.toString.Package_toString_A01", anyDexVm())
- .put("lang.Package.getAnnotations.Package_getAnnotations_A01", any())
- .put(
- "lang.Package.isAnnotationPresentLjava_lang_Class.Package_isAnnotationPresent_A01",
- any())
- .put("lang.Package.getSpecificationTitle.Package_getSpecificationTitle_A01", anyDexVm())
- .put("lang.Package.getImplementationTitle.Package_getImplementationTitle_A01", anyDexVm())
- .put("lang.Package.getPackages.Package_getPackages_A01", anyDexVm())
- .put("lang.Package.hashCode.Package_hashCode_A01", anyDexVm())
- .put("lang.Package.getPackageLjava_lang_String.Package_getPackage_A01", anyDexVm())
- .put(
- "lang.Package.getImplementationVendor.Package_getImplementationVendor_A01",
- anyDexVm())
- .put("lang.Package.isSealedLjava_net_URL.Package_isSealed_A01", anyDexVm())
- .put("lang.StringBuilder.serialization.StringBuilder_serialization_A01", anyDexVm())
- .put(
- "lang.SecurityManager.checkReadLjava_io_FileDescriptor.SecurityManager_checkRead_A02",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkAwtEventQueueAccess.SecurityManager_checkAwtEventQueueAccess_A01",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkWriteLjava_lang_String.SecurityManager_checkWrite_A02",
- anyDexVm())
- .put("lang.SecurityManager.inClassLoader.SecurityManager_inClassLoader_A01", anyDexVm())
- .put(
- "lang.SecurityManager.checkPermissionLjava_security_PermissionLjava_lang_Object.SecurityManager_checkPermission_A02",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkReadLjava_io_FileDescriptor.SecurityManager_checkRead_A01",
- anyDexVm())
- .put("lang.SecurityManager.inCheck.SecurityManager_inCheck_A01", anyDexVm())
- .put(
- "lang.SecurityManager.currentClassLoader.SecurityManager_currentClassLoader_A02",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkPrintJobAccess.SecurityManager_checkPrintJobAccess_A01",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkWriteLjava_lang_String.SecurityManager_checkWrite_A01",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkPackageAccessLjava_lang_String.SecurityManager_checkPackageAccess_A02",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkAcceptLjava_lang_StringI.SecurityManager_checkAccept_A02",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkPermissionLjava_security_PermissionLjava_lang_Object.SecurityManager_checkPermission_A01",
- anyDexVm())
- .put(
- "lang.SecurityManager.currentClassLoader.SecurityManager_currentClassLoader_A01",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkMulticastLjava_net_InetAddress.SecurityManager_checkMulticast_A02",
- anyDexVm())
- .put("lang.SecurityManager.checkListenI.SecurityManager_checkListen_A01", anyDexVm())
- .put(
- "lang.SecurityManager.getSecurityContext.SecurityManager_getSecurityContext_A01",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkPackageAccessLjava_lang_String.SecurityManager_checkPackageAccess_A01",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkMemberAccessLjava_lang_ClassI.SecurityManager_checkMemberAccess_A02",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkMulticastLjava_net_InetAddressB.SecurityManager_checkMulticast_A02",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkAcceptLjava_lang_StringI.SecurityManager_checkAccept_A01",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkMulticastLjava_net_InetAddress.SecurityManager_checkMulticast_A01",
- anyDexVm())
- .put("lang.SecurityManager.Constructor.SecurityManager_Constructor_A01", anyDexVm())
- .put(
- "lang.SecurityManager.getClassContext.SecurityManager_getClassContext_A01",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkMemberAccessLjava_lang_ClassI.SecurityManager_checkMemberAccess_A03",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkDeleteLjava_lang_String.SecurityManager_checkDelete_A01",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkReadLjava_lang_StringLjava_lang_Object.SecurityManager_checkRead_A03",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkMulticastLjava_net_InetAddressB.SecurityManager_checkMulticast_A01",
- anyDexVm())
- .put("lang.SecurityManager.checkListenI.SecurityManager_checkListen_A02", any())
- .put(
- "lang.SecurityManager.checkAccessLjava_lang_Thread.SecurityManager_checkAccess_A01",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkWriteLjava_io_FileDescriptor.SecurityManager_checkWrite_A02",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkDeleteLjava_lang_String.SecurityManager_checkDelete_A02",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkPropertiesAccess.SecurityManager_checkPropertiesAccess_A01",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkReadLjava_lang_StringLjava_lang_Object.SecurityManager_checkRead_A02",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkAccessLjava_lang_ThreadGroup.SecurityManager_checkAccess_A03",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkAccessLjava_lang_Thread.SecurityManager_checkAccess_A03",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkPackageDefinitionLjava_lang_String.SecurityManager_checkPackageDefinition_A02",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkReadLjava_lang_String.SecurityManager_checkRead_A02",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkWriteLjava_io_FileDescriptor.SecurityManager_checkWrite_A01",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkReadLjava_lang_StringLjava_lang_Object.SecurityManager_checkRead_A01",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkExecLjava_lang_String.SecurityManager_checkExec_A03",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkPackageDefinitionLjava_lang_String.SecurityManager_checkPackageDefinition_A01",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkExecLjava_lang_String.SecurityManager_checkExec_A02",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkCreateClassLoader.SecurityManager_checkCreateClassLoader_A01",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkReadLjava_lang_String.SecurityManager_checkRead_A01",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkAccessLjava_lang_ThreadGroup.SecurityManager_checkAccess_A01",
- anyDexVm())
- .put(
- "lang.SecurityManager.inClassLjava_lang_String.SecurityManager_inClass_A03",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkConnectLjava_lang_StringILjava_lang_Object.SecurityManager_checkConnect_A03",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkExecLjava_lang_String.SecurityManager_checkExec_A01",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkSetFactory.SecurityManager_checkSetFactory_A01",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkConnectLjava_lang_StringILjava_lang_Object.SecurityManager_checkConnect_A04",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkPermissionLjava_security_Permission.SecurityManager_checkPermission_A01",
- anyDexVm())
- .put(
- "lang.SecurityManager.inClassLjava_lang_String.SecurityManager_inClass_A01",
- anyDexVm())
- .put(
- "lang.SecurityManager.inClassLjava_lang_String.SecurityManager_inClass_A02",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkPropertyAccessLjava_lang_String.SecurityManager_checkPropertyAccess_A02",
- anyDexVm())
- .put("lang.SecurityManager.checkExitI.SecurityManager_checkExit_A01", anyDexVm())
- .put(
- "lang.SecurityManager.checkConnectLjava_lang_StringILjava_lang_Object.SecurityManager_checkConnect_A02",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkConnectLjava_lang_StringILjava_lang_Object.SecurityManager_checkConnect_A01",
- anyDexVm())
- .put(
- "lang.SecurityManager.classLoaderDepth.SecurityManager_classLoaderDepth_A02",
- anyDexVm())
- .put(
- "lang.SecurityManager.classDepthLjava_lang_String.SecurityManager_classDepth_A02",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkPropertyAccessLjava_lang_String.SecurityManager_checkPropertyAccess_A01",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkPropertyAccessLjava_lang_String.SecurityManager_checkPropertyAccess_A03",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkConnectLjava_lang_StringI.SecurityManager_checkConnect_A02",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkLinkLjava_lang_String.SecurityManager_checkLink_A02",
- anyDexVm())
- .put(
- "lang.SecurityManager.classLoaderDepth.SecurityManager_classLoaderDepth_A01",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkPermissionLjava_security_Permission.SecurityManager_checkPermission_A02",
- anyDexVm())
- .put(
- "lang.SecurityManager.currentLoadedClass.SecurityManager_currentLoadedClass_A01",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkSecurityAccessLjava_lang_String.SecurityManager_checkSecurityAccess_A03",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkConnectLjava_lang_StringI.SecurityManager_checkConnect_A03",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkConnectLjava_lang_StringI.SecurityManager_checkConnect_A01",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkTopLevelWindowLjava_lang_Object.SecurityManager_checkTopLevelWindow_A02",
- anyDexVm())
- .put(
- "lang.SecurityManager.currentLoadedClass.SecurityManager_currentLoadedClass_A02",
- anyDexVm())
- .put(
- "lang.SecurityManager.classDepthLjava_lang_String.SecurityManager_classDepth_A01",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkSecurityAccessLjava_lang_String.SecurityManager_checkSecurityAccess_A01",
- anyDexVm())
- .put("lang.Throwable.serialization.Throwable_serialization_A01", anyDexVm())
- .put(
- "lang.SecurityManager.checkTopLevelWindowLjava_lang_Object.SecurityManager_checkTopLevelWindow_A01",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkLinkLjava_lang_String.SecurityManager_checkLink_A01",
- anyDexVm())
- .put("lang.Throwable.getStackTrace.Throwable_getStackTrace_A01", anyDexVm())
- .put(
- "lang.SecurityManager.checkSystemClipboardAccess.SecurityManager_checkSystemClipboardAccess_A01",
- anyDexVm())
- .put(
- "lang.SecurityManager.checkSecurityAccessLjava_lang_String.SecurityManager_checkSecurityAccess_A02",
- anyDexVm())
- .put(
- "lang.reflect.ReflectPermission.Constructor_java_lang_String.ReflectPermission_Constructor_A03",
- anyDexVm())
- .put(
- "lang.reflect.MalformedParameterizedTypeException.serialization.MalformedParameterizedTypeException_serialization_A01",
- anyDexVm())
- .put(
- "lang.reflect.ReflectPermission.Constructor_java_lang_StringLjava_lang_String.ReflectPermission_Constructor_A02",
- anyDexVm())
- .put(
- "lang.UnsupportedClassVersionError.serialization.UnsupportedClassVersionError_serialization_A01",
- anyDexVm())
- .put(
- "lang.reflect.ReflectPermission.Constructor_java_lang_String.ReflectPermission_Constructor_A01",
- any())
- .put("lang.reflect.ReflectPermission.Class.ReflectPermission_class_A01", anyDexVm())
- .put("lang.reflect.Proxy.serialization.Proxy_serialization_A01", any())
- .put(
- "lang.reflect.ReflectPermission.Constructor_java_lang_StringLjava_lang_String.ReflectPermission_Constructor_A03",
- anyDexVm())
- .put(
- "lang.reflect.ReflectPermission.Constructor_java_lang_String.ReflectPermission_Constructor_A02",
- anyDexVm())
- .put("lang.reflect.ReflectPermission.Class.ReflectPermission_class_A02", anyDexVm())
- .put(
- "lang.reflect.ReflectPermission.Constructor_java_lang_StringLjava_lang_String.ReflectPermission_Constructor_A01",
- any())
- .put(
- "lang.reflect.Proxy.getInvocationHandlerLjava_lang_Object.Proxy_getInvocationHandler_A02",
- match(artRuntimesFromAndJava(Runtime.ART_V5_1_1)))
- .put("lang.reflect.Proxy.Class.Proxy_class_A01", any())
- .put(
- "lang.reflect.Proxy.Class.Proxy_class_A02",
- match(artRuntimesUpTo(Runtime.ART_V4_4_4)))
- .put(
- "lang.reflect.Proxy.Class.Proxy_class_A03",
- match(artRuntimesUpTo(Runtime.ART_V4_4_4)))
- .put(
- "lang.reflect.Proxy.getProxyClassLjava_lang_ClassLoader_Ljava_lang_Class.Proxy_getProxyClass_A01",
- anyDexVm())
- .put(
- "lang.reflect.Proxy.getProxyClassLjava_lang_ClassLoader_Ljava_lang_Class.Proxy_getProxyClass_A03",
- anyDexVm())
- .put(
- "lang.reflect.Proxy.h.Proxy_h_A01",
- match(
- runtimes(
- Runtime.ART_DEFAULT, Runtime.ART_V9_0_0, Runtime.ART_V8_1_0, Runtime.JAVA)))
- .put("lang.reflect.Proxy.serialization.Proxy_serialization_A02", any())
- .put(
- "lang.reflect.GenericSignatureFormatError.serialization.GenericSignatureFormatError_serialization_A01",
- anyDexVm())
- .put(
- "lang.reflect.Proxy.newProxyInstanceLjava_lang_ClassLoader_Ljava_lang_ClassLjava_lang_reflect_InvocationHandler.Proxy_newProxyInstance_A02",
- anyDexVm())
- .put(
- "lang.reflect.Proxy.ConstructorLjava_lang_reflect_InvocationHandler.Proxy_Constructor_A01",
- match(
- runtimes(
- Runtime.ART_DEFAULT, Runtime.ART_V9_0_0, Runtime.ART_V8_1_0, Runtime.JAVA)))
- .put(
- "lang.reflect.Proxy.newProxyInstanceLjava_lang_ClassLoader_Ljava_lang_ClassLjava_lang_reflect_InvocationHandler.Proxy_newProxyInstance_A01",
- anyDexVm())
- .put("lang.reflect.Modifier.isStrictI.Modifier_isStrict_A01", any())
- .put("lang.reflect.Method.getGenericReturnType.Method_getGenericReturnType_A03", any())
- .put("lang.reflect.Method.getGenericReturnType.Method_getGenericReturnType_A02", any())
- .put("lang.reflect.Method.getAnnotationLjava_lang_Class.Method_getAnnotation_A01", any())
- .put(
- "lang.reflect.Method.getGenericExceptionTypes.Method_getGenericExceptionTypes_A02",
- any())
- .put("lang.reflect.Method.isBridge.Method_isBridge_A01", any())
- .put("lang.reflect.Method.isSynthetic.Method_isSynthetic_A01", any())
- .put("lang.reflect.Method.getGenericReturnType.Method_getGenericReturnType_A04", any())
- .put(
- "lang.reflect.Method.getGenericExceptionTypes.Method_getGenericExceptionTypes_A01",
- any())
- .put(
- "lang.reflect.Method.invokeLjava_lang_Object_Ljava_lang_Object.Method_invoke_A07",
- anyDexVm())
- .put(
- "lang.reflect.Method.getGenericExceptionTypes.Method_getGenericExceptionTypes_A04",
- any())
- .put("lang.reflect.Method.getTypeParameters.Method_getTypeParameters_A02", any())
- .put(
- "lang.reflect.Method.getGenericExceptionTypes.Method_getGenericExceptionTypes_A03",
- any())
- .put(
- "lang.reflect.Method.getDeclaredAnnotations.Method_getDeclaredAnnotations_A01", any())
- .put(
- "lang.reflect.Method.getGenericParameterTypes.Method_getGenericParameterTypes_A04",
- any())
- .put("lang.reflect.Method.toGenericString.Method_toGenericString_A01", any())
- .put(
- "lang.reflect.Method.getGenericParameterTypes.Method_getGenericParameterTypes_A03",
- any())
- .put(
- "lang.reflect.InvocationHandler.invokeLjava_lang_ObjectLjava_lang_reflect_Method_Ljava_lang_Object.InvocationHandler_invoke_A01",
- match(artRuntimesUpTo(Runtime.ART_V4_4_4)))
- .put(
- "lang.reflect.InvocationHandler.invokeLjava_lang_ObjectLjava_lang_reflect_Method_Ljava_lang_Object.InvocationHandler_invoke_A02",
- anyDexVm())
- .put("lang.reflect.Method.getDefaultValue.Method_getDefaultValue_A02", any())
- .put(
- "lang.reflect.Method.hashCode.Method_hashCode_A01",
- match(artRuntimesUpTo(Runtime.ART_V4_4_4)))
- .put("lang.reflect.Method.toString.Method_toString_A01", any())
- .put(
- "lang.reflect.Method.getGenericParameterTypes.Method_getGenericParameterTypes_A02",
- any())
- .put("lang.reflect.Field.getFloatLjava_lang_Object.Field_getFloat_A05", anyDexVm())
- .put("lang.reflect.Field.getDeclaringClass.Field_getDeclaringClass_A01", anyDexVm())
- .put("lang.reflect.Field.getByteLjava_lang_Object.Field_getByte_A05", anyDexVm())
- .put("lang.reflect.Field.getCharLjava_lang_Object.Field_getChar_A05", anyDexVm())
- .put("lang.reflect.Field.getBooleanLjava_lang_Object.Field_getBoolean_A05", anyDexVm())
- .put("lang.reflect.Field.setByteLjava_lang_ObjectB.Field_setByte_A05", anyDexVm())
- .put("lang.reflect.Field.setByteLjava_lang_ObjectB.Field_setByte_A01", anyDexVm())
- .put(
- "lang.reflect.Field.setByteLjava_lang_ObjectB.Field_setByte_A02",
- match(artRuntimesUpTo(Runtime.ART_V4_4_4)))
- .put("lang.reflect.Field.setBooleanLjava_lang_ObjectZ.Field_setBoolean_A01", anyDexVm())
- .put(
- "lang.reflect.Field.setBooleanLjava_lang_ObjectZ.Field_setBoolean_A02",
- match(artRuntimesUpTo(Runtime.ART_V4_4_4)))
- .put("lang.reflect.Field.setCharLjava_lang_ObjectC.Field_setChar_A05", anyDexVm())
- .put("lang.reflect.Field.isSynthetic.Field_isSynthetic_A01", any())
- .put("lang.reflect.Field.setBooleanLjava_lang_ObjectZ.Field_setBoolean_A05", anyDexVm())
- .put("lang.reflect.Field.getType.Field_getType_A01", anyDexVm())
- .put("lang.reflect.Field.setCharLjava_lang_ObjectC.Field_setChar_A01", anyDexVm())
- .put(
- "lang.reflect.Field.setCharLjava_lang_ObjectC.Field_setChar_A02",
- match(artRuntimesUpTo(Runtime.ART_V4_4_4)))
- .put("lang.reflect.Field.getDoubleLjava_lang_Object.Field_getDouble_A05", anyDexVm())
- .put("lang.reflect.Field.setFloatLjava_lang_ObjectF.Field_setFloat_A01", anyDexVm())
- .put(
- "lang.reflect.Field.setFloatLjava_lang_ObjectF.Field_setFloat_A02",
- match(artRuntimesUpTo(Runtime.ART_V4_4_4)))
- .put("lang.reflect.Field.getAnnotationLjava_lang_Class.Field_getAnnotation_A01", any())
- .put(
- "lang.reflect.Field.setIntLjava_lang_ObjectI.Field_setInt_A02",
- match(artRuntimesUpTo(Runtime.ART_V4_4_4)))
- .put("lang.reflect.Field.getIntLjava_lang_Object.Field_getInt_A05", anyDexVm())
- .put("lang.reflect.Field.setFloatLjava_lang_ObjectF.Field_setFloat_A05", anyDexVm())
- .put("lang.reflect.Field.getShortLjava_lang_Object.Field_getShort_A05", anyDexVm())
- .put("lang.reflect.Field.getGenericType.Field_getGenericType_A03", any())
- .put("lang.reflect.Field.getDeclaredAnnotations.Field_getDeclaredAnnotations_A01", any())
- .put("lang.reflect.Field.getGenericType.Field_getGenericType_A01", anyDexVm())
- .put("lang.reflect.Field.setIntLjava_lang_ObjectI.Field_setInt_A05", anyDexVm())
- .put("lang.reflect.Field.getGenericType.Field_getGenericType_A02", any())
- .put("lang.reflect.Field.toGenericString.Field_toGenericString_A01", anyDexVm())
- .put("lang.reflect.Field.getGenericType.Field_getGenericType_A04", any())
- .put("lang.reflect.Field.setIntLjava_lang_ObjectI.Field_setInt_A01", anyDexVm())
- .put(
- "lang.reflect.Field.setDoubleLjava_lang_ObjectD.Field_setDouble_A02",
- match(artRuntimesUpTo(Runtime.ART_V4_4_4)))
- .put("lang.reflect.Field.setDoubleLjava_lang_ObjectD.Field_setDouble_A05", anyDexVm())
- .put("lang.reflect.Field.setShortLjava_lang_ObjectS.Field_setShort_A01", anyDexVm())
- .put(
- "lang.reflect.Field.setLongLjava_lang_ObjectJ.Field_setLong_A02",
- match(artRuntimesUpTo(Runtime.ART_V4_4_4)))
- .put("lang.reflect.Field.setLongLjava_lang_ObjectJ.Field_setLong_A05", anyDexVm())
- .put("lang.reflect.Field.setLongLjava_lang_ObjectJ.Field_setLong_A01", anyDexVm())
- .put("lang.reflect.Field.setDoubleLjava_lang_ObjectD.Field_setDouble_A01", anyDexVm())
- .put(
- "lang.reflect.Field.setShortLjava_lang_ObjectS.Field_setShort_A02",
- match(artRuntimesUpTo(Runtime.ART_V4_4_4)))
- .put("lang.reflect.Field.setShortLjava_lang_ObjectS.Field_setShort_A05", anyDexVm())
- .put("lang.reflect.Field.getLjava_lang_Object.Field_get_A05", anyDexVm())
- .put("lang.reflect.Field.getLongLjava_lang_Object.Field_getLong_A05", anyDexVm())
- .put(
- "lang.reflect.Field.setLjava_lang_ObjectLjava_lang_Object.Field_set_A02",
- match(artRuntimesUpTo(Runtime.ART_V4_4_4)))
- .put("lang.reflect.Field.setLjava_lang_ObjectLjava_lang_Object.Field_set_A05", anyDexVm())
- .put("lang.reflect.Field.setLjava_lang_ObjectLjava_lang_Object.Field_set_A01", anyDexVm())
- .put(
- "lang.reflect.Constructor.newInstance_Ljava_lang_Object.Constructor_newInstance_A06",
- anyDexVm())
- .put("lang.reflect.Constructor.isSynthetic.Constructor_isSynthetic_A01", any())
- .put(
- "lang.reflect.Constructor.getGenericExceptionTypes.Constructor_getGenericExceptionTypes_A03",
- any())
- .put(
- "lang.reflect.Constructor.getGenericExceptionTypes.Constructor_getGenericExceptionTypes_A02",
- any())
- .put(
- "lang.reflect.Constructor.getGenericExceptionTypes.Constructor_getGenericExceptionTypes_A01",
- any())
- .put(
- "lang.reflect.Constructor.getAnnotationLjava_lang_Class.Constructor_getAnnotation_A01",
- any())
- .put(
- "lang.reflect.Constructor.getDeclaredAnnotations.Constructor_getDeclaredAnnotations_A01",
- any())
- .put(
- "lang.reflect.Constructor.getGenericExceptionTypes.Constructor_getGenericExceptionTypes_A04",
- any())
- .put(
- "lang.reflect.InvocationTargetException.serialization.InvocationTargetException_serialization_A01",
- anyDexVm())
- .put(
- "lang.reflect.Constructor.toGenericString.Constructor_toGenericString_A01",
- anyDexVm())
- .put(
- "lang.reflect.Constructor.getTypeParameters.Constructor_getTypeParameters_A02", any())
- .put(
- "lang.reflect.Constructor.getGenericParameterTypes.Constructor_getGenericParameterTypes_A03",
- any())
- .put(
- "lang.reflect.Constructor.getGenericParameterTypes.Constructor_getGenericParameterTypes_A04",
- any())
- .put(
- "lang.reflect.Constructor.getGenericParameterTypes.Constructor_getGenericParameterTypes_A02",
- any())
- .put(
- "lang.reflect.AccessibleObject.setAccessibleZ.AccessibleObject_setAccessible_A03",
- anyDexVm())
- .put(
- "lang.reflect.UndeclaredThrowableException.serialization.UndeclaredThrowableException_serialization_A01",
- anyDexVm())
- .put(
- "lang.reflect.AccessibleObject.setAccessibleZ.AccessibleObject_setAccessible_A02",
- anyDexVm())
- .put(
- "lang.reflect.AccessibleObject.setAccessible_Ljava_lang_reflect_AccessibleObjectZ.AccessibleObject_setAccessible_A03",
- anyDexVm())
- .put(
- "lang.reflect.AccessibleObject.isAnnotationPresentLjava_lang_Class.AccessibleObject_isAnnotationPresent_A01",
- any())
- .put(
- "lang.reflect.AccessibleObject.setAccessible_Ljava_lang_reflect_AccessibleObjectZ.AccessibleObject_setAccessible_A02",
- anyDexVm())
- .put(
- "lang.reflect.AccessibleObject.getAnnotations.AccessibleObject_getAnnotations_A01",
- any())
- .put(
- "lang.reflect.AccessibleObject.getDeclaredAnnotations.AccessibleObject_getDeclaredAnnotations_A01",
- any())
- .put(
- "lang.reflect.AccessibleObject.getAnnotationLjava_lang_Class.AccessibleObject_getAnnotation_A01",
- any())
- .put(
- "lang.IllegalAccessException.serialization.IllegalAccessException_serialization_A01",
- anyDexVm())
- .put("lang.Character.getTypeI.Character_getType_A01", any())
- .put("lang.Character.isDigitI.Character_isDigit_A01", any())
- .put("lang.Character.getTypeC.Character_getType_A01", any())
- .put("lang.Character.serialization.Character_serialization_A01", anyDexVm())
- .put("lang.Character.isDigitC.Character_isDigit_A01", any())
- .put("lang.Character.digitCI.Character_digit_A01", any())
- .put("lang.Character.digitII.Character_digit_A01", any())
- .put("lang.Character.isLowerCaseC.Character_isLowerCase_A01", anyDexVm())
- .put(
- "lang.Character.isSpaceCharC.Character_isSpaceChar_A01",
- match(runtimes(Runtime.ART_V4_0_4)))
- .put(
- "lang.Character.isSpaceCharI.Character_isSpaceChar_A01",
- match(runtimes(Runtime.ART_V4_0_4)))
- .put(
- "lang.Character.isWhitespaceC.Character_isWhitespace_A01",
- match(runtimes(Runtime.ART_V4_0_4)))
- .put(
- "lang.Character.isWhitespaceI.Character_isWhitespace_A01",
- match(runtimes(Runtime.ART_V4_0_4)))
- .put("lang.Character.getDirectionalityI.Character_getDirectionality_A01", any())
- .put(
- "lang.Character.UnicodeBlock.ofC.UnicodeBlock_of_A01",
- match(artRuntimesFromAndJava(Runtime.ART_V4_4_4)))
- .put(
- "lang.Character.UnicodeBlock.ofI.UnicodeBlock_of_A01",
- match(artRuntimesFromAndJava(Runtime.ART_V4_4_4)))
- .put("lang.Character.isLowerCaseI.Character_isLowerCase_A01", anyDexVm())
- .put("lang.Process.waitFor.Process_waitFor_A01", anyDexVm())
- .put("lang.System.getProperties.System_getProperties_A01", anyDexVm())
- .put("lang.Process.getErrorStream.Process_getErrorStream_A01", anyDexVm())
- .put("lang.Character.getDirectionalityC.Character_getDirectionality_A01", any())
- .put("lang.Process.exitValue.Process_exitValue_A01", anyDexVm())
- .put("lang.System.loadLjava_lang_String.System_load_A01", anyDexVm())
- .put("lang.Process.getInputStream.Process_getInputStream_A01", anyDexVm())
- .put("lang.System.loadLibraryLjava_lang_String.System_loadLibrary_A01", anyDexVm())
- .put(
- "lang.System.setSecurityManagerLjava_lang_SecurityManager.System_setSecurityManager_A02",
- anyDexVm())
- .put("lang.System.runFinalizersOnExitZ.System_runFinalizersOnExit_A01", anyDexVm())
- .put("lang.System.getenvLjava_lang_String.System_getenv_A01", anyDexVm())
- .put("lang.System.getenv.System_getenv_A01", anyDexVm())
- .put(
- "lang.System.getPropertyLjava_lang_StringLjava_lang_String.System_getProperty_A01",
- anyDexVm())
- .put("lang.System.exitI.System_exit_A01", anyDexVm())
- .put(
- "util.concurrent.ArrayBlockingQueue.serialization.ArrayBlockingQueue_serialization_A01",
- anyDexVm())
- .put(
- "lang.System.arraycopyLjava_lang_ObjectILjava_lang_ObjectII.System_arraycopy_A04",
- anyDexVm())
- .put(
- "lang.System.setPropertiesLjava_util_Properties.System_setProperties_A02", anyDexVm())
- .put("lang.System.clearPropertyLjava_lang_String.System_clearProperty_A02", anyDexVm())
- .put("lang.System.getPropertyLjava_lang_String.System_getProperty_A01", anyDexVm())
- .put(
- "util.concurrent.LinkedBlockingQueue.serialization.LinkedBlockingQueue_serialization_A01",
- anyDexVm())
- .put(
- "util.concurrent.LinkedBlockingDeque.serialization.LinkedBlockingDeque_serialization_A01",
- anyDexVm())
- .put(
- "util.concurrent.ConcurrentLinkedQueue.serialization.ConcurrentLinkedQueue_serialization_A01",
- anyDexVm())
- .put(
- "util.concurrent.SynchronousQueue.serialization.SynchronousQueue_serialization_A01",
- anyDexVm())
- .put(
- "util.concurrent.CopyOnWriteArrayList.serialization.CopyOnWriteArrayList_serialization_A01",
- anyDexVm())
- .put(
- "util.concurrent.CopyOnWriteArrayList.subListII.CopyOnWriteArrayList_subList_A01",
- any())
- .put(
- "util.concurrent.ConcurrentHashMap.serialization.ConcurrentHashMap_serialization_A01",
- match(artRuntimesFrom(Runtime.ART_V5_1_1)))
- .put("util.concurrent.ConcurrentHashMap.keySet.ConcurrentHashMap_keySet_A01", anyDexVm())
- .put(
- "util.concurrent.Executors.privilegedThreadFactory.Executors_privilegedThreadFactory_A01",
- any())
- .put(
- "util.concurrent.Executors.privilegedCallableLjava_util_concurrent_Callable.Executors_privilegedCallable_A01",
- anyDexVm())
- .put(
- "util.concurrent.CopyOnWriteArraySet.serialization.CopyOnWriteArraySet_serialization_A01",
- anyDexVm())
- .put(
- "util.concurrent.Executors.privilegedCallableUsingCurrentClassLoaderLjava_util_concurrent_Callable.Executors_privilegedCallableUsingCurrentClassLoader_A01",
- anyDexVm())
- .put(
- "util.concurrent.PriorityBlockingQueue.ConstructorLjava_util_Collection.PriorityBlockingQueue_Constructor_A01",
- any())
- .put(
- "util.concurrent.PriorityBlockingQueue.serialization.PriorityBlockingQueue_serialization_A01",
- anyDexVm())
- .put(
- "lang.ThreadGroup.destroy.ThreadGroup_destroy_A01",
- match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put("lang.Thread.start.Thread_start_A01", match(runtimes(Runtime.ART_V7_0_0)))
- .put(
- "lang.String.getBytesLjava_lang_String.String_getBytes_A02",
- match(artRuntimesUpTo(Runtime.ART_V7_0_0)))
- .put(
- "util.concurrent.CopyOnWriteArrayList.lastIndexOfLjava_lang_ObjectI.CopyOnWriteArrayList_lastIndexOf_A02",
- match(artRuntimesUpTo(Runtime.ART_V7_0_0)))
- .put(
- "util.concurrent.CopyOnWriteArrayList.lastIndexOfLjava_lang_ObjectI.CopyOnWriteArrayList_lastIndexOf_A01",
- match(artRuntimesUpTo(Runtime.ART_V7_0_0)))
- .put(
- "lang.StringBuffer.getCharsII_CI.StringBuffer_getChars_A03",
- match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put(
- "lang.StringBuffer.appendF.StringBuffer_append_A01",
- match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put(
- "lang.StringBuffer.insertI_CII.StringBuffer_insert_A02",
- match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put(
- "lang.StrictMath.scalbDI.StrictMath_scalb_A03",
- match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put(
- "lang.StrictMath.scalbDI.StrictMath_scalb_A01",
- match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put(
- "lang.StrictMath.scalbFI.StrictMath_scalb_A03",
- match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put(
- "lang.StrictMath.scalbFI.StrictMath_scalb_A01",
- match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put(
- "lang.Thread.ConstructorLjava_lang_ThreadGroupLjava_lang_RunnableLjava_lang_StringJ.Thread_Constructor_A07",
- match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put(
- "lang.Thread.ConstructorLjava_lang_ThreadGroupLjava_lang_RunnableLjava_lang_String.Thread_Constructor_A07",
- match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put(
- "lang.Thread.toString.Thread_toString_A01",
- match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put("lang.Thread.start.Thread_start_A02", match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put(
- "lang.Thread.setPriorityI.Thread_setPriority_A01",
- match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put(
- "lang.ClassLoader.ConstructorLjava_lang_ClassLoader.ClassLoader_Constructor_A01",
- match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put(
- "lang.Enum.compareToLjava_lang_Enum.Enum_compareTo_A03",
- match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put("lang.Enum.hashCode.Enum_hashCode_A01", match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put(
- "lang.StackTraceElement.hashCode.StackTraceElement_hashCode_A01",
- match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put(
- "lang.ProcessBuilder.environment.ProcessBuilder_environment_A01",
- match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put(
- "lang.ProcessBuilder.environment.ProcessBuilder_environment_A03",
- match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put(
- "lang.Float.toStringF.Float_toString_A04", match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put(
- "lang.Float.toStringF.Float_toString_A03", match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put(
- "lang.ThreadGroup.getMaxPriority.ThreadGroup_getMaxPriority_A01",
- match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put(
- "lang.ThreadGroup.uncaughtExceptionLjava_lang_ThreadLjava_lang_Throwable.ThreadGroup_uncaughtException_A02",
- match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put(
- "lang.ThreadGroup.list.ThreadGroup_list_A01",
- match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put(
- "lang.ThreadGroup.setMaxPriorityI.ThreadGroup_setMaxPriority_A01",
- match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put(
- "lang.ThreadGroup.setMaxPriorityI.ThreadGroup_setMaxPriority_A04",
- match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put(
- "lang.ThreadGroup.toString.ThreadGroup_toString_A01",
- match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put(
- "lang.Class.getFieldLjava_lang_String.Class_getField_A01",
- match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put(
- "lang.String.replaceCC.String_replace_A01",
- match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put(
- "lang.Package.isCompatibleWithLjava_lang_String.Package_isCompatibleWith_A02",
- match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put(
- "lang.StringBuilder.appendF.StringBuilder_append_A01",
- match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put(
- "lang.StringBuilder.insertIF.StringBuilder_insert_A01",
- match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put(
- "lang.reflect.AccessibleObject.setAccessibleZ.AccessibleObject_setAccessible_A04",
- match(artRuntimesUpToAndJava(Runtime.ART_V4_4_4)))
- .put(
- "lang.reflect.AccessibleObject.setAccessible_Ljava_lang_reflect_AccessibleObjectZ.AccessibleObject_setAccessible_A04",
- match(artRuntimesUpToAndJava(Runtime.ART_V6_0_1)))
- .put(
- "lang.Character.UnicodeBlock.forName_java_lang_String.UnicodeBlock_forName_A03",
- match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put(
- "lang.System.loadLjava_lang_String.System_load_A02",
- match(artRuntimesUpTo(Runtime.ART_V6_0_1)))
- .put("lang.Math.hypotDD.Math_hypot_A04", match(artRuntimesUpTo(Runtime.ART_V5_1_1)))
- .put(
- "math.BigInteger.probablePrimeIjava_util_Random.BigInteger_probablePrime_A01",
- match(runtimes(Runtime.ART_V4_0_4)))
- .put("lang.Math.sqrtD.Math_sqrt_A01", match(runtimes(Runtime.ART_V4_0_4)))
- .put("lang.StrictMath.cbrtD.StrictMath_cbrt_A01", match(runtimes(Runtime.ART_V4_0_4)))
- .put("lang.StrictMath.log10D.StrictMath_log10_A01", match(runtimes(Runtime.ART_V4_0_4)))
- .put("lang.StrictMath.powDD.StrictMath_pow_A01", match(runtimes(Runtime.ART_V4_0_4)))
- .put("lang.String.indexOfII.String_indexOf_A01", match(runtimes(Runtime.ART_V4_0_4)))
- .put(
- "lang.String.indexOfLjava_lang_StringI.String_indexOf_A01",
- match(runtimes(Runtime.ART_V4_0_4)))
- .put(
- "lang.reflect.Array.getByteLjava_lang_ObjectI.Array_getByte_A03",
- match(runtimes(Runtime.ART_V4_0_4)))
- .put(
- "lang.reflect.Array.getDoubleLjava_lang_ObjectI.Array_getDouble_A01",
- match(runtimes(Runtime.ART_V4_0_4)))
- .put(
- "lang.reflect.Array.getDoubleLjava_lang_ObjectI.Array_getDouble_A03",
- match(runtimes(Runtime.ART_V4_0_4)))
- .put(
- "lang.reflect.Array.getFloatLjava_lang_ObjectI.Array_getFloat_A01",
- match(runtimes(Runtime.ART_V4_0_4)))
- .put(
- "lang.reflect.Array.getFloatLjava_lang_ObjectI.Array_getFloat_A03",
- match(runtimes(Runtime.ART_V4_0_4)))
- .put(
- "lang.reflect.Array.getIntLjava_lang_ObjectI.Array_getInt_A01",
- match(runtimes(Runtime.ART_V4_0_4)))
- .put(
- "lang.reflect.Array.getIntLjava_lang_ObjectI.Array_getInt_A03",
- match(runtimes(Runtime.ART_V4_0_4)))
- .put(
- "lang.reflect.Array.getLongLjava_lang_ObjectI.Array_getLong_A01",
- match(runtimes(Runtime.ART_V4_0_4)))
- .put(
- "lang.reflect.Array.getLongLjava_lang_ObjectI.Array_getLong_A03",
- match(runtimes(Runtime.ART_V4_0_4)))
- .put(
- "lang.reflect.Array.getShortLjava_lang_ObjectI.Array_getShort_A03",
- match(runtimes(Runtime.ART_V4_0_4)))
- .put(
- "lang.reflect.Array.setBooleanLjava_lang_ObjectIZ.Array_setBoolean_A03",
- match(runtimes(Runtime.ART_V4_0_4)))
- .put(
- "lang.reflect.Array.setCharLjava_lang_ObjectIC.Array_setChar_A01",
- match(runtimes(Runtime.ART_V4_0_4)))
- .put(
- "lang.reflect.Array.setLjava_lang_ObjectILjava_lang_Object.Array_set_A01",
- match(runtimes(Runtime.ART_V4_0_4)))
- .put(
- "lang.reflect.Array.setLjava_lang_ObjectILjava_lang_Object.Array_set_A03",
- match(runtimes(Runtime.ART_V4_0_4)))
- .put(
- "lang.reflect.Constructor.toString.Constructor_toString_A01",
- match(runtimes(Runtime.ART_V4_0_4)))
- .put(
- "math.BigInteger.modPowLjava_math_BigIntegerLjava_math_Integer.BigInteger_modPow_A01",
- match(runtimes(Runtime.ART_V4_0_4)))
- .put(
- "util.concurrent.LinkedBlockingDeque.drainToLjava_util_CollectionI.LinkedBlockingDeque_drainTo_A01",
- match(runtimes(Runtime.ART_V4_0_4)))
- .put(
- "util.concurrent.LinkedBlockingQueue.drainToLjava_util_CollectionI.LinkedBlockingQueue_drainTo_A01",
- match(runtimes(Runtime.ART_V4_0_4)))
- .put("lang.Thread.stopLjava_lang_Throwable.Thread_stop_A02", cf())
- .put(
- "lang.AssertionError.ConstructorLjava_lang_Object.AssertionError_Constructor_A01",
- match(runtimes(Runtime.ART_V4_0_4)))
- .put("lang.RuntimePermission.Class.RuntimePermission_class_A13", cf())
- .put("lang.Thread.stopLjava_lang_Throwable.Thread_stop_A01", cf())
- .put("lang.Runtime.addShutdownHookLjava_lang_Thread.Runtime_addShutdownHook_A02", cf())
- .put("lang.ThreadGroup.destroy.ThreadGroup_destroy_A04", cf())
- .put("lang.ThreadGroup.setMaxPriorityI.ThreadGroup_setMaxPriority_A02", cf())
- .put(
- "lang.String.replaceFirstLjava_lang_StringLjava_lang_String.String_replaceFirst_A01",
- cf())
- .put(
- "lang.String.replaceAllLjava_lang_StringLjava_lang_String.String_replaceAll_A01",
- cf())
- .put("lang.System.inheritedChannel.System_inheritedChannel_A01", cf())
- // TODO(b/124842490): Failing with change to JDK 9 for the classfile backend.
- .put("lang.Character.isSpaceCharC.Character_isSpaceChar_A01", cf())
- .put("lang.Character.isSpaceCharI.Character_isSpaceChar_A01", cf())
- .put("lang.Character.isWhitespaceI.Character_isWhitespace_A01", cf())
- .put("lang.Class.getConstructors.Class_getConstructors_A01", cf())
- .put("lang.Class.getPackage.Class_getPackage_A01", cf())
- .put(
- "lang.Class.getResourceAsStreamLjava_lang_String.Class_getResourceAsStream_A01", cf())
- .put("lang.Class.getResourceLjava_lang_String.Class_getResource_A01", cf())
- .put(
- "lang.ClassLoader.defineClassLjava_lang_StringLjava_nio_ByteBufferLjava_security_ProtectionDomain.ClassLoader_defineClass_A01",
- cf())
- .put(
- "lang.ClassLoader.defineClassLjava_lang_String_BII.ClassLoader_defineClass_A01", cf())
- .put(
- "lang.ClassLoader.defineClassLjava_lang_String_BIILjava_security_ProtectionDomain.ClassLoader_defineClass_A01",
- cf())
- .put("lang.ClassLoader.defineClass_BII.ClassLoader_defineClass_A01", cf())
- .put(
- "lang.ClassLoader.definePackageLjava_lang_String6Ljava_net_URL.ClassLoader_definePackage_A03",
- cf())
- .put("lang.Package.getImplementationVersion.Package_getImplementationVersion_A01", cf())
- .put(
- "lang.SecurityManager.checkAwtEventQueueAccess.SecurityManager_checkAwtEventQueueAccess_A01",
- cf())
- .put(
- "lang.SecurityManager.checkSystemClipboardAccess.SecurityManager_checkSystemClipboardAccess_A01",
- cf())
- .put(
- "lang.SecurityManager.checkTopLevelWindowLjava_lang_Object.SecurityManager_checkTopLevelWindow_A01",
- cf())
- .put("lang.StrictMath.toDegreesD.StrictMath_toDegrees_A01", cf())
- .put("lang.StrictMath.toRadiansD.StrictMath_toRadians_A01", cf())
- .put("lang.String.matchesLjava_lang_String.String_matches_A01", cf())
- .put("lang.StringBuffer.append_CII.StringBuffer_append_A03", cf())
- .put("lang.System.getProperties.System_getProperties_A02", cf())
- .put("lang.System.getPropertyLjava_lang_String.System_getProperty_A02", cf())
- .put(
- "lang.System.getPropertyLjava_lang_StringLjava_lang_String.System_getProperty_A02",
- cf())
- .put("lang.Throwable.serialization.Throwable_serialization_A01", cf())
- .put("lang.ref.ReferenceQueue.poll.ReferenceQueue_poll_A01", cf())
- .put("lang.ref.ReferenceQueue.remove.ReferenceQueue_remove_A01", cf())
- .put("lang.ref.ReferenceQueue.removeJ.ReferenceQueue_remove_A01", cf())
- .put("lang.reflect.Constructor.toGenericString.Constructor_toGenericString_A01", cf())
- .put("lang.reflect.Field.getGenericType.Field_getGenericType_A01", cf())
- .put("lang.reflect.Field.toGenericString.Field_toGenericString_A01", cf())
- .build(); // end of failuresToTriage
-
- public static final Multimap<String, TestCondition> bugs =
- new ImmutableListMultimap.Builder<String, TestCondition>()
- // The following StringBuffer/StringBuilder tests fails because we remove, e.g.,
- // new StringBuffer(-5) if it is dead code (but it should trow), see b/133745205
- .put(
- "lang.StringBuffer.ConstructorLjava_lang_String.StringBuffer_Constructor_A02",
- match(R8DEX_COMPILER))
- .put(
- "lang.StringBuffer.ConstructorLjava_lang_CharSequence.StringBuffer_Constructor_A02",
- match(R8DEX_COMPILER))
- .put("lang.StringBuffer.ConstructorI.StringBuffer_Constructor_A02", match(R8DEX_COMPILER))
- .put(
- "lang.StringBuilder.ConstructorI.StringBuilder_Constructor_A02",
- match(R8DEX_COMPILER))
- .put(
- "lang.StringBuilder.ConstructorLjava_lang_CharSequence.StringBuilder_Constructor_A02",
- match(R8DEX_COMPILER))
- .put(
- "lang.StringBuilder.ConstructorLjava_lang_String.StringBuilder_Constructor_A02",
- match(R8DEX_COMPILER))
- .build();
-
- public static final Multimap<String, TestCondition> flakyWhenRun =
- new ImmutableListMultimap.Builder<String, TestCondition>()
- .put("lang.Object.notifyAll.Object_notifyAll_A03", anyDexVm())
- .put("lang.Object.notify.Object_notify_A03", anyDexVm())
- .put(
- "util.concurrent.ConcurrentSkipListSet.addLjava_lang_Object.ConcurrentSkipListSet_add_A01",
- any())
- .put("util.concurrent.SynchronousQueue.ConstructorZ", anyDexVm())
- .put("lang.Thread.interrupt.Thread_interrupt_A04", anyDexVm())
- .put(
- "util.concurrent.SynchronousQueue.ConstructorZ.SynchronousQueue_Constructor_A01",
- anyDexVm())
- .put("lang.Thread.getState.Thread_getState_A01", anyDexVm())
- .put("lang.Thread.join.Thread_join_A01", anyDexVm())
- .put("lang.ThreadGroup.destroy.ThreadGroup_destroy_A01", match(JAVA_RUNTIME))
- .put(
- "util.concurrent.ScheduledThreadPoolExecutor.getTaskCount.ScheduledThreadPoolExecutor_getTaskCount_A01",
- any())
- .put(
- "lang.ref.PhantomReference.clear.PhantomReference_clear_A01",
- match(artRuntimesUpToAndJava(Runtime.ART_V4_4_4)))
- .put(
- "lang.ref.SoftReference.clear.SoftReference_clear_A01",
- match(artRuntimesUpTo(Runtime.ART_V4_4_4)))
- .put(
- "lang.ref.WeakReference.clear.WeakReference_clear_A01",
- match(and(artRuntimesUpTo(Runtime.ART_V4_4_4), JAVA_RUNTIME)))
- .put(
- "lang.ref.PhantomReference.isEnqueued.PhantomReference_isEnqueued_A01",
- match(
- and(
- runtimes(Runtime.ART_V9_0_0, Runtime.ART_V8_1_0),
- artRuntimesUpTo(Runtime.ART_V4_4_4),
- JAVA_RUNTIME)))
- .put("lang.ref.WeakReference.isEnqueued.WeakReference_isEnqueued_A01", any())
- .put(
- "lang.ref.WeakReference.enqueue.WeakReference_enqueue_A01",
- match(artRuntimesUpTo(Runtime.ART_V4_4_4)))
- .put(
- "lang.ref.SoftReference.isEnqueued.SoftReference_isEnqueued_A01",
- match(
- and(
- runtimes(Runtime.ART_V9_0_0, Runtime.ART_V8_1_0),
- artRuntimesUpTo(Runtime.ART_V4_4_4),
- JAVA_RUNTIME)))
- .put(
- "lang.ref.SoftReference.enqueue.SoftReference_enqueue_A01",
- match(and(artRuntimesUpTo(Runtime.ART_V4_4_4), JAVA_RUNTIME)))
- .put(
- "lang.ref.ReferenceQueue.poll.ReferenceQueue_poll_A01",
- match(artRuntimesUpTo(Runtime.ART_V4_4_4)))
- .put("lang.Runtime.gc.Runtime_gc_A01", cf())
- .put("lang.Runtime.runFinalizersOnExitZ.Runtime_runFinalizersOnExit_A01", cf())
- .put(
- "util.concurrent.AbstractExecutorService.invokeAllLjava_util_CollectionJLjava_util_concurrent_TimeUnit.AbstractExecutorService_invokeAll_A06",
- match(runtimes(Runtime.ART_V4_0_4)))
- .put(
- "util.concurrent.Executors.newCachedThreadPoolLjava_util_concurrent_ThreadFactory.Executors_newCachedThreadPool_A01",
- anyDexVm())
- .put(
- "util.concurrent.Executors.newCachedThreadPool.Executors_newCachedThreadPool_A01",
- match(runtimes(Runtime.ART_V5_1_1)))
- .put("lang.ref.SoftReference.get.SoftReference_get_A01", cf())
- .put("lang.ref.WeakReference.get.WeakReference_get_A01", cf())
- .build(); // end of flakyWhenRun
-
- public static final Set<String> hasMissingClasses =
- ImmutableSet.of(
- "lang.RuntimePermission.Class.RuntimePermission_class_A01",
- "lang.RuntimePermission.Class.RuntimePermission_class_A03",
- "lang.RuntimePermission.Class.RuntimePermission_class_A04",
- "lang.RuntimePermission.Class.RuntimePermission_class_A05",
- "lang.RuntimePermission.Class.RuntimePermission_class_A06",
- "lang.RuntimePermission.Class.RuntimePermission_class_A07",
- "lang.RuntimePermission.Class.RuntimePermission_class_A08",
- "lang.RuntimePermission.Class.RuntimePermission_class_A09",
- "lang.RuntimePermission.Class.RuntimePermission_class_A11",
- "lang.RuntimePermission.Class.RuntimePermission_class_A12",
- "lang.RuntimePermission.Class.RuntimePermission_class_A14",
- "lang.RuntimePermission.Class.RuntimePermission_class_A15",
- "lang.RuntimePermission.Class.RuntimePermission_class_A19",
- "lang.RuntimePermission.Class.RuntimePermission_class_A20",
- "lang.RuntimePermission.Class.RuntimePermission_class_A21",
- "lang.RuntimePermission.Class.RuntimePermission_class_A22",
- "lang.RuntimePermission.Class.RuntimePermission_class_A24",
- "lang.RuntimePermission.Class.RuntimePermission_class_A25",
- "lang.reflect.Proxy.serialization.Proxy_serialization_A02");
-
- public static final Multimap<String, TestCondition> timeoutsWhenRun =
- new ImmutableListMultimap.Builder<String, TestCondition>()
- .put("lang.Thread.interrupt.Thread_interrupt_A01", anyDexVm())
- .put("lang.Thread.resume.Thread_resume_A01", anyDexVm())
- .put("lang.Thread.stop.Thread_stop_A01", anyDexVm())
- .put("lang.Thread.suspend.Thread_suspend_A01", anyDexVm())
- .put(
- "lang.Thread.ConstructorLjava_lang_ThreadGroupLjava_lang_RunnableLjava_lang_StringJ.Thread_Constructor_A04",
- anyDexVm())
- .put(
- "lang.Thread.ConstructorLjava_lang_ThreadGroupLjava_lang_RunnableLjava_lang_StringJ.Thread_Constructor_A03",
- anyDexVm())
- .put(
- "lang.Thread.ConstructorLjava_lang_ThreadGroupLjava_lang_RunnableLjava_lang_StringJ.Thread_Constructor_A05",
- anyDexVm())
- .put("lang.Thread.setNameLjava_lang_String.Thread_setName_A02", anyDexVm())
- .put("lang.Thread.stop.Thread_stop_A02", anyDexVm())
- .put(
- "lang.Thread.ConstructorLjava_lang_ThreadGroupLjava_lang_RunnableLjava_lang_String.Thread_Constructor_A02",
- anyDexVm())
- .put(
- "lang.Thread.ConstructorLjava_lang_ThreadGroupLjava_lang_RunnableLjava_lang_String.Thread_Constructor_A03",
- anyDexVm())
- .put("lang.Thread.getStackTrace.Thread_getStackTrace_A03", anyDexVm())
- .put(
- "lang.Thread.setDefaultUncaughtExceptionHandler.Thread_setDefaultUncaughtExceptionHandler_A02",
- anyDexVm())
- .put("lang.Thread.checkAccess.Thread_checkAccess_A01", anyDexVm())
- .put(
- "lang.Thread.ConstructorLjava_lang_ThreadGroupLjava_lang_RunnableLjava_lang_String.Thread_Constructor_A04",
- anyDexVm())
- .put(
- "lang.Thread.setUncaughtExceptionHandler.Thread_setUncaughtExceptionHandler_A02",
- anyDexVm())
- .put("lang.Thread.stopLjava_lang_Throwable.Thread_stop_A01", anyDexVm())
- .put("lang.Thread.getAllStackTraces.Thread_getAllStackTraces_A02", anyDexVm())
- .put(
- "lang.Thread.setContextClassLoaderLjava_lang_ClassLoader.Thread_setContextClassLoader_A02",
- anyDexVm())
- .put("lang.Thread.setPriorityI.Thread_setPriority_A02", anyDexVm())
- .put("lang.Thread.stopLjava_lang_Throwable.Thread_stop_A02", anyDexVm())
- .put(
- "lang.Runtime.execLjava_lang_String_Ljava_lang_StringLjava_io_File.Runtime_exec_A04",
- anyDexVm())
- .put("lang.Thread.getContextClassLoader.Thread_getContextClassLoader_A02", anyDexVm())
- .put("lang.ThreadGroup.suspend.ThreadGroup_suspend_A01", cf())
- .put("lang.ThreadGroup.suspend.ThreadGroup_suspend_A02", anyDexVm())
- .put("lang.Thread.setDaemonZ.Thread_setDaemon_A03", anyDexVm())
- .put("lang.ProcessBuilder.environment.ProcessBuilder_environment_A07", anyDexVm())
- .put(
- "lang.Runtime.exec_Ljava_lang_String_Ljava_lang_StringLjava_io_File.Runtime_exec_A04",
- anyDexVm())
- .put("lang.Runtime.execLjava_lang_String_Ljava_lang_String.Runtime_exec_A04", anyDexVm())
- .put("lang.Runtime.exec_Ljava_lang_String.Runtime_exec_A04", anyDexVm())
- .put("lang.Runtime.execLjava_lang_String.Runtime_exec_A04", anyDexVm())
- .put("lang.System.clearPropertyLjava_lang_String.System_clearProperty_A03", anyDexVm())
- .put("lang.System.getSecurityManager.System_getSecurityManager_A01", anyDexVm())
- .put("lang.System.setInLjava_io_InputStream.System_setIn_A02", anyDexVm())
- .put("lang.System.setOutLjava_io_PrintStream.System_setOut_A02", anyDexVm())
- .put("lang.ThreadGroup.destroy.ThreadGroup_destroy_A04", anyDexVm())
- .put("lang.ThreadGroup.enumerate_ThreadGroupZ.ThreadGroup_enumerate_A03", anyDexVm())
- .put("lang.ThreadGroup.enumerate_Thread.ThreadGroup_enumerate_A03", anyDexVm())
- .put("lang.ThreadGroup.enumerate_ThreadZ.ThreadGroup_enumerate_A03", anyDexVm())
- .put("lang.ThreadGroup.interrupt.ThreadGroup_interrupt_A02", anyDexVm())
- .put("lang.ThreadGroup.resume.ThreadGroup_resume_A02", anyDexVm())
- .put("lang.ThreadGroup.setMaxPriorityI.ThreadGroup_setMaxPriority_A02", anyDexVm())
- .put("lang.Runtime.exec_Ljava_lang_String_Ljava_lang_String.Runtime_exec_A04", anyDexVm())
- .put("lang.System.getenvLjava_lang_String.System_getenv_A03", anyDexVm())
- .put(
- "lang.System.setPropertyLjava_lang_StringLjava_lang_String.System_setProperty_A02",
- anyDexVm())
- .put("lang.ThreadGroup.enumerate_ThreadGroup.ThreadGroup_enumerate_A03", anyDexVm())
- .put("lang.ThreadGroup.getParent.ThreadGroup_getParent_A02", anyDexVm())
- .put("lang.ThreadGroup.setDaemonZ.ThreadGroup_setDaemon_A02", anyDexVm())
- .put("lang.ThreadGroup.stop.ThreadGroup_stop_A02", any())
- .put("lang.Class.getSuperclass.Class_getSuperclass_A01", anyDexVm())
- .put("lang.System.getenv.System_getenv_A03", anyDexVm())
- .put("lang.System.inheritedChannel.System_inheritedChannel_A01", anyDexVm())
- .put(
- "util.concurrent.ArrayBlockingQueue.containsLjava_lang_Object.ArrayBlockingQueue_contains_A01",
- anyDexVm())
- .put(
- "lang.System.arraycopyLjava_lang_ObjectILjava_lang_ObjectII.System_arraycopy_A03",
- anyDexVm())
- .put("lang.System.setErrLjava_io_PrintStream.System_setErr_A02", anyDexVm())
- .put(
- "util.concurrent.ArrayBlockingQueue.containsLjava_lang_Object.ArrayBlockingQueue_contains_A01",
- anyDexVm())
- .put(
- "lang.System.setSecurityManagerLjava_lang_SecurityManager.System_setSecurityManager_A01",
- anyDexVm())
- .put(
- "util.concurrent.ArrayBlockingQueue.containsLjava_lang_Object.ArrayBlockingQueue_contains_A01",
- anyDexVm())
- .put(
- "util.concurrent.ArrayBlockingQueue.containsLjava_lang_Object.ArrayBlockingQueue_contains_A01",
- anyDexVm())
- .put(
- "lang.System.setPropertiesLjava_util_Properties.System_setProperties_A01", anyDexVm())
- .put(
- "util.concurrent.CopyOnWriteArrayList.ConstructorLjava_util_Collection.CopyOnWriteArrayList_Constructor_A02",
- anyDexVm())
- .put("util.concurrent.CyclicBarrier.reset.CyclicBarrier_reset_A03", any())
- .put("lang.System.clearPropertyLjava_lang_String.System_clearProperty_A01", anyDexVm())
- .put("lang.System.getenv.System_getenv_A04", anyDexVm())
- .put("lang.RuntimePermission.Class.RuntimePermission_class_A02", anyDexVm())
- .put("lang.RuntimePermission.Class.RuntimePermission_class_A13", anyDexVm())
- .build(); // end of timeoutsWhenRun
-
- public static final Multimap<String, TestCondition> requiresInliningDisabled =
- new ImmutableListMultimap.Builder<String, TestCondition>()
- .put("lang.Throwable.printStackTrace.Throwable_printStackTrace_A01", match(R8_COMPILER))
- .put("lang.Throwable.printStackTraceLjava_io_PrintWriter.Throwable_printStackTrace_A01",
- match(R8_COMPILER))
- .put("lang.Throwable.printStackTraceLjava_io_PrintStream.Throwable_printStackTrace_A01",
- match(R8_COMPILER))
- .put("lang.ref.SoftReference.isEnqueued.SoftReference_isEnqueued_A01", match(R8_COMPILER))
- .put("lang.ref.WeakReference.isEnqueued.WeakReference_isEnqueued_A01", match(R8_COMPILER))
- .put("lang.StackTraceElement.getMethodName.StackTraceElement_getMethodName_A01",
- match(R8_COMPILER))
- .put("lang.Thread.dumpStack.Thread_dumpStack_A01", match(R8_COMPILER))
- .build();
-
- public static final Set<String> compilationFailsWithAsmMethodTooLarge = ImmutableSet.of();
-
- private static boolean testMatch(
- Multimap<String, TestCondition> testConditions,
- String name,
- CompilerUnderTest compilerUnderTest,
- Runtime runtime,
- CompilationMode compilationMode) {
- Collection<TestCondition> entries = testConditions.get(name);
- for (TestCondition entry : entries) {
- if (entry.test(DexTool.NONE, compilerUnderTest, runtime, compilationMode)) {
- return true;
- }
- }
- return false;
- }
-
- public static <T> T getExpectedOutcome(
- String name,
- CompilerUnderTest compilerUnderTest,
- Runtime runtime,
- CompilationMode compilationMode,
- BiFunction<Outcome, Boolean, T> consumer) {
-
- Outcome outcome = null;
-
- if (testMatch(failuresToTriage, name, compilerUnderTest, runtime, compilationMode)) {
- outcome = Outcome.FAILS_WHEN_RUN;
- }
- if (testMatch(bugs, name, compilerUnderTest, runtime, compilationMode)) {
- outcome = Outcome.FAILS_WHEN_RUN;
- }
- if (testMatch(timeoutsWhenRun, name, compilerUnderTest, runtime, compilationMode)) {
- assert outcome == null;
- outcome = Outcome.TIMEOUTS_WHEN_RUN;
- }
- if (testMatch(flakyWhenRun, name, compilerUnderTest, runtime, compilationMode)) {
- assert outcome == null;
- outcome = Outcome.FLAKY_WHEN_RUN;
- }
- if (outcome == null) {
- outcome = Outcome.PASSES;
- }
- boolean disableInlining =
- testMatch(requiresInliningDisabled, name, compilerUnderTest, runtime, compilationMode);
- return consumer.apply(outcome, disableInlining);
- }
-}
diff --git a/src/test/java/com/android/tools/r8/KotlinTestBase.java b/src/test/java/com/android/tools/r8/KotlinTestBase.java
index 8dd8a44..d4f443a 100644
--- a/src/test/java/com/android/tools/r8/KotlinTestBase.java
+++ b/src/test/java/com/android/tools/r8/KotlinTestBase.java
@@ -51,6 +51,10 @@
this.kotlinParameters = kotlinParameters;
}
+ public static CfRuntime getKotlincHostRuntime(TestRuntime runtime) {
+ return runtime.isCf() ? runtime.asCf() : TestRuntime.getCheckedInJdk9();
+ }
+
protected static List<Path> getKotlinFilesInTestPackage(Package pkg) throws IOException {
String folder = DescriptorUtils.getBinaryNameFromJavaType(pkg.getName());
return Files.walk(Paths.get(ToolHelper.TESTS_DIR, "java", folder))
diff --git a/src/test/java/com/android/tools/r8/L8TestBuilder.java b/src/test/java/com/android/tools/r8/L8TestBuilder.java
index 7a42ab1..2ff60ba 100644
--- a/src/test/java/com/android/tools/r8/L8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/L8TestBuilder.java
@@ -184,7 +184,10 @@
.inspect(
inspector ->
inspector.forAllClasses(
- clazz -> assertTrue(clazz.getFinalName().startsWith("j$."))));
+ clazz ->
+ assertTrue(
+ clazz.getFinalName().startsWith("j$.")
+ || clazz.getFinalName().startsWith("java."))));
}
private Collection<Path> getProgramFiles() {
diff --git a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
index 352e12b..c860721 100644
--- a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
@@ -6,11 +6,8 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
-import com.android.tools.r8.JctfTestSpecifications.Outcome;
import com.android.tools.r8.TestCondition.Runtime;
import com.android.tools.r8.TestCondition.RuntimeSet;
-import com.android.tools.r8.TestRuntime.CfVm;
-import com.android.tools.r8.TestRuntime.DexRuntime;
import com.android.tools.r8.ToolHelper.ArtCommandBuilder;
import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.ToolHelper.DexVm.Kind;
@@ -36,14 +33,12 @@
import com.google.common.collect.ObjectArrays;
import com.google.common.collect.Sets;
import java.io.File;
-import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
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.HashMap;
@@ -53,7 +48,6 @@
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ExecutionException;
-import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
@@ -110,13 +104,6 @@
DexVm.Version.V12_0_0,
DexVm.Version.V13_MASTER);
- // Input jar for jctf tests.
- private static final String JCTF_COMMON_JAR = "build/libs/jctfCommon.jar";
-
- // Parent dir for on-the-fly compiled jctf dex output.
- private static final String JCTF_TESTS_PREFIX = "build/classes/java/jctfTests";
- private static final String JCTF_TESTS_LIB_PREFIX =
- JCTF_TESTS_PREFIX + "/com/google/jctf/test/lib";
private static final String JUNIT_TEST_RUNNER = "org.junit.runner.JUnitCore";
private static final String JUNIT_JAR = "third_party/junit/junit-4.13-beta-2.jar";
private static final String HAMCREST_JAR =
@@ -1097,27 +1084,6 @@
"663-odd-dex-size4" // No input class files
);
- // Some JCTF test cases require test classes from other tests. These are listed here.
- private static final Map<String, List<String>> jctfTestsExternalClassFiles =
- new ImmutableMap.Builder<String, List<String>>()
- .put("lang.RuntimePermission.Class.RuntimePermission_class_A13",
- new ImmutableList.Builder<String>()
- .add("lang/Thread/stop/Thread_stop_A02.class")
- .add("lang/Thread/stopLjava_lang_Throwable/Thread_stop_A02.class")
- .build())
- .put("lang.RuntimePermission.Class.RuntimePermission_class_A02",
- new ImmutableList.Builder<String>()
- .add("lang/Class/getClassLoader/Class_getClassLoader_A03.class")
- .add("lang/ClassLoader/getParent/ClassLoader_getParent_A02.class")
- .add("lang/Thread/getContextClassLoader/Thread_getContextClassLoader_A02.class")
- .add("lang/Runtime/exitI/Runtime_exit_A02.class")
- .build())
- .put("lang.Runtime.exitI.Runtime_exit_A03",
- new ImmutableList.Builder<String>()
- .add("lang/Runtime/exitI/Runtime_exit_A02.class")
- .build())
- .build();
-
// Tests to skip on some conditions
private static final Multimap<String, TestCondition> testToSkip =
new ImmutableListMultimap.Builder<String, TestCondition>()
@@ -1346,65 +1312,6 @@
this.configuration = configuration;
}
- TestSpecification(
- String name,
- DexTool dexTool,
- File directory,
- boolean skipRun,
- boolean failsOnRun,
- boolean disableInlining,
- boolean hasMissingClasses,
- DexVm dexVm) {
- this(
- name,
- dexTool,
- directory,
- skipRun,
- ToolHelper.isWindows() && dexVm.getKind() == Kind.HOST,
- false,
- failsOnRun,
- false,
- false,
- null,
- false,
- false,
- disableInlining,
- true, // Disable class inlining for JCTF tests.
- hasMissingClasses,
- true, // Disable desugaring for JCTF tests.
- ImmutableList.of(),
- null);
- }
-
- TestSpecification(
- String name,
- DexTool dexTool,
- File directory,
- boolean skipRun,
- boolean failsOnRun,
- boolean disableInlining,
- boolean hasMissingClasses) {
- this(
- name,
- dexTool,
- directory,
- skipRun,
- false,
- false,
- failsOnRun,
- false,
- false,
- null,
- false,
- false,
- disableInlining,
- true, // Disable class inlining for JCTF tests.
- hasMissingClasses,
- true, // Disable desugaring for JCTF tests.
- ImmutableList.of(),
- null);
- }
-
public File resolveFile(String name) {
return directory.toPath().resolve(name).toFile();
}
@@ -1874,75 +1781,6 @@
}
- private ArrayList<File> getJctfTestAuxClassFiles(File classFile) {
- // Collect additional files from the same directory with file names like
- // <dir>/<filename_wo_ext>$*.class and <dir>/<filename_wo_ext>_*.class
- String classFileString = classFile.toString();
- assert classFileString.endsWith(".class");
-
- String auxClassFileBase =
- new File(
- classFileString.substring(0, classFileString.length() - ".class".length()))
- .getName();
-
- ArrayList<File> auxClassFiles = new ArrayList<>();
-
- File[] files = classFile.getParentFile()
- .listFiles(
- (File file) -> isAuxClassFile(file.getName(), auxClassFileBase));
- if (files != null) {
- auxClassFiles.addAll(Arrays.asList(files));
- }
-
- if (auxClassFileBase.matches(".*[A-Z]\\d\\d")) {
- // Also collect all the files in this directory that doesn't match this pattern
- // They will be helper classes defined in one of the test class files but we don't know in
- // which one, so we just add them to all tests.
- final int SUFFIX_LENGTH_TO_STRIP = 3; // one letter (usually 'A' and two digits)
- String testClassFilePattern =
- auxClassFileBase.substring(0, auxClassFileBase.length() - SUFFIX_LENGTH_TO_STRIP)
- + "[A-Z]\\d\\d.*\\.class";
- files = classFile.getParentFile()
- .listFiles(
- (File file) -> file.getName().matches(".*\\.class") && !file.getName()
- .matches(testClassFilePattern));
- if (files != null) {
- auxClassFiles.addAll(Arrays.asList(files));
- }
- }
-
- return auxClassFiles;
- }
-
- private static BiFunction<Outcome, Boolean, TestSpecification> jctfOutcomeToSpecification(
- String name, DexTool dexTool, File resultDir, DexVm dexVm) {
- return (outcome, noInlining) ->
- new TestSpecification(
- name,
- dexTool,
- resultDir,
- outcome == JctfTestSpecifications.Outcome.TIMEOUTS_WHEN_RUN
- || outcome == JctfTestSpecifications.Outcome.FLAKY_WHEN_RUN,
- outcome == JctfTestSpecifications.Outcome.FAILS_WHEN_RUN,
- noInlining,
- JctfTestSpecifications.hasMissingClasses.contains(name),
- dexVm);
- }
-
- private static BiFunction<Outcome, Boolean, TestSpecification> jctfOutcomeToSpecificationJava(
- String name, File resultDir) {
- return (outcome, noInlining) ->
- new TestSpecification(
- name,
- DexTool.NONE,
- resultDir,
- outcome == JctfTestSpecifications.Outcome.TIMEOUTS_WHEN_RUN
- || outcome == JctfTestSpecifications.Outcome.FLAKY_WHEN_RUN,
- outcome == JctfTestSpecifications.Outcome.FAILS_WHEN_RUN,
- noInlining,
- JctfTestSpecifications.hasMissingClasses.contains(name));
- }
-
private static Runtime getRuntime(TestRuntime vm) {
if (vm.isCf()) {
return Runtime.JAVA;
@@ -1998,321 +1836,6 @@
}
}
- protected void runJctfTest(
- CompilerUnderTest compilerUnderTest, String classFilePath, String fullClassName)
- throws IOException, CompilationFailedException {
- VmErrors vmErrors = runJctfTestCore(compilerUnderTest, classFilePath, fullClassName);
- if (vmErrors.message != null) {
- throw new RuntimeException(vmErrors.message.toString());
- }
- }
-
- private VmErrors runJctfTestCore(
- CompilerUnderTest compilerUnderTest, String classFilePath, String fullClassName)
- throws IOException, CompilationFailedException {
- VmErrors vmErrors = new VmErrors();
- List<TestRuntime> vms = new ArrayList<>();
- if (compilerUnderTest == CompilerUnderTest.R8CF) {
- // TODO(b/135411839): Run on all java runtimes.
- vms.add(TestRuntime.getDefaultJavaRuntime());
- } else {
- for (DexVm vm : TestParametersBuilder.getAvailableDexVms()) {
- // TODO(144966342): Disabled for triaging failures
- if (vm.getVersion() == DexVm.Version.V10_0_0) {
- System.out.println("Running on 10.0.0 is disabled, see b/144966342");
- continue;
- }
- if (vm.getVersion() == DexVm.Version.V12_0_0
- || vm.getVersion() == DexVm.Version.V13_MASTER) {
- System.out.println("Running on 12.0.0 or V13_MASTER is disabled, see b/197078995");
- continue;
- }
- vms.add(new DexRuntime(vm));
- }
- }
-
- CompilerUnderTest firstCompilerUnderTest =
- compilerUnderTest == CompilerUnderTest.R8_AFTER_D8
- ? CompilerUnderTest.D8
- : compilerUnderTest;
- CompilationMode compilationMode = defaultCompilationMode(compilerUnderTest);
-
- List<VmSpec> vmSpecs = new ArrayList<>();
- for (TestRuntime vm : vms) {
- File resultDir =
- temp.newFolder(
- firstCompilerUnderTest.toString().toLowerCase() + "-output-" + vm.toString());
-
- TestSpecification specification =
- JctfTestSpecifications.getExpectedOutcome(
- name,
- firstCompilerUnderTest,
- getRuntime(vm),
- compilationMode,
- compilerUnderTest == CompilerUnderTest.R8CF
- ? jctfOutcomeToSpecificationJava(name, resultDir)
- : jctfOutcomeToSpecification(name, DexTool.NONE, resultDir, vm.asDex().getVm()));
-
- if (!specification.skipTest) {
- vmSpecs.add(new VmSpec(vm, specification));
- }
- }
-
- if (vmSpecs.isEmpty()) {
- return vmErrors;
- }
-
- File classFile = new File(JCTF_TESTS_PREFIX + "/" + classFilePath);
- if (!classFile.exists()) {
- throw new FileNotFoundException(
- "Class file for Jctf test not found: \"" + classFile.toString() + "\".");
- }
-
- ArrayList<File> classFiles = new ArrayList<>();
- classFiles.add(classFile);
-
- // some tests need files from other tests
- int langIndex = fullClassName.indexOf(".java.");
- assert langIndex >= 0;
- List<String> externalClassFiles = jctfTestsExternalClassFiles
- .get(fullClassName.substring(langIndex + ".java.".length()));
-
- if (externalClassFiles != null) {
- for (String s : externalClassFiles) {
- classFiles.add(new File(JCTF_TESTS_LIB_PREFIX + "/java/" + s));
- }
- }
-
- ArrayList<File> allClassFiles = new ArrayList<>();
-
- for (File f : classFiles) {
- allClassFiles.add(f);
- allClassFiles.addAll(getJctfTestAuxClassFiles(f));
- }
-
- File jctfCommonFile = new File(JCTF_COMMON_JAR);
- if (!jctfCommonFile.exists()) {
- throw new FileNotFoundException(
- "Jar file of Jctf tests common code not found: \"" + jctfCommonFile.toString() + "\".");
- }
-
- File junitFile = new File(JUNIT_JAR);
- if (!junitFile.exists()) {
- throw new FileNotFoundException(
- "Junit Jar not found: \"" + junitFile.toString() + "\".");
- }
-
- File hamcrestFile = new File(HAMCREST_JAR);
- if (!hamcrestFile.exists()) {
- throw new FileNotFoundException(
- "Hamcrest Jar not found: \"" + hamcrestFile.toString() + "\".");
- }
-
- // allClassFiles may contain duplicated files, that's why the HashSet
- Set<String> fileNames = new HashSet<>();
-
- fileNames.addAll(Arrays.asList(
- jctfCommonFile.getCanonicalPath(),
- junitFile.getCanonicalPath(),
- hamcrestFile.getCanonicalPath()
- ));
-
- for (File f : allClassFiles) {
- fileNames.add(f.getCanonicalPath());
- }
-
- if (compilerUnderTest == CompilerUnderTest.R8CF) {
- assert vmSpecs.size() == 1
- : "Running the same test on multiple JVMs should share the same build.";
- for (VmSpec vmSpec : vmSpecs) {
- runJctfTestDoRunOnJava(
- fileNames, vmSpec.spec, fullClassName, compilationMode, vmSpec.vm.asCf().getVm());
- }
- return vmErrors;
- }
-
- CompilationOptions compilationOptions = null;
- File compiledDir = temp.newFolder();
- for (VmSpec vmSpec : vmSpecs) {
- CompilationOptions thisOptions = new CompilationOptions(vmSpec.spec);
- if (compilationOptions == null) {
- compilationOptions = thisOptions;
- executeCompilerUnderTest(
- firstCompilerUnderTest,
- fileNames,
- compiledDir.getAbsolutePath(),
- compilationMode,
- compilationOptions);
- } else {
- // For now compile options don't change across vms.
- assert compilationOptions.equals(thisOptions);
- }
- Files.copy(
- compiledDir.toPath().resolve("classes.dex"),
- vmSpec.spec.directory.toPath().resolve("classes.dex"));
-
- AssertionError vmError = null;
- try {
- runJctfTestDoRunOnArt(fileNames, vmSpec.spec, fullClassName, vmSpec.vm.asDex().getVm());
- } catch (AssertionError e) {
- vmError = e;
- }
- if (vmSpec.spec.failsOnRun && vmError == null) {
- vmErrors.addShouldHaveFailedError(firstCompilerUnderTest, vmSpec.vm);
- } else if (!vmSpec.spec.failsOnRun && vmError != null) {
- vmErrors.addFailedOnRunError(firstCompilerUnderTest, vmSpec.vm, vmError);
- }
- }
-
- if (compilerUnderTest != CompilerUnderTest.R8_AFTER_D8) {
- return vmErrors;
- }
-
- // Second pass (R8), if R8_AFTER_D8.
- CompilationOptions r8CompilationOptions = null;
- File r8CompiledDir = temp.newFolder();
- for (VmSpec vmSpec : vmSpecs) {
- if (vmSpec.spec.failsOnRun || vmErrors.failedVms.contains(vmSpec.vm)) {
- continue;
- }
- File r8ResultDir = temp.newFolder("r8-output-" + vmSpec.vm.toString());
- TestSpecification specification =
- JctfTestSpecifications.getExpectedOutcome(
- name,
- CompilerUnderTest.R8_AFTER_D8,
- getRuntime(vmSpec.vm),
- CompilationMode.RELEASE,
- jctfOutcomeToSpecification(name, DexTool.DX, r8ResultDir, vmSpec.vm.asDex().getVm()));
- if (specification.skipTest) {
- continue;
- }
- CompilationOptions thisOptions = new CompilationOptions(specification);
- if (r8CompilationOptions == null) {
- r8CompilationOptions = thisOptions;
- executeCompilerUnderTest(
- CompilerUnderTest.R8,
- Collections.singletonList(compiledDir.toPath().resolve("classes.dex").toString()),
- r8CompiledDir.getAbsolutePath(),
- CompilationMode.RELEASE,
- r8CompilationOptions);
- } else {
- // For now compile options don't change across vms.
- assert r8CompilationOptions.equals(thisOptions);
- }
- Files.copy(
- r8CompiledDir.toPath().resolve("classes.dex"),
- specification.directory.toPath().resolve("classes.dex"));
- try {
- runJctfTestDoRunOnArt(fileNames, specification, fullClassName, vmSpec.vm.asDex().getVm());
- } catch (AssertionError e) {
- if (!specification.failsOnRun) {
- vmErrors.addFailedOnRunError(CompilerUnderTest.R8, vmSpec.vm, e);
- }
- }
- }
- return vmErrors;
- }
-
- private void runJctfTestDoRunOnArt(
- Collection<String> fileNames,
- TestSpecification specification,
- String fullClassName,
- DexVm dexVm)
- throws IOException {
- if (!ToolHelper.artSupported() && !ToolHelper.dealsWithGoldenFiles()) {
- return;
- }
-
- File processedFile;
-
- // Collect the generated dex files.
- File[] outputFiles =
- specification.directory.listFiles((File file) -> file.getName().endsWith(".dex"));
- assert outputFiles.length == 1;
- processedFile = outputFiles[0];
-
- boolean compileOnly = System.getProperty("jctf_compile_only", "0").equals("1");
- if (compileOnly || specification.skipRun) {
- if (ToolHelper.isDex2OatSupported()) {
- // verify dex code instead of running it
- Path oatFile = temp.getRoot().toPath().resolve("all.oat");
- ToolHelper.runDex2Oat(processedFile.toPath(), oatFile);
- }
- return;
- }
-
- ArtCommandBuilder builder = buildArtCommand(processedFile, specification, dexVm);
- if (dexVm.isNewerThan(DexVm.ART_4_4_4_HOST)) {
- builder.appendArtOption("-Ximage:/system/non/existent/image.art");
- builder.appendArtOption("-Xnoimage-dex2oat");
- }
- for (String s : ToolHelper.getBootLibs(dexVm)) {
- builder.appendBootClasspath(new File(s).getCanonicalPath());
- }
- builder.setMainClass(JUNIT_TEST_RUNNER);
- builder.appendProgramArgument(fullClassName);
-
- try {
- ToolHelper.runArt(builder);
- } catch (AssertionError e) {
- addDexInformationToVerificationError(fileNames, processedFile,
- specification.resolveFile("classes.dex"), e);
- throw e;
- }
- }
-
- private void runJctfTestDoRunOnJava(
- Collection<String> fileNames,
- TestSpecification specification,
- String fullClassName,
- CompilationMode mode,
- CfVm vm)
- throws IOException, CompilationFailedException {
- assert TestParametersBuilder.isSystemJdk(vm);
- if (JctfTestSpecifications.compilationFailsWithAsmMethodTooLarge.contains(specification.name)) {
- expectException(org.objectweb.asm.MethodTooLargeException.class);
- }
- executeCompilerUnderTest(
- CompilerUnderTest.R8CF,
- fileNames,
- specification.directory.getAbsolutePath(),
- mode,
- new CompilationOptions(specification));
-
- boolean compileOnly = System.getProperty("jctf_compile_only", "0").equals("1");
-
- if (compileOnly || specification.skipRun) {
- return;
- }
-
- if (specification.failsOnRun) {
- expectException(AssertionError.class);
- }
-
- // Some tests rely on an OutOfMemoryError being thrown (fx MemoryHog.getBigArray()). To ensure
- // compatible test results locally and externally, we need to synchronize the max heap size when
- // running the test.
- ProcessResult result =
- ToolHelper.runJava(
- specification.directory.toPath(),
- "-Xmx" + ToolHelper.BOT_MAX_HEAP_SIZE,
- JUNIT_TEST_RUNNER,
- fullClassName);
-
- if (result.exitCode != 0) {
- throw new AssertionError(
- "Test failed on java.\nSTDOUT >>>\n"
- + result.stdout
- + "\n<<< STDOUT\nSTDERR >>>\n"
- + result.stderr
- + "\n<<< STDERR\n");
- }
-
- if (specification.failsOnRun) {
- System.err.println("Should have failed run with java.");
- }
- }
-
protected void runArtTest(DexVm dexVm, CompilerUnderTest compilerUnderTest) throws Throwable {
CompilerUnderTest firstCompilerUnderTest =
compilerUnderTest == CompilerUnderTest.R8_AFTER_D8
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index f5ddeeb..4daa6a9 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -18,6 +18,7 @@
import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.KotlinCompilerTool.KotlinTargetVersion;
import com.android.tools.r8.TestRuntime.CfRuntime;
+import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper.ArtCommandBuilder;
import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.ToolHelper.ProcessResult;
@@ -349,6 +350,10 @@
TemporaryFolder temp,
KotlinCompiler kotlinCompiler,
KotlinTargetVersion kotlinTargetVersion) {
+ // TODO(b/227161720): Kotlinc fails to run on JDK17.
+ if (jdk.isNewerThanOrEqual(CfVm.JDK17)) {
+ jdk = TestRuntime.getCheckedInJdk9();
+ }
return KotlinCompilerTool.create(jdk, temp, kotlinCompiler, kotlinTargetVersion);
}
@@ -359,6 +364,10 @@
public KotlinCompilerTool kotlinc(
CfRuntime jdk, KotlinCompiler kotlinCompiler, KotlinTargetVersion kotlinTargetVersion) {
+ // TODO(b/227161720): Kotlinc fails to run on JDK17.
+ if (jdk.isNewerThanOrEqual(CfVm.JDK17)) {
+ jdk = TestRuntime.getCheckedInJdk9();
+ }
return KotlinCompilerTool.create(jdk, temp, kotlinCompiler, kotlinTargetVersion);
}
diff --git a/src/test/java/com/android/tools/r8/TestRuntime.java b/src/test/java/com/android/tools/r8/TestRuntime.java
index dd19c1e..336ffd1 100644
--- a/src/test/java/com/android/tools/r8/TestRuntime.java
+++ b/src/test/java/com/android/tools/r8/TestRuntime.java
@@ -29,6 +29,11 @@
JDK9("jdk9", 53),
JDK10("jdk10", 54),
JDK11("jdk11", 55),
+ JDK12("jdk12", 56),
+ JDK13("jdk13", 57),
+ JDK14("jdk14", 58),
+ JDK15("jdk15", 59),
+ JDK16("jdk16", 60),
JDK17("jdk17", 61),
JDK18("jdk18", 62),
;
@@ -53,7 +58,7 @@
}
public static CfVm last() {
- return JDK11;
+ return JDK17;
}
public boolean lessThan(CfVm other) {
@@ -125,14 +130,15 @@
return new CfRuntime(CfVm.JDK11, getCheckedInJdkHome(CfVm.JDK11));
}
- // TODO(b/169692487): Add this to 'getCheckedInCfRuntimes' when we start having support for JDK17.
public static CfRuntime getCheckedInJdk17() {
return new CfRuntime(CfVm.JDK17, getCheckedInJdkHome(CfVm.JDK17));
}
public static List<CfRuntime> getCheckedInCfRuntimes() {
CfRuntime[] jdks =
- new CfRuntime[] {getCheckedInJdk8(), getCheckedInJdk9(), getCheckedInJdk11()};
+ new CfRuntime[] {
+ getCheckedInJdk8(), getCheckedInJdk9(), getCheckedInJdk11(), getCheckedInJdk17(),
+ };
Builder<CfRuntime> builder = ImmutableList.builder();
for (CfRuntime jdk : jdks) {
if (jdk != null) {
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index e0bb322..5b8bb7a 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -1305,7 +1305,7 @@
AndroidApp app = command.getInputApp();
if (app.getLibraryResourceProviders().isEmpty()) {
// Add the android library matching the minsdk. We filter out junit and testing classes
- // from the android jar to avoid duplicate classes in art and jctf tests.
+ // from the android jar to avoid duplicate classes in art tests.
AndroidApp.Builder builder = AndroidApp.builder(app);
addFilteredAndroidJar(builder, AndroidApiLevel.getAndroidApiLevel(command.getMinApiLevel()));
app = builder.build();
diff --git a/src/test/java/com/android/tools/r8/annotations/SourceDebugExtensionTest.java b/src/test/java/com/android/tools/r8/annotations/SourceDebugExtensionTest.java
index 14b6376..814e454 100644
--- a/src/test/java/com/android/tools/r8/annotations/SourceDebugExtensionTest.java
+++ b/src/test/java/com/android/tools/r8/annotations/SourceDebugExtensionTest.java
@@ -12,11 +12,10 @@
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.KotlinCompilerTool.KotlinTargetVersion;
+import com.android.tools.r8.KotlinTestBase;
import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestRuntime;
-import com.android.tools.r8.TestRuntime.CfRuntime;
import com.android.tools.r8.retrace.KotlinInlineFunctionRetraceTest;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.codeinspector.AnnotationSubject;
@@ -52,11 +51,13 @@
@Test
public void testR8() throws IOException, CompilationFailedException, ExecutionException {
- CfRuntime cfRuntime =
- parameters.isCfRuntime() ? parameters.getRuntime().asCf() : TestRuntime.getCheckedInJdk9();
KotlinCompiler kotlinc = kotlinTestParameters.getCompiler();
Path kotlinSources =
- kotlinc(cfRuntime, getStaticTemp(), kotlinc, KotlinTargetVersion.JAVA_8)
+ kotlinc(
+ KotlinTestBase.getKotlincHostRuntime(parameters.getRuntime()),
+ getStaticTemp(),
+ kotlinc,
+ KotlinTargetVersion.JAVA_8)
.addSourceFiles(
getFilesInTestFolderRelativeToClass(
KotlinInlineFunctionRetraceTest.class, "kt", ".kt"))
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineDuplicateMethodTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineDuplicateMethodTest.java
index 2e96c90..e8d6257 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineDuplicateMethodTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineDuplicateMethodTest.java
@@ -16,6 +16,7 @@
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
+import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.SingleTestRunResult;
import com.android.tools.r8.TestBase;
@@ -25,6 +26,7 @@
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.testing.AndroidBuildVersion;
import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import java.lang.reflect.Method;
@@ -62,6 +64,8 @@
.apply(setMockApiLevelForClass(LibraryClass.class, classApiLevel))
.apply(setMockApiLevelForDefaultInstanceInitializer(LibraryClass.class, classApiLevel))
.apply(setMockApiLevelForMethod(addedOn23(), methodApiLevel))
+ // TODO(b/213552119): Remove when enabled by default.
+ .apply(ApiModelingTestHelper::enableApiCallerIdentification)
.apply(ApiModelingTestHelper::enableOutliningOfMethods)
.apply(ApiModelingTestHelper::disableStubbingOfClasses);
}
@@ -72,27 +76,41 @@
}
@Test
- public void testD8() throws Exception {
+ public void testD8Debug() throws Exception {
// TODO(b/197078995): Make this work on 12+.
- assumeTrue(
- parameters.isDexRuntime()
- && parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0));
+ assumeFalse(
+ parameters.isCfRuntime()
+ || parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
testForD8()
+ .setMode(CompilationMode.DEBUG)
.apply(this::setupTestBuilder)
.compile()
.applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
.run(parameters.getRuntime(), Main.class)
.apply(this::checkOutput)
- // TODO(b/213552119): Assert that we did not outline any methods.
- .inspect(ApiModelingTestHelper::assertNoSynthesizedClasses);
+ .inspect(this::inspect);
+ }
+
+ @Test
+ public void testD8Release() throws Exception {
+ assumeFalse(
+ parameters.isCfRuntime()
+ || parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
+ testForD8()
+ .setMode(CompilationMode.RELEASE)
+ .apply(this::setupTestBuilder)
+ .compile()
+ .applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
+ .run(parameters.getRuntime(), Main.class)
+ .apply(this::checkOutput)
+ .inspect(this::inspect);
}
@Test
public void testR8() throws Exception {
// TODO(b/197078995): Make this work on 12+.
- assumeFalse(
- parameters.isDexRuntime()
- && parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
+ assumeTrue(
+ parameters.isCfRuntime() || parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0));
testForR8(parameters.getBackend())
.apply(this::setupTestBuilder)
.addKeepMainRule(Main.class)
@@ -101,47 +119,44 @@
.applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
.run(parameters.getRuntime(), Main.class)
.apply(this::checkOutput)
- .inspect(
- inspector -> {
- int classCount =
- parameters.isDexRuntime() && parameters.getApiLevel().isLessThan(methodApiLevel)
- ? 4
- : 3;
- assertEquals(classCount, inspector.allClasses().size());
- Method testMethod = TestClass.class.getDeclaredMethod("test");
- verifyThat(inspector, parameters, addedOn23())
- .isOutlinedFromUntil(testMethod, methodApiLevel);
- if (parameters.isDexRuntime()
- && parameters.getApiLevel().isLessThan(methodApiLevel)) {
- // Verify that we invoke the synthesized outline, addedOn23, twice.
- Optional<FoundMethodSubject> synthesizedAddedOn23 =
- inspector.allClasses().stream()
- .flatMap(clazz -> clazz.allMethods().stream())
- .filter(
- methodSubject ->
- methodSubject.isSynthetic()
- && invokesMethodWithName("addedOn23").matches(methodSubject))
- .findFirst();
- assertTrue(synthesizedAddedOn23.isPresent());
- MethodSubject testMethodSubject = inspector.method(testMethod);
- assertThat(testMethodSubject, isPresent());
- assertEquals(
- 2,
- testMethodSubject
- .streamInstructions()
- .filter(
- instructionSubject -> {
- if (!instructionSubject.isInvoke()) {
- return false;
- }
- return instructionSubject
- .getMethod()
- .asMethodReference()
- .equals(synthesizedAddedOn23.get().asMethodReference());
- })
- .count());
- }
- });
+ .inspect(this::inspect);
+ }
+
+ private void inspect(CodeInspector inspector) throws Exception {
+ int classCount =
+ parameters.isDexRuntime() && parameters.getApiLevel().isLessThan(methodApiLevel) ? 4 : 3;
+ assertEquals(classCount, inspector.allClasses().size());
+ Method testMethod = TestClass.class.getDeclaredMethod("test");
+ verifyThat(inspector, parameters, addedOn23()).isOutlinedFromUntil(testMethod, methodApiLevel);
+ if (parameters.isDexRuntime() && parameters.getApiLevel().isLessThan(methodApiLevel)) {
+ // Verify that we invoke the synthesized outline, addedOn23, twice.
+ Optional<FoundMethodSubject> synthesizedAddedOn23 =
+ inspector.allClasses().stream()
+ .flatMap(clazz -> clazz.allMethods().stream())
+ .filter(
+ methodSubject ->
+ methodSubject.isSynthetic()
+ && invokesMethodWithName("addedOn23").matches(methodSubject))
+ .findFirst();
+ assertTrue(synthesizedAddedOn23.isPresent());
+ MethodSubject testMethodSubject = inspector.method(testMethod);
+ assertThat(testMethodSubject, isPresent());
+ assertEquals(
+ 2,
+ testMethodSubject
+ .streamInstructions()
+ .filter(
+ instructionSubject -> {
+ if (!instructionSubject.isInvoke()) {
+ return false;
+ }
+ return instructionSubject
+ .getMethod()
+ .asMethodReference()
+ .equals(synthesizedAddedOn23.get().asMethodReference());
+ })
+ .count());
+ }
}
private void checkOutput(SingleTestRunResult<?> runResult) {
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineHorizontalMergingTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineHorizontalMergingTest.java
index 497e0fd..fb98821 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineHorizontalMergingTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineHorizontalMergingTest.java
@@ -13,6 +13,7 @@
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
+import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.SingleTestRunResult;
import com.android.tools.r8.TestBase;
@@ -22,6 +23,7 @@
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.testing.AndroidBuildVersion;
import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
import java.util.List;
import java.util.stream.Collectors;
@@ -72,6 +74,8 @@
.apply(
setMockApiLevelForMethod(
OtherLibraryClass.class.getMethod("addedOn27"), secondMethodApiLevel))
+ // TODO(b/213552119): Remove when enabled by default.
+ .apply(ApiModelingTestHelper::enableApiCallerIdentification)
.apply(ApiModelingTestHelper::enableOutliningOfMethods)
.apply(ApiModelingTestHelper::disableStubbingOfClasses);
}
@@ -85,12 +89,13 @@
}
@Test
- public void testD8() throws Exception {
+ public void testD8Debug() throws Exception {
// TODO(b/197078995): Make this work on 12+.
assumeTrue(
parameters.isDexRuntime()
&& parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0));
testForD8(parameters.getBackend())
+ .setMode(CompilationMode.DEBUG)
.apply(this::setupTestBuilder)
.compile()
.applyIf(
@@ -98,8 +103,37 @@
b -> b.addBootClasspathClasses(LibraryClass.class, OtherLibraryClass.class))
.run(parameters.getRuntime(), Main.class)
.apply(this::checkOutput)
- // TODO(b/213552119): Assert that we did not outline any methods.
- .inspect(ApiModelingTestHelper::assertNoSynthesizedClasses);
+ .inspect(
+ inspector -> {
+ // TODO(b/187675788): Update when horizontal merging is enabled for D8 for debug mode.
+ if (parameters.getApiLevel().isLessThan(firstMethodApiLevel)) {
+ // We have generated 4 outlines two having api level 23 and two having api level 27.
+ assertEquals(7, inspector.allClasses().size());
+ } else if (parameters.getApiLevel().isLessThan(secondMethodApiLevel)) {
+ assertEquals(5, inspector.allClasses().size());
+ } else {
+ // No outlining on this api level.
+ assertEquals(3, inspector.allClasses().size());
+ }
+ });
+ }
+
+ @Test
+ public void testD8Release() throws Exception {
+ // TODO(b/197078995): Make this work on 12+.
+ assumeFalse(
+ parameters.isCfRuntime()
+ || parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
+ testForD8(parameters.getBackend())
+ .setMode(CompilationMode.RELEASE)
+ .apply(this::setupTestBuilder)
+ .compile()
+ .applyIf(
+ addToBootClasspath(),
+ b -> b.addBootClasspathClasses(LibraryClass.class, OtherLibraryClass.class))
+ .run(parameters.getRuntime(), Main.class)
+ .apply(this::checkOutput)
+ .inspect(this::inspect);
}
@Test
@@ -118,64 +152,64 @@
b -> b.addBootClasspathClasses(LibraryClass.class, OtherLibraryClass.class))
.run(parameters.getRuntime(), Main.class)
.apply(this::checkOutput)
- .inspect(
- inspector -> {
- // No need to check further on CF.
- List<FoundMethodSubject> outlinedAddedOn23 =
- inspector.allClasses().stream()
- .flatMap(clazz -> clazz.allMethods().stream())
- .filter(
- methodSubject ->
- methodSubject.isSynthetic()
- && invokesMethodWithName("addedOn23").matches(methodSubject))
- .collect(Collectors.toList());
- List<FoundMethodSubject> outlinedAddedOn27 =
- inspector.allClasses().stream()
- .flatMap(clazz -> clazz.allMethods().stream())
- .filter(
- methodSubject ->
- methodSubject.isSynthetic()
- && invokesMethodWithName("addedOn27").matches(methodSubject))
- .collect(Collectors.toList());
- if (parameters.isCfRuntime()) {
- assertTrue(outlinedAddedOn23.isEmpty());
- assertTrue(outlinedAddedOn27.isEmpty());
- assertEquals(3, inspector.allClasses().size());
- } else if (parameters.getApiLevel().isLessThan(firstMethodApiLevel)) {
- // We have generated 4 outlines two having api level 23 and two having api level 27.
- // Check that the levels are horizontally merged.
- assertEquals(5, inspector.allClasses().size());
- assertEquals(2, outlinedAddedOn23.size());
- assertTrue(
- outlinedAddedOn23.stream()
- .allMatch(
- outline ->
- outline.getMethod().getHolderType()
- == outlinedAddedOn23.get(0).getMethod().getHolderType()));
- assertEquals(2, outlinedAddedOn27.size());
- assertTrue(
- outlinedAddedOn27.stream()
- .allMatch(
- outline ->
- outline.getMethod().getHolderType()
- == outlinedAddedOn27.get(0).getMethod().getHolderType()));
- } else if (parameters.getApiLevel().isLessThan(secondMethodApiLevel)) {
- assertTrue(outlinedAddedOn23.isEmpty());
- assertEquals(4, inspector.allClasses().size());
- assertEquals(2, outlinedAddedOn27.size());
- assertTrue(
- outlinedAddedOn27.stream()
- .allMatch(
- outline ->
- outline.getMethod().getHolderType()
- == outlinedAddedOn27.get(0).getMethod().getHolderType()));
- } else {
- // No outlining on this api level.
- assertTrue(outlinedAddedOn23.isEmpty());
- assertTrue(outlinedAddedOn27.isEmpty());
- assertEquals(3, inspector.allClasses().size());
- }
- });
+ .inspect(this::inspect);
+ }
+
+ private void inspect(CodeInspector inspector) {
+ List<FoundMethodSubject> outlinedAddedOn23 =
+ inspector.allClasses().stream()
+ .flatMap(clazz -> clazz.allMethods().stream())
+ .filter(
+ methodSubject ->
+ methodSubject.isSynthetic()
+ && invokesMethodWithName("addedOn23").matches(methodSubject))
+ .collect(Collectors.toList());
+ List<FoundMethodSubject> outlinedAddedOn27 =
+ inspector.allClasses().stream()
+ .flatMap(clazz -> clazz.allMethods().stream())
+ .filter(
+ methodSubject ->
+ methodSubject.isSynthetic()
+ && invokesMethodWithName("addedOn27").matches(methodSubject))
+ .collect(Collectors.toList());
+ if (parameters.isCfRuntime()) {
+ assertTrue(outlinedAddedOn23.isEmpty());
+ assertTrue(outlinedAddedOn27.isEmpty());
+ assertEquals(3, inspector.allClasses().size());
+ } else if (parameters.getApiLevel().isLessThan(firstMethodApiLevel)) {
+ // We have generated 4 outlines two having api level 23 and two having api level 27.
+ // Check that the levels are horizontally merged.
+ assertEquals(5, inspector.allClasses().size());
+ assertEquals(2, outlinedAddedOn23.size());
+ assertTrue(
+ outlinedAddedOn23.stream()
+ .allMatch(
+ outline ->
+ outline.getMethod().getHolderType()
+ == outlinedAddedOn23.get(0).getMethod().getHolderType()));
+ assertEquals(2, outlinedAddedOn27.size());
+ assertTrue(
+ outlinedAddedOn27.stream()
+ .allMatch(
+ outline ->
+ outline.getMethod().getHolderType()
+ == outlinedAddedOn27.get(0).getMethod().getHolderType()));
+ } else if (parameters.getApiLevel().isLessThan(secondMethodApiLevel)) {
+ assertTrue(outlinedAddedOn23.isEmpty());
+ assertEquals(4, inspector.allClasses().size());
+ assertEquals(2, outlinedAddedOn27.size());
+ assertTrue(
+ outlinedAddedOn27.stream()
+ .allMatch(
+ outline ->
+ outline.getMethod().getHolderType()
+ == outlinedAddedOn27.get(0).getMethod().getHolderType()));
+ } else {
+ // No outlining on this api level.
+ assertTrue(outlinedAddedOn23.isEmpty());
+ assertTrue(outlinedAddedOn27.isEmpty());
+ assertEquals(3, inspector.allClasses().size());
+ }
}
private void checkOutput(SingleTestRunResult<?> runResult) {
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodAndStubClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodAndStubClassTest.java
index 89c2f76..2411e94 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodAndStubClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodAndStubClassTest.java
@@ -11,6 +11,7 @@
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
+import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.SingleTestRunResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestCompilerBuilder;
@@ -20,6 +21,7 @@
import com.android.tools.r8.apimodel.ApiModelMockClassTest.TestClass;
import com.android.tools.r8.testing.AndroidBuildVersion;
import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
import java.lang.reflect.Method;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -51,6 +53,8 @@
.addDefaultRuntimeLibrary(parameters)
.setMinApi(parameters.getApiLevel())
.addAndroidBuildVersion()
+ // TODO(b/213552119): Remove when enabled by default.
+ .apply(ApiModelingTestHelper::enableApiCallerIdentification)
.apply(ApiModelingTestHelper::enableStubbingOfClasses)
.apply(ApiModelingTestHelper::enableOutliningOfMethods)
.apply(setMockApiLevelForClass(LibraryClass.class, libraryClassLevel))
@@ -64,19 +68,35 @@
}
@Test
- public void testD8() throws Exception {
+ public void testD8Debug() throws Exception {
// TODO(b/197078995): Make this work on 12+.
assumeTrue(
parameters.isDexRuntime()
&& parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0));
testForD8(parameters.getBackend())
+ .setMode(CompilationMode.DEBUG)
.apply(this::setupTestBuilder)
.compile()
.applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
.run(parameters.getRuntime(), Main.class)
.apply(this::checkOutput)
- // TODO(b/213552119): Assert that we did not outline any methods.
- .inspect(ApiModelingTestHelper::assertNoSynthesizedClasses);
+ .inspect(this::inspect);
+ }
+
+ @Test
+ public void testD8Release() throws Exception {
+ // TODO(b/197078995): Make this work on 12+.
+ assumeFalse(
+ parameters.isCfRuntime()
+ || parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
+ testForD8(parameters.getBackend())
+ .setMode(CompilationMode.RELEASE)
+ .apply(this::setupTestBuilder)
+ .compile()
+ .applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
+ .run(parameters.getRuntime(), Main.class)
+ .apply(this::checkOutput)
+ .inspect(this::inspect);
}
@Test
@@ -92,13 +112,14 @@
.applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
.run(parameters.getRuntime(), Main.class)
.apply(this::checkOutput)
- .inspect(
- inspector -> {
- verifyThat(inspector, parameters, LibraryClass.class).stubbedUntil(libraryClassLevel);
- verifyThat(inspector, parameters, apiMethod())
- .isOutlinedFromUntil(
- Main.class.getDeclaredMethod("main", String[].class), libraryMethodLevel);
- });
+ .inspect(this::inspect);
+ }
+
+ private void inspect(CodeInspector inspector) throws Exception {
+ verifyThat(inspector, parameters, LibraryClass.class).stubbedUntil(libraryClassLevel);
+ verifyThat(inspector, parameters, apiMethod())
+ .isOutlinedFromUntil(
+ Main.class.getDeclaredMethod("main", String[].class), libraryMethodLevel);
}
private void checkOutput(SingleTestRunResult<?> runResult) {
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodMissingClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodMissingClassTest.java
index 8ee8ad4..cf440c9 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodMissingClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodMissingClassTest.java
@@ -16,6 +16,7 @@
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
+import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.SingleTestRunResult;
import com.android.tools.r8.TestBase;
@@ -25,6 +26,7 @@
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.testing.AndroidBuildVersion;
import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import java.lang.reflect.Method;
@@ -69,6 +71,8 @@
LibraryClass.class, initialLibraryMockLevel))
.apply(setMockApiLevelForMethod(addedOn23(), initialLibraryMockLevel))
.apply(setMockApiLevelForMethod(addedOn27(), finalLibraryMethodLevel))
+ // TODO(b/213552119): Remove when enabled by default.
+ .apply(ApiModelingTestHelper::enableApiCallerIdentification)
.apply(ApiModelingTestHelper::enableOutliningOfMethods)
.apply(ApiModelingTestHelper::disableStubbingOfClasses);
}
@@ -82,19 +86,34 @@
}
@Test
- public void testD8() throws Exception {
+ public void testD8Debug() throws Exception {
// TODO(b/197078995): Make this work on 12+.
assumeTrue(
parameters.isDexRuntime()
&& parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0));
testForD8(parameters.getBackend())
+ .setMode(CompilationMode.DEBUG)
.apply(this::setupTestBuilder)
.compile()
.applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
.run(parameters.getRuntime(), Main.class)
.apply(this::checkOutput)
- // TODO(b/213552119): Assert that we did not outline any methods.
- .inspect(ApiModelingTestHelper::assertNoSynthesizedClasses);
+ .inspect(this::inspect);
+ }
+
+ @Test
+ public void testD8Release() throws Exception {
+ assumeFalse(
+ parameters.isCfRuntime()
+ || parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
+ testForD8(parameters.getBackend())
+ .setMode(CompilationMode.RELEASE)
+ .apply(this::setupTestBuilder)
+ .compile()
+ .applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
+ .run(parameters.getRuntime(), Main.class)
+ .apply(this::checkOutput)
+ .inspect(this::inspect);
}
@Test
@@ -111,40 +130,37 @@
.applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
.run(parameters.getRuntime(), Main.class)
.apply(this::checkOutput)
- .inspect(
- inspector -> {
- // No need to check further on CF.
- if (parameters.isCfRuntime()) {
- assertEquals(3, inspector.allClasses().size());
- return;
- }
- Method testMethod = TestClass.class.getDeclaredMethod("test");
- MethodSubject testMethodSubject = inspector.method(testMethod);
- assertThat(testMethodSubject, isPresent());
- Optional<FoundMethodSubject> synthesizedMissingNotReferenced =
- inspector.allClasses().stream()
- .flatMap(clazz -> clazz.allMethods().stream())
- .filter(
- methodSubject ->
- methodSubject.isSynthetic()
- && invokesMethodWithName("missingNotReferenced")
- .matches(methodSubject))
- .findFirst();
- assertFalse(synthesizedMissingNotReferenced.isPresent());
- verifyThat(inspector, parameters, addedOn23()).isNotOutlinedFrom(testMethod);
- verifyThat(inspector, parameters, addedOn27())
- .isOutlinedFromUntil(testMethod, finalLibraryMethodLevel);
- verifyThat(
- inspector,
- parameters,
- LibraryClass.class.getDeclaredMethod("missingAndReferenced"))
- .isNotOutlinedFrom(testMethod);
- if (parameters.getApiLevel().isLessThan(finalLibraryMethodLevel)) {
- assertEquals(4, inspector.allClasses().size());
- } else {
- assertEquals(3, inspector.allClasses().size());
- }
- });
+ .inspect(this::inspect);
+ }
+
+ private void inspect(CodeInspector inspector) throws Exception {
+ // No need to check further on CF.
+ if (parameters.isCfRuntime()) {
+ assertEquals(3, inspector.allClasses().size());
+ return;
+ }
+ Method testMethod = TestClass.class.getDeclaredMethod("test");
+ MethodSubject testMethodSubject = inspector.method(testMethod);
+ assertThat(testMethodSubject, isPresent());
+ Optional<FoundMethodSubject> synthesizedMissingNotReferenced =
+ inspector.allClasses().stream()
+ .flatMap(clazz -> clazz.allMethods().stream())
+ .filter(
+ methodSubject ->
+ methodSubject.isSynthetic()
+ && invokesMethodWithName("missingNotReferenced").matches(methodSubject))
+ .findFirst();
+ assertFalse(synthesizedMissingNotReferenced.isPresent());
+ verifyThat(inspector, parameters, addedOn23()).isNotOutlinedFrom(testMethod);
+ verifyThat(inspector, parameters, addedOn27())
+ .isOutlinedFromUntil(testMethod, finalLibraryMethodLevel);
+ verifyThat(inspector, parameters, LibraryClass.class.getDeclaredMethod("missingAndReferenced"))
+ .isNotOutlinedFrom(testMethod);
+ if (parameters.getApiLevel().isLessThan(finalLibraryMethodLevel)) {
+ assertEquals(4, inspector.allClasses().size());
+ } else {
+ assertEquals(3, inspector.allClasses().size());
+ }
}
private void checkOutput(SingleTestRunResult<?> runResult) {
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodProtectedTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodProtectedTest.java
index 4428a33..d63e01b 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodProtectedTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodProtectedTest.java
@@ -10,6 +10,7 @@
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
+import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.SingleTestRunResult;
@@ -73,6 +74,8 @@
.transform())
.setMinApi(AndroidApiLevel.B)
.addAndroidBuildVersion(runApiLevel())
+ // TODO(b/213552119): Remove when enabled by default.
+ .apply(ApiModelingTestHelper::enableApiCallerIdentification)
.apply(setMockApiLevelForClass(LibraryClass.class, classApiLevel))
.apply(setMockApiLevelForDefaultInstanceInitializer(LibraryClass.class, classApiLevel))
.apply(
@@ -89,12 +92,28 @@
}
@Test
- public void testD8() throws Exception {
+ public void testD8Debug() throws Exception {
// TODO(b/197078995): Make this work on 12+.
assumeTrue(
parameters.isDexRuntime()
&& parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0));
testForD8()
+ .setMode(CompilationMode.DEBUG)
+ .apply(this::setupTestBuilder)
+ .compile()
+ .applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
+ .run(parameters.getRuntime(), Main.class)
+ .apply(this::checkOutput);
+ }
+
+ @Test
+ public void testD8Release() throws Exception {
+ // TODO(b/197078995): Make this work on 12+.
+ assumeFalse(
+ parameters.isCfRuntime()
+ || parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
+ testForD8()
+ .setMode(CompilationMode.RELEASE)
.apply(this::setupTestBuilder)
.compile()
.applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodUnknownTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodUnknownTest.java
index 2461448..940864c 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodUnknownTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodUnknownTest.java
@@ -8,6 +8,7 @@
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
+import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.SingleTestRunResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestCompilerBuilder;
@@ -42,6 +43,8 @@
.setMinApi(parameters.getApiLevel())
.addAndroidBuildVersion()
.apply(setMockApiLevelForClass(LibraryClass.class, classApiLevel))
+ // TODO(b/213552119): Remove when enabled by default.
+ .apply(ApiModelingTestHelper::enableApiCallerIdentification)
.apply(ApiModelingTestHelper::enableOutliningOfMethods)
.apply(ApiModelingTestHelper::disableStubbingOfClasses);
}
@@ -52,12 +55,30 @@
}
@Test
- public void testD8() throws Exception {
+ public void testD8Debug() throws Exception {
// TODO(b/197078995): Make this work on 12+.
assumeTrue(
parameters.isDexRuntime()
&& parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0));
testForD8()
+ .setMode(CompilationMode.DEBUG)
+ .apply(this::setupTestBuilder)
+ .compile()
+ // Assert that we did not outline any methods.
+ .inspect(ApiModelingTestHelper::assertNoSynthesizedClasses)
+ .applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
+ .run(parameters.getRuntime(), Main.class)
+ .apply(this::checkOutput);
+ }
+
+ @Test
+ public void testD8Release() throws Exception {
+ // TODO(b/197078995): Make this work on 12+.
+ assumeFalse(
+ parameters.isCfRuntime()
+ || parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
+ testForD8()
+ .setMode(CompilationMode.RELEASE)
.apply(this::setupTestBuilder)
.compile()
// Assert that we did not outline any methods.
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlinePackagePrivateTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlinePackagePrivateTest.java
index 9e8115d..94ae936 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlinePackagePrivateTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlinePackagePrivateTest.java
@@ -9,6 +9,7 @@
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
+import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.D8TestCompileResult;
import com.android.tools.r8.SingleTestRunResult;
import com.android.tools.r8.TestBase;
@@ -83,12 +84,31 @@
.apply(
setMockApiLevelForMethod(
LibraryClass.class.getDeclaredMethod("addedOn10"), methodApiLevel))
+ // TODO(b/213552119): Remove when enabled by default.
+ .apply(ApiModelingTestHelper::enableApiCallerIdentification)
.apply(ApiModelingTestHelper::enableOutliningOfMethods)
.apply(ApiModelingTestHelper::disableStubbingOfClasses);
}
@Test
- public void testD8() throws Exception {
+ public void testD8Debug() throws Exception {
+ // TODO(b/197078995): Make this work on 12+.
+ assumeTrue(
+ parameters.isDexRuntime()
+ && parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0));
+ testForD8()
+ .setMode(CompilationMode.DEBUG)
+ .apply(this::setupTestBuilder)
+ .compile()
+ // Assert that we did not outline any methods.
+ .inspect(ApiModelingTestHelper::assertNoSynthesizedClasses)
+ .applyIf(willInvokeLibraryMethods(), b -> b.addBootClasspathClasses(LibraryClass.class))
+ .run(parameters.getRuntime(), Main.class)
+ .apply(this::checkResultOnBootClassPath);
+ }
+
+ @Test
+ public void testD8Release() throws Exception {
// TODO(b/197078995): Make this work on 12+.
assumeTrue(
parameters.isDexRuntime()
diff --git a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkCollection.java b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkCollection.java
index 5dc4bd9..a8f662f 100644
--- a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkCollection.java
+++ b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkCollection.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.benchmarks.appdumps.TiviBenchmarks;
import com.android.tools.r8.benchmarks.desugaredlib.LegacyDesugaredLibraryBenchmark;
import com.android.tools.r8.benchmarks.helloworld.HelloWorldBenchmark;
+import com.android.tools.r8.benchmarks.retrace.RetraceStackTraceBenchmark;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
@@ -47,6 +48,7 @@
HelloWorldBenchmark.configs().forEach(collection::addBenchmark);
LegacyDesugaredLibraryBenchmark.configs().forEach(collection::addBenchmark);
TiviBenchmarks.configs().forEach(collection::addBenchmark);
+ RetraceStackTraceBenchmark.configs().forEach(collection::addBenchmark);
return collection;
}
diff --git a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkDependency.java b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkDependency.java
index 9e18997..4bf5334 100644
--- a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkDependency.java
+++ b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkDependency.java
@@ -33,6 +33,10 @@
this.name = name;
this.directoryName = directoryName;
this.location = location;
+ String firstChar = name.substring(0, 1);
+ if (!firstChar.equals(firstChar.toLowerCase()) || name.contains("_")) {
+ throw new BenchmarkConfigError("Benchmark name should use lowerCamelCase, found: " + name);
+ }
}
public String getName() {
diff --git a/src/test/java/com/android/tools/r8/benchmarks/retrace/RetraceStackTraceBenchmark.java b/src/test/java/com/android/tools/r8/benchmarks/retrace/RetraceStackTraceBenchmark.java
new file mode 100644
index 0000000..e1f0d55
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/benchmarks/retrace/RetraceStackTraceBenchmark.java
@@ -0,0 +1,86 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.benchmarks.retrace;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.benchmarks.BenchmarkBase;
+import com.android.tools.r8.benchmarks.BenchmarkConfig;
+import com.android.tools.r8.benchmarks.BenchmarkDependency;
+import com.android.tools.r8.benchmarks.BenchmarkMethod;
+import com.android.tools.r8.benchmarks.BenchmarkTarget;
+import com.android.tools.r8.retrace.ProguardMapProducer;
+import com.android.tools.r8.retrace.Retrace;
+import com.android.tools.r8.retrace.RetraceCommand;
+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.List;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+/** Example of setting up a benchmark based on the testing infrastructure. */
+@RunWith(Parameterized.class)
+public class RetraceStackTraceBenchmark extends BenchmarkBase {
+
+ private static final BenchmarkDependency benchmarkDependency =
+ new BenchmarkDependency("retraceBenchmark", "retrace_benchmark", Paths.get("third_party"));
+
+ @Parameters(name = "{0}")
+ public static List<Object[]> data() {
+ return parametersFromConfigs(configs());
+ }
+
+ public RetraceStackTraceBenchmark(BenchmarkConfig config, TestParameters parameters) {
+ super(config, parameters);
+ }
+
+ /** Static method to add benchmarks to the benchmark collection. */
+ public static List<BenchmarkConfig> configs() {
+ return ImmutableList.<BenchmarkConfig>builder()
+ .add(
+ BenchmarkConfig.builder()
+ .setName("RetraceStackTraceWithProguardMap")
+ .setTarget(BenchmarkTarget.R8_NON_COMPAT)
+ .measureRunTime()
+ .setMethod(benchmarkRetrace())
+ .setFromRevision(12266)
+ .measureWarmup()
+ .addDependency(benchmarkDependency)
+ .build())
+ .build();
+ }
+
+ public static BenchmarkMethod benchmarkRetrace() {
+ return environment ->
+ runner(environment.getConfig())
+ .setWarmupIterations(1)
+ .setBenchmarkIterations(4)
+ .reportResultSum()
+ .run(
+ results -> {
+ Path dependencyRoot = benchmarkDependency.getRoot(environment);
+ List<String> stackTrace =
+ Files.readAllLines(dependencyRoot.resolve("stacktrace.txt"));
+ List<String> retraced = new ArrayList<>();
+ long start = System.nanoTime();
+ Retrace.run(
+ RetraceCommand.builder()
+ .setProguardMapProducer(
+ ProguardMapProducer.fromPath(dependencyRoot.resolve("r8lib.jar.map")))
+ .setStackTrace(stackTrace)
+ .setRetracedStackTraceConsumer(retraced::addAll)
+ .build());
+ long end = System.nanoTime();
+ // Add a simple check to ensure that we do not, in case of invalid retracing,
+ // record an optimal benchmark result.
+ if (retraced.size() < stackTrace.size()) {
+ throw new RuntimeException("Unexpected missing lines in retraced result");
+ }
+ results.addRuntimeResult(end - start);
+ });
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/cf/bootstrap/KotlinCompilerTreeShakingTest.java b/src/test/java/com/android/tools/r8/cf/bootstrap/KotlinCompilerTreeShakingTest.java
index d5e17f4..d7a4cdc 100644
--- a/src/test/java/com/android/tools/r8/cf/bootstrap/KotlinCompilerTreeShakingTest.java
+++ b/src/test/java/com/android/tools/r8/cf/bootstrap/KotlinCompilerTreeShakingTest.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.KotlinCompilerTool.KotlinTargetVersion;
+import com.android.tools.r8.KotlinTestBase;
import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
@@ -58,7 +59,7 @@
// Compile Hello.kt and make sure it works as expected.
Path classPathBefore =
kotlinc(
- parameters.getRuntime().asCf(),
+ KotlinTestBase.getKotlincHostRuntime(parameters.getRuntime()),
kotlinTestParameters.getCompiler(),
kotlinTestParameters.getTargetVersion())
.addSourceFiles(HELLO_KT)
diff --git a/src/test/java/com/android/tools/r8/classmerging/KeptTargetsIncompleteDiamondTest.java b/src/test/java/com/android/tools/r8/classmerging/KeptTargetsIncompleteDiamondTest.java
index 51e4d41..e4a1a1a 100644
--- a/src/test/java/com/android/tools/r8/classmerging/KeptTargetsIncompleteDiamondTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/KeptTargetsIncompleteDiamondTest.java
@@ -78,7 +78,8 @@
// }
AppView<AppInfoWithLiveness> appView = computeAppViewWithLiveness(I.class, I.class);
DexMethod method = buildNullaryVoidMethod(I.class, "foo", appView.dexItemFactory());
- MethodResolutionResult resolutionResult = appView.appInfo().resolveMethodOnInterface(method);
+ MethodResolutionResult resolutionResult =
+ appView.appInfo().resolveMethodOnInterfaceHolder(method);
DexType typeI = buildType(I.class, appView.dexItemFactory());
DexType typeL = buildType(L.class, appView.dexItemFactory());
DexType typeA = buildType(A.class, appView.dexItemFactory());
@@ -119,7 +120,8 @@
// }
AppView<AppInfoWithLiveness> appView = computeAppViewWithLiveness(I.class, I.class);
DexMethod method = buildNullaryVoidMethod(I.class, "foo", appView.dexItemFactory());
- MethodResolutionResult resolutionResult = appView.appInfo().resolveMethodOnInterface(method);
+ MethodResolutionResult resolutionResult =
+ appView.appInfo().resolveMethodOnInterfaceHolder(method);
DexType typeI = buildType(I.class, appView.dexItemFactory());
DexType typeL = buildType(L.class, appView.dexItemFactory());
DexType typeA = buildType(A.class, appView.dexItemFactory());
@@ -159,7 +161,8 @@
// }
AppView<AppInfoWithLiveness> appView = computeAppViewWithLiveness(J.class, J.class);
DexMethod method = buildNullaryVoidMethod(I.class, "foo", appView.dexItemFactory());
- MethodResolutionResult resolutionResult = appView.appInfo().resolveMethodOnInterface(method);
+ MethodResolutionResult resolutionResult =
+ appView.appInfo().resolveMethodOnInterfaceHolder(method);
DexType typeI = buildType(I.class, appView.dexItemFactory());
DexType typeB = buildType(A.class, appView.dexItemFactory());
DexProgramClass classI = appView.definitionForProgramType(typeI);
@@ -196,7 +199,8 @@
// }
AppView<AppInfoWithLiveness> appView = computeAppViewWithLiveness(J.class, A.class);
DexMethod method = buildNullaryVoidMethod(I.class, "foo", appView.dexItemFactory());
- MethodResolutionResult resolutionResult = appView.appInfo().resolveMethodOnInterface(method);
+ MethodResolutionResult resolutionResult =
+ appView.appInfo().resolveMethodOnInterfaceHolder(method);
DexType typeI = buildType(I.class, appView.dexItemFactory());
DexType typeB = buildType(A.class, appView.dexItemFactory());
DexProgramClass classI = appView.definitionForProgramType(typeI);
@@ -235,7 +239,8 @@
// }
AppView<AppInfoWithLiveness> appView = computeAppViewWithLiveness(I.class, I.class);
DexMethod method = buildNullaryVoidMethod(I.class, "foo", appView.dexItemFactory());
- MethodResolutionResult resolutionResult = appView.appInfo().resolveMethodOnInterface(method);
+ MethodResolutionResult resolutionResult =
+ appView.appInfo().resolveMethodOnInterfaceHolder(method);
DexType typeI = buildType(I.class, appView.dexItemFactory());
DexType typeB = buildType(A.class, appView.dexItemFactory());
DexProgramClass classI = appView.definitionForProgramType(typeI);
diff --git a/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTestCollection.java b/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTestCollection.java
index 1ca2f2b..501370c 100644
--- a/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTestCollection.java
+++ b/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTestCollection.java
@@ -9,6 +9,8 @@
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.compilerapi.assertionconfiguration.AssertionConfigurationTest;
+import com.android.tools.r8.compilerapi.desugardependencies.DesugarDependenciesTest;
+import com.android.tools.r8.compilerapi.globalsynthetics.GlobalSyntheticsTest;
import com.android.tools.r8.compilerapi.inputdependencies.InputDependenciesTest;
import com.android.tools.r8.compilerapi.mapid.CustomMapIdTest;
import com.android.tools.r8.compilerapi.mockdata.MockClass;
@@ -32,11 +34,13 @@
ImmutableList.of(
ApiTestingSetUpTest.ApiTest.class,
CustomMapIdTest.ApiTest.class,
- CustomSourceFileTest.ApiTest.class);
+ CustomSourceFileTest.ApiTest.class,
+ AssertionConfigurationTest.ApiTest.class,
+ InputDependenciesTest.ApiTest.class,
+ DesugarDependenciesTest.ApiTest.class);
private static final List<Class<? extends CompilerApiTest>> CLASSES_PENDING_BINARY_COMPATIBILITY =
- ImmutableList.of(
- AssertionConfigurationTest.ApiTest.class, InputDependenciesTest.ApiTest.class);
+ ImmutableList.of(GlobalSyntheticsTest.ApiTest.class);
private final TemporaryFolder temp;
diff --git a/src/test/java/com/android/tools/r8/compilerapi/desugardependencies/DesugarDependenciesTest.java b/src/test/java/com/android/tools/r8/compilerapi/desugardependencies/DesugarDependenciesTest.java
new file mode 100644
index 0000000..2b83f85
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/compilerapi/desugardependencies/DesugarDependenciesTest.java
@@ -0,0 +1,86 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.compilerapi.desugardependencies;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.D8;
+import com.android.tools.r8.D8Command;
+import com.android.tools.r8.DesugarGraphConsumer;
+import com.android.tools.r8.DexIndexedConsumer;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.compilerapi.CompilerApiTest;
+import com.android.tools.r8.compilerapi.CompilerApiTestRunner;
+import com.android.tools.r8.origin.Origin;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import org.junit.Test;
+
+public class DesugarDependenciesTest extends CompilerApiTestRunner {
+
+ public DesugarDependenciesTest(TestParameters parameters) {
+ super(parameters);
+ }
+
+ @Override
+ public Class<? extends CompilerApiTest> binaryTestClass() {
+ return ApiTest.class;
+ }
+
+ @Test
+ public void testDesugarDependencies() throws Exception {
+ ApiTest test = new ApiTest(ApiTest.PARAMETERS);
+ runTest(test::run);
+ }
+
+ private interface Runner {
+ void run() throws Exception;
+ }
+
+ private void runTest(Runner test) throws Exception {
+ test.run();
+ }
+
+ public static class ApiTest extends CompilerApiTest {
+
+ public ApiTest(Object parameters) {
+ super(parameters);
+ }
+
+ public void run() throws Exception {
+ D8.run(
+ D8Command.builder()
+ .addClassProgramData(getBytesForClass(getMockClass()), Origin.unknown())
+ .addLibraryFiles(getJava8RuntimeJar())
+ .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
+ .setDesugarGraphConsumer(
+ new DesugarGraphConsumer() {
+ private final Set<Origin> desugaringUnit = ConcurrentHashMap.newKeySet();
+
+ @Override
+ public void acceptProgramNode(Origin node) {
+ desugaringUnit.add(node);
+ }
+
+ @Override
+ public void accept(Origin dependent, Origin dependency) {
+ assertTrue(desugaringUnit.contains(dependent));
+ }
+
+ @Override
+ public void finished() {
+ // Input unit contains just the mock class.
+ assertEquals(1, desugaringUnit.size());
+ }
+ })
+ .build());
+ }
+
+ @Test
+ public void testDesugarDependencies() throws Exception {
+ run();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/compilerapi/globalsynthetics/GlobalSyntheticsTest.java b/src/test/java/com/android/tools/r8/compilerapi/globalsynthetics/GlobalSyntheticsTest.java
new file mode 100644
index 0000000..edc42c2
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/compilerapi/globalsynthetics/GlobalSyntheticsTest.java
@@ -0,0 +1,87 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.compilerapi.globalsynthetics;
+
+import com.android.tools.r8.D8;
+import com.android.tools.r8.D8Command;
+import com.android.tools.r8.DexIndexedConsumer;
+import com.android.tools.r8.GlobalSyntheticsConsumer;
+import com.android.tools.r8.GlobalSyntheticsResourceProvider;
+import com.android.tools.r8.ResourceException;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.compilerapi.CompilerApiTest;
+import com.android.tools.r8.compilerapi.CompilerApiTestRunner;
+import com.android.tools.r8.origin.Origin;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.Test;
+
+public class GlobalSyntheticsTest extends CompilerApiTestRunner {
+
+ public GlobalSyntheticsTest(TestParameters parameters) {
+ super(parameters);
+ }
+
+ @Override
+ public Class<? extends CompilerApiTest> binaryTestClass() {
+ return ApiTest.class;
+ }
+
+ @Test
+ public void testGlobalSynthetics() throws Exception {
+ new ApiTest(ApiTest.PARAMETERS).run();
+ }
+
+ public static class ApiTest extends CompilerApiTest {
+
+ public ApiTest(Object parameters) {
+ super(parameters);
+ }
+
+ public void run() throws Exception {
+ GlobalSyntheticsResourceProvider provider =
+ new GlobalSyntheticsResourceProvider() {
+ @Override
+ public Origin getOrigin() {
+ return Origin.unknown();
+ }
+
+ @Override
+ public InputStream getByteStream() throws ResourceException {
+ throw new IllegalStateException();
+ }
+ };
+ List<GlobalSyntheticsResourceProvider> providers = new ArrayList<>();
+ // Don't actually add the provider as we don't have any bytes to return.
+ if (false) {
+ providers.add(provider);
+ }
+ D8.run(
+ D8Command.builder()
+ .addClassProgramData(getBytesForClass(getMockClass()), Origin.unknown())
+ .addLibraryFiles(getJava8RuntimeJar())
+ .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
+ .setIntermediate(true)
+ .addGlobalSyntheticsFiles()
+ .addGlobalSyntheticsFiles(new ArrayList<>())
+ .addGlobalSyntheticsResourceProviders()
+ .addGlobalSyntheticsResourceProviders(providers)
+ .setGlobalSyntheticsConsumer(
+ new GlobalSyntheticsConsumer() {
+ @Override
+ public void accept(byte[] bytes) {
+ // Nothing is actually received here as MockClass does not give rise to
+ // globals.
+ }
+ })
+ .build());
+ }
+
+ @Test
+ public void testGlobalSynthetics() throws Exception {
+ run();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java
index f79b585..93ea904 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java
@@ -51,13 +51,7 @@
}
private String expectedOutput() {
- return StringUtils.lines(
- "Hello",
- "Larry",
- "Page",
- parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N)
- ? "Caught java.io.UncheckedIOException"
- : "Caught j$.io.UncheckedIOException");
+ return StringUtils.lines("Hello", "Larry", "Page", "Caught java.io.UncheckedIOException");
}
DesugaredLibrarySpecification configurationAlternative3(
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideConflictWithLibrary2Test.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideConflictWithLibrary2Test.java
index e836c76..7d73298 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideConflictWithLibrary2Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideConflictWithLibrary2Test.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.desugar.desugaredlibrary;
-import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@@ -90,12 +89,11 @@
}
private void checkResult(TestRunResult<?> result) {
- if (parameters.isCfRuntime() && parameters.getRuntime().asCf().getVm().equals(CfVm.JDK11)) {
- // TODO(b/145566657): For some reason JDK11 throws AbstractMethodError.
- result.assertFailureWithErrorThatMatches(containsString(AbstractMethodError.class.getName()));
+ if (parameters.isCfRuntime() && parameters.getRuntime().asCf().isNewerThanOrEqual(CfVm.JDK11)) {
+ // TODO(b/145566657): For some reason JDK11+ throws AbstractMethodError.
+ result.assertFailureWithErrorThatThrows(AbstractMethodError.class);
} else {
- result.assertFailureWithErrorThatMatches(
- containsString(IncompatibleClassChangeError.class.getName()));
+ result.assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class);
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IterableTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IterableTest.java
index e2cdf17..8fd4cd4 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IterableTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IterableTest.java
@@ -8,6 +8,8 @@
import com.android.tools.r8.LibraryDesugaringTestConfiguration;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -91,7 +93,12 @@
.addProgramFiles(jar)
.addRunClasspathFiles(buildDesugaredLibraryClassFile(parameters.getApiLevel()))
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutput(EXPECTED_OUTPUT);
+ .applyIf(
+ // TODO(b/227161271): Figure out the cause and resolution for this issue.
+ parameters.isCfRuntime(CfVm.JDK17)
+ && parameters.getApiLevel().equals(AndroidApiLevel.B),
+ r -> r.assertFailureWithErrorThatThrows(ExceptionInInitializerError.class),
+ r -> r.assertSuccessWithOutput(EXPECTED_OUTPUT));
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/graph/CompilationDependentSetTest.java b/src/test/java/com/android/tools/r8/desugar/graph/CompilationDependentSetTest.java
new file mode 100644
index 0000000..b0f6682
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/graph/CompilationDependentSetTest.java
@@ -0,0 +1,97 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.desugar.graph;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.D8TestBuilder;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.google.common.collect.ImmutableSet;
+import java.nio.file.Path;
+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 CompilationDependentSetTest extends TestBase {
+
+ public interface I {
+ // Empty.
+ }
+
+ public static class A implements I {
+ // Empty.
+ }
+
+ public static class B {
+ // Empty.
+ }
+
+ public static class TestClass {
+
+ public static void main(String[] args) {
+ System.out.println("Hello World!");
+ }
+ }
+
+ // Test runner follows.
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimes().withAllApiLevels().build();
+ }
+
+ private final TestParameters parameters;
+
+ public CompilationDependentSetTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ if (parameters.isCfRuntime()) {
+ testForJvm()
+ .addProgramClasses(I.class, A.class, B.class, TestClass.class)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("Hello World!");
+ } else {
+ Path dexInputForB =
+ testForD8()
+ .addProgramClasses(B.class)
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .writeToZip();
+
+ D8TestBuilder builder = testForD8();
+ DesugarGraphTestConsumer consumer = new DesugarGraphTestConsumer();
+ builder.getBuilder().setDesugarGraphConsumer(consumer);
+ Origin originI = DesugarGraphUtils.addClassWithOrigin(I.class, builder);
+ Origin originA = DesugarGraphUtils.addClassWithOrigin(A.class, builder);
+ Origin originTestClass = DesugarGraphUtils.addClassWithOrigin(TestClass.class, builder);
+ builder
+ .addProgramFiles(dexInputForB)
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("Hello World!");
+ // If API level indicates desugaring is needed check the edges are reported.
+ if (parameters.getApiLevel().getLevel() < AndroidApiLevel.N.getLevel()) {
+ assertTrue(consumer.contains(originI, originA));
+ assertEquals(1, consumer.totalEdgeCount());
+ } else {
+ assertEquals(0, consumer.totalEdgeCount());
+ }
+ // Regardless of API the potential inputs are reported.
+ // Note that the DEX input is not a desugaring candidate and thus not included in the unit.
+ assertEquals(
+ ImmutableSet.of(originI, originA, originTestClass),
+ consumer.getDesugaringCompilationUnit());
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/graph/DesugarGraphTestConsumer.java b/src/test/java/com/android/tools/r8/desugar/graph/DesugarGraphTestConsumer.java
index cb0da77..d80d81e 100644
--- a/src/test/java/com/android/tools/r8/desugar/graph/DesugarGraphTestConsumer.java
+++ b/src/test/java/com/android/tools/r8/desugar/graph/DesugarGraphTestConsumer.java
@@ -22,6 +22,9 @@
private boolean finished = false;
+ // Set of all origins for the desugaring candidates in the compilation unit.
+ private final Set<Origin> desugaringCompilationUnit = new HashSet<>();
+
// Map from a dependency to its immediate dependents.
private final Map<Origin, Set<Origin>> dependents = new HashMap<>();
@@ -81,6 +84,16 @@
return count;
}
+ public Set<Origin> getDesugaringCompilationUnit() {
+ assertTrue(finished);
+ return desugaringCompilationUnit;
+ }
+
+ @Override
+ public synchronized void acceptProgramNode(Origin node) {
+ desugaringCompilationUnit.add(node);
+ }
+
@Override
public synchronized void accept(Origin dependent, Origin dependency) {
assertFalse(finished);
diff --git a/src/test/java/com/android/tools/r8/desugar/graph/InterfaceToImplementingClassDependencyTest.java b/src/test/java/com/android/tools/r8/desugar/graph/InterfaceToImplementingClassDependencyTest.java
index 705410a..6339195 100644
--- a/src/test/java/com/android/tools/r8/desugar/graph/InterfaceToImplementingClassDependencyTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/graph/InterfaceToImplementingClassDependencyTest.java
@@ -33,7 +33,7 @@
// Note: the dependency of I for the compilation of A exists even when no default methods do.
public interface I {
- // Emtpy.
+ // Empty.
}
public static class A implements I {
diff --git a/src/test/java/com/android/tools/r8/desugar/jdk8272564/Jdk8272564Test.java b/src/test/java/com/android/tools/r8/desugar/jdk8272564/Jdk8272564Test.java
index 191cc22..13e021d 100644
--- a/src/test/java/com/android/tools/r8/desugar/jdk8272564/Jdk8272564Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/jdk8272564/Jdk8272564Test.java
@@ -11,7 +11,7 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.TestRuntime;
+import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.examples.jdk18.jdk8272564.Jdk8272564;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.InternalOptions.TestingOptions;
@@ -30,9 +30,8 @@
public static TestParametersCollection data() {
// TODO(b/218293990): Right now the JDK 18 tests are built with -target 17, as our Gradle
// version does not know of -target 18.
- // TODO(b/174431251): This should be replaced with .withCfRuntimes(start = jdk17).
return getTestParameters()
- .withCustomRuntime(TestRuntime.getCheckedInJdk17())
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK17)
.withDexRuntimes()
.withAllApiLevelsAlsoForCf()
.build();
@@ -119,20 +118,24 @@
assertJdk8272564NotFixedCode(inspector, 19, 0);
}
+ private boolean isDefaultCfParameters() {
+ return parameters.isCfRuntime() && parameters.getApiLevel().equals(AndroidApiLevel.B);
+ }
+
@Test
// See https://bugs.openjdk.java.net/browse/JDK-8272564.
public void testJdk8272564Compiler() throws Exception {
- assumeTrue(parameters.isCfRuntime());
+ assumeTrue(isDefaultCfParameters());
// Ensure that the test is running with CF input from fixing JDK-8272564.
assertJdk8272564FixedCode(new CodeInspector(Jdk8272564.jar()));
}
@Test
public void testJvm() throws Exception {
- assumeTrue(parameters.isCfRuntime());
+ assumeTrue(isDefaultCfParameters());
testForJvm()
.addRunClasspathFiles(Jdk8272564.jar())
- .run(TestRuntime.getCheckedInJdk17(), Jdk8272564.Main.typeName())
+ .run(parameters.getRuntime(), Jdk8272564.Main.typeName())
.assertSuccess();
}
@@ -150,6 +153,7 @@
@Test
public void testR8() throws Exception {
+ assumeTrue(parameters.isDexRuntime() || isDefaultCfParameters());
// The R8 lens code rewriter rewrites to the code prior to fixing JDK-8272564.
testForR8(parameters.getBackend())
.addProgramFiles(Jdk8272564.jar())
diff --git a/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaFactoryTest.java b/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaFactoryTest.java
new file mode 100644
index 0000000..21ed11f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaFactoryTest.java
@@ -0,0 +1,158 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.desugar.lambdas;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.android.tools.r8.DesugarTestConfiguration;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+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 LambdaFactoryTest extends TestBase {
+
+ @Parameter() public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build();
+ }
+
+ private static final String EXPECTED_OUTPUT = StringUtils.lines("1", "2", "3", "4.0", "5");
+
+ private boolean isLambdaFactoryMethod(MethodSubject method) {
+ return method.isSynthetic() && method.isStatic() && method.getFinalName().equals("create");
+ }
+
+ private boolean isInvokingLambdaFactoryMethod(InstructionSubject instruction) {
+ return instruction.isInvokeStatic()
+ && SyntheticItemsTestUtils.isExternalSynthetic(
+ instruction.getMethod().getHolderType().asClassReference())
+ && instruction.getMethod().getName().toString().equals("create");
+ }
+
+ private void inspectDesugared(CodeInspector inspector) {
+ inspector.forAllClasses(
+ clazz -> {
+ if (SyntheticItemsTestUtils.isExternalSynthetic(clazz.getFinalReference())) {
+ assertTrue(clazz.allMethods().stream().anyMatch(this::isLambdaFactoryMethod));
+ }
+ });
+ assertEquals(
+ 3,
+ inspector
+ .clazz(TestClass.class)
+ .mainMethod()
+ .streamInstructions()
+ .filter(this::isInvokingLambdaFactoryMethod)
+ .count());
+ }
+
+ private void inspectNotDesugared(CodeInspector inspector) {
+ inspector.forAllClasses(
+ clazz -> {
+ if (SyntheticItemsTestUtils.isExternalSynthetic(clazz.getFinalReference())) {
+ assertTrue(clazz.allMethods().stream().noneMatch(this::isLambdaFactoryMethod));
+ }
+ });
+ assertEquals(
+ 0,
+ inspector
+ .clazz(TestClass.class)
+ .mainMethod()
+ .streamInstructions()
+ .filter(this::isInvokingLambdaFactoryMethod)
+ .count());
+ }
+
+ @Test
+ public void testDesugaring() throws Exception {
+ testForDesugaring(
+ parameters,
+ options -> {
+ options.testing.alwaysGenerateLambdaFactoryMethods = true;
+ })
+ .addInnerClasses(getClass())
+ .run(parameters.getRuntime(), TestClass.class)
+ .applyIf(
+ DesugarTestConfiguration::isDesugared,
+ r -> {
+ try {
+ r.inspect(this::inspectDesugared);
+ } catch (Exception e) {
+ fail();
+ }
+ },
+ r -> {
+ try {
+ r.inspect(this::inspectNotDesugared);
+ } catch (Exception e) {
+ fail();
+ }
+ })
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(TestClass.class)
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), TestClass.class)
+ .inspect(
+ inspector -> {
+ if (parameters.isDexRuntime()) {
+ // Lambdas are fully inlined when desugaring.
+ assertEquals(1, inspector.allClasses().size());
+ assertEquals(1, inspector.clazz(TestClass.class).allMethods().size());
+ }
+ })
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
+ }
+
+ interface MyConsumer<T> {
+ void create(T o);
+ }
+
+ interface MyTriConsumer<T, U, V> {
+ void accept(T o1, U o2, V o3);
+ }
+
+ static class TestClass {
+
+ public static void greet() {
+ System.out.println("1");
+ }
+
+ public static void greet(MyConsumer<String> consumer) {
+ consumer.create("2");
+ }
+
+ public static void greetTri(long l, double d, String s) {
+ System.out.println(l);
+ System.out.println(d);
+ System.out.println(s);
+ }
+
+ public static void main(String[] args) throws Exception {
+ ((Runnable) TestClass::greet).run();
+ greet(System.out::println);
+ ((MyTriConsumer<Long, Double, String>) TestClass::greetTri).accept(3L, 4.0, "5");
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordAnnotationTest.java b/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordAnnotationTest.java
index 2446b14..1624c29 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordAnnotationTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordAnnotationTest.java
@@ -5,11 +5,13 @@
package com.android.tools.r8.desugar.records;
import static com.android.tools.r8.utils.InternalOptions.TestingOptions;
+import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestRuntime.CfRuntime;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.StringUtils;
import java.util.List;
import org.junit.Test;
@@ -36,18 +38,21 @@
@Parameterized.Parameters(name = "{0}")
public static List<Object[]> data() {
- // TODO(b/174431251): This should be replaced with .withCfRuntimes(start = jdk16).
return buildParameters(
getTestParameters()
- .withCustomRuntime(CfRuntime.getCheckedInJdk17())
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK17)
.withDexRuntimes()
.withAllApiLevelsAlsoForCf()
.build());
}
+ private boolean isDefaultCfParameters() {
+ return parameters.isCfRuntime() && parameters.getApiLevel().equals(AndroidApiLevel.B);
+ }
+
@Test
public void testD8AndJvm() throws Exception {
- if (parameters.isCfRuntime()) {
+ if (isDefaultCfParameters()) {
testForJvm()
.addProgramClassFileData(PROGRAM_DATA)
.run(parameters.getRuntime(), MAIN_TYPE)
@@ -64,6 +69,7 @@
@Test
public void testR8() throws Exception {
+ assumeTrue(parameters.isDexRuntime() || isDefaultCfParameters());
R8FullTestBuilder builder =
testForR8(parameters.getBackend())
.addProgramClassFileData(PROGRAM_DATA)
diff --git a/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordTest.java b/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordTest.java
index 7a64c3c..5f1b68f 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordTest.java
@@ -9,7 +9,7 @@
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestRuntime.CfRuntime;
+import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.utils.StringUtils;
import java.util.List;
import org.junit.Test;
@@ -33,10 +33,9 @@
@Parameterized.Parameters(name = "{0}")
public static List<Object[]> data() {
- // TODO(b/174431251): This should be replaced with .withCfRuntimes(start = jdk17).
return buildParameters(
getTestParameters()
- .withCustomRuntime(CfRuntime.getCheckedInJdk17())
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK17)
.withDexRuntimes()
.withAllApiLevelsAlsoForCf()
.build());
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordInstanceOfTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordInstanceOfTest.java
index 1c32b27..743b2b4 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordInstanceOfTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordInstanceOfTest.java
@@ -7,7 +7,7 @@
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestRuntime.CfRuntime;
+import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.utils.InternalOptions.TestingOptions;
import com.android.tools.r8.utils.StringUtils;
import java.util.List;
@@ -31,10 +31,9 @@
@Parameterized.Parameters(name = "{0}")
public static List<Object[]> data() {
- // TODO(b/174431251): This should be replaced with .withCfRuntimes(start = jdk17).
return buildParameters(
getTestParameters()
- .withCustomRuntime(CfRuntime.getCheckedInJdk17())
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK17)
.withDexRuntimes()
.withAllApiLevelsAlsoForCf()
.build());
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomTest.java
index 7207f6d..61ee05b 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomTest.java
@@ -7,7 +7,7 @@
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestRuntime.CfRuntime;
+import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.utils.InternalOptions.TestingOptions;
import com.android.tools.r8.utils.StringUtils;
import java.util.List;
@@ -48,10 +48,9 @@
@Parameterized.Parameters(name = "{0}")
public static List<Object[]> data() {
- // TODO(b/174431251): This should be replaced with .withCfRuntimes(start = jdk17).
return buildParameters(
getTestParameters()
- .withCustomRuntime(CfRuntime.getCheckedInJdk17())
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK17)
.withDexRuntimes()
.withAllApiLevelsAlsoForCf()
.build());
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordLibMergeTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordLibMergeTest.java
index 7c32b98..53eff63 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordLibMergeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordLibMergeTest.java
@@ -7,7 +7,7 @@
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestRuntime.CfRuntime;
+import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.utils.InternalOptions.TestingOptions;
import com.android.tools.r8.utils.StringUtils;
import java.nio.file.Path;
@@ -34,10 +34,9 @@
@Parameterized.Parameters(name = "{0}")
public static List<Object[]> data() {
- // TODO(b/174431251): This should be replaced with .withCfRuntimes(start = jdk17).
return buildParameters(
getTestParameters()
- .withCustomRuntime(CfRuntime.getCheckedInJdk17())
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK17)
.withDexRuntimes()
.withAllApiLevelsAlsoForCf()
.build());
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordMergeTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordMergeTest.java
index 8401196..cf3c955 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordMergeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordMergeTest.java
@@ -4,15 +4,25 @@
package com.android.tools.r8.desugar.records;
+import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
+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.assertThrows;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.D8TestCompileResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestRuntime.CfRuntime;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.errors.DuplicateTypesDiagnostic;
+import com.android.tools.r8.errors.MissingGlobalSyntheticsConsumerDiagnostic;
+import com.android.tools.r8.synthesis.globals.GlobalSyntheticsConsumerAndProvider;
import com.android.tools.r8.utils.InternalOptions.TestingOptions;
import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
import java.nio.file.Path;
-import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -34,66 +44,93 @@
StringUtils.lines("Jane Doe", "42", "Jane Doe", "42");
private final TestParameters parameters;
- private final boolean intermediate;
- public RecordMergeTest(TestParameters parameters, boolean intermediate) {
+ public RecordMergeTest(TestParameters parameters) {
this.parameters = parameters;
- this.intermediate = intermediate;
}
- @Parameterized.Parameters(name = "{0}, intermediate: {1}")
- public static List<Object[]> data() {
- // TODO(b/174431251): This should be replaced with .withCfRuntimes(start = jdk17).
- return buildParameters(
- getTestParameters()
- .withCustomRuntime(CfRuntime.getCheckedInJdk17())
- .withDexRuntimes()
- .withAllApiLevelsAlsoForCf()
- .build(),
- BooleanUtils.values());
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build();
+ }
+
+ @Test
+ public void testFailureWithoutGlobalSyntheticsConsumer() throws Exception {
+ assertThrows(
+ CompilationFailedException.class,
+ () ->
+ testForD8(parameters.getBackend())
+ .addProgramClassFileData(PROGRAM_DATA_1)
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
+ .setIntermediate(true)
+ .compileWithExpectedDiagnostics(
+ diagnostics ->
+ diagnostics
+ .assertOnlyErrors()
+ .assertErrorsMatch(
+ diagnosticType(MissingGlobalSyntheticsConsumerDiagnostic.class))));
}
@Test
public void testMergeDesugaredInputs() throws Exception {
+ GlobalSyntheticsConsumerAndProvider globals1 = new GlobalSyntheticsConsumerAndProvider();
Path output1 =
testForD8(parameters.getBackend())
.addProgramClassFileData(PROGRAM_DATA_1)
.setMinApi(parameters.getApiLevel())
.addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
- .setIntermediate(intermediate)
+ .setIntermediate(true)
+ .apply(b -> b.getBuilder().setGlobalSyntheticsConsumer(globals1))
.compile()
+ .inspect(this::assertDoesNotHaveRecordTag)
.writeToZip();
+
+ GlobalSyntheticsConsumerAndProvider globals2 = new GlobalSyntheticsConsumerAndProvider();
Path output2 =
testForD8(parameters.getBackend())
.addProgramClassFileData(PROGRAM_DATA_2)
.setMinApi(parameters.getApiLevel())
.addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
- .setIntermediate(intermediate)
+ .setIntermediate(true)
+ .apply(b -> b.getBuilder().setGlobalSyntheticsConsumer(globals2))
.compile()
+ .inspect(this::assertDoesNotHaveRecordTag)
.writeToZip();
+
+ assertTrue(globals1.hasBytes());
+ assertTrue(globals2.hasBytes());
+
D8TestCompileResult result =
testForD8(parameters.getBackend())
.addProgramFiles(output1, output2)
+ .apply(b -> b.getBuilder().addGlobalSyntheticsResourceProviders(globals1, globals2))
.setMinApi(parameters.getApiLevel())
.addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
- .compile();
+ .compile()
+ .inspect(this::assertHasRecordTag);
+
result.run(parameters.getRuntime(), MAIN_TYPE_1).assertSuccessWithOutput(EXPECTED_RESULT_1);
result.run(parameters.getRuntime(), MAIN_TYPE_2).assertSuccessWithOutput(EXPECTED_RESULT_2);
}
@Test
public void testMergeDesugaredAndNonDesugaredInputs() throws Exception {
+ GlobalSyntheticsConsumerAndProvider globals1 = new GlobalSyntheticsConsumerAndProvider();
Path output1 =
testForD8(parameters.getBackend())
.addProgramClassFileData(PROGRAM_DATA_1)
.setMinApi(parameters.getApiLevel())
.addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
- .setIntermediate(intermediate)
+ .setIntermediate(true)
+ .apply(b -> b.getBuilder().setGlobalSyntheticsConsumer(globals1))
.compile()
.writeToZip();
+
D8TestCompileResult result =
testForD8(parameters.getBackend())
.addProgramFiles(output1)
+ .apply(b -> b.getBuilder().addGlobalSyntheticsResourceProviders(globals1))
.addProgramClassFileData(PROGRAM_DATA_2)
.setMinApi(parameters.getApiLevel())
.addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
@@ -101,4 +138,48 @@
result.run(parameters.getRuntime(), MAIN_TYPE_1).assertSuccessWithOutput(EXPECTED_RESULT_1);
result.run(parameters.getRuntime(), MAIN_TYPE_2).assertSuccessWithOutput(EXPECTED_RESULT_2);
}
+
+ @Test
+ public void testMergeNonIntermediates() throws Exception {
+ Path output1 =
+ testForD8(parameters.getBackend())
+ .addProgramClassFileData(PROGRAM_DATA_1)
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
+ .compile()
+ .inspect(this::assertHasRecordTag)
+ .writeToZip();
+
+ Path output2 =
+ testForD8(parameters.getBackend())
+ .addProgramClassFileData(PROGRAM_DATA_2)
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
+ .compile()
+ .inspect(this::assertHasRecordTag)
+ .writeToZip();
+
+ assertThrows(
+ CompilationFailedException.class,
+ () ->
+ testForD8(parameters.getBackend())
+ .addProgramFiles(output1, output2)
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
+ .compileWithExpectedDiagnostics(
+ diagnostics ->
+ diagnostics
+ .assertOnlyErrors()
+ .assertErrorsMatch(diagnosticType(DuplicateTypesDiagnostic.class))));
+ }
+
+ private void assertHasRecordTag(CodeInspector inspector) {
+ // Note: this should be asserting on record tag.
+ assertThat(inspector.clazz("java.lang.Record"), isPresent());
+ }
+
+ private void assertDoesNotHaveRecordTag(CodeInspector inspector) {
+ // Note: this should be asserting on record tag.
+ assertThat(inspector.clazz("java.lang.Record"), isAbsent());
+ }
}
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordReflectionTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordReflectionTest.java
index 82891db..7b1096d 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordReflectionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordReflectionTest.java
@@ -6,7 +6,7 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestRuntime.CfRuntime;
+import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.utils.InternalOptions.TestingOptions;
import com.android.tools.r8.utils.StringUtils;
import java.util.List;
@@ -40,9 +40,8 @@
@Parameterized.Parameters(name = "{0}")
public static List<Object[]> data() {
- // TODO(b/174431251): This should be replaced with .withCfRuntimes(start = jdk17).
return buildParameters(
- getTestParameters().withCustomRuntime(CfRuntime.getCheckedInJdk17()).build());
+ getTestParameters().withCfRuntimesStartingFromIncluding(CfVm.JDK17).build());
}
@Test
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordWithMembersTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordWithMembersTest.java
index f22f8cd..eb8ef2d 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordWithMembersTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordWithMembersTest.java
@@ -7,7 +7,7 @@
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestRuntime.CfRuntime;
+import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.utils.InternalOptions.TestingOptions;
import com.android.tools.r8.utils.StringUtils;
import java.util.List;
@@ -33,10 +33,9 @@
@Parameterized.Parameters(name = "{0}")
public static List<Object[]> data() {
- // TODO(b/174431251): This should be replaced with .withCfRuntimes(start = jdk17).
return buildParameters(
getTestParameters()
- .withCustomRuntime(CfRuntime.getCheckedInJdk17())
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK17)
.withDexRuntimes()
.withAllApiLevelsAlsoForCf()
.build());
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 56dab1e..212098c 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
@@ -4,16 +4,20 @@
package com.android.tools.r8.desugar.records;
+import static org.junit.Assume.assumeTrue;
+import com.android.tools.r8.GlobalSyntheticsConsumer;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfRuntime;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.synthesis.globals.GlobalSyntheticsConsumerAndProvider;
+import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.InternalOptions.TestingOptions;
import com.android.tools.r8.utils.StringUtils;
import java.nio.file.Path;
import java.util.List;
-import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -35,23 +39,30 @@
@Parameterized.Parameters(name = "{0}")
public static List<Object[]> data() {
- // TODO(b/174431251): This should be replaced with .withCfRuntimes(start = jdk17).
return buildParameters(
getTestParameters()
- .withCustomRuntime(CfRuntime.getCheckedInJdk17())
- .withDexRuntimes()
+ .withAllRuntimes()
.withAllApiLevelsAlsoForCf()
.build());
}
+ private boolean isCfWithNativeRecordSupport() {
+ return parameters.isCfRuntime()
+ && parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK14)
+ && parameters.getApiLevel().equals(AndroidApiLevel.B);
+ }
+
@Test
- public void testD8AndJvm() throws Exception {
- if (parameters.isCfRuntime()) {
- testForJvm()
- .addProgramClassFileData(PROGRAM_DATA)
- .run(parameters.getRuntime(), MAIN_TYPE)
- .assertSuccessWithOutput(EXPECTED_RESULT);
- }
+ public void testReference() throws Exception {
+ assumeTrue(isCfWithNativeRecordSupport());
+ testForJvm()
+ .addProgramClassFileData(PROGRAM_DATA)
+ .run(parameters.getRuntime(), MAIN_TYPE)
+ .assertSuccessWithOutput(EXPECTED_RESULT);
+ }
+
+ @Test
+ public void testD8() throws Exception {
testForD8(parameters.getBackend())
.addProgramClassFileData(PROGRAM_DATA)
.setMinApi(parameters.getApiLevel())
@@ -66,10 +77,12 @@
@Test
public void testD8Intermediate() throws Exception {
- Assume.assumeTrue(parameters.isDexRuntime());
- Path path = compileIntermediate();
+ assumeTrue(parameters.isDexRuntime());
+ GlobalSyntheticsConsumerAndProvider globals = new GlobalSyntheticsConsumerAndProvider();
+ Path path = compileIntermediate(globals);
testForD8()
.addProgramFiles(path)
+ .apply(b -> b.getBuilder().addGlobalSyntheticsResourceProviders(globals))
.setMinApi(parameters.getApiLevel())
.setIncludeClassesChecksum(true)
.run(parameters.getRuntime(), MAIN_TYPE)
@@ -78,11 +91,13 @@
@Test
public void testD8IntermediateNoDesugaringInStep2() throws Exception {
- Assume.assumeTrue(parameters.isDexRuntime());
- Path path = compileIntermediate();
+ assumeTrue(parameters.isDexRuntime());
+ GlobalSyntheticsConsumerAndProvider globals = new GlobalSyntheticsConsumerAndProvider();
+ Path path = compileIntermediate(globals);
// In Android Studio they disable desugaring at this point to improve build speed.
testForD8()
.addProgramFiles(path)
+ .apply(b -> b.getBuilder().addGlobalSyntheticsResourceProviders(globals))
.setMinApi(parameters.getApiLevel())
.setIncludeClassesChecksum(true)
.disableDesugaring()
@@ -90,19 +105,22 @@
.assertSuccessWithOutput(EXPECTED_RESULT);
}
- private Path compileIntermediate() throws Exception {
+ private Path compileIntermediate(GlobalSyntheticsConsumer globalSyntheticsConsumer)
+ throws Exception {
return testForD8(Backend.DEX)
.addProgramClassFileData(PROGRAM_DATA)
.setMinApi(parameters.getApiLevel())
.addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.setIntermediate(true)
.setIncludeClassesChecksum(true)
+ .apply(b -> b.getBuilder().setGlobalSyntheticsConsumer(globalSyntheticsConsumer))
.compile()
.writeToZip();
}
@Test
public void testR8() throws Exception {
+ assumeTrue(parameters.isDexRuntime() || isCfWithNativeRecordSupport());
R8FullTestBuilder builder =
testForR8(parameters.getBackend())
.addProgramClassFileData(PROGRAM_DATA)
@@ -129,6 +147,7 @@
@Test
public void testR8NoMinification() throws Exception {
+ assumeTrue(parameters.isDexRuntime() || isCfWithNativeRecordSupport());
R8FullTestBuilder builder =
testForR8(parameters.getBackend())
.addProgramClassFileData(PROGRAM_DATA)
diff --git a/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordFieldTest.java b/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordFieldTest.java
index 5c520cc..24ae5d7 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordFieldTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordFieldTest.java
@@ -9,7 +9,7 @@
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestRuntime.CfRuntime;
+import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.utils.StringUtils;
import java.util.List;
import org.junit.Test;
@@ -32,10 +32,9 @@
@Parameterized.Parameters(name = "{0}")
public static List<Object[]> data() {
- // TODO(b/174431251): This should be replaced with .withCfRuntimes(start = jdk16).
return buildParameters(
getTestParameters()
- .withCustomRuntime(CfRuntime.getCheckedInJdk17())
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK17)
.withDexRuntimes()
.withAllApiLevelsAlsoForCf()
.build());
diff --git a/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordMethodTest.java b/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordMethodTest.java
index 4c2ddf5..702cc75 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordMethodTest.java
@@ -9,7 +9,7 @@
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestRuntime.CfRuntime;
+import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.utils.StringUtils;
import java.util.List;
import org.junit.Test;
@@ -32,10 +32,9 @@
@Parameterized.Parameters(name = "{0}")
public static List<Object[]> data() {
- // TODO(b/174431251): This should be replaced with .withCfRuntimes(start = jdk16).
return buildParameters(
getTestParameters()
- .withCustomRuntime(CfRuntime.getCheckedInJdk17())
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK17)
.withDexRuntimes()
.withAllApiLevelsAlsoForCf()
.build());
diff --git a/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordReflectionTest.java b/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordReflectionTest.java
index 7317cea..0687934 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordReflectionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordReflectionTest.java
@@ -9,7 +9,7 @@
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestRuntime.CfRuntime;
+import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.utils.StringUtils;
import java.util.List;
import org.junit.Test;
@@ -32,10 +32,9 @@
@Parameterized.Parameters(name = "{0}")
public static List<Object[]> data() {
- // TODO(b/174431251): This should be replaced with .withCfRuntimes(start = jdk16).
return buildParameters(
getTestParameters()
- .withCustomRuntime(CfRuntime.getCheckedInJdk17())
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK17)
.withDexRuntimes()
.withAllApiLevelsAlsoForCf()
.build());
diff --git a/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeTest.java b/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeTest.java
index 35293b5..3a5ba83 100644
--- a/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeTest.java
@@ -12,7 +12,7 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestRuntime;
+import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.examples.jdk17.Sealed;
import com.android.tools.r8.utils.AndroidApiLevel;
import java.util.List;
@@ -24,17 +24,18 @@
@RunWith(Parameterized.class)
public class SealedAttributeTest extends TestBase {
+ private final TestParameters parameters;
private final Backend backend;
- @Parameters(name = "{0}")
+ @Parameters(name = "{0}, backend:{1}")
public static List<Object[]> data() {
- // TODO(b/174431251): This should be replaced with .withCfRuntimes(start = jdk17).
return buildParameters(
- getTestParameters().withCustomRuntime(TestRuntime.getCheckedInJdk17()).build(),
+ getTestParameters().withCfRuntimesStartingFromIncluding(CfVm.JDK17).build(),
Backend.values());
}
public SealedAttributeTest(TestParameters parameters, Backend backend) {
+ this.parameters = parameters;
this.backend = backend;
}
@@ -43,7 +44,7 @@
assumeTrue(backend == Backend.CF);
testForJvm()
.addRunClasspathFiles(Sealed.jar())
- .run(TestRuntime.getCheckedInJdk17(), Sealed.Main.typeName())
+ .run(parameters.getRuntime(), Sealed.Main.typeName())
.assertSuccessWithOutputLines("R8 compiler", "D8 compiler");
}
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/ConstClassEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/ConstClassEnumUnboxingTest.java
new file mode 100644
index 0000000..8f1d0ab
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/enumunboxing/ConstClassEnumUnboxingTest.java
@@ -0,0 +1,53 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.enumunboxing;
+
+import com.android.tools.r8.TestParameters;
+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 ConstClassEnumUnboxingTest extends EnumUnboxingTestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameter(1)
+ public EnumKeepRules enumKeepRules;
+
+ @Parameters(name = "{0}, keep: {1}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withAllRuntimesAndApiLevels().build(), getAllEnumKeepRules());
+ }
+
+ @Test
+ public void testEnumUnboxing() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(ConstClassEnumUnboxingTest.class)
+ .addKeepMainRule(Main.class)
+ .addKeepRules(enumKeepRules.getKeepRules())
+ .addEnumUnboxingInspector(inspector -> inspector.assertUnboxed(MyEnum.class))
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("int");
+ }
+
+ enum MyEnum {
+ A
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ System.out.println(MyEnum.class.getName());
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/NullValuedFieldEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/NullValuedFieldEnumUnboxingTest.java
new file mode 100644
index 0000000..db8a047
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/enumunboxing/NullValuedFieldEnumUnboxingTest.java
@@ -0,0 +1,63 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.enumunboxing;
+
+import com.android.tools.r8.TestParameters;
+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 NullValuedFieldEnumUnboxingTest extends EnumUnboxingTestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameter(1)
+ public EnumKeepRules enumKeepRules;
+
+ @Parameters(name = "{0}, keep: {1}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withAllRuntimesAndApiLevels().build(), getAllEnumKeepRules());
+ }
+
+ @Test
+ public void testEnumUnboxing() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(NullValuedFieldEnumUnboxingTest.class)
+ .addKeepMainRule(Main.class)
+ .addKeepRules(enumKeepRules.getKeepRules())
+ .addEnumUnboxingInspector(inspector -> inspector.assertUnboxed(MyEnum.class))
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("a", "null");
+ }
+
+ enum MyEnum {
+ A("a"),
+ B(null);
+
+ String value;
+
+ MyEnum(String value) {
+ this.value = value;
+ }
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ MyEnum a = System.currentTimeMillis() > 0 ? MyEnum.A : MyEnum.B;
+ MyEnum b = System.currentTimeMillis() > 0 ? MyEnum.B : MyEnum.A;
+ System.out.println(a.value);
+ System.out.println(b.value);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/VirtualMethodOverrideEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/VirtualMethodOverrideEnumUnboxingTest.java
index c11a623..9dcd9cb 100644
--- a/src/test/java/com/android/tools/r8/enumunboxing/VirtualMethodOverrideEnumUnboxingTest.java
+++ b/src/test/java/com/android/tools/r8/enumunboxing/VirtualMethodOverrideEnumUnboxingTest.java
@@ -6,7 +6,7 @@
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
import com.android.tools.r8.KeepConstantArguments;
import com.android.tools.r8.NeverClassInline;
@@ -67,7 +67,8 @@
MethodSubject methodOnB =
inspector.clazz(B.class).uniqueMethodWithFinalName(methodOnA.getFinalName());
assertThat(methodOnB, isPresent());
- assertTrue(methodOnB.streamInstructions().anyMatch(x -> x.asDexInstruction().isInvokeSuper()));
+ // TODO(b/171784168): Should be true.
+ assertFalse(methodOnB.streamInstructions().anyMatch(x -> x.asDexInstruction().isInvokeSuper()));
}
static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/examples/newarray/NewArrayTestRunner.java b/src/test/java/com/android/tools/r8/examples/newarray/NewArrayTestRunner.java
index d980c97..219dbed 100644
--- a/src/test/java/com/android/tools/r8/examples/newarray/NewArrayTestRunner.java
+++ b/src/test/java/com/android/tools/r8/examples/newarray/NewArrayTestRunner.java
@@ -3,24 +3,34 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.examples.newarray;
+import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.BooleanUtils;
import com.google.common.collect.ImmutableList;
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 NewArrayTestRunner extends TestBase {
- static final Class<?> CLASS = NewArray.class;
+ private static final Class<?> CLASS = NewArray.class;
- private final TestParameters parameters;
- private final CompilationMode mode;
+ @Parameter(0)
+ public boolean enableMultiANewArrayDesugaringForClassFiles;
+
+ @Parameter(1)
+ public TestParameters parameters;
+
+ @Parameter(2)
+ public CompilationMode mode;
private static final List<String> EXPECTED =
ImmutableList.of(
@@ -56,20 +66,19 @@
"8,8,8,8",
"2,4,6,8,10,12,14,16,false,0,0,0,0,0.0,0.0,null");
- @Parameterized.Parameters(name = "{0}, {1}")
+ @Parameters(name = "{1}, {2}, force desugaring: {0}")
public static List<Object[]> data() {
return buildParameters(
- getTestParameters().withAllRuntimes().withAllApiLevels().build(), CompilationMode.values());
- }
-
- public NewArrayTestRunner(TestParameters parameters, CompilationMode mode) {
- this.parameters = parameters;
- this.mode = mode;
+ BooleanUtils.values(),
+ getTestParameters().withAllRuntimesAndApiLevels().build(),
+ CompilationMode.values());
}
@Test
public void runReference() throws Exception {
- assumeTrue(parameters.isCfRuntime() && mode == CompilationMode.DEBUG);
+ assumeFalse(enableMultiANewArrayDesugaringForClassFiles);
+ assumeTrue(parameters.isCfRuntime());
+ assumeTrue(mode == CompilationMode.DEBUG);
testForJvm(getStaticTemp())
.addProgramClassesAndInnerClasses(CLASS)
.run(parameters.getRuntime(), CLASS)
@@ -78,6 +87,7 @@
@Test
public void testD8() throws Exception {
+ assumeFalse(enableMultiANewArrayDesugaringForClassFiles);
assumeTrue(parameters.isDexRuntime());
testForD8()
.addProgramClassesAndInnerClasses(CLASS)
@@ -89,9 +99,14 @@
@Test
public void testR8() throws Exception {
+ assumeTrue(parameters.isCfRuntime() || !enableMultiANewArrayDesugaringForClassFiles);
testForR8(parameters.getBackend())
.addProgramClassesAndInnerClasses(CLASS)
.addKeepMainRule(CLASS)
+ .addOptionsModification(
+ options ->
+ options.testing.enableMultiANewArrayDesugaringForClassFiles =
+ enableMultiANewArrayDesugaringForClassFiles)
.setMinApi(parameters.getApiLevel())
.setMode(mode)
.run(parameters.getRuntime(), CLASS)
diff --git a/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java b/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java
index 06666db..d3e91bb 100644
--- a/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java
+++ b/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java
@@ -96,7 +96,10 @@
CodeInspector inspector = new CodeInspector(appInfo.app());
ProgramMethod method = getMethod(inspector, DEFAULT_CLASS_NAME, "int", "x", ImmutableList.of());
assertFalse(
- appInfo.resolveMethodOnClass(method.getReference()).getSingleTarget().isVirtualMethod());
+ appInfo
+ .resolveMethodOnClassHolder(method.getReference())
+ .getSingleTarget()
+ .isVirtualMethod());
assertNull(appInfo.lookupDirectTarget(method.getReference(), method));
assertNotNull(appInfo.lookupStaticTarget(method.getReference(), method));
@@ -178,14 +181,14 @@
assertFalse(
appInfo
- .resolveMethodOnClass(methodXOnTestSuper.getReference(), classTestSuper)
+ .resolveMethodOnClass(classTestSuper, methodXOnTestSuper.getReference())
.getSingleTarget()
.isVirtualMethod());
assertNull(
appInfo
- .resolveMethodOnClass(methodXOnTestSuper.getReference(), classTest)
+ .resolveMethodOnClass(classTest, methodXOnTestSuper.getReference())
.getSingleTarget());
- assertNull(appInfo.resolveMethodOnClass(methodXOnTestReference, classTest).getSingleTarget());
+ assertNull(appInfo.resolveMethodOnClass(classTest, methodXOnTestReference).getSingleTarget());
assertNull(appInfo.lookupDirectTarget(methodXOnTestSuper.getReference(), methodXOnTestSuper));
assertNull(appInfo.lookupDirectTarget(methodXOnTestReference, methodYOnTest));
diff --git a/src/test/java/com/android/tools/r8/graph/invokestatic/InvokeStaticOnInterfaceTest.java b/src/test/java/com/android/tools/r8/graph/invokestatic/InvokeStaticOnInterfaceTest.java
index a94f02a..61d3d32 100644
--- a/src/test/java/com/android/tools/r8/graph/invokestatic/InvokeStaticOnInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/graph/invokestatic/InvokeStaticOnInterfaceTest.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.graph.invokestatic;
+import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -48,11 +49,11 @@
.run(parameters.getRuntime(), Main.class);
if (parameters.getRuntime().asCf().isNewerThan(CfVm.JDK8)) {
runResult.assertFailureWithErrorThatMatches(
- containsString(
- "java.lang.IncompatibleClassChangeError: Method "
- + I.class.getTypeName()
- + ".foo()V"
- + " must be InterfaceMethodref constant"));
+ allOf(
+ containsString("java.lang.IncompatibleClassChangeError: Method"),
+ // JVM method formatting changed between jdk11 and jdk17
+ containsString(I.class.getTypeName() + ".foo()"),
+ containsString("must be InterfaceMethodref constant")));
} else {
runResult.assertSuccessWithOutputLines("Hello World!");
}
@@ -85,10 +86,11 @@
.run(parameters.getRuntime(), Main.class);
if (parameters.getRuntime().asCf().isNewerThan(CfVm.JDK8)) {
runResult.assertFailureWithErrorThatMatches(
- containsString(
- "java.lang.IncompatibleClassChangeError: Method"
- + " com.android.tools.r8.graph.invokestatic.InvokeStaticOnInterfaceTest$I.foo()V"
- + " must be InterfaceMethodref constant"));
+ allOf(
+ containsString("java.lang.IncompatibleClassChangeError: Method"),
+ containsString(
+ "com.android.tools.r8.graph.invokestatic.InvokeStaticOnInterfaceTest$I.foo()"),
+ containsString("must be InterfaceMethodref constant")));
} else {
runResult.assertSuccessWithOutputLines("Hello World!");
}
diff --git a/src/test/java/com/android/tools/r8/graph/invokevirtual/InvokeVirtualPrivateBaseWithDefaultDirectInvokeTest.java b/src/test/java/com/android/tools/r8/graph/invokevirtual/InvokeVirtualPrivateBaseWithDefaultDirectInvokeTest.java
index a8a222d..9df5458 100644
--- a/src/test/java/com/android/tools/r8/graph/invokevirtual/InvokeVirtualPrivateBaseWithDefaultDirectInvokeTest.java
+++ b/src/test/java/com/android/tools/r8/graph/invokevirtual/InvokeVirtualPrivateBaseWithDefaultDirectInvokeTest.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.utils.AndroidApiLevel;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -31,9 +32,13 @@
this.parameters = parameters;
}
+ private boolean isDefaultCfParameters() {
+ return parameters.isCfRuntime() && parameters.getApiLevel().equals(AndroidApiLevel.B);
+ }
+
@Test
public void testJvm() throws Exception {
- assumeTrue(parameters.isCfRuntime());
+ assumeTrue(isDefaultCfParameters());
testForJvm()
.addInnerClasses(getClass())
.run(parameters.getRuntime(), Main.class)
@@ -51,6 +56,7 @@
@Test
public void testR8() throws Exception {
+ assumeTrue(parameters.isDexRuntime() || isDefaultCfParameters());
testForR8(parameters.getBackend())
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
@@ -70,7 +76,9 @@
(nonDesugaredCf && parameters.isCfRuntime())
|| parameters.canUseDefaultAndStaticInterfaceMethodsWhenDesugaring();
// JDK 11 allows this incorrect dispatch for some reason.
- if (parameters.isCfRuntime(CfVm.JDK11) && isNotDesugared) {
+ if (parameters.isCfRuntime()
+ && parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK11)
+ && isNotDesugared) {
result.assertSuccessWithOutputLines("I::foo");
return;
}
diff --git a/src/test/java/com/android/tools/r8/internal/GMSCoreLatestTest.java b/src/test/java/com/android/tools/r8/internal/GMSCoreLatestTest.java
index c9d943e..4ad8b97 100644
--- a/src/test/java/com/android/tools/r8/internal/GMSCoreLatestTest.java
+++ b/src/test/java/com/android/tools/r8/internal/GMSCoreLatestTest.java
@@ -65,9 +65,6 @@
builder ->
builder.addOptionsModification(
options -> {
- options
- .getOpenClosedInterfacesOptions()
- .suppressArrayAssignmentsToJavaLangSerializable();
options.testing.processingContextsConsumer =
id -> assertNull(idsRoundOne.put(id, id));
}));
@@ -80,9 +77,6 @@
builder ->
builder.addOptionsModification(
options -> {
- options
- .getOpenClosedInterfacesOptions()
- .suppressArrayAssignmentsToJavaLangSerializable();
options.testing.processingContextsConsumer =
id -> {
AssertionUtils.assertNotNull(idsRoundOne.get(id));
diff --git a/src/test/java/com/android/tools/r8/internal/GMSCoreV10Test.java b/src/test/java/com/android/tools/r8/internal/GMSCoreV10Test.java
index 34b77bd..a6277d6 100644
--- a/src/test/java/com/android/tools/r8/internal/GMSCoreV10Test.java
+++ b/src/test/java/com/android/tools/r8/internal/GMSCoreV10Test.java
@@ -63,9 +63,6 @@
builder ->
builder.addOptionsModification(
options -> {
- options
- .getOpenClosedInterfacesOptions()
- .suppressArrayAssignmentsToJavaLangSerializable();
options.testing.processingContextsConsumer =
id -> assertTrue(idsRoundOne.add(id));
}));
@@ -78,9 +75,6 @@
builder ->
builder.addOptionsModification(
options -> {
- options
- .getOpenClosedInterfacesOptions()
- .suppressArrayAssignmentsToJavaLangSerializable();
options.testing.processingContextsConsumer =
id -> assertTrue(idsRoundTwo.add(id));
}));
@@ -104,9 +98,6 @@
builder.addOptionsModification(
options -> {
options.testing.forceJumboStringProcessing = true;
- options
- .getOpenClosedInterfacesOptions()
- .suppressArrayAssignmentsToJavaLangSerializable();
}))
.runDex2Oat(parameters.getRuntime())
.assertNoVerificationErrors();
diff --git a/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java b/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java
index 2f98c5c..956d59e 100644
--- a/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java
+++ b/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java
@@ -72,11 +72,11 @@
// Check lookup will produce the same result.
DexMethod id = method.getReference();
assertEquals(
- appInfo().resolveMethodOnClass(method.getReference(), id.holder).getSingleTarget(), method);
+ appInfo().resolveMethodOnClass(id.holder, method.getReference()).getSingleTarget(), method);
// Check lookup targets with include method.
MethodResolutionResult resolutionResult =
- appInfo().resolveMethodOnClass(method.getReference(), clazz);
+ appInfo().resolveMethodOnClass(clazz, method.getReference());
AppInfoWithLiveness appInfo = null; // TODO(b/154881041): Remove or compute liveness.
LookupResult lookupResult =
resolutionResult.lookupVirtualDispatchTargets(
diff --git a/src/test/java/com/android/tools/r8/internal/proto/Proto2ShrinkingTest.java b/src/test/java/com/android/tools/r8/internal/proto/Proto2ShrinkingTest.java
index 63dae9c..51acd65 100644
--- a/src/test/java/com/android/tools/r8/internal/proto/Proto2ShrinkingTest.java
+++ b/src/test/java/com/android/tools/r8/internal/proto/Proto2ShrinkingTest.java
@@ -23,6 +23,7 @@
import com.google.common.collect.ImmutableSet;
import java.nio.file.Path;
import java.util.List;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
diff --git a/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java b/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java
index 328f9ff..8b89088 100644
--- a/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java
+++ b/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.ir;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -14,7 +13,6 @@
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.conversion.IRConverter;
-import com.android.tools.r8.smali.SmaliBuilder;
import com.android.tools.r8.smali.SmaliBuilder.MethodSignature;
import com.android.tools.r8.smali.SmaliTestBase;
import com.android.tools.r8.utils.AndroidApp;
@@ -26,7 +24,6 @@
import java.io.IOException;
import java.util.List;
import java.util.concurrent.ExecutionException;
-import org.antlr.runtime.RecognitionException;
public class IrInjectionTestBase extends SmaliTestBase {
@@ -105,7 +102,7 @@
public String run() throws IOException {
Timing timing = Timing.empty();
IRConverter converter = new IRConverter(appView, timing, null);
- converter.replaceCodeForTesting(method, code);
+ converter.replaceCodeForTesting(code);
AndroidApp app = writeDex();
return runOnArtRaw(app, DEFAULT_MAIN_CLASS_NAME).stdout;
}
diff --git a/src/test/java/com/android/tools/r8/ir/LinearFlowIteratorTest.java b/src/test/java/com/android/tools/r8/ir/LinearFlowIteratorTest.java
index f191b3b..9d4d133 100644
--- a/src/test/java/com/android/tools/r8/ir/LinearFlowIteratorTest.java
+++ b/src/test/java/com/android/tools/r8/ir/LinearFlowIteratorTest.java
@@ -111,10 +111,9 @@
public void nextWillContinueThroughGotoBlocks() throws Exception {
IRCode code = simpleCode();
InstructionListIterator it = new LinearFlowInstructionListIterator(code, code.entryBlock());
- it.next(); // Argument
- it.next(); // ConstNumber 0/NULL
- it.next(); // ArrayGet
- assert it.next().isReturn(); // Return
+ assertTrue(it.next().isArgument());
+ assertTrue(it.next().isConstNumber());
+ assertTrue(it.next().isThrow());
}
@Test
@@ -154,9 +153,8 @@
InstructionListIterator it = new LinearFlowInstructionListIterator(code, code.blocks.get(1));
Instruction current = it.previous();
assertTrue(current.isConstNumber() && current.getOutType().isReferenceType());
- it.next();
- current = it.next();
- assertTrue(current.isArrayGet());
+ assertTrue(it.next().isConstNumber());
+ assertTrue(it.next().isThrow());
}
@Test
diff --git a/src/test/java/com/android/tools/r8/ir/SplitBlockTest.java b/src/test/java/com/android/tools/r8/ir/SplitBlockTest.java
index 1662269..a376a2e 100644
--- a/src/test/java/com/android/tools/r8/ir/SplitBlockTest.java
+++ b/src/test/java/com/android/tools/r8/ir/SplitBlockTest.java
@@ -87,6 +87,7 @@
// Try split between all non-argument instructions in the first block.
for (int i = argumentInstructions; i < firstBlockInstructions; i++) {
TestApplication test = codeWithoutCatchHandlers();
+ AppView<?> appView = test.appView;
IRCode code = test.code;
assertEquals(initialBlockCount, code.blocks.size());
@@ -100,7 +101,7 @@
InstructionListIterator iterator = test.listIteratorAt(block, i);
BasicBlock newBlock = iterator.split(code);
- assertTrue(code.isConsistentSSA());
+ assertTrue(code.isConsistentSSA(appView));
assertEquals(initialBlockCount + 1, code.blocks.size());
assertEquals(i + 1, code.entryBlock().getInstructions().size());
@@ -121,6 +122,7 @@
// Try split out all non-argument instructions in the first block.
for (int i = argumentInstructions; i < firstBlockInstructions - 1; i++) {
TestApplication test = codeWithoutCatchHandlers();
+ AppView<?> appView = test.appView;
IRCode code = test.code;
assertEquals(initialBlockCount, code.blocks.size());
@@ -134,7 +136,7 @@
InstructionListIterator iterator = test.listIteratorAt(block, i);
BasicBlock newBlock = iterator.split(code, 1);
- assertTrue(code.isConsistentSSA());
+ assertTrue(code.isConsistentSSA(appView));
assertEquals(initialBlockCount + 2, code.blocks.size());
assertEquals(i + 1, code.entryBlock().getInstructions().size());
@@ -208,6 +210,7 @@
// Try split between all instructions in second block.
for (int i = 1; i < secondBlockInstructions; i++) {
TestApplication test = codeWithCatchHandlers(codeThrows, twoGuards);
+ AppView<?> appView = test.appView;
IRCode code = test.code;
assertEquals(initialBlockCount, code.blocks.size());
@@ -217,7 +220,7 @@
InstructionListIterator iterator = test.listIteratorAt(block, i);
BasicBlock newBlock = iterator.split(code);
- assertTrue(code.isConsistentSSA());
+ assertTrue(code.isConsistentSSA(appView));
assertEquals(initialBlockCount + 1, code.blocks.size());
assertEquals(i + 1, code.blocks.get(1).getInstructions().size());
@@ -247,6 +250,7 @@
// Try split out all instructions in second block.
for (int i = 1; i < secondBlockInstructions - 1; i++) {
TestApplication test = codeWithCatchHandlers(codeThrows, twoGuards);
+ AppView<?> appView = test.appView;
IRCode code = test.code;
assertEquals(initialBlockCount, code.blocks.size());
@@ -256,7 +260,7 @@
InstructionListIterator iterator = test.listIteratorAt(block, i);
BasicBlock newBlock = iterator.split(code, 1);
- assertTrue(code.isConsistentSSA());
+ assertTrue(code.isConsistentSSA(appView));
assertEquals(initialBlockCount + 2, code.blocks.size());
assertEquals(i + 1, code.blocks.get(1).getInstructions().size());
@@ -323,6 +327,7 @@
// Try split between all non-argument instructions in the first block.
for (int i = argumentInstructions; i < firstBlockInstructions; i++) {
TestApplication test = codeWithIf(hitTrueBranch);
+ AppView<?> appView = test.appView;
IRCode code = test.code;
assertEquals(initialBlockCount, code.blocks.size());
@@ -336,7 +341,7 @@
InstructionListIterator iterator = test.listIteratorAt(block, i);
BasicBlock newBlock = iterator.split(code);
- assertTrue(code.isConsistentSSA());
+ assertTrue(code.isConsistentSSA(appView));
assertEquals(initialBlockCount + 1, code.blocks.size());
assertEquals(i + 1, code.entryBlock().getInstructions().size());
@@ -444,6 +449,7 @@
// Try split between all non-argument instructions in the first block.
for (int i = argumentInstructions; i < firstBlockInstructions; i++) {
TestApplication test = codeWithSwitch(hitCase);
+ AppView<?> appView = test.appView;
IRCode code = test.code;
assertEquals(initialBlockCount, code.blocks.size());
@@ -457,7 +463,7 @@
InstructionListIterator iterator = test.listIteratorAt(block, i);
BasicBlock newBlock = iterator.split(code);
- assertTrue(code.isConsistentSSA());
+ assertTrue(code.isConsistentSSA(appView));
assertEquals(initialBlockCount + 1, code.blocks.size());
assertEquals(i + 1, code.entryBlock().getInstructions().size());
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/ConstantRemovalTest.java b/src/test/java/com/android/tools/r8/ir/optimize/ConstantRemovalTest.java
index e4ee9bc..1427b24 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/ConstantRemovalTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/ConstantRemovalTest.java
@@ -22,6 +22,7 @@
import com.android.tools.r8.ir.code.Position.SyntheticPosition;
import com.android.tools.r8.ir.code.Return;
import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.ir.regalloc.LinearScanRegisterAllocator;
import com.android.tools.r8.ir.regalloc.LiveIntervals;
import com.android.tools.r8.origin.Origin;
@@ -145,8 +146,9 @@
new NumberGenerator(),
basicBlockNumberGenerator,
IRMetadata.unknown(),
- Origin.unknown());
- PeepholeOptimizer.optimize(code, new MockLinearScanRegisterAllocator(appView, code));
+ Origin.unknown(),
+ new MutableMethodConversionOptions(options));
+ PeepholeOptimizer.optimize(appView, code, new MockLinearScanRegisterAllocator(appView, code));
// Check that all four constant number instructions remain.
assertEquals(
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTest.java
index 19ff50d..9d6d411 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTest.java
@@ -65,7 +65,7 @@
AssumeInserter assumeInserter = new AssumeInserter(appView);
assumeInserter.insertAssumeInstructions(code, Timing.empty());
- assertTrue(code.isConsistentSSA());
+ assertTrue(code.isConsistentSSA(appView));
checkCountOfNonNull(code, expectedNumberOfNonNull);
if (testAugmentedIRCode != null) {
@@ -73,7 +73,7 @@
}
CodeRewriter.removeAssumeInstructions(appView, code);
- assertTrue(code.isConsistentSSA());
+ assertTrue(code.isConsistentSSA(appView));
checkCountOfNonNull(code, 0);
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/TrivialGotoEliminationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/TrivialGotoEliminationTest.java
index 868036c..7bbc000 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/TrivialGotoEliminationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/TrivialGotoEliminationTest.java
@@ -28,6 +28,7 @@
import com.android.tools.r8.ir.code.Return;
import com.android.tools.r8.ir.code.Throw;
import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
@@ -53,7 +54,9 @@
private final IRMetadata metadata = IRMetadata.unknown();
@Test
- public void trivialGotoInEntryBlock() {
+ public void trivialGotoInEntryBlock() throws Exception {
+ AppView<AppInfo> appView = computeAppView(AndroidApp.builder().build());
+ InternalOptions options = appView.options();
// Setup silly block structure:
//
// block0:
@@ -92,7 +95,6 @@
// Check that the goto in block0 remains. There was a bug in the trivial goto elimination
// that ended up removing that goto changing the code to start with the unreachable
// throw.
- InternalOptions options = new InternalOptions();
options.debug = true;
IRCode code =
new IRCode(
@@ -102,8 +104,9 @@
new NumberGenerator(),
basicBlockNumberGenerator,
IRMetadata.unknown(),
- Origin.unknown());
- CodeRewriter.collapseTrivialGotos(code);
+ Origin.unknown(),
+ new MutableMethodConversionOptions(options));
+ CodeRewriter.collapseTrivialGotos(appView, code);
assertTrue(code.entryBlock().isTrivialGoto());
assertTrue(blocks.contains(block0));
assertTrue(blocks.contains(block1));
@@ -189,8 +192,9 @@
new NumberGenerator(),
basicBlockNumberGenerator,
IRMetadata.unknown(),
- Origin.unknown());
- CodeRewriter.collapseTrivialGotos(code);
+ Origin.unknown(),
+ new MutableMethodConversionOptions(options));
+ CodeRewriter.collapseTrivialGotos(appView, code);
assertTrue(block0.getInstructions().get(1).isIf());
assertEquals(block1, block0.getInstructions().get(1).asIf().fallthroughBlock());
assertTrue(blocks.containsAll(ImmutableList.of(block0, block1, block2, block3)));
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/ifs/IfThrowNullPointerExceptionTest.java b/src/test/java/com/android/tools/r8/ir/optimize/ifs/IfThrowNullPointerExceptionTest.java
index d0b977b..53a83d5 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/ifs/IfThrowNullPointerExceptionTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/ifs/IfThrowNullPointerExceptionTest.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
@@ -47,7 +48,7 @@
testForJvm()
.addTestClasspath()
.run(parameters.getRuntime(), TestClass.class)
- .assertSuccessWithOutput(getExpectedStdout());
+ .assertSuccessWithOutput(getExpectedStdout(false));
}
@Test
@@ -60,7 +61,7 @@
.compile()
.inspect(this::inspect)
.run(parameters.getRuntime(), TestClass.class)
- .assertSuccessWithOutput(getExpectedStdout());
+ .assertSuccessWithOutput(getExpectedStdout(false));
}
@Test
@@ -72,7 +73,7 @@
.compile()
.inspect(this::inspect)
.run(parameters.getRuntime(), TestClass.class)
- .assertSuccessWithOutput(getExpectedStdout());
+ .assertSuccessWithOutput(getExpectedStdout(true));
}
private void inspect(CodeInspector inspector) {
@@ -114,7 +115,21 @@
}
}
- private String getExpectedStdout() {
+ private String getExpectedStdout(boolean isR8) {
+ if (parameters.isCfRuntime() && parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK17)) {
+ // Newer JVMs have added support for printing the expression and local causing the NPE.
+ if (isR8) {
+ return StringUtils.lines(
+ "Caught NPE: Cannot invoke \"Object.getClass()\" because \"<parameter1>\" is null",
+ "Caught NPE: x was null",
+ "Caught NPE: Cannot invoke \"Object.getClass()\" because \"<parameter1>\" is null");
+ } else {
+ return StringUtils.lines(
+ "Caught NPE: null",
+ "Caught NPE: x was null",
+ "Caught NPE: Cannot throw exception because \"null\" is null");
+ }
+ }
if (parameters.isCfRuntime() || isDalvik()) {
return StringUtils.lines("Caught NPE: null", "Caught NPE: x was null", "Caught NPE: null");
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/ArrayInstanceOfCloneableAndSerializableTest.java b/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/ArrayInstanceOfCloneableAndSerializableTest.java
new file mode 100644
index 0000000..fc8ca51
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/ArrayInstanceOfCloneableAndSerializableTest.java
@@ -0,0 +1,92 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.optimize.instanceofremoval;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import java.io.Serializable;
+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 ArrayInstanceOfCloneableAndSerializableTest extends TestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ @Test
+ public void testJvm() throws Exception {
+ assumeTrue(parameters.isCfRuntime());
+ testForJvm()
+ .addTestClasspath()
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("true", "true");
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ assumeTrue(parameters.isDexRuntime());
+ testForD8()
+ .addProgramClasses(Main.class)
+ .release()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(
+ inspector -> {
+ MethodSubject mainMethodSubject = inspector.clazz(Main.class).mainMethod();
+ assertEquals(
+ 2,
+ mainMethodSubject
+ .streamInstructions()
+ .filter(InstructionSubject::isInstanceOf)
+ .count());
+ })
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("true", "true");
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(Main.class)
+ .addKeepMainRule(Main.class)
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(
+ inspector -> {
+ MethodSubject mainMethodSubject = inspector.clazz(Main.class).mainMethod();
+ assertTrue(
+ mainMethodSubject
+ .streamInstructions()
+ .noneMatch(InstructionSubject::isInstanceOf));
+ })
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("true", "true");
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ byte[] bytes = new byte[0];
+ System.out.println(bytes instanceof Cloneable);
+ System.out.println(bytes instanceof Serializable);
+ }
+ }
+}
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 2254355..7688f9b 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
@@ -334,8 +334,7 @@
"DIRECT: void movetohost.HostConflictField.<init>()",
"STATIC: String movetohost.CandidateConflictField.bar(String)",
"STATIC: String movetohost.CandidateConflictField.foo()",
- "STATIC: String movetohost.MoveToHostTestClass.next()",
- "String movetohost.CandidateConflictField.field"),
+ "STATIC: String movetohost.MoveToHostTestClass.next()"),
references(clazz, "testConflictField", "void"));
assertThat(inspector.clazz(CandidateConflictMethod.class), isPresent());
diff --git a/src/test/java/com/android/tools/r8/ir/regalloc/IdenticalAfterRegisterAllocationTest.java b/src/test/java/com/android/tools/r8/ir/regalloc/IdenticalAfterRegisterAllocationTest.java
index 9e9b1c4..4319780 100644
--- a/src/test/java/com/android/tools/r8/ir/regalloc/IdenticalAfterRegisterAllocationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/regalloc/IdenticalAfterRegisterAllocationTest.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.ir.code.NumericType;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.utils.InternalOptions;
import java.util.List;
import org.junit.Test;
@@ -86,6 +87,8 @@
assertTrue(value3.needsRegister());
// value1 and value2 represent different constants and the additions are therefore
// not equivalent.
- assertFalse(add0.identicalAfterRegisterAllocation(add1, allocator));
+ assertFalse(
+ add0.identicalAfterRegisterAllocation(
+ add1, allocator, new MutableMethodConversionOptions(allocator.options())));
}
}
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 24f1672..932c051 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
@@ -7,7 +7,6 @@
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.graph.AppInfo;
-import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DebugLocalInfo;
import com.android.tools.r8.graph.DexApplication;
@@ -112,6 +111,11 @@
}
@Override
+ public void replaceCurrentInstructionWithNullCheck(AppView<?> appView, Value object) {
+ throw new Unimplemented();
+ }
+
+ @Override
public void replaceCurrentInstructionWithStaticGet(
AppView<?> appView, IRCode code, DexField field, Set<Value> affectedValues) {
throw new Unimplemented();
@@ -130,7 +134,7 @@
@Override
public void replaceCurrentInstructionWithThrowNull(
- AppView<? extends AppInfoWithClassHierarchy> appView,
+ AppView<?> appView,
IRCode code,
ListIterator<BasicBlock> blockIterator,
Set<BasicBlock> blocksToRemove,
diff --git a/src/test/java/com/android/tools/r8/java_language/pattern_matching_for_instenceof/PattternMatchingForInstanceOfTest.java b/src/test/java/com/android/tools/r8/java_language/pattern_matching_for_instenceof/PattternMatchingForInstanceOfTest.java
index 95cf5b2..e81d20c 100644
--- a/src/test/java/com/android/tools/r8/java_language/pattern_matching_for_instenceof/PattternMatchingForInstanceOfTest.java
+++ b/src/test/java/com/android/tools/r8/java_language/pattern_matching_for_instenceof/PattternMatchingForInstanceOfTest.java
@@ -7,7 +7,7 @@
import com.android.tools.r8.R8TestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestRuntime.CfRuntime;
+import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.examples.jdk17.PatternMatchingForInstanceof;
import com.android.tools.r8.utils.InternalOptions.TestingOptions;
import com.google.common.collect.ImmutableList;
@@ -31,10 +31,9 @@
@Parameters(name = "{0}")
public static List<Object[]> data() {
- // TODO(b/174431251): This should be replaced with .withCfRuntimes(start = jdk17).
return buildParameters(
getTestParameters()
- .withCustomRuntime(CfRuntime.getCheckedInJdk17())
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK17)
.withDexRuntimes()
.withAllApiLevelsAlsoForCf()
.build());
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergerValidationTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergerValidationTest.java
index 35087f5..3d0fa60 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergerValidationTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergerValidationTest.java
@@ -10,8 +10,6 @@
import com.android.tools.r8.KotlinTestBase;
import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestRuntime;
-import com.android.tools.r8.TestRuntime.CfRuntime;
import com.android.tools.r8.utils.DescriptorUtils;
import java.nio.file.Path;
import java.util.Collection;
@@ -43,9 +41,8 @@
String pkg = getClass().getPackage().getName();
String folder = DescriptorUtils.getBinaryNameFromJavaType(pkg);
- CfRuntime cfRuntime = parameters.getRuntime().asCf();
Path ktClasses =
- kotlinc(cfRuntime, kotlinc, targetVersion)
+ kotlinc(getKotlincHostRuntime(parameters.getRuntime()), kotlinc, targetVersion)
.addSourceFiles(getKotlinFileInTest(folder, "b143165163"))
.compile();
testForR8(parameters.getBackend())
@@ -68,10 +65,8 @@
String pkg = getClass().getPackage().getName();
String folder = DescriptorUtils.getBinaryNameFromJavaType(pkg);
- CfRuntime cfRuntime =
- parameters.isCfRuntime() ? parameters.getRuntime().asCf() : TestRuntime.getCheckedInJdk9();
Path ktClasses =
- kotlinc(cfRuntime, kotlinc, targetVersion)
+ kotlinc(getKotlincHostRuntime(parameters.getRuntime()), kotlinc, targetVersion)
.addSourceFiles(getKotlinFileInTest(folder, "b143165163"))
.compile();
testForR8(parameters.getBackend())
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaGroupGCLimitTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaGroupGCLimitTest.java
index 89f57c8..e021fe5 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaGroupGCLimitTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaGroupGCLimitTest.java
@@ -74,7 +74,7 @@
mergeGroup ->
mergeGroup.size()
<= defaultHorizontalClassMergerOptions
- .getMaxClassGroupSize()));
+ .getMaxClassGroupSizeInR8()));
})
.allowDiagnosticWarningMessages()
.compile()
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrimitiveTypeRewriteTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrimitiveTypeRewriteTest.java
index 39d2473..4cbb2e0 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrimitiveTypeRewriteTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrimitiveTypeRewriteTest.java
@@ -6,6 +6,7 @@
import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
+import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
@@ -119,9 +120,10 @@
runResult.assertSuccessWithOutputLines(EXPECTED);
} else {
runResult.assertFailureWithErrorThatMatches(
- containsString(
- "java.lang.NoSuchMethodError:"
- + " com.android.tools.r8.kotlin.metadata.primitive_type_rewrite_lib.LibKt.foo()"));
+ allOf(
+ containsString("java.lang.NoSuchMethodError:"),
+ containsString(
+ "com.android.tools.r8.kotlin.metadata.primitive_type_rewrite_lib.LibKt.foo()")));
}
}
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInlinePropertyTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInlinePropertyTest.java
index 94b410e..c693a41 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInlinePropertyTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInlinePropertyTest.java
@@ -52,7 +52,7 @@
public void smokeTest() throws Exception {
Path libJar = libJars.getForConfiguration(kotlinc, targetVersion);
Path output =
- kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
+ kotlinc(getKotlincHostRuntime(parameters.getRuntime()), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/inline_property_app", "main"))
.setOutputPath(temp.newFolder().toPath())
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
index 249e78d..dd40ecf 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -59,7 +59,9 @@
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.Position.SyntheticPosition;
import com.android.tools.r8.ir.code.ValueTypeConstraint;
+import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.ir.conversion.SourceCode;
import com.android.tools.r8.ir.regalloc.LinearScanRegisterAllocator;
import com.android.tools.r8.ir.regalloc.RegisterAllocator;
@@ -868,9 +870,16 @@
.disableAndroidApiLevelCheck()
.build();
ProgramMethod programMethod = new ProgramMethod(programClass, method);
- IRCode ir = code.buildIR(programMethod, appView, Origin.unknown());
+ IRCode ir =
+ code.buildIR(
+ programMethod,
+ appView,
+ Origin.unknown(),
+ new MutableMethodConversionOptions(options));
RegisterAllocator allocator = new LinearScanRegisterAllocator(appView, ir);
- method.setCode(ir, BytecodeMetadataProvider.empty(), allocator, appView);
+ programMethod.setCode(
+ new DexBuilder(ir, BytecodeMetadataProvider.empty(), allocator, options).build(),
+ appView);
directMethods[i] = method;
}
programClass.getMethodCollection().addDirectMethods(Arrays.asList(directMethods));
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromFieldAnnotationTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromFieldAnnotationTest.java
index 71e9638..c0c9739 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromFieldAnnotationTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromFieldAnnotationTest.java
@@ -31,13 +31,20 @@
@Test(expected = CompilationFailedException.class)
public void testNoRules() throws Exception {
compileWithExpectedDiagnostics(
- Main.class, diagnostics -> inspectDiagnosticsWithNoRules(diagnostics, referencedFrom));
+ Main.class,
+ diagnostics -> inspectDiagnosticsWithNoRules(diagnostics, referencedFrom),
+ builder -> builder.addKeepClassAndMembersRules(Main.class));
}
@Test
public void testDontWarnMainClass() throws Exception {
compileWithExpectedDiagnostics(
- Main.class, TestDiagnosticMessages::assertNoMessages, addDontWarn(Main.class));
+ Main.class,
+ TestDiagnosticMessages::assertNoMessages,
+ builder ->
+ builder
+ .addDontWarn(MissingRuntimeAnnotation.class)
+ .addKeepClassAndMembersRules(Main.class));
}
@Test
@@ -45,7 +52,10 @@
compileWithExpectedDiagnostics(
Main.class,
TestDiagnosticMessages::assertNoMessages,
- addDontWarn(MissingRuntimeAnnotation.class));
+ builder ->
+ builder
+ .addDontWarn(MissingRuntimeAnnotation.class)
+ .addKeepClassAndMembersRules(Main.class));
}
@Test
@@ -53,7 +63,11 @@
compileWithExpectedDiagnostics(
Main.class,
diagnostics -> inspectDiagnosticsWithIgnoreWarnings(diagnostics, referencedFrom),
- addIgnoreWarnings());
+ builder ->
+ builder
+ .addIgnoreWarnings()
+ .addKeepClassAndMembersRules(Main.class)
+ .allowDiagnosticWarningMessages());
}
@Override
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/sourcelibrary/MemberResolutionAsmTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/sourcelibrary/MemberResolutionAsmTest.java
index da28db3..20403fb 100644
--- a/src/test/java/com/android/tools/r8/naming/applymapping/sourcelibrary/MemberResolutionAsmTest.java
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/sourcelibrary/MemberResolutionAsmTest.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.naming.applymapping.shared.NoMappingDumps.HasMappingDump;
import com.android.tools.r8.naming.applymapping.shared.NoMappingDumps.NoMappingDump;
@@ -158,7 +159,9 @@
private String getMethodSignature(String type, String method) {
if (parameters.isCfRuntime()) {
- return type + "." + method + "()V";
+ return parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK17)
+ ? ("void " + type + "." + method + "()")
+ : (type + "." + method + "()V");
}
assert parameters.isDexRuntime();
Version version = parameters.getRuntime().asDex().getVm().getVersion();
diff --git a/src/test/java/com/android/tools/r8/resolution/ArrayTargetLookupTest.java b/src/test/java/com/android/tools/r8/resolution/ArrayTargetLookupTest.java
index f13728a..7ea76aa 100644
--- a/src/test/java/com/android/tools/r8/resolution/ArrayTargetLookupTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/ArrayTargetLookupTest.java
@@ -50,18 +50,18 @@
};
DexEncodedMethod langObjectNotifyMethod =
appInfo
- .resolveMethodOnClass(
+ .resolveMethodOnClassHolder(
factory.createMethod(fooType, factory.createProto(factory.voidType), "notify"))
.getSingleTarget();
for (DexType arrType : arrayTypes) {
assertNull(
appInfo
- .resolveMethodOnClass(
+ .resolveMethodOnClassHolder(
factory.createMethod(arrType, factory.createProto(arrType), "clone"))
.getSingleTarget());
DexEncodedMethod target =
appInfo
- .resolveMethodOnClass(
+ .resolveMethodOnClassHolder(
factory.createMethod(arrType, factory.createProto(factory.voidType), "notify"))
.getSingleTarget();
assertEquals(langObjectNotifyMethod, target);
diff --git a/src/test/java/com/android/tools/r8/resolution/InvokeSuperCallInStaticTest.java b/src/test/java/com/android/tools/r8/resolution/InvokeSuperCallInStaticTest.java
index 8d5a997..67007d2c 100644
--- a/src/test/java/com/android/tools/r8/resolution/InvokeSuperCallInStaticTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/InvokeSuperCallInStaticTest.java
@@ -59,7 +59,7 @@
Main.class);
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(Base.class, "collect", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
assertTrue(resolutionResult.isSingleResolution());
DexProgramClass context =
appView.definitionForProgramType(buildType(A.class, appInfo.dexItemFactory()));
diff --git a/src/test/java/com/android/tools/r8/resolution/SingleResolutionWithFailingDispatchTest.java b/src/test/java/com/android/tools/r8/resolution/SingleResolutionWithFailingDispatchTest.java
index a5acf15..df001ed 100644
--- a/src/test/java/com/android/tools/r8/resolution/SingleResolutionWithFailingDispatchTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/SingleResolutionWithFailingDispatchTest.java
@@ -49,7 +49,7 @@
}
private void inspectRunResult(TestRunResult<?> runResult) {
- if (parameters.isCfRuntime(CfVm.JDK11)) {
+ if (parameters.isCfRuntime() && parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK11)) {
runResult.assertFailureWithErrorThatThrows(AbstractMethodError.class);
} else {
runResult.assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class);
diff --git a/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java b/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java
index 8c72e58..76cf55a 100644
--- a/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java
@@ -194,7 +194,7 @@
buildNullaryVoidMethod(invokeReceiver, methodName, appInfo.dexItemFactory());
ProgramMethod context =
appInfo.definitionForProgramType(reference.holder).getProgramDefaultInitializer();
- Assert.assertNotNull(appInfo.resolveMethodOnClass(reference).getSingleTarget());
+ Assert.assertNotNull(appInfo.resolveMethodOnClassHolder(reference).getSingleTarget());
DexEncodedMethod singleVirtualTarget =
appInfo.lookupSingleVirtualTarget(appView, reference, context, false);
if (singleTargetHolderOrNull == null) {
@@ -209,8 +209,8 @@
@Test
public void lookupVirtualTargets() {
DexMethod method = buildNullaryVoidMethod(invokeReceiver, methodName, appInfo.dexItemFactory());
- Assert.assertNotNull(appInfo.resolveMethodOnClass(method).getSingleTarget());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ Assert.assertNotNull(appInfo.resolveMethodOnClassHolder(method).getSingleTarget());
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
if (resolutionResult.isVirtualTarget()) {
LookupResult lookupResult =
resolutionResult.lookupVirtualDispatchTargets(
diff --git a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodTest.java b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodTest.java
index 9a14cad..9de13d2 100644
--- a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodTest.java
@@ -11,7 +11,6 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.MethodResolutionResult;
@@ -92,7 +91,7 @@
@Test
public void resolveTarget() {
MethodResolutionResult resolutionResult =
- appInfo.resolveMethodOnClass(methodOnB, methodOnB.holder);
+ appInfo.resolveMethodOnClass(methodOnB.holder, methodOnB);
DexClass context = appInfo.definitionFor(methodOnB.holder);
assertTrue(resolutionResult.isIllegalAccessErrorResult(context, appInfo));
}
diff --git a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodWithVirtualParentTest.java b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodWithVirtualParentTest.java
index 8171081..d8ad8dd 100644
--- a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodWithVirtualParentTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodWithVirtualParentTest.java
@@ -108,7 +108,7 @@
@Test
public void testResolution() {
MethodResolutionResult resolutionResult =
- appInfo.resolveMethodOnClass(methodOnB, methodOnB.holder);
+ appInfo.resolveMethodOnClass(methodOnB.holder, methodOnB);
assertTrue(resolutionResult.isFailedResolution());
}
diff --git a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentTest.java b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentTest.java
index ac0cdef..c40f080 100644
--- a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentTest.java
@@ -175,7 +175,7 @@
public void lookupSingleTarget() {
DexProgramClass bClass = appView.definitionForProgramType(methodOnB.holder);
MethodResolutionResult resolutionResult =
- appInfo.resolveMethodOnClass(methodOnB, methodOnB.holder);
+ appInfo.resolveMethodOnClass(methodOnB.holder, methodOnB);
DexEncodedMethod resolved = resolutionResult.getSingleTarget();
assertEquals(methodOnA, resolved.getReference());
assertFalse(resolutionResult.isVirtualTarget());
@@ -188,7 +188,7 @@
@Test
public void lookupVirtualTargets() {
MethodResolutionResult resolutionResult =
- appInfo.resolveMethodOnClass(methodOnB, methodOnB.holder);
+ appInfo.resolveMethodOnClass(methodOnB.holder, methodOnB);
DexEncodedMethod resolved = resolutionResult.getSingleTarget();
assertEquals(methodOnA, resolved.getReference());
assertFalse(resolutionResult.isVirtualTarget());
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java
index 6289967..5638929 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.resolution.access;
import static com.android.tools.r8.TestRuntime.CfVm.JDK11;
+import static com.android.tools.r8.TestRuntime.CfVm.JDK17;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -186,7 +187,13 @@
.addProgramClasses(getClasses())
.addProgramClassFileData(getTransformedClasses())
.run(parameters.getRuntime(), Main.class)
- .apply(runResult -> checkExpectedResult(runResult, false));
+ .applyIf(
+ // TODO(b/227160049): Incorrect nest-based access allowed on JDK17!?
+ inSameNest
+ && parameters.isCfRuntime()
+ && parameters.asCfRuntime().isNewerThanOrEqual(JDK17),
+ runResult -> runResult.assertSuccessWithOutputLines("A::bar"),
+ runResult -> checkExpectedResult(runResult, false));
}
@Test
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessTest.java
index cbbfa70..f1a35bb 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessTest.java
@@ -74,7 +74,7 @@
DexProgramClass bClass =
appInfo.definitionFor(buildType(B.class, appInfo.dexItemFactory())).asProgramClass();
DexMethod bar = buildMethod(A.class.getDeclaredMethod("bar"), appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(bar);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(bar);
assertEquals(OptionalBool.of(inSameNest), resolutionResult.isAccessibleFrom(bClass, appInfo));
}
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessWithIntermediateClassTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessWithIntermediateClassTest.java
index 795f109..d68610e 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessWithIntermediateClassTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessWithIntermediateClassTest.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.resolution.access;
import static com.android.tools.r8.TestRuntime.CfVm.JDK11;
+import static com.android.tools.r8.TestRuntime.CfVm.JDK17;
import static org.hamcrest.core.StringContains.containsString;
import static org.junit.Assert.assertEquals;
@@ -72,7 +73,7 @@
DexProgramClass bClass =
appInfo.definitionFor(buildType(B.class, appInfo.dexItemFactory())).asProgramClass();
DexMethod bar = buildMethod(A.class.getDeclaredMethod("bar"), appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(bar);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(bar);
assertEquals(OptionalBool.of(inSameNest), resolutionResult.isAccessibleFrom(bClass, appInfo));
}
@@ -82,7 +83,13 @@
.addProgramClasses(getClasses())
.addProgramClassFileData(getTransformedClasses())
.run(parameters.getRuntime(), Main.class)
- .apply(runResult -> checkExpectedResult(runResult, false));
+ .applyIf(
+ // TODO(b/227160049): Incorrect nest-based access allowed on JDK17!?
+ inSameNest
+ && parameters.isCfRuntime()
+ && parameters.asCfRuntime().isNewerThanOrEqual(JDK17),
+ runResult -> runResult.assertSuccessWithOutputLines("A::bar"),
+ runResult -> checkExpectedResult(runResult, false));
}
@Test
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessTest.java
index 5251469..ccc0430 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessTest.java
@@ -76,7 +76,7 @@
DexProgramClass bClass =
appInfo.definitionFor(buildType(B.class, appInfo.dexItemFactory())).asProgramClass();
DexMethod bar = buildMethod(A.class.getDeclaredMethod("bar"), appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(bar);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(bar);
assertEquals(OptionalBool.of(inSameNest), resolutionResult.isAccessibleFrom(bClass, appInfo));
}
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessWithIntermediateClassTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessWithIntermediateClassTest.java
index 9adae80..f2f7dd9 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessWithIntermediateClassTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessWithIntermediateClassTest.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.resolution.access;
import static com.android.tools.r8.TestRuntime.CfVm.JDK11;
+import static com.android.tools.r8.TestRuntime.CfVm.JDK17;
import static org.junit.Assert.assertEquals;
import com.android.tools.r8.TestBase;
@@ -71,7 +72,7 @@
DexProgramClass bClass =
appInfo.definitionFor(buildType(B.class, appInfo.dexItemFactory())).asProgramClass();
DexMethod bar = buildMethod(A.class.getDeclaredMethod("bar"), appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(bar);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(bar);
assertEquals(OptionalBool.of(inSameNest), resolutionResult.isAccessibleFrom(bClass, appInfo));
}
@@ -81,7 +82,13 @@
.addProgramClasses(getClasses())
.addProgramClassFileData(getTransformedClasses())
.run(parameters.getRuntime(), Main.class)
- .apply(runResult -> checkExpectedResult(runResult, false));
+ .applyIf(
+ // TODO(b/227160049): Incorrect nest-based access allowed on JDK17!?
+ inSameNest
+ && parameters.isCfRuntime()
+ && parameters.asCfRuntime().isNewerThanOrEqual(JDK17),
+ runResult -> runResult.assertSuccessWithOutputLines("A::bar"),
+ runResult -> checkExpectedResult(runResult, false));
}
@Test
diff --git a/src/test/java/com/android/tools/r8/resolution/access/SelfVirtualMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/SelfVirtualMethodAccessTest.java
index ea12cad..a91d3ed 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/SelfVirtualMethodAccessTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/SelfVirtualMethodAccessTest.java
@@ -59,7 +59,7 @@
DexProgramClass aClass =
appInfo.definitionFor(buildType(A.class, appInfo.dexItemFactory())).asProgramClass();
DexMethod bar = buildMethod(A.class.getDeclaredMethod("bar"), appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(bar);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(bar);
assertEquals(OptionalBool.TRUE, resolutionResult.isAccessibleFrom(aClass, appInfo));
}
diff --git a/src/test/java/com/android/tools/r8/resolution/access/indirectmethod/IndirectMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/indirectmethod/IndirectMethodAccessTest.java
index 8341bba..9ae877d 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/indirectmethod/IndirectMethodAccessTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/indirectmethod/IndirectMethodAccessTest.java
@@ -65,7 +65,7 @@
DexProgramClass cClass =
appInfo.definitionFor(buildType(C.class, appInfo.dexItemFactory())).asProgramClass();
DexMethod bar = buildMethod(B.class.getMethod("foo"), appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(bar);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(bar);
assertEquals(
OptionalBool.TRUE, resolutionResult.isAccessibleForVirtualDispatchFrom(cClass, appInfo));
}
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/AbstractAllTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/AbstractAllTest.java
index 4911f70..81a0f45 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/AbstractAllTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/AbstractAllTest.java
@@ -45,7 +45,7 @@
buildClasses(CLASSES).addLibraryFile(parameters.getDefaultRuntimeLibrary()).build();
AppInfoWithLiveness appInfo = computeAppViewWithLiveness(app, Main.class).appInfo();
DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
DexEncodedMethod resolutionTarget = resolutionResult.getSingleTarget();
// Currently R8 will resolve to L::f as that is the first in the topological search.
// Resolution may return any of the matches, so it is valid if this expectation changes.
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultLeftAbstractRightTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultLeftAbstractRightTest.java
index 47d664f..d708d1e 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultLeftAbstractRightTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultLeftAbstractRightTest.java
@@ -51,7 +51,7 @@
.buildWithLiveness()
.appInfo();
DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
DexEncodedMethod resolutionTarget = resolutionResult.getSingleTarget();
assertEquals(L.class.getTypeName(), resolutionTarget.getHolderType().toSourceString());
}
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultRightAbstractLeftTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultRightAbstractLeftTest.java
index f6b2df5..8f94ef3 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultRightAbstractLeftTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultRightAbstractLeftTest.java
@@ -51,7 +51,7 @@
.buildWithLiveness()
.appInfo();
DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
DexEncodedMethod resolutionTarget = resolutionResult.getSingleTarget();
assertEquals(R.class.getTypeName(), resolutionTarget.getHolderType().toSourceString());
}
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAbstractLeftTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAbstractLeftTest.java
index 49edcae..6b31505 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAbstractLeftTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAbstractLeftTest.java
@@ -53,7 +53,7 @@
Main.class)
.appInfo();
DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
DexEncodedMethod resolutionTarget = resolutionResult.getSingleTarget();
assertEquals(L.class.getTypeName(), resolutionTarget.getHolderType().toSourceString());
}
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAbstractRightTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAbstractRightTest.java
index 1aa65c6..0b78a07 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAbstractRightTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAbstractRightTest.java
@@ -53,7 +53,7 @@
Main.class)
.appInfo();
DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
DexEncodedMethod resolutionTarget = resolutionResult.getSingleTarget();
assertEquals(R.class.getTypeName(), resolutionTarget.getHolderType().toSourceString());
}
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndBothTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndBothTest.java
index af70288..7f09e71 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndBothTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndBothTest.java
@@ -53,7 +53,7 @@
.buildWithLiveness()
.appInfo();
DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
Set<String> holders = new HashSet<>();
resolutionResult
.asFailedResolution()
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndLeftTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndLeftTest.java
index d2d08a5..0f37198 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndLeftTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndLeftTest.java
@@ -50,7 +50,7 @@
.buildWithLiveness()
.appInfo();
DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
DexEncodedMethod resolutionTarget = resolutionResult.getSingleTarget();
assertEquals(L.class.getTypeName(), resolutionTarget.getHolderType().toSourceString());
}
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndRightTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndRightTest.java
index 1b900b4..8d35771 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndRightTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndRightTest.java
@@ -50,7 +50,7 @@
.buildWithLiveness()
.appInfo();
DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
DexEncodedMethod resolutionTarget = resolutionResult.getSingleTarget();
assertEquals(R.class.getTypeName(), resolutionTarget.getHolderType().toSourceString());
}
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/TwoDefaultMethodsWithoutTopTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/TwoDefaultMethodsWithoutTopTest.java
index 8901542..290dbec 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/TwoDefaultMethodsWithoutTopTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/TwoDefaultMethodsWithoutTopTest.java
@@ -58,7 +58,7 @@
.buildWithLiveness()
.appInfo();
DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
if (minApi.isLessThan(apiLevelWithDefaultInterfaceMethodsSupport())) {
// When desugaring a forwarding method throwing ICCE is inserted.
// Check that the resolved method throws such an exception.
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultWithoutTopTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultWithoutTopTest.java
index 467ca50..8908dce 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultWithoutTopTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultWithoutTopTest.java
@@ -63,7 +63,7 @@
.buildWithLiveness();
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnInterface(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnInterfaceHolder(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
@@ -112,7 +112,7 @@
.buildWithLiveness();
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnInterface(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnInterfaceHolder(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DuplicateImportsTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DuplicateImportsTest.java
index af2dde1..8122941 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DuplicateImportsTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DuplicateImportsTest.java
@@ -63,7 +63,7 @@
.buildWithLiveness();
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnInterface(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnInterfaceHolder(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceWithStaticTargetTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceWithStaticTargetTest.java
index 48c4221..ca5e24e 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceWithStaticTargetTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceWithStaticTargetTest.java
@@ -56,7 +56,7 @@
AssertionError.class,
() ->
appInfo
- .resolveMethodOnInterface(method)
+ .resolveMethodOnInterfaceHolder(method)
.lookupVirtualDispatchTargets(context, appInfo));
}
diff --git a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateClasspathWidenTest.java b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateClasspathWidenTest.java
index e59ea7a..bff70ca 100644
--- a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateClasspathWidenTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateClasspathWidenTest.java
@@ -74,7 +74,7 @@
.buildWithLiveness();
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(Abstract.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Abstract.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateReentryTest.java b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateReentryTest.java
index 4b2877d..255fbed 100644
--- a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateReentryTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateReentryTest.java
@@ -59,7 +59,7 @@
Main.class);
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(A.class, "bar", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(A.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateReentryWithNarrowingTest.java b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateReentryWithNarrowingTest.java
index be967fb..f33ee0b 100644
--- a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateReentryWithNarrowingTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateReentryWithNarrowingTest.java
@@ -63,7 +63,7 @@
Main.class);
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(A.class, "bar", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(A.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateWithDefaultMethod2Test.java b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateWithDefaultMethod2Test.java
index 8262061..be8acd3 100644
--- a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateWithDefaultMethod2Test.java
+++ b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateWithDefaultMethod2Test.java
@@ -73,7 +73,7 @@
Main.class);
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(A.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateWithDefaultMethodTest.java b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateWithDefaultMethodTest.java
index 876a991..8846bf2 100644
--- a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateWithDefaultMethodTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateWithDefaultMethodTest.java
@@ -67,7 +67,7 @@
Main.class);
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(A.class, appInfo.dexItemFactory()));
assertTrue(resolutionResult.isAccessibleFrom(context, appView).isFalse());
diff --git a/src/test/java/com/android/tools/r8/resolution/packageprivate/WidenAccessOutsidePackageTest.java b/src/test/java/com/android/tools/r8/resolution/packageprivate/WidenAccessOutsidePackageTest.java
index 219c239..da660f2 100644
--- a/src/test/java/com/android/tools/r8/resolution/packageprivate/WidenAccessOutsidePackageTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/packageprivate/WidenAccessOutsidePackageTest.java
@@ -60,7 +60,7 @@
Main.class);
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(A.class, "bar", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(A.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/singletarget/InstantiatedLowerBoundTest.java b/src/test/java/com/android/tools/r8/resolution/singletarget/InstantiatedLowerBoundTest.java
index 7664322..58c64b1 100644
--- a/src/test/java/com/android/tools/r8/resolution/singletarget/InstantiatedLowerBoundTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/singletarget/InstantiatedLowerBoundTest.java
@@ -131,7 +131,7 @@
DexMethod fooA = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
DexMethod fooB = buildNullaryVoidMethod(B.class, "foo", appInfo.dexItemFactory());
DexMethod fooC = buildNullaryVoidMethod(C.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolution = appInfo.resolveMethodOnClass(fooA);
+ MethodResolutionResult resolution = appInfo.resolveMethodOnClassHolder(fooA);
DexProgramClass context = appView.definitionForProgramType(typeMain);
DexProgramClass upperBound = appView.definitionForProgramType(typeA);
DexProgramClass lowerBound = appView.definitionForProgramType(typeC);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/AbstractInMiddleTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/AbstractInMiddleTest.java
index 4da75f6..e856ed2 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/AbstractInMiddleTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/AbstractInMiddleTest.java
@@ -59,7 +59,7 @@
Main.class);
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceSubTypeTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceSubTypeTest.java
index d91d19f..665ef74 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceSubTypeTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceSubTypeTest.java
@@ -62,7 +62,7 @@
.buildWithLiveness();
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceTest.java
index 69c8c7a..df0722f 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceTest.java
@@ -62,7 +62,7 @@
.buildWithLiveness();
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultWithoutTopTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultWithoutTopTest.java
index 65d8316..d4541ac 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultWithoutTopTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultWithoutTopTest.java
@@ -63,7 +63,7 @@
.buildWithLiveness();
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvalidResolutionToThisTarget.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvalidResolutionToThisTarget.java
index 10c5b6f..6aac0fb 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvalidResolutionToThisTarget.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvalidResolutionToThisTarget.java
@@ -59,7 +59,7 @@
Main.class);
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
assertTrue(resolutionResult.isSingleResolution());
DexType mainType = buildType(Main.class, appInfo.dexItemFactory());
DexProgramClass main = appView.definitionForProgramType(mainType);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvokeVirtualToInterfaceDefinitionTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvokeVirtualToInterfaceDefinitionTest.java
index 14f9d2a..a1f6b17 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvokeVirtualToInterfaceDefinitionTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvokeVirtualToInterfaceDefinitionTest.java
@@ -62,7 +62,7 @@
.buildWithLiveness();
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/KeptTargetsIncompleteLookupTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/KeptTargetsIncompleteLookupTest.java
index 3b675c7..19f951a 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/KeptTargetsIncompleteLookupTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/KeptTargetsIncompleteLookupTest.java
@@ -87,7 +87,7 @@
});
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(initial, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
DexProgramClass context =
DexProgramClass.asProgramClassOrNull(
appView
@@ -238,7 +238,7 @@
.build());
AppInfoWithClassHierarchy appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(B.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
DexType typeA = buildType(A.class, appInfo.dexItemFactory());
DexType typeB = buildType(B.class, appInfo.dexItemFactory());
DexProgramClass classB = appInfo.definitionForProgramType(typeB);
@@ -273,7 +273,7 @@
Unrelated.class);
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(Unrelated.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Unrelated.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/PackagePrivateChainTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/PackagePrivateChainTest.java
index 001075d..33bfc01 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/PackagePrivateChainTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/PackagePrivateChainTest.java
@@ -62,7 +62,7 @@
Main.class);
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(Top.class, "clear", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(TopRunner.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/PackagePrivateFinalOverrideTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/PackagePrivateFinalOverrideTest.java
index 84021e7..28d1cc2 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/PackagePrivateFinalOverrideTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/PackagePrivateFinalOverrideTest.java
@@ -68,7 +68,7 @@
Main.class);
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(ViewModel.class, "clear", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
DexProgramClass context =
appView.definitionForProgramType(
buildType(ViewModelRunner.class, appInfo.dexItemFactory()));
@@ -119,7 +119,7 @@
Main.class);
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(ViewModel.class, "clear", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
@@ -171,7 +171,7 @@
Main.class);
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(ViewModel.class, "clear", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
DexProgramClass context =
appView.definitionForProgramType(
buildType(ViewModelRunnerWithCast.class, appInfo.dexItemFactory()));
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/PrivateOverrideOfVirtualTargetTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/PrivateOverrideOfVirtualTargetTest.java
index eda5153..24aa358 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/PrivateOverrideOfVirtualTargetTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/PrivateOverrideOfVirtualTargetTest.java
@@ -61,7 +61,7 @@
Main.class);
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(A.class, "bar", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(B.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/ProtectedDifferentPackageLookupTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/ProtectedDifferentPackageLookupTest.java
index 3a4a369..3ffdf09 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/ProtectedDifferentPackageLookupTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/ProtectedDifferentPackageLookupTest.java
@@ -54,7 +54,7 @@
AppView<AppInfoWithLiveness> appView = computeAppViewWithLiveness(builder.build(), Main.class);
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/ProtectedSamePackageLookupTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/ProtectedSamePackageLookupTest.java
index 10fb0d9..337ba95 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/ProtectedSamePackageLookupTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/ProtectedSamePackageLookupTest.java
@@ -50,7 +50,7 @@
PackagePrivateChainTest.Main.class);
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnClassHolder(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/TargetInDefaultMethodTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/TargetInDefaultMethodTest.java
index 162d3c4..8769eca 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/TargetInDefaultMethodTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/TargetInDefaultMethodTest.java
@@ -63,7 +63,7 @@
.buildWithLiveness();
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory());
- MethodResolutionResult resolutionResult = appInfo.resolveMethodOnInterface(method);
+ MethodResolutionResult resolutionResult = appInfo.resolveMethodOnInterfaceHolder(method);
DexProgramClass context =
appView.definitionForProgramType(buildType(Main.class, appInfo.dexItemFactory()));
LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(context, appInfo);
diff --git a/src/test/java/com/android/tools/r8/retrace/StackTraceRegularExpressionParserTests.java b/src/test/java/com/android/tools/r8/retrace/StackTraceRegularExpressionParserTests.java
index 2e60c6b..91428db 100644
--- a/src/test/java/com/android/tools/r8/retrace/StackTraceRegularExpressionParserTests.java
+++ b/src/test/java/com/android/tools/r8/retrace/StackTraceRegularExpressionParserTests.java
@@ -1084,6 +1084,57 @@
});
}
+ /* This is a regression test for b/222749348 */
+ @Test
+ public void testGroups() {
+ runRetraceTest(
+ "(?:(?:.*?%c %m\\(%s(?:: %l)?\\)))",
+ new StackTraceForTest() {
+ @Override
+ public List<String> obfuscatedStackTrace() {
+ return ImmutableList.of(
+ "FOO bar(PG: 1)",
+ "FOO bar(PG : 1)",
+ "FOO bar(PG:1)",
+ "FOO bar(PG:1 )",
+ "FOO bar(PG: 1 )");
+ }
+
+ @Override
+ public String mapping() {
+ return StringUtils.lines(
+ "this.was.Deobfuscated -> FOO:",
+ " int[] mFontFamily -> a",
+ " 1:3:void someMethod(int):65:67 -> bar");
+ }
+
+ @Override
+ public List<String> retracedStackTrace() {
+ return ImmutableList.of(
+ "this.was.Deobfuscated someMethod(Deobfuscated.java: 65)",
+ "this.was.Deobfuscated someMethod(Deobfuscated.java: 65)",
+ "FOO bar(PG:1)",
+ "FOO bar(PG:1 )",
+ "FOO bar(PG: 1 )");
+ }
+
+ @Override
+ public List<String> retraceVerboseStackTrace() {
+ return ImmutableList.of(
+ "this.was.Deobfuscated void someMethod(int)(Deobfuscated.java: 65)",
+ "this.was.Deobfuscated void someMethod(int)(Deobfuscated.java: 65)",
+ "FOO bar(PG:1)",
+ "FOO bar(PG:1 )",
+ "FOO bar(PG: 1 )");
+ }
+
+ @Override
+ public int expectedWarnings() {
+ return 0;
+ }
+ });
+ }
+
private TestDiagnosticMessagesImpl runRetraceTest(
String regularExpression, StackTraceForTest stackTraceForTest) {
TestDiagnosticMessagesImpl diagnosticsHandler = new TestDiagnosticMessagesImpl();
diff --git a/src/test/java/com/android/tools/r8/rewrite/JavaScriptScriptEngineTest.java b/src/test/java/com/android/tools/r8/rewrite/JavaScriptScriptEngineTest.java
index a9491f4..5e4932e 100644
--- a/src/test/java/com/android/tools/r8/rewrite/JavaScriptScriptEngineTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/JavaScriptScriptEngineTest.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.utils.StringUtils;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
@@ -56,22 +57,18 @@
testForR8(parameters.getBackend())
.addInnerClasses(JavaScriptScriptEngineTest.class)
.addKeepMainRule(TestClass.class)
+ .setMinApi(parameters.getApiLevel())
.applyIf(
parameters.isDexRuntime(),
- testBuilder ->
- testBuilder.addOptionsModification(
- options ->
- options
- .getOpenClosedInterfacesOptions()
- .suppressAllOpenInterfacesDueToMissingClasses()))
- .setMinApi(parameters.getApiLevel())
- .apply(
- b -> {
- if (parameters.isDexRuntime()) {
- addRhinoForAndroid(b);
- addKeepRulesForAndroidRhino(b);
- b.allowDiagnosticWarningMessages();
- }
+ testBuilder -> {
+ testBuilder.addOptionsModification(
+ options ->
+ options
+ .getOpenClosedInterfacesOptions()
+ .suppressAllOpenInterfacesDueToMissingClasses());
+ addRhinoForAndroid(testBuilder);
+ addKeepRulesForAndroidRhino(testBuilder);
+ testBuilder.allowDiagnosticWarningMessages();
})
.compile()
.applyIf(
@@ -84,8 +81,13 @@
"required for default or static interface methods desugaring"),
equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))))
.run(parameters.getRuntime(), TestClass.class)
- .assertSuccessWithOutput(
- parameters.isCfRuntime() ? EXPECTED_NASHORN_OUTPUT : EXPECTED_RHINO_OUTPUT);
+ .applyIf(
+ // TODO(b/227162584): Fails to find any engine on JDK17.
+ parameters.isCfRuntime(CfVm.JDK17),
+ r -> r.assertFailureWithErrorThatThrows(NullPointerException.class),
+ r ->
+ r.assertSuccessWithOutput(
+ parameters.isCfRuntime() ? EXPECTED_NASHORN_OUTPUT : EXPECTED_RHINO_OUTPUT));
}
static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/rewrite/ScriptEngineTest.java b/src/test/java/com/android/tools/r8/rewrite/ScriptEngineTest.java
index 7bb21a3..bf0084b 100644
--- a/src/test/java/com/android/tools/r8/rewrite/ScriptEngineTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/ScriptEngineTest.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.DataEntryResource;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.StreamUtils;
import com.android.tools.r8.utils.StringUtils;
@@ -103,7 +104,10 @@
// comes with "Oracle Nashorn" included.
.assertSuccessWithOutput(
parameters.isCfRuntime()
- ? StringUtils.lines("MyEngine1", "MyEngine2", "Oracle Nashorn")
+ // TODO(b/227162584): It looks like the JS engine is not in the jdk anymore.
+ ? (parameters.isCfRuntime(CfVm.JDK17)
+ ? StringUtils.lines("MyEngine1", "MyEngine2")
+ : StringUtils.lines("MyEngine1", "MyEngine2", "Oracle Nashorn"))
: StringUtils.lines("Mozilla Rhino", "MyEngine1", "MyEngine2"));
// TODO(b/136633154): On the JVM this should always be there as the service loading is in
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlersimple/AssertionConfigurationAssertionHandlerKotlinSimpleTest.java b/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlersimple/AssertionConfigurationAssertionHandlerKotlinSimpleTest.java
index dc6353d..e460253 100644
--- a/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlersimple/AssertionConfigurationAssertionHandlerKotlinSimpleTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlersimple/AssertionConfigurationAssertionHandlerKotlinSimpleTest.java
@@ -58,10 +58,10 @@
@Override
protected void configureR8(R8FullTestBuilder builder) {
- builder.applyIf(
- !kotlinStdlibAsLibrary
- && !useJvmAssertions
- && !kotlinParameters.is(KotlinCompilerVersion.KOTLINC_1_3_72),
- b -> b.addDontWarn("org.jetbrains.annotations.NotNull"));
+ boolean referencesNotNull =
+ !kotlinParameters.is(KotlinCompilerVersion.KOTLINC_1_3_72)
+ && !kotlinStdlibAsLibrary
+ && !useJvmAssertions;
+ builder.applyIf(referencesNotNull, b -> b.addDontWarn("org.jetbrains.annotations.NotNull"));
}
}
diff --git a/src/test/java/com/android/tools/r8/shaking/ClasspathAndProgramSharedSuperTypeTest.java b/src/test/java/com/android/tools/r8/shaking/ClasspathAndProgramSharedSuperTypeTest.java
new file mode 100644
index 0000000..4363f33
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/ClasspathAndProgramSharedSuperTypeTest.java
@@ -0,0 +1,81 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.shaking;
+
+import static org.hamcrest.core.StringContains.containsString;
+import static org.junit.Assert.assertThrows;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import 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 ClasspathAndProgramSharedSuperTypeTest extends TestBase {
+
+ @Parameter() public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ // TODO(b/226054007): R8 should maintain classpath type.
+ assertThrows(
+ CompilationFailedException.class,
+ () ->
+ testForR8(parameters.getBackend())
+ .addProgramClasses(SharedSuperType.class, ProgramClass.class, Main.class)
+ .addClasspathClasses(SharedSuperType.class, ClasspathClass.class)
+ .setMinApi(parameters.getApiLevel())
+ .addKeepMainRule(Main.class)
+ .compileWithExpectedDiagnostics(
+ diagnostics ->
+ diagnostics.assertErrorMessageThatMatches(
+ containsString(
+ "Failed lookup of non-missing type: "
+ + typeName(SharedSuperType.class)))));
+ }
+
+ public static class SharedSuperType {
+
+ public void foo() {
+ System.out.println("SharedSuperType::foo");
+ }
+ }
+
+ public static class ClasspathClass extends SharedSuperType {
+
+ @Override
+ public void foo() {
+ System.out.println("ClasspathClass::foo");
+ super.foo();
+ }
+ }
+
+ /* Not referenced in live part of the program */
+ public static class ProgramClass extends SharedSuperType {
+
+ @Override
+ public void foo() {
+ System.out.println("ProgramClass::foo");
+ super.foo();
+ }
+ }
+
+ public static class Main {
+
+ public static void main(String[] args) {
+ new ClasspathClass().foo();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java b/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java
index 9d3e55f..604caae 100644
--- a/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java
@@ -8,7 +8,6 @@
import static org.hamcrest.CoreMatchers.anyOf;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.core.IsNot.not;
import com.android.tools.r8.D8TestRunResult;
import com.android.tools.r8.DXTestRunResult;
@@ -71,11 +70,6 @@
case DX:
case D8:
- case R8:
- if (parameters.isCfRuntime()) {
- assert compiler == Compiler.R8;
- return StringUtils.joinLines("Hello!", "Goodbye!", "");
- }
switch (parameters.getDexRuntimeVersion()) {
case V4_0_4:
case V4_4_4:
@@ -104,6 +98,14 @@
throw new Unreachable();
}
+ case R8:
+ return StringUtils.joinLines(
+ "Hello!",
+ "Unexpected outcome of getstatic",
+ "Unexpected outcome of checkcast",
+ "Goodbye!",
+ "");
+
case PROGUARD:
return StringUtils.joinLines(
"Hello!", "Unexpected outcome of checkcast", "Goodbye!", "");
@@ -123,10 +125,6 @@
@Override
public String getExpectedOutput(
Compiler compiler, TestParameters parameters, boolean useInterface) {
- if (useInterface) {
- return StringUtils.joinLines("Hello!", "In verifiable method!", "Goodbye!", "");
- }
-
switch (compiler) {
case R8:
case PROGUARD:
@@ -135,6 +133,9 @@
return StringUtils.joinLines("Hello!", "In verifiable method!", "Goodbye!", "");
default:
+ if (useInterface) {
+ return StringUtils.joinLines("Hello!", "In verifiable method!", "Goodbye!", "");
+ }
// The code fails with a verification error because the verifiableMethod() is being
// called on UnverifiableClass, which does not verify due to unverifiableMethod().
return StringUtils.joinLines("Hello!", "");
@@ -329,17 +330,12 @@
break;
case INVOKE_VERIFIABLE_METHOD_ON_UNVERIFIABLE_CLASS:
- if (useInterface) {
+ if (useInterface || compiler == Compiler.R8 || compiler == Compiler.PROGUARD) {
result.assertSuccessWithOutput(getExpectedOutput(compiler));
} else {
- if (compiler == Compiler.R8
- || compiler == Compiler.PROGUARD) {
- result.assertSuccessWithOutput(getExpectedOutput(compiler));
- } else {
- result
- .assertFailureWithOutput(getExpectedOutput(compiler))
- .assertFailureWithErrorThatMatches(getMatcherForExpectedError());
- }
+ result
+ .assertFailureWithOutput(getExpectedOutput(compiler))
+ .assertFailureWithErrorThatMatches(getMatcherForExpectedError(compiler));
}
break;
@@ -347,18 +343,9 @@
if (useInterface) {
result.assertSuccessWithOutput(getExpectedOutput(compiler));
} else {
- if (compiler == Compiler.R8) {
- result
- .assertFailureWithOutput(getExpectedOutput(compiler))
- .assertFailureWithErrorThatMatches(
- allOf(
- containsString("java.lang.NullPointerException"),
- not(containsString("java.lang.VerifyError"))));
- } else {
- result
- .assertFailureWithOutput(getExpectedOutput(compiler))
- .assertFailureWithErrorThatMatches(getMatcherForExpectedError());
- }
+ result
+ .assertFailureWithOutput(getExpectedOutput(compiler))
+ .assertFailureWithErrorThatMatches(getMatcherForExpectedError(compiler));
}
break;
@@ -371,7 +358,10 @@
return mode.getExpectedOutput(compiler, parameters, useInterface);
}
- private Matcher<String> getMatcherForExpectedError() {
+ private Matcher<String> getMatcherForExpectedError(Compiler compiler) {
+ if (compiler == Compiler.R8 && mode == Mode.INVOKE_UNVERIFIABLE_METHOD) {
+ return containsString("java.lang.NullPointerException");
+ }
if (parameters.isCfRuntime()) {
return allOf(
containsString("java.lang.VerifyError"),
diff --git a/src/test/java/com/android/tools/r8/shaking/allowshrinking/KeepClassFieldsAllowShrinkingCompatibilityTest.java b/src/test/java/com/android/tools/r8/shaking/allowshrinking/KeepClassFieldsAllowShrinkingCompatibilityTest.java
index 314ea33..35d4d6b 100644
--- a/src/test/java/com/android/tools/r8/shaking/allowshrinking/KeepClassFieldsAllowShrinkingCompatibilityTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/allowshrinking/KeepClassFieldsAllowShrinkingCompatibilityTest.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.shaking.allowshrinking;
import static com.android.tools.r8.utils.codeinspector.CodeMatchers.accessesField;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
import static com.android.tools.r8.utils.codeinspector.Matchers.notIf;
@@ -107,7 +108,8 @@
// This does not match the R8 behavior for an unused method, so there may be an
// optimization opportunity here.
// (See KeepClassMethodsAllowShrinkingCompatibilityTest regarding methods).
- assertThat(aBar, isPresentAndRenamed(allowObfuscation));
+ assertThat(
+ aBar, shrinker.isR8() ? isAbsent() : isPresentAndRenamed(allowObfuscation));
assertThat(inspector.clazz(TestClass.class).mainMethod(), accessesField(aFoo));
if (shrinker.isR8()) {
assertThat(bFoo, not(isPresent()));
diff --git a/src/test/java/com/android/tools/r8/shaking/b169045091/B169045091.java b/src/test/java/com/android/tools/r8/shaking/b169045091/B169045091.java
index 1c6a438..3a32244 100644
--- a/src/test/java/com/android/tools/r8/shaking/b169045091/B169045091.java
+++ b/src/test/java/com/android/tools/r8/shaking/b169045091/B169045091.java
@@ -99,12 +99,18 @@
// Test that HelloGreeter.greet() is accessible to TestClass.
DexMethod helloReference = buildNullaryVoidMethod(HelloGreeter.class, "hello", dexItemFactory);
assertTrue(
- appInfo.resolveMethodOnClass(helloReference).isAccessibleFrom(context, appView).isTrue());
+ appInfo
+ .resolveMethodOnClassHolder(helloReference)
+ .isAccessibleFrom(context, appView)
+ .isTrue());
// Test that WorldGreeter.greet() is inaccessible to TestClass.
DexMethod worldReference = buildNullaryVoidMethod(WorldGreeter.class, "world", dexItemFactory);
assertTrue(
- appInfo.resolveMethodOnClass(worldReference).isAccessibleFrom(context, appView).isFalse());
+ appInfo
+ .resolveMethodOnClassHolder(worldReference)
+ .isAccessibleFrom(context, appView)
+ .isFalse());
}
public static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedFieldTypeTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedFieldTypeTest.java
index 12c0643..8e4f9f4 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedFieldTypeTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedFieldTypeTest.java
@@ -65,12 +65,16 @@
public static void main(String[] args) {
TestClass obj = new TestClass();
- if (false) {
+ if (alwaysFalse()) {
obj.field = new B();
System.out.println(obj.field);
}
System.out.print(obj.get().getClass().getName());
}
+
+ static boolean alwaysFalse() {
+ return false;
+ }
}
public MergedFieldTypeWithCollisionTest(
diff --git a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptSingletonIsNotCyclicTest.java b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptSingletonIsNotCyclicTest.java
index a14683a..b34d36d 100644
--- a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptSingletonIsNotCyclicTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptSingletonIsNotCyclicTest.java
@@ -101,13 +101,13 @@
// TestClass.foo is kept by TestClass.<init>.
QueryNode testFooFieldNode =
inspector.field(testFooFieldRef).assertPresent().assertKeptBy(testInit);
- // The type Foo is not kept by TestClass.<init>, but TestClass.foo.
+ // The type Foo is kept by TestClass.<init> and TestClass.foo.
QueryNode fooClassNode =
inspector
.clazz(fooClassRef)
.assertRenamed()
.assertKeptBy(testFooFieldNode)
- .assertNotKeptBy(testInit);
+ .assertKeptBy(testInit);
// Foo.<clinit> is kept by Foo
QueryNode fooClInit = inspector.method(fooClInitRef).assertPresent().assertKeptBy(fooClassNode);
// The type Foo is also kept by Foo.<clinit>
diff --git a/src/test/java/com/android/tools/r8/synthesis/globals/GlobalSyntheticsConsumerAndProvider.java b/src/test/java/com/android/tools/r8/synthesis/globals/GlobalSyntheticsConsumerAndProvider.java
new file mode 100644
index 0000000..57f5622
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/synthesis/globals/GlobalSyntheticsConsumerAndProvider.java
@@ -0,0 +1,41 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.synthesis.globals;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import com.android.tools.r8.GlobalSyntheticsConsumer;
+import com.android.tools.r8.GlobalSyntheticsResourceProvider;
+import com.android.tools.r8.ResourceException;
+import com.android.tools.r8.origin.Origin;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+public class GlobalSyntheticsConsumerAndProvider
+ implements GlobalSyntheticsConsumer, GlobalSyntheticsResourceProvider {
+
+ private byte[] bytes;
+
+ @Override
+ public void accept(byte[] bytes) {
+ assertNull(this.bytes);
+ assertNotNull(bytes);
+ this.bytes = bytes;
+ }
+
+ @Override
+ public Origin getOrigin() {
+ return Origin.unknown();
+ }
+
+ @Override
+ public InputStream getByteStream() throws ResourceException {
+ return new ByteArrayInputStream(bytes);
+ }
+
+ public boolean hasBytes() {
+ return true;
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/tracereferences/TraceMethodResolutionWithLibraryAndProgramClassTest.java b/src/test/java/com/android/tools/r8/tracereferences/TraceMethodResolutionWithLibraryAndProgramClassTest.java
new file mode 100644
index 0000000..4dcf1cd
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/tracereferences/TraceMethodResolutionWithLibraryAndProgramClassTest.java
@@ -0,0 +1,147 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.tracereferences;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.ZipUtils.ZipBuilder;
+import com.google.common.collect.ImmutableSet;
+import java.nio.file.Path;
+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.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+// This is a regression test for b/226170842.
+@RunWith(Parameterized.class)
+public class TraceMethodResolutionWithLibraryAndProgramClassTest extends TestBase {
+
+ @Parameter() public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
+
+ static class SeenReferencesConsumer implements TraceReferencesConsumer {
+
+ private final Set<MethodReference> seenMethods = new HashSet<>();
+ private final Set<MethodReference> seenMissingMethods = new HashSet<>();
+
+ @Override
+ public void acceptType(TracedClass tracedClass, DiagnosticsHandler handler) {}
+
+ @Override
+ public void acceptField(TracedField tracedField, DiagnosticsHandler handler) {}
+
+ @Override
+ public void acceptMethod(TracedMethod tracedMethod, DiagnosticsHandler handler) {
+ if (tracedMethod.isMissingDefinition()) {
+ seenMissingMethods.add(tracedMethod.getReference());
+ } else {
+ seenMethods.add(tracedMethod.getReference());
+ }
+ }
+ }
+
+ @Test
+ public void testInvalidResolution() throws Exception {
+ Path dir = temp.newFolder().toPath();
+ Path libJar =
+ ZipBuilder.builder(dir.resolve("lib.jar"))
+ .addFilesRelative(
+ ToolHelper.getClassPathForTests(), ToolHelper.getClassFileForTestClass(A.class))
+ .addBytes(
+ DescriptorUtils.getPathFromJavaType(B.class),
+ transformer(B.class).removeMethods(MethodPredicate.all()).transform())
+ .build();
+ Path targetJar =
+ ZipBuilder.builder(dir.resolve("target.jar"))
+ .addBytes(
+ DescriptorUtils.getPathFromJavaType(A.class),
+ transformer(A.class).removeMethods(MethodPredicate.all()).transform())
+ .addFilesRelative(
+ ToolHelper.getClassPathForTests(), ToolHelper.getClassFileForTestClass(B.class))
+ .build();
+ Path sourceJar =
+ ZipBuilder.builder(dir.resolve("source.jar"))
+ .addFilesRelative(
+ ToolHelper.getClassPathForTests(), ToolHelper.getClassFileForTestClass(Main.class))
+ .build();
+ SeenReferencesConsumer consumer = new SeenReferencesConsumer();
+ TraceReferences.run(
+ TraceReferencesCommand.builder()
+ .addLibraryFiles(ToolHelper.getMostRecentAndroidJar())
+ .addLibraryFiles(libJar)
+ .addTargetFiles(targetJar)
+ .addSourceFiles(sourceJar)
+ .setConsumer(consumer)
+ .build());
+ ImmutableSet<MethodReference> foundSet =
+ ImmutableSet.of(
+ Reference.methodFromMethod(A.class.getMethod("foo")),
+ Reference.methodFromMethod(A.class.getMethod("bar")));
+ ImmutableSet<MethodReference> missingSet =
+ ImmutableSet.of(
+ Reference.methodFromMethod(B.class.getMethod("baz")),
+ Reference.methodFromMethod(B.class.getMethod("qux")));
+ assertEquals(foundSet, consumer.seenMethods);
+ // TODO(b/226170842): Methods should not be missing.
+ assertEquals(missingSet, consumer.seenMissingMethods);
+ }
+
+ // A is added to both library and program, but the program one is missing the methods {foo,bar}
+ public static class A {
+
+ public static boolean foo() {
+ return true;
+ }
+
+ public int bar() {
+ return 42;
+ }
+ }
+
+ // B is added to both library and program, but the library one is missing the methods {baz,qux}
+ public static class B {
+
+ public static boolean baz() {
+ return false;
+ }
+
+ public int qux() {
+ return 42;
+ }
+ }
+
+ public static class Main {
+
+ public static void main(String[] args) {
+ A a = getAInstance(null);
+ B b = getBInstance(null);
+ int value = (A.foo() && B.baz()) ? a.bar() : b.qux();
+ }
+
+ private static A getAInstance(Object o) {
+ return (A) o;
+ }
+
+ private static B getBInstance(Object o) {
+ return (B) o;
+ }
+ }
+}
diff --git a/third_party/binary_compatibility_tests/compiler_api_tests.tar.gz.sha1 b/third_party/binary_compatibility_tests/compiler_api_tests.tar.gz.sha1
index c55bcfe..d9e0fb6 100644
--- a/third_party/binary_compatibility_tests/compiler_api_tests.tar.gz.sha1
+++ b/third_party/binary_compatibility_tests/compiler_api_tests.tar.gz.sha1
@@ -1 +1 @@
-bf40dc3b9e57b7759d8da51fb70d9995af1a188d
\ No newline at end of file
+2b8f463bcc995898411329d9cd55892289d5763e
\ No newline at end of file
diff --git a/third_party/jctf.tar.gz.sha1 b/third_party/jctf.tar.gz.sha1
deleted file mode 100644
index ebad250..0000000
--- a/third_party/jctf.tar.gz.sha1
+++ /dev/null
@@ -1 +0,0 @@
-7104dcb8474c494083a204b6200207b42f6cf935
\ No newline at end of file
diff --git a/third_party/openjdk/jdk-18/linux.tar.gz.sha1 b/third_party/openjdk/jdk-18/linux.tar.gz.sha1
index 3c8efd9..3ee16d6 100644
--- a/third_party/openjdk/jdk-18/linux.tar.gz.sha1
+++ b/third_party/openjdk/jdk-18/linux.tar.gz.sha1
@@ -1 +1 @@
-b545df5778c9025fe105dddcd8b3830d8731137b
\ No newline at end of file
+3685c34b5ad5a901a5cada63f7c7eb5ca3a45a0c
\ No newline at end of file
diff --git a/third_party/openjdk/jdk-18/osx.tar.gz.sha1 b/third_party/openjdk/jdk-18/osx.tar.gz.sha1
index 9699f89..ea720a2 100644
--- a/third_party/openjdk/jdk-18/osx.tar.gz.sha1
+++ b/third_party/openjdk/jdk-18/osx.tar.gz.sha1
@@ -1 +1 @@
-527883f93a157ae249f83f461b0368d87c8fe6a1
\ No newline at end of file
+077a30ec9b354e875da54edce59d44ed480ff3eb
\ No newline at end of file
diff --git a/third_party/openjdk/jdk-18/windows.tar.gz.sha1 b/third_party/openjdk/jdk-18/windows.tar.gz.sha1
index 854167c..4120e12 100644
--- a/third_party/openjdk/jdk-18/windows.tar.gz.sha1
+++ b/third_party/openjdk/jdk-18/windows.tar.gz.sha1
@@ -1 +1 @@
-b1e3cb3be67dd78423a0a96c0214ac97b5edd112
\ No newline at end of file
+98b0f7b4198f2257c57ee68f553f46112eb260e4
\ No newline at end of file
diff --git a/tools/archive_desugar_jdk_libs.py b/tools/archive_desugar_jdk_libs.py
index cc9bee4..2f13541 100755
--- a/tools/archive_desugar_jdk_libs.py
+++ b/tools/archive_desugar_jdk_libs.py
@@ -29,7 +29,7 @@
import sys
import utils
-VERSION_FILE = 'VERSION.txt'
+VERSION_FILE = 'VERSION_JDK11.txt'
LIBRARY_NAME = 'desugar_jdk_libs'
def ParseOptions(argv):
@@ -37,7 +37,7 @@
result.add_option('--variant',
help='.',
choices = ['jdk8', 'jdk11'],
- default='jdk8')
+ default='jdk11')
result.add_option('--dry-run', '--dry_run',
help='Running on bot, use third_party dependency.',
default=False,
@@ -65,7 +65,7 @@
+ version_file + ' is expected to have exactly one line')
version = lines[0].strip()
utils.check_basic_semver_version(
- version, 'in version file ' + version_file_name)
+ version, 'in version file ' + version_file_name, allowPrerelease = True)
return version
diff --git a/tools/asmifier.py b/tools/asmifier.py
index 1a8e4ac..2b6a799 100755
--- a/tools/asmifier.py
+++ b/tools/asmifier.py
@@ -25,7 +25,7 @@
cmd.append('org.objectweb.asm.util.ASMifier')
cmd.extend(args)
utils.PrintCmd(cmd)
- result = subprocess.check_output(cmd)
+ result = subprocess.check_output(cmd).decode('utf-8')
print(result)
return result
@@ -45,9 +45,9 @@
help = False
args.append(arg)
if help:
- print "asmifier.py [--no-build] [--no-debug] <classfile>*"
- print " --no-build Don't run R8 dependencies."
- print " --no-debug Don't include local variable information in output."
+ print("asmifier.py [--no-build] [--no-debug] <classfile>*")
+ print(" --no-build Don't run R8 dependencies.")
+ print(" --no-debug Don't include local variable information in output.")
return
try:
run(args, build)
diff --git a/tools/create_jctf_tests.py b/tools/create_jctf_tests.py
deleted file mode 100755
index 38e1f9c..0000000
--- a/tools/create_jctf_tests.py
+++ /dev/null
@@ -1,136 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2017, 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.
-
-from __future__ import print_function
-from glob import glob
-from itertools import chain
-from os import makedirs
-from os.path import exists, join, dirname
-from shutil import rmtree
-from string import Template
-import os
-import re
-import sys
-
-import utils
-
-JCTFROOT = join(utils.REPO_ROOT, 'third_party', 'jctf')
-DESTINATION_DIR = join(utils.REPO_ROOT, 'build', 'generated', 'test', 'java',
- 'com', 'android', 'tools', 'r8', 'jctf')
-PACKAGE_PREFIX = 'com.google.jctf.test.lib.java.'
-RELATIVE_TESTDIR = join('LibTests', 'src', 'com', 'google', 'jctf', 'test',
- 'lib', 'java')
-TESTDIR = join(JCTFROOT, RELATIVE_TESTDIR)
-TEMPLATE = Template(
-"""// Copyright (c) 2017, 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.jctf.${compilerUnderTest}.${relativePackage};
-
-import org.junit.Test;
-import com.android.tools.r8.R8RunArtTestsTest;
-
-/**
- * Auto-generated test for the jctf test:
- * ${name}
- *
- * DO NOT EDIT THIS FILE. EDIT THE HERE DOCUMENT TEMPLATE IN
- * tools/create_jctf_tests.py INSTEAD!
- */
-public class ${testClassName} extends R8RunArtTestsTest {
-
- public ${testClassName}() {
- super("${nameWithoutPackagePrefix}", DexTool.NONE);
- }
-
- @Test
- public void run${testClassName}() throws Exception {
- // For testing with other Art VMs than the default set the system property
- // 'dex_vm' to the desired VM string (e.g. '4.4.4', see ToolHelper.DexVm)
- runJctfTest(CompilerUnderTest.${compilerUnderTestEnum},
- "$classFile",
- "$name"
- );
- }
-}
-""")
-
-EXIT_FAILURE = 1
-RE_PACKAGE = re.compile('package\\s+(com[^\\s;]*)')
-
-def fix_long_path(p):
- if os.name == 'nt':
- p = ('\\\\?\\' + p).decode('utf-8')
- return p
-
-def file_contains_string(filepath, search_string):
- with open(fix_long_path(filepath)) as f:
- return search_string in f.read()
-
-def read_package_from_java_file(filepath):
- with open(fix_long_path(filepath)) as f:
- for line in f:
- m = RE_PACKAGE.search(line)
- if m:
- return m.groups()[0]
- raise IOError("Can't find package statement in java file: " + filepath)
-
-
-def generate_test(class_name, compiler_under_test, compiler_under_test_enum,
- relative_package):
- filename = join(DESTINATION_DIR, compiler_under_test,
- relative_package.replace('.', os.sep), class_name + '.java')
- utils.makedirs_if_needed(dirname(filename))
-
- full_class_name = '{}{}.{}'.format(PACKAGE_PREFIX, relative_package,
- class_name)
- contents = TEMPLATE.substitute(
- compilerUnderTest = compiler_under_test,
- relativePackage = relative_package,
- name = full_class_name,
- testClassName = class_name,
- compilerUnderTestEnum = compiler_under_test_enum,
- classFile = full_class_name.replace('.', '/') + '.class',
- nameWithoutPackagePrefix = '{}.{}'.format(relative_package, class_name))
-
- with open(fix_long_path(filename), 'w') as f:
- f.write(contents)
-
-def Main():
- if not exists(JCTFROOT):
- print('JCTF test package not found in {}'.format(JCTFROOT),
- file = sys.stderr)
- return EXIT_FAILURE
-
- for tool in ['d8', 'r8']:
- p = fix_long_path(join(DESTINATION_DIR, tool))
- if exists(p):
- rmtree(p)
- makedirs(p)
-
- java_files = (chain.from_iterable(glob(join(x[0], '*.java'))
- for x in os.walk(TESTDIR)))
-
- dot_java_dot = '.java.'
-
- for f in java_files:
- if not file_contains_string(f, '@Test'):
- continue
-
- class_name = os.path.splitext(os.path.basename(f))[0]
- assert class_name.find('-') < 0
-
- package = read_package_from_java_file(f)
-
- idx = package.find(dot_java_dot)
- assert idx >= 0
- relative_package = package[idx + len(dot_java_dot):]
-
- generate_test(class_name, 'd8', 'R8_AFTER_D8', relative_package)
- generate_test(class_name, 'r8cf', 'R8CF', relative_package)
-
-
-if __name__ == '__main__':
- sys.exit(Main())
diff --git a/tools/find_haning_test.py b/tools/find_haning_test.py
index 786fbcf..3c65317 100755
--- a/tools/find_haning_test.py
+++ b/tools/find_haning_test.py
@@ -5,7 +5,7 @@
import argparse
import sys
-import urllib
+
def ParseOptions():
parser = argparse.ArgumentParser(
@@ -14,7 +14,7 @@
def get_started(stdout):
# Lines look like:
- # Start executing test runBigInteger_ZERO_A01 [com.android.tools.r8.jctf.r8cf.math.BigInteger.ZERO.BigInteger_ZERO_A01]
+ # Start executing test runBigInteger_ZERO_A01 [com.android.tools.r8.x.r8cf.math.BigInteger.ZERO.BigInteger_ZERO_A01]
start_lines = []
for line in stdout:
if line.startswith('Start executing test'):
@@ -24,7 +24,7 @@
def get_ended(stdout):
# Lines look like:
- # Done executing test runBigInteger_subtract_A01 [com.android.tools.r8.jctf.r8cf.math.BigInteger.subtractLjava_math_BigInteger.BigInteger_subtract_A01] with result: SUCCESS
+ # Done executing test runBigInteger_subtract_A01 [com.android.tools.r8.x.r8cf.math.BigInteger.subtractLjava_math_BigInteger.BigInteger_subtract_A01] with result: SUCCESS
done_lines = []
for line in stdout:
if line.startswith('Done executing test'):
diff --git a/tools/test.py b/tools/test.py
index ec4bb00..665ab5f 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -7,9 +7,6 @@
# if an argument is given, run only tests with that pattern. This script will
# force the tests to run, even if no input changed.
-import archive_desugar_jdk_libs
-import download_kotlin_dev
-import notify
import optparse
import os
import shutil
@@ -18,7 +15,10 @@
import time
import uuid
+import archive_desugar_jdk_libs
+import download_kotlin_dev
import gradle
+import notify
import utils
if utils.is_python3():
@@ -57,6 +57,7 @@
'jdk8',
'jdk9',
'jdk11',
+ 'jdk17',
] + [ 'dex-%s' % dexvm for dexvm in ALL_ART_VMS ]
def ParseOptions():
@@ -100,15 +101,6 @@
help='Tool to run ART tests with: "r8" (default) or "d8" or "r8cf"'
' (r8 w/CF-backend). Ignored if "--all_tests" enabled.',
default=None, choices=["r8", "d8", "r8cf"])
- result.add_option('--jctf',
- help='Run JCTF tests with: "r8" (default) or "d8" or "r8cf".',
- default=False, action='store_true')
- result.add_option('--only-jctf', '--only_jctf',
- help='Run only JCTF tests with: "r8" (default) or "d8" or "r8cf".',
- default=False, action='store_true')
- result.add_option('--jctf-compile-only', '--jctf_compile_only',
- help="Don't run, only compile JCTF tests.",
- default=False, action='store_true')
result.add_option('--disable-assertions', '--disable_assertions',
help='Disable assertions when running tests.',
default=False, action='store_true')
@@ -276,14 +268,8 @@
gradle_args.append('-Ptool=%s' % options.tool)
if options.one_line_per_test:
gradle_args.append('-Pone_line_per_test')
- if options.jctf:
- gradle_args.append('-Pjctf')
- if options.only_jctf:
- gradle_args.append('-Ponly_jctf')
if options.test_namespace:
gradle_args.append('-Ptest_namespace=%s' % options.test_namespace)
- if options.jctf_compile_only:
- gradle_args.append('-Pjctf_compile_only')
if options.disable_assertions:
gradle_args.append('-Pdisable_assertions')
if options.with_code_coverage:
@@ -298,14 +284,7 @@
gradle_args.append('-Pkotlin_compiler_dev')
download_kotlin_dev.download_newest()
if os.name == 'nt':
- # temporary hack
gradle_args.append('-Pno_internal')
- gradle_args.append('-x')
- gradle_args.append('createJctfTests')
- gradle_args.append('-x')
- gradle_args.append('jctfCommonJar')
- gradle_args.append('-x')
- gradle_args.append('jctfTestsClasses')
if options.test_dir:
gradle_args.append('-Ptest_dir=' + options.test_dir)
if not os.path.exists(options.test_dir):
@@ -407,11 +386,6 @@
timeout_handler, (timestamp_file, print_stacks_timeout,))
rotate_test_reports()
- if options.only_jctf:
- # Note: not setting -Pruntimes will run with all available runtimes.
- return_code = gradle.RunGradle(gradle_args, throw_on_failure=False)
- return archive_and_return(return_code, options)
-
# Now run tests on selected runtime(s).
if options.runtimes:
if options.dex_vm != 'default':
@@ -476,7 +450,7 @@
return return_code
def print_jstacks():
- processes = subprocess.check_output(['ps', 'aux'])
+ processes = subprocess.check_output(['ps', 'aux']).decode('utf-8')
for l in processes.splitlines():
if 'art' in l or 'dalvik' in l:
print('Running art of dalvik process: \n%s' % l)