Merge commit 'e2ff4cb5293f7554ddb5cca73c71b15fd2bcbdca' into dev-release
Change-Id: I71311dcfa1c1b7fe906f27291b3cae62a5c3275b
diff --git a/.gitignore b/.gitignore
index edb84ad..78a056c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -96,6 +96,8 @@
third_party/dependencies_new.tar.gz
third_party/desugar/desugar_*.tar.gz
third_party/desugar/desugar_*/
+third_party/examplesAndroidOLegacy
+third_party/examplesAndroidOLegacy.tar.gz
third_party/framework
third_party/framework.tar.gz
third_party/gmail/*
diff --git a/build.gradle b/build.gradle
index 7485331b..c766f7b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -251,6 +251,7 @@
examplesAndroidOCompile group: 'org.ow2.asm', name: 'asm', version: asmVersion
examplesAndroidOCompile files("third_party/android_jar/lib-v26/android.jar")
+ examplesAndroidOCompile files("third_party/examplesAndroidOLegacy")
examplesAndroidPCompile group: 'org.ow2.asm', name: 'asm', version: asmVersion
// Import Guava for @Nullable annotation
@@ -313,6 +314,7 @@
"dagger/2.41",
"dart-sdk",
"ddmlib",
+ "examplesAndroidOLegacy",
"gradle/gradle",
"google/google-java-format/1.14.0",
"google-java-format",
@@ -1298,29 +1300,14 @@
task buildExampleAndroidOJars {
dependsOn downloadDeps
def examplesDir = file("src/test/examplesAndroidO")
- // NOTE: we want to enable a scenario when test needs to reference some
- // classes generated by legacy (1.6) Java compiler to test some specific
- // behaviour. To do so we compile all the java files located in sub-directory
- // called 'legacy' with Java 1.6, then compile the rest of the files with
- // Java 1.8 and a reference to previously generated 1.6 classes.
-
- // Compiling all classes in dirs 'legacy' with old Java version.
- task "compile_examplesAndroidO_Legacy"(type: JavaCompile) {
- source = fileTree(dir: examplesDir, include: '**/legacy/**/*.java')
- destinationDir = file("build/test/examplesAndroidOLegacy/classes")
- classpath = sourceSets.main.compileClasspath
- sourceCompatibility = JavaVersion.VERSION_1_6
- targetCompatibility = JavaVersion.VERSION_1_6
- options.compilerArgs += ["-Xlint:-options", "-parameters"]
- }
// Compiling the rest of the files as Java 1.8 code.
task "compile_examplesAndroidO"(type: JavaCompile) {
- dependsOn "compile_examplesAndroidO_Legacy"
source = fileTree(dir: examplesDir, include: '**/*.java', exclude: '**/legacy/**/*.java')
destinationDir = file("build/test/examplesAndroidO/classes")
classpath = sourceSets.main.compileClasspath
classpath += files("build/test/examplesAndroidOLegacy/classes")
- classpath += files("third_party/android_jar/lib-v26/android.jar")
+ classpath += files("third_party/android_jar/lib-v26/android.jar")
+ classpath += files("third_party/examplesAndroidOLegacy")
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
options.compilerArgs += ["-Xlint:-options", "-parameters"]
@@ -1333,7 +1320,7 @@
dependsOn: "compile_examplesAndroidO") {
main = name + ".TestGenerator"
classpath = files(destinationDir, sourceSets.main.compileClasspath)
- args destinationDir
+ args destinationDir, file("build/test/examplesAndroidO/classes/${name}").toString()
}
} else {
task "generate_examplesAndroidO_${name}" () {}
@@ -1377,8 +1364,8 @@
task "generate_examplesAndroidP_${name}"(type: JavaExec,
dependsOn: "compile_examplesAndroidP") {
main = name + ".TestGenerator"
- classpath = files(destinationDir, sourceSets.main.compileClasspath)
- args destinationDir
+ classpath = files(destinationDir.toString(), sourceSets.main.compileClasspath)
+ args destinationDir, file("build/test/examplesAndroidP/classes/${name}").toString()
}
} else {
task "generate_examplesAndroidP_${name}" () {}
diff --git a/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt b/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt
index 12fd28d..2a369cd 100644
--- a/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt
+++ b/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt
@@ -11,6 +11,7 @@
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.file.ConfigurableFileCollection
+import org.gradle.api.file.DuplicatesStrategy
import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.api.tasks.JavaExec
import org.gradle.api.tasks.SourceSet
@@ -116,6 +117,7 @@
// The TEST_SOURCE_SET_NAME is the source set defined by writing java { sourcesets.test { ... }}
.getByName(SourceSet.TEST_SOURCE_SET_NAME)
val destinationDir = getRoot().resolveAll("build", "test", name)
+ val generateDir = getRoot().resolveAll("build", "generated", name)
val classesOutput = destinationDir.resolve("classes")
testSourceSet.java.destinationDirectory.set(classesOutput)
testSourceSet.resources.destinationDirectory.set(destinationDir)
@@ -128,24 +130,35 @@
arrayOf("compileTestJava", "debuginfo-all", "debuginfo-none").forEach { taskName ->
if (!project.getTasksByName(taskName, false).isEmpty()) {
var generationTask : Task? = null
- val taskSpecificClassesOutput = getOutputName(classesOutput.toString(), taskName)
+ val compileOutput = getOutputName(classesOutput.toString(), taskName)
if (exampleDir.resolve("TestGenerator.java").isFile) {
+ val generatedOutput = Paths.get(
+ getOutputName(generateDir.toString(), taskName), exampleDir.name).toString()
generationTask = tasks.register<JavaExec>(
"generate-$name-${exampleDir.name}-$taskName") {
dependsOn(taskName)
mainClass.set("${exampleDir.name}.TestGenerator")
- classpath = files(taskSpecificClassesOutput, testSourceSet.compileClasspath)
- args(taskSpecificClassesOutput)
+ classpath = files(compileOutput, testSourceSet.compileClasspath)
+ args(compileOutput, generatedOutput)
+ outputs.dirs(generatedOutput)
}.get()
}
jarTasks.add(tasks.register<Jar>("jar-$name-${exampleDir.name}-$taskName") {
dependsOn(taskName)
- if (generationTask != null) {
- dependsOn(generationTask)
- }
archiveFileName.set("${getOutputName(exampleDir.name, taskName)}.jar")
destinationDirectory.set(destinationDir)
- from(taskSpecificClassesOutput) {
+ duplicatesStrategy = DuplicatesStrategy.EXCLUDE
+ if (generationTask != null) {
+ // If a generation task exists, we first take the generated output and add to the
+ // current jar. Running with DuplicatesStrategy.EXCLUDE ensure that we do not
+ // overwrite with the non-generated file.
+ dependsOn(generationTask)
+ from(generationTask.outputs.files.singleFile.parentFile) {
+ include("${exampleDir.name}/**/*.class")
+ exclude("**/TestGenerator*")
+ }
+ }
+ from(compileOutput) {
include("${exampleDir.name}/**/*.class")
exclude("**/TestGenerator*")
}
@@ -356,6 +369,10 @@
"ddmlib",
Paths.get("third_party", "ddmlib").toFile(),
Paths.get("third_party", "ddmlib.tar.gz.sha1").toFile())
+ val examplesAndroidOLegacy = ThirdPartyDependency(
+ "examplesAndroidOLegacy",
+ Paths.get("third_party", "examplesAndroidOLegacy").toFile(),
+ Paths.get("third_party", "examplesAndroidOLegacy.tar.gz.sha1").toFile())
val desugarJdkLibs = ThirdPartyDependency(
"desugar-jdk-libs",
Paths.get("third_party", "openjdk", "desugar_jdk_libs").toFile(),
diff --git a/d8_r8/commonBuildSrc/src/main/kotlin/TestConfigurationHelper.kt b/d8_r8/commonBuildSrc/src/main/kotlin/TestConfigurationHelper.kt
index 4ca414d..c3acc59 100644
--- a/d8_r8/commonBuildSrc/src/main/kotlin/TestConfigurationHelper.kt
+++ b/d8_r8/commonBuildSrc/src/main/kotlin/TestConfigurationHelper.kt
@@ -2,7 +2,12 @@
// 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.
+import java.io.File
+import java.util.Date
import org.gradle.api.tasks.testing.Test
+import org.gradle.api.tasks.testing.TestListener
+import org.gradle.api.tasks.testing.TestDescriptor
+import org.gradle.api.tasks.testing.TestResult
class TestConfigurationHelper {
@@ -69,6 +74,25 @@
test.maxHeapSize = "4G"
}
+ test.addTestListener(object: TestListener {
+ override fun beforeSuite(desc: TestDescriptor?) { }
+ override fun afterSuite(desc: TestDescriptor?, result: TestResult?) { }
+ override fun beforeTest(desc: TestDescriptor?) {
+ if (project.hasProperty("one_line_per_test")) {
+ println("Start executing ${desc}")
+ }
+ }
+ override fun afterTest(desc: TestDescriptor?, result: TestResult?) {
+ if (project.hasProperty("one_line_per_test")) {
+ println("Done executing ${desc} with result: ${result?.resultType}")
+ }
+ if (project.hasProperty("update_test_timestamp")) {
+ File(project.property("update_test_timestamp")!!.toString())
+ .writeText(Date().getTime().toString())
+ }
+ }
+ })
+
val userDefinedCoresPerFork = System.getenv("R8_GRADLE_CORES_PER_FORK")
val processors = Runtime.getRuntime().availableProcessors()
// See https://docs.gradle.org/current/dsl/org.gradle.api.tasks.testing.Test.html.
@@ -78,8 +102,8 @@
// On work machines this seems to give the best test execution time (without freezing).
test.maxParallelForks = processors.div(3)
// On low cpu count machines (bots) we under subscribe, so increase the count.
- if (processors == 8) {
- test.maxParallelForks = 3
+ if (processors == 32) {
+ test.maxParallelForks = 15
}
}
}
diff --git a/d8_r8/gradle.properties b/d8_r8/gradle.properties
index 1de43f9..35bcb0b 100644
--- a/d8_r8/gradle.properties
+++ b/d8_r8/gradle.properties
@@ -11,6 +11,7 @@
org.gradle.parallel=true
org.gradle.caching=true
+org.gradle.configuration-cache=true
# Do not download any jdks or detect them. We provide them.
org.gradle.java.installations.auto-detect=false
diff --git a/d8_r8/keepanno/gradle.properties b/d8_r8/keepanno/gradle.properties
index 1de43f9..35bcb0b 100644
--- a/d8_r8/keepanno/gradle.properties
+++ b/d8_r8/keepanno/gradle.properties
@@ -11,6 +11,7 @@
org.gradle.parallel=true
org.gradle.caching=true
+org.gradle.configuration-cache=true
# Do not download any jdks or detect them. We provide them.
org.gradle.java.installations.auto-detect=false
diff --git a/d8_r8/library_desugar/gradle.properties b/d8_r8/library_desugar/gradle.properties
index 1de43f9..35bcb0b 100644
--- a/d8_r8/library_desugar/gradle.properties
+++ b/d8_r8/library_desugar/gradle.properties
@@ -11,6 +11,7 @@
org.gradle.parallel=true
org.gradle.caching=true
+org.gradle.configuration-cache=true
# Do not download any jdks or detect them. We provide them.
org.gradle.java.installations.auto-detect=false
diff --git a/d8_r8/main/build.gradle.kts b/d8_r8/main/build.gradle.kts
index 4ba82d6..b6a8bda 100644
--- a/d8_r8/main/build.gradle.kts
+++ b/d8_r8/main/build.gradle.kts
@@ -79,10 +79,6 @@
val depsJar by registering(Jar::class) {
dependsOn(keepAnnoJarTask)
- doFirst {
- println(header("R8 full dependencies"))
- mainJarDependencies().forEach({ println(it) })
- }
dependsOn(resourceShrinkerJarTask)
dependsOn(resourceShrinkerDepsTask)
from(mainJarDependencies().map(::zipTree))
diff --git a/d8_r8/main/gradle.properties b/d8_r8/main/gradle.properties
index 1de43f9..35bcb0b 100644
--- a/d8_r8/main/gradle.properties
+++ b/d8_r8/main/gradle.properties
@@ -11,6 +11,7 @@
org.gradle.parallel=true
org.gradle.caching=true
+org.gradle.configuration-cache=true
# Do not download any jdks or detect them. We provide them.
org.gradle.java.installations.auto-detect=false
diff --git a/d8_r8/r8lib/gradle.properties b/d8_r8/r8lib/gradle.properties
index 1de43f9..35bcb0b 100644
--- a/d8_r8/r8lib/gradle.properties
+++ b/d8_r8/r8lib/gradle.properties
@@ -11,6 +11,7 @@
org.gradle.parallel=true
org.gradle.caching=true
+org.gradle.configuration-cache=true
# Do not download any jdks or detect them. We provide them.
org.gradle.java.installations.auto-detect=false
diff --git a/d8_r8/resourceshrinker/build.gradle.kts b/d8_r8/resourceshrinker/build.gradle.kts
index 205df05..60a037b 100644
--- a/d8_r8/resourceshrinker/build.gradle.kts
+++ b/d8_r8/resourceshrinker/build.gradle.kts
@@ -55,8 +55,6 @@
}
val depsJar by registering(Jar::class) {
- println(header("Resource shrinker dependencies"))
- jarDependencies().forEach({ println(it) })
from(jarDependencies().map(::zipTree))
exclude("**/*.proto")
exclude("versions-offline/**")
diff --git a/d8_r8/resourceshrinker/gradle.properties b/d8_r8/resourceshrinker/gradle.properties
index 1de43f9..35bcb0b 100644
--- a/d8_r8/resourceshrinker/gradle.properties
+++ b/d8_r8/resourceshrinker/gradle.properties
@@ -11,6 +11,7 @@
org.gradle.parallel=true
org.gradle.caching=true
+org.gradle.configuration-cache=true
# Do not download any jdks or detect them. We provide them.
org.gradle.java.installations.auto-detect=false
diff --git a/d8_r8/settings.gradle.kts b/d8_r8/settings.gradle.kts
index c62627b..9abecbf 100644
--- a/d8_r8/settings.gradle.kts
+++ b/d8_r8/settings.gradle.kts
@@ -18,7 +18,17 @@
return current.getParentFile()
}
-fun downloadFromGoogleStorage(sha1File : File) {
+fun downloadFromGoogleStorage(outputDir : File) {
+ val targz = File(outputDir.toString() + ".tar.gz")
+ val sha1File = File(targz.toString() + ".sha1")
+ if (outputDir.exists()
+ && outputDir.isDirectory
+ && targz.exists()
+ && sha1File.lastModified() <= targz.lastModified()) {
+ // We already downloaded, no need to recheck the hash
+ return
+ }
+
val cmd = listOf(
"download_from_google_storage.py",
"--extract",
@@ -27,6 +37,7 @@
"--sha1_file",
"${sha1File}"
)
+
println("Executing command: ${cmd.joinToString(" ")}")
val process = ProcessBuilder().command(cmd).start()
process.waitFor()
@@ -41,8 +52,8 @@
}
val thirdParty = getRepoRoot().resolve("third_party")
-downloadFromGoogleStorage(thirdParty.resolve("dependencies.tar.gz.sha1"))
-downloadFromGoogleStorage(thirdParty.resolve("dependencies_new.tar.gz.sha1"))
+downloadFromGoogleStorage(thirdParty.resolve("dependencies"))
+downloadFromGoogleStorage(thirdParty.resolve("dependencies_new"))
pluginManagement {
repositories {
diff --git a/d8_r8/test/gradle.properties b/d8_r8/test/gradle.properties
index 1de43f9..35bcb0b 100644
--- a/d8_r8/test/gradle.properties
+++ b/d8_r8/test/gradle.properties
@@ -11,6 +11,7 @@
org.gradle.parallel=true
org.gradle.caching=true
+org.gradle.configuration-cache=true
# Do not download any jdks or detect them. We provide them.
org.gradle.java.installations.auto-detect=false
diff --git a/d8_r8/test_modules/tests_bootstrap/build.gradle.kts b/d8_r8/test_modules/tests_bootstrap/build.gradle.kts
index af2fb9f..b196db9 100644
--- a/d8_r8/test_modules/tests_bootstrap/build.gradle.kts
+++ b/d8_r8/test_modules/tests_bootstrap/build.gradle.kts
@@ -50,9 +50,7 @@
withType<KotlinCompile> {
kotlinOptions {
- // We are using a new JDK to compile to an older language version, which is not directly
- // compatible with java toolchains.
- jvmTarget = "1.8"
+ enabled = false
}
}
diff --git a/d8_r8/test_modules/tests_bootstrap/gradle.properties b/d8_r8/test_modules/tests_bootstrap/gradle.properties
index 1de43f9..35bcb0b 100644
--- a/d8_r8/test_modules/tests_bootstrap/gradle.properties
+++ b/d8_r8/test_modules/tests_bootstrap/gradle.properties
@@ -11,6 +11,7 @@
org.gradle.parallel=true
org.gradle.caching=true
+org.gradle.configuration-cache=true
# Do not download any jdks or detect them. We provide them.
org.gradle.java.installations.auto-detect=false
diff --git a/d8_r8/test_modules/tests_java_10/gradle.properties b/d8_r8/test_modules/tests_java_10/gradle.properties
index 1de43f9..35bcb0b 100644
--- a/d8_r8/test_modules/tests_java_10/gradle.properties
+++ b/d8_r8/test_modules/tests_java_10/gradle.properties
@@ -11,6 +11,7 @@
org.gradle.parallel=true
org.gradle.caching=true
+org.gradle.configuration-cache=true
# Do not download any jdks or detect them. We provide them.
org.gradle.java.installations.auto-detect=false
diff --git a/d8_r8/test_modules/tests_java_11/gradle.properties b/d8_r8/test_modules/tests_java_11/gradle.properties
index 1de43f9..35bcb0b 100644
--- a/d8_r8/test_modules/tests_java_11/gradle.properties
+++ b/d8_r8/test_modules/tests_java_11/gradle.properties
@@ -11,6 +11,7 @@
org.gradle.parallel=true
org.gradle.caching=true
+org.gradle.configuration-cache=true
# Do not download any jdks or detect them. We provide them.
org.gradle.java.installations.auto-detect=false
diff --git a/d8_r8/test_modules/tests_java_17/gradle.properties b/d8_r8/test_modules/tests_java_17/gradle.properties
index 1de43f9..35bcb0b 100644
--- a/d8_r8/test_modules/tests_java_17/gradle.properties
+++ b/d8_r8/test_modules/tests_java_17/gradle.properties
@@ -11,6 +11,7 @@
org.gradle.parallel=true
org.gradle.caching=true
+org.gradle.configuration-cache=true
# Do not download any jdks or detect them. We provide them.
org.gradle.java.installations.auto-detect=false
diff --git a/d8_r8/test_modules/tests_java_20/gradle.properties b/d8_r8/test_modules/tests_java_20/gradle.properties
index 1de43f9..35bcb0b 100644
--- a/d8_r8/test_modules/tests_java_20/gradle.properties
+++ b/d8_r8/test_modules/tests_java_20/gradle.properties
@@ -11,6 +11,7 @@
org.gradle.parallel=true
org.gradle.caching=true
+org.gradle.configuration-cache=true
# Do not download any jdks or detect them. We provide them.
org.gradle.java.installations.auto-detect=false
diff --git a/d8_r8/test_modules/tests_java_8/build.gradle.kts b/d8_r8/test_modules/tests_java_8/build.gradle.kts
index 49672fa..0d9db78 100644
--- a/d8_r8/test_modules/tests_java_8/build.gradle.kts
+++ b/d8_r8/test_modules/tests_java_8/build.gradle.kts
@@ -19,6 +19,7 @@
srcDir(root.resolveAll("src", "test", "java"))
}
}
+
// We are using a new JDK to compile to an older language version, which is not directly
// compatible with java toolchains.
sourceCompatibility = JavaVersion.VERSION_1_8
@@ -74,6 +75,7 @@
ThirdPartyDeps.desugarJdkLibs,
ThirdPartyDeps.desugarJdkLibsLegacy,
ThirdPartyDeps.desugarJdkLibs11,
+ ThirdPartyDeps.examplesAndroidOLegacy,
ThirdPartyDeps.gson,
ThirdPartyDeps.jacoco,
ThirdPartyDeps.java8Runtime,
@@ -147,15 +149,7 @@
}
withType<KotlinCompile> {
- dependsOn(gradle.includedBuild("keepanno").task(":jar"))
- dependsOn(gradle.includedBuild("resourceshrinker").task(":jar"))
- dependsOn(gradle.includedBuild("main").task(":jar"))
- dependsOn(thirdPartyCompileDependenciesTask)
- kotlinOptions {
- // We are using a new JDK to compile to an older language version, which is not directly
- // compatible with java toolchains.
- jvmTarget = "1.8"
- }
+ enabled = false
}
withType<Test> {
@@ -196,6 +190,7 @@
exclude("com/android/tools/r8/classmerging/vertical/ForceInlineConstructorWithRetargetedLibMemberTest**")
exclude("com/android/tools/r8/ir/optimize/inliner/InlineMethodWithRetargetedLibMemberTest**")
exclude("com/android/tools/r8/profile/art/DesugaredLibraryArtProfileRewritingTest**")
+ exclude("com/android/tools/r8/profile/art/dump/DumpArtProfileProvidersTest**")
}
val testJar by registering(Jar::class) {
@@ -210,10 +205,6 @@
dependsOn(gradle.includedBuild("keepanno").task(":jar"))
dependsOn(gradle.includedBuild("resourceshrinker").task(":jar"))
dependsOn(thirdPartyCompileDependenciesTask)
- doFirst {
- println(header("Test Java 8 dependencies"))
- }
- testDependencies().forEach({ println(it) })
from(testDependencies().map(::zipTree))
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
archiveFileName.set("deps.jar")
diff --git a/d8_r8/test_modules/tests_java_8/gradle.properties b/d8_r8/test_modules/tests_java_8/gradle.properties
index 1de43f9..35bcb0b 100644
--- a/d8_r8/test_modules/tests_java_8/gradle.properties
+++ b/d8_r8/test_modules/tests_java_8/gradle.properties
@@ -11,6 +11,7 @@
org.gradle.parallel=true
org.gradle.caching=true
+org.gradle.configuration-cache=true
# Do not download any jdks or detect them. We provide them.
org.gradle.java.installations.auto-detect=false
diff --git a/d8_r8/test_modules/tests_java_9/gradle.properties b/d8_r8/test_modules/tests_java_9/gradle.properties
index 1de43f9..35bcb0b 100644
--- a/d8_r8/test_modules/tests_java_9/gradle.properties
+++ b/d8_r8/test_modules/tests_java_9/gradle.properties
@@ -11,6 +11,7 @@
org.gradle.parallel=true
org.gradle.caching=true
+org.gradle.configuration-cache=true
# Do not download any jdks or detect them. We provide them.
org.gradle.java.installations.auto-detect=false
diff --git a/d8_r8/test_modules/tests_java_examples/gradle.properties b/d8_r8/test_modules/tests_java_examples/gradle.properties
index 1de43f9..35bcb0b 100644
--- a/d8_r8/test_modules/tests_java_examples/gradle.properties
+++ b/d8_r8/test_modules/tests_java_examples/gradle.properties
@@ -11,6 +11,7 @@
org.gradle.parallel=true
org.gradle.caching=true
+org.gradle.configuration-cache=true
# Do not download any jdks or detect them. We provide them.
org.gradle.java.installations.auto-detect=false
diff --git a/d8_r8/test_modules/tests_java_examplesAndroidN/gradle.properties b/d8_r8/test_modules/tests_java_examplesAndroidN/gradle.properties
index 1de43f9..35bcb0b 100644
--- a/d8_r8/test_modules/tests_java_examplesAndroidN/gradle.properties
+++ b/d8_r8/test_modules/tests_java_examplesAndroidN/gradle.properties
@@ -11,6 +11,7 @@
org.gradle.parallel=true
org.gradle.caching=true
+org.gradle.configuration-cache=true
# Do not download any jdks or detect them. We provide them.
org.gradle.java.installations.auto-detect=false
diff --git a/d8_r8/test_modules/tests_java_examplesAndroidO/build.gradle.kts b/d8_r8/test_modules/tests_java_examplesAndroidO/build.gradle.kts
index 048fc5d..062128c 100644
--- a/d8_r8/test_modules/tests_java_examplesAndroidO/build.gradle.kts
+++ b/d8_r8/test_modules/tests_java_examplesAndroidO/build.gradle.kts
@@ -22,8 +22,14 @@
targetCompatibility = JavaVersion.VERSION_1_8
}
+// NOTE: we want to enable a scenario when test needs to reference some classes generated by legacy
+// (1.6) Java compiler to test some specific behaviour. To do so we compile all the java files
+// located in a sub-directory called 'legacy' with Java 1.6, then compile the rest of the files with
+// Java 1.8 and a reference to previously generated 1.6 classes.
+
dependencies {
testCompileOnly(Deps.asm)
+ testCompileOnly(resolve(ThirdPartyDeps.examplesAndroidOLegacy))
testCompileOnly(resolve(getThirdPartyAndroidJar("lib-v26"),"android.jar"))
}
@@ -33,6 +39,7 @@
val thirdPartyCompileDependenciesTask = ensureThirdPartyDependencies(
"compileDeps",
listOf(
+ ThirdPartyDeps.examplesAndroidOLegacy,
Jdk.JDK_11.getThirdPartyDependency(),
getThirdPartyAndroidJar("lib-v26")))
diff --git a/d8_r8/test_modules/tests_java_examplesAndroidO/gradle.properties b/d8_r8/test_modules/tests_java_examplesAndroidO/gradle.properties
index 1de43f9..35bcb0b 100644
--- a/d8_r8/test_modules/tests_java_examplesAndroidO/gradle.properties
+++ b/d8_r8/test_modules/tests_java_examplesAndroidO/gradle.properties
@@ -11,6 +11,7 @@
org.gradle.parallel=true
org.gradle.caching=true
+org.gradle.configuration-cache=true
# Do not download any jdks or detect them. We provide them.
org.gradle.java.installations.auto-detect=false
diff --git a/d8_r8/test_modules/tests_java_examplesAndroidP/gradle.properties b/d8_r8/test_modules/tests_java_examplesAndroidP/gradle.properties
index 1de43f9..35bcb0b 100644
--- a/d8_r8/test_modules/tests_java_examplesAndroidP/gradle.properties
+++ b/d8_r8/test_modules/tests_java_examplesAndroidP/gradle.properties
@@ -11,6 +11,7 @@
org.gradle.parallel=true
org.gradle.caching=true
+org.gradle.configuration-cache=true
# Do not download any jdks or detect them. We provide them.
org.gradle.java.installations.auto-detect=false
diff --git a/d8_r8/test_modules/tests_java_kotlinR8TestResources/gradle.properties b/d8_r8/test_modules/tests_java_kotlinR8TestResources/gradle.properties
index 1de43f9..35bcb0b 100644
--- a/d8_r8/test_modules/tests_java_kotlinR8TestResources/gradle.properties
+++ b/d8_r8/test_modules/tests_java_kotlinR8TestResources/gradle.properties
@@ -11,6 +11,7 @@
org.gradle.parallel=true
org.gradle.caching=true
+org.gradle.configuration-cache=true
# Do not download any jdks or detect them. We provide them.
org.gradle.java.installations.auto-detect=false
diff --git a/src/main/java/com/android/tools/r8/MapConsumerToPartitionMapConsumer.java b/src/main/java/com/android/tools/r8/MapConsumerToPartitionMapConsumer.java
index fcd3113..2fd47d9 100644
--- a/src/main/java/com/android/tools/r8/MapConsumerToPartitionMapConsumer.java
+++ b/src/main/java/com/android/tools/r8/MapConsumerToPartitionMapConsumer.java
@@ -10,7 +10,9 @@
import com.android.tools.r8.naming.ProguardMapMarkerInfo;
import com.android.tools.r8.retrace.ProguardMapPartitioner;
import com.android.tools.r8.retrace.internal.ProguardMapProducerInternal;
+import com.android.tools.r8.utils.ListUtils;
import java.io.IOException;
+import java.util.List;
public class MapConsumerToPartitionMapConsumer implements MapConsumer {
@@ -27,7 +29,9 @@
ProguardMapMarkerInfo makerInfo,
ClassNameMapper classNameMapper) {
try {
- classNameMapper.setPreamble(makerInfo.toPreamble());
+ List<String> newPreamble =
+ ListUtils.joinNewArrayList(makerInfo.toPreamble(), classNameMapper.getPreamble());
+ classNameMapper.setPreamble(newPreamble);
partitionMapConsumer.acceptMappingPartitionMetadata(
ProguardMapPartitioner.builder(diagnosticsHandler)
.setProguardMapProducer(new ProguardMapProducerInternal(classNameMapper))
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
index b58107d..d18a979 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
@@ -280,14 +280,13 @@
executorService.submit(
() -> {
try {
- String content = map.getString();
builder.setProguardMap(
ClassNameMapper.mapperFromString(
- content,
+ map.getString(),
options.reporter,
options.mappingComposeOptions().allowEmptyMappedRanges,
options.testing.enableExperimentalMapFileVersion,
- false));
+ true));
} catch (IOException | ResourceException e) {
throw new CompilationError("Failure to read proguard map file", e, map.getOrigin());
}
diff --git a/src/main/java/com/android/tools/r8/dex/JumboStringRewriter.java b/src/main/java/com/android/tools/r8/dex/JumboStringRewriter.java
index dede86b..70305e4 100644
--- a/src/main/java/com/android/tools/r8/dex/JumboStringRewriter.java
+++ b/src/main/java/com/android/tools/r8/dex/JumboStringRewriter.java
@@ -29,6 +29,7 @@
import com.android.tools.r8.dex.code.DexInstruction;
import com.android.tools.r8.dex.code.DexNop;
import com.android.tools.r8.dex.code.DexSwitchPayload;
+import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexCode;
import com.android.tools.r8.graph.DexCode.Try;
import com.android.tools.r8.graph.DexCode.TryHandler;
@@ -41,6 +42,7 @@
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.lightir.ByteUtils;
import com.google.common.collect.Lists;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap;
@@ -200,12 +202,56 @@
for (int i = 0; i < code.tries.length; i++) {
Try theTry = code.tries[i];
TryTargets targets = tryTargets.get(theTry);
- result[i] = new Try(targets.getStartOffset(), targets.getStartToEndDelta(), -1);
+ int startToEndDelta = targets.getStartToEndDelta();
+ if (startToEndDelta > ByteUtils.MAX_U2) {
+ return rewriteSplitTryOffsets(code);
+ }
+ result[i] = new Try(targets.getStartOffset(), startToEndDelta, -1);
result[i].handlerIndex = theTry.handlerIndex;
}
return result;
}
+ // Note: this algorithm should be aligned with DexBuilder.splitOverflowingRanges.
+ private Try[] rewriteSplitTryOffsets(DexCode code) {
+ // It is unlikely we have 10 overflows (unlikely we have any to begin with).
+ int tentativeCapacity = code.tries.length + 10;
+ List<Try> result = new ArrayList<>(tentativeCapacity);
+ for (Try theTry : code.tries) {
+ TryTargets targets = tryTargets.get(theTry);
+ int startToEndDelta = targets.getStartToEndDelta();
+ int start = targets.getStartOffset();
+ while (startToEndDelta > ByteUtils.MAX_U2) {
+ // Find instruction offset under limit.
+ int maxOffset = start + ByteUtils.MAX_U2;
+ int intermediateEnd = -1;
+ for (int i = code.instructions.length - 1; i >= 0; i--) {
+ DexInstruction instruction = code.instructions[i];
+ // Note that the instructions have been expanded, so getOffset is the rewritten offset.
+ if (instruction.getOffset() <= maxOffset) {
+ intermediateEnd = instruction.getOffset();
+ break;
+ }
+ }
+ if (intermediateEnd <= start) {
+ throw new Unreachable("Unexpected try-catch handler end point: " + intermediateEnd);
+ }
+ int intermediateDelta = intermediateEnd - start;
+ Try splitTry = new Try(start, intermediateDelta, -1);
+ splitTry.handlerIndex = theTry.handlerIndex;
+ result.add(splitTry);
+ start = intermediateEnd;
+ startToEndDelta -= intermediateDelta;
+ }
+ assert startToEndDelta > 0;
+ Try rewrittenTry = new Try(start, startToEndDelta, -1);
+ rewrittenTry.handlerIndex = theTry.handlerIndex;
+ result.add(rewrittenTry);
+ }
+ assert result.size() > code.tries.length;
+ return result.toArray(Try.EMPTY_ARRAY);
+ }
+
private TryHandler[] rewriteHandlerOffsets() {
DexCode code = getCode();
TryHandler[] result = new TryHandler[code.handlers.length];
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 83ca93c..7b2d440 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCode.java
@@ -38,6 +38,7 @@
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
+import com.android.tools.r8.lightir.ByteUtils;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.ArrayUtils;
import com.android.tools.r8.utils.DexDebugUtils.PositionInfo;
@@ -912,6 +913,7 @@
this.instructionCount = instructionCount;
this.handlerOffset = handlerOffset;
this.handlerIndex = NO_INDEX;
+ assert ByteUtils.isU2(instructionCount);
}
@Override
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 a360308..c40197a 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
@@ -724,7 +724,10 @@
public boolean needsRegister() {
assert needsRegister >= 0;
- assert !hasUsersInfo() || (needsRegister > 0) == internalComputeNeedsRegister();
+ // This has quadratic behavior so don't check for large user sets.
+ assert !hasUsersInfo()
+ || numberOfAllUsers() > 100
+ || (needsRegister > 0) == internalComputeNeedsRegister();
return needsRegister > 0;
}
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 14b9549..89ab593 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
@@ -65,6 +65,7 @@
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.conversion.passes.TrivialGotosCollapser;
import com.android.tools.r8.ir.regalloc.RegisterAllocator;
+import com.android.tools.r8.lightir.ByteUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.InternalOutputMode;
import com.google.common.collect.BiMap;
@@ -339,7 +340,7 @@
}
// Construct try-catch info.
- TryInfo tryInfo = computeTryInfo();
+ TryInfo tryInfo = computeTryInfo(dexInstructions);
// Return the dex code.
DexCode code =
@@ -825,11 +826,13 @@
// Helpers for computing the try items and handlers.
- private TryInfo computeTryInfo() {
+ private TryInfo computeTryInfo(List<DexInstruction> dexInstructions) {
// Canonical map of handlers.
BiMap<CatchHandlers<BasicBlock>, Integer> canonicalHandlers = HashBiMap.create();
// Compute the list of try items and their handlers.
List<TryItem> tryItems = computeTryItems(canonicalHandlers);
+ // Split the try items if they overflow the range limit.
+ tryItems = splitOverflowingRanges(tryItems, dexInstructions);
// Compute handler sets before dex items which depend on the handler index.
Try[] tries = getDexTryItems(tryItems, canonicalHandlers);
TryHandler[] handlers = getDexTryHandlers(canonicalHandlers.inverse());
@@ -916,6 +919,65 @@
return coalescedTryItems;
}
+ private static int numberOfOverflowingRanges(List<TryItem> tryItems) {
+ int numberOfOverflows = 0;
+ for (TryItem tryItem : tryItems) {
+ int instructionCount = tryItem.end - tryItem.start;
+ while (instructionCount > ByteUtils.MAX_U2) {
+ ++numberOfOverflows;
+ instructionCount -= ByteUtils.MAX_U2;
+ }
+ }
+ return numberOfOverflows;
+ }
+
+ // Note: this algorithm should be aligned with JumboStringRewriter.rewriteSplitTryOffsets.
+ private List<TryItem> splitOverflowingRanges(
+ List<TryItem> tryItems, List<DexInstruction> dexInstructions) {
+ // The fast path is that there will not be any overflows.
+ int overflows = numberOfOverflowingRanges(tryItems);
+ if (overflows == 0) {
+ return tryItems;
+ }
+ // The overflow may not fall on an instruction header, so we add a single entry just in case.
+ // Multiple try items overflowing is unlikely so that just causes reallocating the backing.
+ int tentativeCapacity = tryItems.size() + overflows + 1;
+ ArrayList<TryItem> splitTryItems = new ArrayList<>(tentativeCapacity);
+ for (TryItem tryItem : tryItems) {
+ if (tryItem.end - tryItem.start <= ByteUtils.MAX_U2) {
+ splitTryItems.add(tryItem);
+ continue;
+ }
+ final CatchHandlers<BasicBlock> handlers = tryItem.handlers;
+ final int end = tryItem.end;
+ // The iteration is based on the start offset advancing on each split.
+ int start = tryItem.start;
+ while (end - start > ByteUtils.MAX_U2) {
+ // Find a new end that does not overflow the U2 limit on the delta.
+ // It must be on an instruction offset so scan backwards in the block to find one.
+ int maxOffset = start + ByteUtils.MAX_U2;
+ assert maxOffset < end;
+ int intermediateEnd = -1;
+ for (int i = dexInstructions.size() - 1; i >= 0; i--) {
+ DexInstruction instruction = dexInstructions.get(i);
+ if (instruction.getOffset() <= maxOffset) {
+ intermediateEnd = instruction.getOffset();
+ break;
+ }
+ }
+ if (intermediateEnd <= start) {
+ throw new Unreachable("Unexpected try-catch handler end point: " + intermediateEnd);
+ }
+ splitTryItems.add(new TryItem(handlers, start, intermediateEnd));
+ start = intermediateEnd;
+ }
+ assert start < end;
+ splitTryItems.add(new TryItem(handlers, start, end));
+ }
+ assert splitTryItems.size() >= tryItems.size() + overflows;
+ return splitTryItems;
+ }
+
private int trimEnd(BasicBlock block) {
// Trim the range end for non-throwing instructions when end has been computed.
List<com.android.tools.r8.ir.code.Instruction> instructions = block.getInstructions();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
index 38ce1d8..3c8315b 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
@@ -187,7 +187,7 @@
appView
.contextIndependentDefinitionForWithResolutionResult(provider.method.holder)
.toSingleClassWithProgramOverLibrary();
- if (!clazz.isProgramDefinition()) {
+ if (clazz == null || !clazz.isProgramDefinition()) {
appView
.reporter()
.warning(
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNamingForMapApplier.java b/src/main/java/com/android/tools/r8/naming/ClassNamingForMapApplier.java
index ac54eba..5957cef 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNamingForMapApplier.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNamingForMapApplier.java
@@ -65,6 +65,12 @@
if (signature.isQualified()) {
qualifiedMethodMembers.computeIfAbsent(signature, k -> new ArrayList<>(2)).add(entry);
} else if (methodMembers.put(signature, entry) != null) {
+ // TODO(b/293630963): We are simply not able to handle positions correctly for outlines
+ // at this point. Remove when we do not call GraphLens.getOriginalMethodSignature when
+ // constructing positions.
+ if (true) {
+ return this;
+ }
reporter.error(
ProguardMapError.duplicateSourceMember(
signature.toString(), this.originalName, entry.getPosition()));
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapStringConsumer.java b/src/main/java/com/android/tools/r8/naming/ProguardMapStringConsumer.java
index be3d3ba..71b60d9 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapStringConsumer.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapStringConsumer.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.StringConsumer;
import com.android.tools.r8.utils.ChainableStringConsumer;
+import com.android.tools.r8.utils.StringUtils;
/***
* Default implementation of a MapConsumer that wraps around a string consumer for streamed string
@@ -29,6 +30,7 @@
ClassNameMapper classNameMapper) {
this.diagnosticsHandler = diagnosticsHandler;
accept(markerInfo.serializeToString());
+ accept(StringUtils.unixLines(classNameMapper.getPreamble()));
classNameMapper.write(this);
}
diff --git a/src/test/examplesAndroidO/invokecustom/TestGenerator.java b/src/test/examplesAndroidO/invokecustom/TestGenerator.java
index a4cd89a..4879521 100644
--- a/src/test/examplesAndroidO/invokecustom/TestGenerator.java
+++ b/src/test/examplesAndroidO/invokecustom/TestGenerator.java
@@ -13,6 +13,7 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
@@ -26,19 +27,24 @@
public class TestGenerator {
private final Path classNamePath;
+ private final Path outputClassNamePath;
public static void main(String[] args) throws IOException {
- assert args.length == 1;
- TestGenerator testGenerator = new TestGenerator(Paths.get(args[0],
- TestGenerator.class.getPackage().getName(), InvokeCustom.class.getSimpleName() + ".class"));
+ assert args.length == 2;
+ String fileName = InvokeCustom.class.getSimpleName() + ".class";
+ Path inputFile = Paths.get(args[0], TestGenerator.class.getPackage().getName(), fileName);
+ Path outputFile = Paths.get(args[1], fileName);
+ TestGenerator testGenerator = new TestGenerator(inputFile, outputFile);
testGenerator.generateTests();
}
- public TestGenerator(Path classNamePath) {
+ public TestGenerator(Path classNamePath, Path outputClassNamePath) {
this.classNamePath = classNamePath;
+ this.outputClassNamePath = outputClassNamePath;
}
private void generateTests() throws IOException {
+ Files.createDirectories(outputClassNamePath.getParent());
try (InputStream input = Files.newInputStream(classNamePath)) {
ClassReader cr = new ClassReader(input);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
@@ -63,7 +69,8 @@
super.visitEnd();
}
}, 0);
- try (OutputStream output = Files.newOutputStream(classNamePath)) {
+ try (OutputStream output =
+ Files.newOutputStream(outputClassNamePath, StandardOpenOption.CREATE)) {
output.write(cw.toByteArray());
}
}
diff --git a/src/test/examplesAndroidO/invokecustom2/TestGenerator.java b/src/test/examplesAndroidO/invokecustom2/TestGenerator.java
index 377084e..2a4eba4 100644
--- a/src/test/examplesAndroidO/invokecustom2/TestGenerator.java
+++ b/src/test/examplesAndroidO/invokecustom2/TestGenerator.java
@@ -14,6 +14,7 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
@@ -25,19 +26,24 @@
public class TestGenerator {
private final Path classNamePath;
+ private final Path outputClassNamePath;
public static void main(String[] args) throws IOException {
- assert args.length == 1;
- TestGenerator testGenerator = new TestGenerator(Paths.get(args[0],
- TestGenerator.class.getPackage().getName(), InvokeCustom.class.getSimpleName() + ".class"));
+ assert args.length == 2;
+ String fileName = invokecustom.InvokeCustom.class.getSimpleName() + ".class";
+ Path inputFile = Paths.get(args[0], TestGenerator.class.getPackage().getName(), fileName);
+ Path outputFile = Paths.get(args[1], fileName);
+ TestGenerator testGenerator = new TestGenerator(inputFile, outputFile);
testGenerator.generateTests();
}
- public TestGenerator(Path classNamePath) {
+ public TestGenerator(Path classNamePath, Path outputClassNamePath) {
this.classNamePath = classNamePath;
+ this.outputClassNamePath = outputClassNamePath;
}
private void generateTests() throws IOException {
+ Files.createDirectories(outputClassNamePath.getParent());
try (InputStream input = Files.newInputStream(classNamePath)) {
ClassReader cr = new ClassReader(input);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
@@ -58,7 +64,8 @@
super.visitEnd();
}
}, 0);
- try (OutputStream output = Files.newOutputStream(classNamePath)) {
+ try (OutputStream output =
+ Files.newOutputStream(outputClassNamePath, StandardOpenOption.CREATE)) {
output.write(cw.toByteArray());
}
}
diff --git a/src/test/examplesAndroidO/stringconcat/TestGenerator.java b/src/test/examplesAndroidO/stringconcat/TestGenerator.java
index 72bdfbf..4755c4d 100644
--- a/src/test/examplesAndroidO/stringconcat/TestGenerator.java
+++ b/src/test/examplesAndroidO/stringconcat/TestGenerator.java
@@ -12,6 +12,7 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.List;
import org.objectweb.asm.ClassReader;
@@ -40,13 +41,16 @@
false);
public static void main(String[] args) throws IOException {
- assert args.length == 1;
- generateTests(Paths.get(args[0],
- TestGenerator.class.getPackage().getName(),
- StringConcat.class.getSimpleName() + ".class"));
+ assert args.length == 2;
+ String fileName = StringConcat.class.getSimpleName() + ".class";
+ Path inputFile = Paths.get(args[0], TestGenerator.class.getPackage().getName(), fileName);
+ Path outputFile = Paths.get(args[1], fileName);
+ generateTests(inputFile, outputFile);
}
- private static void generateTests(Path classNamePath) throws IOException {
+ private static void generateTests(Path classNamePath, Path outputClassNamePath)
+ throws IOException {
+ Files.createDirectories(outputClassNamePath.getParent());
try (InputStream input = Files.newInputStream(classNamePath)) {
ClassReader cr = new ClassReader(input);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
@@ -221,7 +225,8 @@
};
}
}, 0);
- try (OutputStream output = Files.newOutputStream(classNamePath)) {
+ try (OutputStream output =
+ Files.newOutputStream(outputClassNamePath, StandardOpenOption.CREATE)) {
output.write(cw.toByteArray());
}
}
diff --git a/src/test/examplesAndroidOLegacy/README.txt b/src/test/examplesAndroidOLegacy/README.txt
new file mode 100644
index 0000000..5a90476
--- /dev/null
+++ b/src/test/examplesAndroidOLegacy/README.txt
@@ -0,0 +1,13 @@
+// Copyright (c) 2023, 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 examplesAndroidOLegacy source set is no longer included in build.gradle
+after transitioning to gradle v8. If we need to update the project, one should
+generate new class files and place in third_party/examplesAndroidOLegacy or
+make a direct dependency on the generated jars.
+
+See this commit where we check in the class files to get a sense of how to
+compile the source sets:
+https://r8-review.git.corp.google.com/c/r8/+/83161
+
diff --git a/src/test/examplesAndroidO/lambdadesugaring/legacy/Legacy.java b/src/test/examplesAndroidOLegacy/lambdadesugaring/legacy/Legacy.java
similarity index 100%
rename from src/test/examplesAndroidO/lambdadesugaring/legacy/Legacy.java
rename to src/test/examplesAndroidOLegacy/lambdadesugaring/legacy/Legacy.java
diff --git a/src/test/examplesAndroidP/invokecustom/TestGenerator.java b/src/test/examplesAndroidP/invokecustom/TestGenerator.java
index b08441c..ef5f8de 100644
--- a/src/test/examplesAndroidP/invokecustom/TestGenerator.java
+++ b/src/test/examplesAndroidP/invokecustom/TestGenerator.java
@@ -13,6 +13,7 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
@@ -24,19 +25,24 @@
public class TestGenerator {
private final Path classNamePath;
+ private final Path outputClassNamePath;
public static void main(String[] args) throws IOException {
- assert args.length == 1;
- TestGenerator testGenerator = new TestGenerator(Paths.get(args[0],
- TestGenerator.class.getPackage().getName(), InvokeCustom.class.getSimpleName() + ".class"));
+ assert args.length == 2;
+ String fileName = InvokeCustom.class.getSimpleName() + ".class";
+ Path inputFile = Paths.get(args[0], TestGenerator.class.getPackage().getName(), fileName);
+ Path outputFile = Paths.get(args[1], fileName);
+ TestGenerator testGenerator = new TestGenerator(inputFile, outputFile);
testGenerator.generateTests();
}
- public TestGenerator(Path classNamePath) {
+ public TestGenerator(Path classNamePath, Path outputClassNamePath) {
this.classNamePath = classNamePath;
+ this.outputClassNamePath = outputClassNamePath;
}
private void generateTests() throws IOException {
+ Files.createDirectories(outputClassNamePath.getParent());
try (InputStream inputStream = Files.newInputStream(classNamePath)) {
ClassReader cr = new ClassReader(inputStream);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
@@ -52,7 +58,8 @@
super.visitEnd();
}
}, 0);
- try (OutputStream output = Files.newOutputStream(classNamePath)) {
+ try (OutputStream output =
+ Files.newOutputStream(outputClassNamePath, StandardOpenOption.CREATE)) {
output.write(cw.toByteArray());
}
}
diff --git a/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
index 646e805..d3a155f 100644
--- a/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
@@ -27,13 +27,13 @@
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
-import java.nio.file.DirectoryStream;
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.Collections;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -118,8 +118,10 @@
private Path makeRelative(Path testJarFile, Path classFile) {
Path regularParent =
testJarFile.getParent().resolve(Paths.get("classes"));
- Path legacyParent = regularParent.resolve(Paths.get("..",
- regularParent.getFileName().toString() + "Legacy", "classes"));
+ Path legacyParent =
+ regularParent.resolve(
+ Paths.get(
+ ToolHelper.THIRD_PARTY_DIR, regularParent.getFileName().toString() + "Legacy"));
if (classFile.startsWith(regularParent)) {
return regularParent.relativize(classFile);
@@ -129,13 +131,22 @@
}
private List<String> collectClassFiles(Path testJarFile) {
- List<String> result = new ArrayList<>();
+ Map<String, String> result = new HashMap<>();
// Collect Java 8 classes.
- collectClassFiles(getClassesRoot(testJarFile), result, false);
+ visitFiles(
+ getClassesRoot(testJarFile),
+ path -> result.put(path.toFile().getName(), path.toString()));
+ // Collect generated classes, overwrite non-generated files.
+ visitFiles(
+ getGeneratedRoot(testJarFile),
+ path -> result.put(path.toFile().getName(), path.toString()));
// Collect legacy classes.
- collectClassFiles(getLegacyClassesRoot(testJarFile), result, true);
- Collections.sort(result);
- return result;
+ visitFiles(
+ getLegacyClassesRoot(testJarFile, packageName),
+ path -> result.put(path.toFile().getName(), path.toString()));
+ List<String> files = new ArrayList<>(result.values());
+ Collections.sort(files);
+ return files;
}
Path getClassesRoot(Path testJarFile) {
@@ -143,30 +154,10 @@
return parent.resolve(Paths.get("classes", packageName));
}
- Path getLegacyClassesRoot(Path testJarFile) {
- Path parent = testJarFile.getParent();
- Path legacyPath = Paths.get("..",
- parent.getFileName().toString() + "Legacy", "classes", packageName);
- return parent.resolve(legacyPath);
- }
-
- private void collectClassFiles(Path dir, List<String> result, boolean takeLegacy) {
- if (Files.exists(dir)) {
- try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
- for (Path entry: stream) {
- if (Files.isDirectory(entry)) {
- if (entry.getFileName().toString().equals("legacy") && !takeLegacy) {
- return;
- }
- collectClassFiles(entry, result, takeLegacy);
- } else {
- result.add(entry.toString());
- }
- }
- } catch (IOException x) {
- throw new AssertionError(x);
- }
- }
+ Path getGeneratedRoot(Path testJarFile) {
+ String sourceSet = testJarFile.getParent().toFile().getName();
+ Path parent = testJarFile.getParent().getParent().getParent();
+ return parent.resolve(Paths.get("generated", sourceSet, packageName));
}
AndroidApp compileClassFilesInIntermediate(
diff --git a/src/test/java/com/android/tools/r8/D8LazyRunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/D8LazyRunExamplesAndroidOTest.java
index 78bbcf3..a803a91 100644
--- a/src/test/java/com/android/tools/r8/D8LazyRunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/D8LazyRunExamplesAndroidOTest.java
@@ -38,7 +38,7 @@
@Override
void addClasspathReference(Path testJarFile, D8Command.Builder builder) {
addClasspathPath(getClassesRoot(testJarFile), builder);
- addClasspathPath(getLegacyClassesRoot(testJarFile), builder);
+ addClasspathPath(getLegacyClassesRoot(testJarFile, packageName), builder);
}
private void addClasspathPath(Path location, D8Command.Builder builder) {
diff --git a/src/test/java/com/android/tools/r8/D8RunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/D8RunExamplesAndroidOTest.java
index b4cc992..b8e9066 100644
--- a/src/test/java/com/android/tools/r8/D8RunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/D8RunExamplesAndroidOTest.java
@@ -41,13 +41,10 @@
ToolHelper.getAndroidJar(
androidJarVersion == null ? builder.getMinApiLevel() : androidJarVersion.getLevel()));
builder.addProgramFiles(inputFile);
+ visitFiles(getLegacyClassesRoot(inputFile, packageName), builder::addProgramFiles);
ToolHelper.runD8(builder, this::combinedOptionConsumer);
}
- D8TestRunner withIntermediate(boolean intermediate) {
- return withBuilderTransformation(builder -> builder.setIntermediate(intermediate));
- }
-
@Override
D8TestRunner self() {
return this;
diff --git a/src/test/java/com/android/tools/r8/R8RunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/R8RunExamplesAndroidOTest.java
index fa1d579..9acb6cf 100644
--- a/src/test/java/com/android/tools/r8/R8RunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunExamplesAndroidOTest.java
@@ -129,7 +129,7 @@
.withBuilderTransformation(
b -> b.addProguardConfiguration(PROGUARD_OPTIONS, Origin.unknown()))
.withDexCheck(inspector -> checkLambdaCount(inspector, 10, "lambdadesugaring"))
- .run();
+ .run(Paths.get(ToolHelper.THIRD_PARTY_DIR, "examplesAndroidOLegacy"));
test("lambdadesugaring", "lambdadesugaring", "LambdaDesugaring")
.withOptionConsumer(o -> o.testing.enableLir())
@@ -137,7 +137,7 @@
.withBuilderTransformation(
b -> b.addProguardConfiguration(PROGUARD_OPTIONS, Origin.unknown()))
.withDexCheck(inspector -> checkLambdaCount(inspector, 1, "lambdadesugaring"))
- .run();
+ .run(Paths.get(ToolHelper.THIRD_PARTY_DIR, "examplesAndroidOLegacy"));
}
@Test
@@ -157,7 +157,7 @@
"}"),
Origin.unknown()))
.withDexCheck(inspector -> checkTestMultipleInterfacesCheckCastCount(inspector, 0))
- .run();
+ .run(Paths.get(ToolHelper.THIRD_PARTY_DIR, "examplesAndroidOLegacy"));
}
@Test
@@ -169,7 +169,7 @@
.withBuilderTransformation(
b -> b.addProguardConfiguration(PROGUARD_OPTIONS, Origin.unknown()))
.withDexCheck(inspector -> checkLambdaCount(inspector, 10, "lambdadesugaring"))
- .run();
+ .run(Paths.get(ToolHelper.THIRD_PARTY_DIR, "examplesAndroidOLegacy"));
test("lambdadesugaring", "lambdadesugaring", "LambdaDesugaring")
.withMinApiLevel(AndroidApiLevel.N)
@@ -177,7 +177,7 @@
.withBuilderTransformation(
b -> b.addProguardConfiguration(PROGUARD_OPTIONS, Origin.unknown()))
.withDexCheck(inspector -> checkLambdaCount(inspector, 1, "lambdadesugaring"))
- .run();
+ .run(Paths.get(ToolHelper.THIRD_PARTY_DIR, "examplesAndroidOLegacy"));
}
@Override
@@ -326,9 +326,9 @@
for (Consumer<R8Command.Builder> transformation : builderTransformations) {
transformation.accept(builder);
}
-
builder.addLibraryFiles(ToolHelper.getAndroidJar(
androidJarVersion == null ? builder.getMinApiLevel() : androidJarVersion.getLevel()));
+ visitFiles(getLegacyClassesRoot(inputFile, packageName), builder::addProgramFiles);
R8Command command = builder.addProgramFiles(inputFile).build();
ToolHelper.runR8(command, this::combinedOptionConsumer);
}
diff --git a/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
index 59e0d13..276f815 100644
--- a/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
@@ -12,6 +12,7 @@
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeFalse;
+import com.android.tools.r8.TestRuntime.CfRuntime;
import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.origin.Origin;
@@ -37,6 +38,8 @@
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
@@ -168,7 +171,7 @@
return Paths.get(EXAMPLE_DIR, packageName + JAR_EXTENSION);
}
- void run() throws Throwable {
+ void run(Path... additionalJavaClasspaths) throws Throwable {
if (minSdkErrorExpected(testName)) {
thrown.expect(CompilationFailedException.class);
}
@@ -190,7 +193,11 @@
}
}
- execute(testName, qualifiedMainClass, new Path[]{inputFile}, new Path[]{out}, args);
+ List<Path> paths = new ArrayList<>();
+ paths.add(inputFile);
+ paths.addAll(Arrays.asList(additionalJavaClasspaths));
+
+ execute(testName, qualifiedMainClass, paths.toArray(new Path[0]), new Path[] {out}, args);
}
abstract C withMinApiLevel(AndroidApiLevel minApiLevel);
@@ -368,7 +375,7 @@
test("lambdadesugaring", "lambdadesugaring", "LambdaDesugaring")
.withMinApiLevel(ToolHelper.getMinApiLevelForDexVmNoHigherThan(AndroidApiLevel.K))
.withKeepAll()
- .run();
+ .run(Paths.get(ToolHelper.THIRD_PARTY_DIR, "examplesAndroidOLegacy"));
}
@Test
@@ -599,6 +606,7 @@
.addLibraryFiles(ToolHelper.getAndroidJar(minApi))
.setIntermediate(true)
.addProgramFiles(input);
+ visitFiles(getLegacyClassesRoot(input, packageName), command::addProgramFiles);
ToolHelper.runD8(command, option -> {
option.interfaceMethodDesugaring = OffOrAuto.Auto;
});
@@ -645,7 +653,9 @@
javaArgs.add(0, qualifiedMainClass);
ToolHelper.ProcessResult javaResult =
ToolHelper.runJava(
- ImmutableList.copyOf(jars), javaArgs.toArray(StringUtils.EMPTY_ARRAY));
+ CfRuntime.getCheckedInJdk11(),
+ ImmutableList.copyOf(jars),
+ javaArgs.toArray(StringUtils.EMPTY_ARRAY));
assertEquals("JVM run failed", javaResult.exitCode, 0);
assertTrue(
"JVM output does not match art output.\n\tjvm: "
@@ -671,4 +681,25 @@
}
}
+ protected Path getLegacyClassesRoot(Path testJarFile, String packageName) {
+ Path parent = testJarFile.getParent();
+ return Paths.get(
+ ToolHelper.THIRD_PARTY_DIR, parent.getFileName().toString() + "Legacy", packageName);
+ }
+
+ public void visitFiles(Path dir, Consumer<Path> consumer) {
+ if (Files.exists(dir)) {
+ try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
+ for (Path entry : stream) {
+ if (Files.isDirectory(entry)) {
+ visitFiles(entry, consumer);
+ } else {
+ consumer.accept(entry);
+ }
+ }
+ } catch (IOException x) {
+ throw new AssertionError(x);
+ }
+ }
+ }
}
diff --git a/src/test/java/com/android/tools/r8/androidresources/AndroidResourceTestingUtils.java b/src/test/java/com/android/tools/r8/androidresources/AndroidResourceTestingUtils.java
index 6130b2a..c1dde31 100644
--- a/src/test/java/com/android/tools/r8/androidresources/AndroidResourceTestingUtils.java
+++ b/src/test/java/com/android/tools/r8/androidresources/AndroidResourceTestingUtils.java
@@ -105,17 +105,17 @@
public static class AndroidTestResourceBuilder {
private String manifest;
- private Map<String, String> stringValues = new TreeMap<>();
- private Map<String, byte[]> drawables = new TreeMap<>();
- private List<Class> classesToRemap = new ArrayList();
+ private final Map<String, String> stringValues = new TreeMap<>();
+ private final Map<String, byte[]> drawables = new TreeMap<>();
+ private final List<Class<?>> classesToRemap = new ArrayList<>();
// Create the android resources from the passed in R classes
// All values will be generated based on the fields in the class.
// This takes the actual inner classes (e.g., R$String)
// These R classes will be used to rewrite the namespace and class names on the aapt2
// generated names.
- AndroidTestResourceBuilder addRClassInitializeWithDefaultValues(Class... rClasses) {
- for (Class rClass : rClasses) {
+ AndroidTestResourceBuilder addRClassInitializeWithDefaultValues(Class<?>... rClasses) {
+ for (Class<?> rClass : rClasses) {
classesToRemap.add(rClass);
RClassType rClassType = RClassType.fromClass(rClass);
for (Field declaredField : rClass.getDeclaredFields()) {
diff --git a/src/test/java/com/android/tools/r8/androidresources/ResourceShrinkerIntegrationTest.java b/src/test/java/com/android/tools/r8/androidresources/ResourceShrinkerIntegrationTest.java
index dbb464b..e234c69 100644
--- a/src/test/java/com/android/tools/r8/androidresources/ResourceShrinkerIntegrationTest.java
+++ b/src/test/java/com/android/tools/r8/androidresources/ResourceShrinkerIntegrationTest.java
@@ -28,7 +28,7 @@
}
@Test
- public void testResourceShrinkerClassAvailable() throws Exception {
+ public void testResourceShrinkerClassAvailable() {
if (ToolHelper.isNewGradleSetup()) {
assertTrue(
ResourceTracing.getImpl().getClass() != ResourceTracing.NoOpResourceTracingImpl.class);
diff --git a/src/test/java/com/android/tools/r8/dex/TryCatchRangeOverflowTest.java b/src/test/java/com/android/tools/r8/dex/TryCatchRangeOverflowTest.java
new file mode 100644
index 0000000..e9caf80
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/dex/TryCatchRangeOverflowTest.java
@@ -0,0 +1,194 @@
+// Copyright (c) 2023, 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.dex;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+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.graph.DebugLocalInfo;
+import com.android.tools.r8.graph.DexCode.Try;
+import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.ir.code.Add;
+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.NumericType;
+import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import java.util.Arrays;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+// Regression test for b/297320921
+@RunWith(Parameterized.class)
+public class TryCatchRangeOverflowTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withDefaultDexRuntime().withMinimumApiLevel().build();
+ }
+
+ public TryCatchRangeOverflowTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ // Each add/2addr instruction has size 1, so we add have as many instruction minus some padding
+ // to make room for the instructions before and after but still in the same block.
+ // Notice that this value may change if the generated code by the compiler changes. It must then
+ // be updated to the precise limit again so that the test for jumbo-string exactly hits the
+ // crossing point.
+ private final int PADDING = 33;
+ private final int UNSPLIT_LIMIT = 0xFFFF - PADDING;
+ private final int SPLIT_2_LIMIT = 0xFFFF * 2 - PADDING;
+
+ @Test
+ public void testWithinU2() throws Exception {
+ parameters.assumeDexRuntime();
+ int addCount = UNSPLIT_LIMIT;
+ compile(addCount)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("" + addCount)
+ .inspect(inspector -> checkTryCatchHandlers(1, inspector));
+ }
+
+ @Test
+ public void testJumboExceedsU2() throws Exception {
+ parameters.assumeDexRuntime();
+ int addCount = UNSPLIT_LIMIT;
+ compile(addCount)
+ .addOptionsModification(o -> o.testing.forceJumboStringProcessing = true)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("" + addCount)
+ .inspect(inspector -> checkTryCatchHandlers(2, inspector));
+ }
+
+ @Test
+ public void testExceedsU2() throws Exception {
+ parameters.assumeDexRuntime();
+ // Test with a few values above the limit.
+ for (int addCount : Arrays.asList(UNSPLIT_LIMIT + 1, UNSPLIT_LIMIT + 2, UNSPLIT_LIMIT + 100)) {
+ compile(addCount)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("" + addCount)
+ .inspect(inspector -> checkTryCatchHandlers(2, inspector));
+ }
+ }
+
+ @Test
+ public void testWithinU2x2() throws Exception {
+ parameters.assumeDexRuntime();
+ int addCount = SPLIT_2_LIMIT;
+ compile(addCount)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("" + addCount)
+ .inspect(inspector -> checkTryCatchHandlers(2, inspector));
+ }
+
+ @Test
+ public void testJumboExceedsU2x2() throws Exception {
+ parameters.assumeDexRuntime();
+ int addCount = SPLIT_2_LIMIT;
+ compile(addCount)
+ .addOptionsModification(o -> o.testing.forceJumboStringProcessing = true)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("" + addCount)
+ .inspect(inspector -> checkTryCatchHandlers(3, inspector));
+ }
+
+ @Test
+ public void testExceedsU2x2() throws Exception {
+ parameters.assumeDexRuntime();
+ int addCount = SPLIT_2_LIMIT + 1;
+ compile(addCount)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("" + addCount)
+ .inspect(inspector -> checkTryCatchHandlers(3, inspector));
+ }
+
+ private D8TestBuilder compile(int addCount) throws Exception {
+ return testForD8(Backend.DEX)
+ .addProgramClasses(TestClass.class)
+ .addOptionsModification(
+ o ->
+ o.testing.irModifier =
+ (code, appView) -> amendCodeWithAddInstructions(addCount, code))
+ .setMinApi(parameters);
+ }
+
+ private static void amendCodeWithAddInstructions(int addCount, IRCode code) {
+ if (!code.context().getReference().qualifiedName().endsWith("main")) {
+ return;
+ }
+ InstructionListIterator it = code.instructionListIterator();
+ while (it.hasNext()) {
+ Instruction instruction = it.next();
+ if (instruction.isAdd()) {
+ TypeElement outType = instruction.getOutType();
+ DebugLocalInfo localInfo = instruction.getLocalInfo();
+ // Create the last value which will replace the users of the original value in the
+ // continuations.
+ Value newLastValue = code.createValue(outType, localInfo);
+ instruction.outValue().replaceUsers(newLastValue);
+
+ Add add = instruction.asAdd();
+ NumericType numericType = add.getNumericType();
+ assert add.rightValue().isConstNumber();
+ for (int i = 1; i < addCount; i++) {
+ Value dest = i == addCount - 1 ? newLastValue : code.createValue(outType, localInfo);
+ Add newAdd = Add.create(numericType, dest, add.outValue(), add.rightValue());
+ add.outValue().addDebugLocalEnd(newAdd);
+ newAdd.setPosition(add.getPosition());
+ it.add(newAdd);
+ add = newAdd;
+ }
+ return;
+ }
+ }
+ fail("Expected to find an Add instruction.");
+ }
+
+ private static void checkTryCatchHandlers(int tryCount, CodeInspector inspector)
+ throws NoSuchMethodException {
+
+ MethodSubject main = inspector.method(TestClass.class.getMethod("main", String[].class));
+ Try[] tries = main.getMethod().getCode().asDexCode().tries;
+ assertEquals(Arrays.toString(tries), tryCount, tries.length);
+ }
+
+ static class TestClass {
+
+ public static void main(String[] args) {
+ int i = 0;
+ try {
+ String str;
+ int len = args.length;
+ if (len == 0) {
+ str = "";
+ } else if (len == 1 /* Using a constant 1 here causes the add to be an add/2addr */) {
+ str = "Strings might become jumbos";
+ } else if (len % 2 == 0) {
+ str = "We need 4";
+ } else {
+ str = "to ensure overflow.";
+ }
+ i = str.length();
+ ++i; // repeated count number of times.
+ i += args[0].length();
+ } catch (Throwable e) {
+ System.out.println(i);
+ return;
+ }
+ System.out.println("unexpected i " + i);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeUnknownJsonD8Test.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeUnknownJsonD8Test.java
new file mode 100644
index 0000000..032f5da
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeUnknownJsonD8Test.java
@@ -0,0 +1,107 @@
+// Copyright (c) 2023, 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.mappingcompose;
+
+import static com.android.tools.r8.mappingcompose.ComposeTestHelpers.doubleToSingleQuote;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.D8TestBuilder;
+import com.android.tools.r8.PartitionMapConsumer;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ThrowableConsumer;
+import com.android.tools.r8.retrace.MappingPartition;
+import com.android.tools.r8.retrace.MappingPartitionMetadata;
+import com.android.tools.r8.retrace.PartitionMappingSupplier;
+import com.android.tools.r8.retrace.PartitionedToProguardMappingConverter;
+import com.android.tools.r8.utils.Box;
+import com.android.tools.r8.utils.FileUtils;
+import java.nio.file.Path;
+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/297927590. */
+@RunWith(Parameterized.class)
+public class ComposeUnknownJsonD8Test extends TestBase {
+
+ @Parameter() public TestParameters parameters;
+
+ private static final String CUSTOM_DATA = "# {'id':'custom_info','base64/deflate':''}";
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withDefaultDexRuntime().withMinimumApiLevel().build();
+ }
+
+ private void testD8(ThrowableConsumer<D8TestBuilder> testBuilder) throws Exception {
+ Path inputMap = temp.newFolder().toPath().resolve("input.map");
+ FileUtils.writeTextFile(
+ inputMap,
+ CUSTOM_DATA,
+ "# {'id':'com.android.tools.r8.mapping','version':'2.2'}",
+ "X -> X:");
+ testForD8(parameters.getBackend())
+ .addProgramClasses(A.class)
+ .setMinApi(parameters)
+ .addOptionsModification(
+ options ->
+ assertTrue(options.mappingComposeOptions().enableExperimentalMappingComposition))
+ .apply(b -> b.getBuilder().setProguardInputMapFile(inputMap))
+ .apply(testBuilder)
+ .allowStdoutMessages()
+ .collectStdout()
+ .compile()
+ .assertStdoutThatMatches(containsString("Info: Could not find a handler for custom_info"));
+ }
+
+ @Test
+ public void testD8CompositionMappingFile() throws Exception {
+ StringBuilder mappingComposed = new StringBuilder();
+ testD8(
+ builder ->
+ builder
+ .getBuilder()
+ .setProguardMapConsumer((string, handler) -> mappingComposed.append(string)));
+ assertThat(doubleToSingleQuote(mappingComposed.toString()), containsString(CUSTOM_DATA));
+ }
+
+ @Test
+ public void testD8CompositionPartition() throws Exception {
+ Box<byte[]> metadataBytes = new Box<>();
+ testD8(
+ builder ->
+ builder
+ .getBuilder()
+ .setPartitionMapConsumer(
+ new PartitionMapConsumer() {
+ @Override
+ public void acceptMappingPartition(MappingPartition mappingPartition) {}
+
+ @Override
+ public void acceptMappingPartitionMetadata(
+ MappingPartitionMetadata mappingPartitionMetadata) {
+ metadataBytes.set(mappingPartitionMetadata.getBytes());
+ }
+ }));
+ StringBuilder mappingComposed = new StringBuilder();
+ PartitionedToProguardMappingConverter.builder()
+ .setPartitionMappingSupplier(
+ PartitionMappingSupplier.builder()
+ .setMetadata(metadataBytes.get())
+ .setMappingPartitionFromKeySupplier(key -> new byte[0])
+ .build())
+ .setConsumer((string, handler) -> mappingComposed.append(string))
+ .build()
+ .run();
+ assertThat(doubleToSingleQuote(mappingComposed.toString()), containsString(CUSTOM_DATA));
+ }
+
+ public static class A {}
+}
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeWithMissingDebugInfoTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeWithMissingDebugInfoTest.java
new file mode 100644
index 0000000..950abdc
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeWithMissingDebugInfoTest.java
@@ -0,0 +1,98 @@
+// Copyright (c) 2023, 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.mappingcompose;
+
+import static junit.framework.TestCase.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.references.Reference;
+import com.android.tools.r8.retrace.ProguardMapProducer;
+import com.android.tools.r8.retrace.ProguardMappingSupplier;
+import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
+import com.android.tools.r8.utils.FileUtils;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.Collectors;
+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/297970886 */
+@RunWith(Parameterized.class)
+public class ComposeWithMissingDebugInfoTest extends TestBase {
+
+ @Parameter() public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withDexRuntimesAndAllApiLevels().build();
+ }
+
+ @Test
+ public void testD8WithComposition() throws Exception {
+ Path inputMap = temp.newFolder().toPath().resolve("input.map");
+ FileUtils.writeTextFile(
+ inputMap,
+ "# {'id':'com.android.tools.r8.mapping','version':'2.2'}",
+ typeName(Main.class) + " -> " + typeName(Main.class) + ":",
+ " 12:12:int foo():12:12 -> a",
+ " 112:112:int foo():112:112 -> a");
+ StringBuilder mappingComposed = new StringBuilder();
+ testForD8(parameters.getBackend())
+ .addProgramClassFileData(
+ transformer(Main.class)
+ .setPredictiveLineNumbering(MethodPredicate.onName("a"), 12)
+ .transform())
+ .release()
+ .setMinApi(parameters)
+ .apply(
+ b ->
+ b.getBuilder()
+ .setProguardInputMapFile(inputMap)
+ .setProguardMapConsumer((string, handler) -> mappingComposed.append(string)))
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("42");
+ Set<String> foundMethods =
+ ProguardMappingSupplier.builder()
+ .setProguardMapProducer(ProguardMapProducer.fromString(mappingComposed.toString()))
+ .setLoadAllDefinitions(true)
+ .build()
+ .createRetracer(new DiagnosticsHandler() {})
+ .retraceMethod(
+ Reference.method(
+ Reference.classFromTypeName(typeName(Main.class)),
+ "a",
+ new ArrayList<>(),
+ Reference.typeFromTypeName("int")))
+ .stream()
+ .map(method -> method.getRetracedMethod().getMethodName())
+ .collect(Collectors.toSet());
+ Set<String> expectedMethods = new HashSet<>();
+ expectedMethods.add("a");
+ // TODO(b/297970886): We should observe 'foo' and not 'a'.
+ assertEquals(expectedMethods, foundMethods);
+ }
+
+ public static class Main {
+
+ private int val;
+
+ public static void main(String[] args) {
+ System.out.println(new Main().a());
+ }
+
+ private int a() {
+ val = 42;
+ return val;
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/naming/SeedMapperTests.java b/src/test/java/com/android/tools/r8/naming/SeedMapperTests.java
index bb88cdb..31e8267 100644
--- a/src/test/java/com/android/tools/r8/naming/SeedMapperTests.java
+++ b/src/test/java/com/android/tools/r8/naming/SeedMapperTests.java
@@ -88,7 +88,10 @@
Reporter reporter = new Reporter(testDiagnosticMessages);
try {
SeedMapper.seedMapperFromFile(reporter, applyMappingFile);
- fail("Should have thrown an error");
+ // TODO(b/293630963): Re-enable check.
+ if (false) {
+ fail("Should have thrown an error");
+ }
} catch (RuntimeException e) {
assertEquals(1, testDiagnosticMessages.getErrors().size());
Diagnostic diagnostic = testDiagnosticMessages.getErrors().get(0);
diff --git a/third_party/dependencies.tar.gz.sha1 b/third_party/dependencies.tar.gz.sha1
index fc52c9a..1c1ad7b 100644
--- a/third_party/dependencies.tar.gz.sha1
+++ b/third_party/dependencies.tar.gz.sha1
@@ -1 +1 @@
-0ed74e4bea29a056eb1870c244e6b0cf46aaac70
\ No newline at end of file
+cfbdceb60320ae102577b1cc274ce0af4432722a
\ No newline at end of file
diff --git a/third_party/dependencies_new.tar.gz.sha1 b/third_party/dependencies_new.tar.gz.sha1
index a678343..89aecc2 100644
--- a/third_party/dependencies_new.tar.gz.sha1
+++ b/third_party/dependencies_new.tar.gz.sha1
@@ -1 +1 @@
-ce954d74e0bb5c3b2f116c327558e71819e38a48
\ No newline at end of file
+80d787df74a6a07f673def5ebc38dff24515fe1c
\ No newline at end of file
diff --git a/third_party/examplesAndroidOLegacy.tar.gz.sha1 b/third_party/examplesAndroidOLegacy.tar.gz.sha1
new file mode 100644
index 0000000..6a750e4
--- /dev/null
+++ b/third_party/examplesAndroidOLegacy.tar.gz.sha1
@@ -0,0 +1 @@
+8b3f21b30f966d72d47925f2156e4912d9e68d97
\ No newline at end of file
diff --git a/tools/create_local_maven_with_dependencies.py b/tools/create_local_maven_with_dependencies.py
index 138af36..1c345b7 100755
--- a/tools/create_local_maven_with_dependencies.py
+++ b/tools/create_local_maven_with_dependencies.py
@@ -69,7 +69,7 @@
'org.jetbrains.kotlin:kotlin-script-runtime:1.8.10',
'org.jetbrains.kotlin:kotlin-tooling-core:1.8.10',
'net.ltgt.errorprone:net.ltgt.errorprone.gradle.plugin:3.0.1',
-
+ 'com.google.errorprone:javac:9+181-r4173-1',
# Resource shrinker
'com.android.tools.build:aapt2-proto:{version}'.format(version = AAPT2_PROTO_VERSION),
'com.android.tools.layoutlib:layoutlib-api:{version}'.format(version = STUDIO_SDK_VERSION),
diff --git a/tools/r8_release.py b/tools/r8_release.py
index b991ad2..c5c5f51 100755
--- a/tools/r8_release.py
+++ b/tools/r8_release.py
@@ -7,6 +7,7 @@
import datetime
import os.path
import re
+import stat
import subprocess
import sys
import urllib.request
@@ -27,6 +28,23 @@
GITHUB_DESUGAR_JDK_LIBS = 'https://github.com/google/desugar_jdk_libs'
+def install_gerrit_change_id_hook(checkout_dir):
+ with utils.ChangedWorkingDirectory(checkout_dir):
+ # Fancy way of getting the string ".git".
+ git_dir = subprocess.check_output(
+ ['git', 'rev-parse', '--git-dir']).decode('utf-8').strip()
+ commit_msg_hooks = '%s/hooks/commit-msg' % git_dir
+ if not os.path.exists(os.path.dirname(commit_msg_hooks)):
+ os.mkdir(os.path.dirname(commit_msg_hooks))
+ # Install commit hook to generate Gerrit 'Change-Id:'.
+ urllib.request.urlretrieve(
+ 'https://gerrit-review.googlesource.com/tools/hooks/commit-msg',
+ commit_msg_hooks)
+ st = os.stat(commit_msg_hooks)
+ os.chmod(
+ commit_msg_hooks,
+ st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
+
def checkout_r8(temp, branch):
subprocess.check_call(['git', 'clone', utils.REPO_SOURCE, temp])
with utils.ChangedWorkingDirectory(temp):
@@ -36,6 +54,7 @@
'--upstream',
'origin/%s' % branch,
'dev-release'])
+ install_gerrit_change_id_hook(temp)
return temp
@@ -70,7 +89,7 @@
# Verify that the merge point from main is not empty.
merge_diff_output = subprocess.check_output([
- 'git', 'diff', 'HEAD..%s' % commithash]).decode('utf-8')
+ 'git', 'diff', 'HEAD..%s' % commithash]).decode('utf-8')
other_diff = version_change_diff(
merge_diff_output, old_version, "main")
if not other_diff:
@@ -78,14 +97,16 @@
'is the same as exiting release (%s).' % old_version)
sys.exit(1)
+ subprocess.check_call([
+ 'git', 'cl', 'new-branch', 'release-%s' % version])
+
if args.dev_pre_cherry_pick:
for pre_commit in args.dev_pre_cherry_pick:
subprocess.check_call([
'git', 'cherry-pick', '--no-edit', pre_commit])
# Merge the desired commit from main on to the branch.
- subprocess.check_call([
- 'git', 'merge', '--no-ff', '--no-edit', commithash])
+ subprocess.check_call(['git', 'merge', '--no-ff', '--no-edit', commithash])
# Rewrite the version, commit and validate.
sed(old_version, version, R8_VERSION_FILE)
@@ -98,19 +119,15 @@
validate_version_change_diff(version_diff_output, "main", version)
- # Double check that we want to push the release.
- if not args.dry_run:
- answer = input('Publish dev release version %s [y/N]:' % version)
- if answer != 'y':
- print('Aborting dev release for %s' % version)
- sys.exit(1)
+ maybe_check_call(args, ['git', 'cl', 'upload', '--no-squash'])
- maybe_check_call(args, [
- 'git', 'push', 'origin', 'HEAD:%s' % R8_DEV_BRANCH])
- maybe_tag(args, version)
+ if args.dry_run:
+ input(
+ 'DryRun: check %s for content of version %s [enter to continue]:'
+ % (temp, version))
- return "%s dev version %s from hash %s" % (
- 'DryRun: omitted publish of' if args.dry_run else 'Published',
+ return "%s dev version %s from hash %s for review" % (
+ 'DryRun: omitted upload of' if args.dry_run else 'Uploaded',
version,
commithash)