Add support for running r8lib on tests

Bug: b/270105162
Change-Id: Id4c0c180fa984a8a6b7061e3679cb8cca3af43c3
diff --git a/d8_r8/build.gradle.kts b/d8_r8/build.gradle.kts
index 9d01153..704cb23 100644
--- a/d8_r8/build.gradle.kts
+++ b/d8_r8/build.gradle.kts
@@ -14,6 +14,5 @@
     dependsOn(gradle.includedBuild("main").task(":clean"))
     dependsOn(gradle.includedBuild("library_desugar").task(":clean"))
     dependsOn(gradle.includedBuild("test").task(":clean"))
-    dependsOn(gradle.includedBuild("r8lib").task(":clean"))
   }
 }
diff --git a/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt b/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt
index f447a8f..f04b5c3 100644
--- a/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt
+++ b/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt
@@ -74,6 +74,10 @@
   }
 }
 
+fun Test.configure(isR8Lib: Boolean = false, r8Jar: File? = null) {
+  TestConfigurationHelper.setupTestTask(this, isR8Lib, r8Jar)
+}
+
 fun Project.getRoot() : File {
   return computeRoot(this.projectDir)
 }
@@ -324,6 +328,7 @@
   val kotlinReflect by lazy { "org.jetbrains.kotlin:kotlin-reflect:${Versions.kotlinVersion}" }
   val mockito by lazy { "org.mockito:mockito-core:${Versions.mockito}" }
   val smali by lazy { "com.android.tools.smali:smali:${Versions.smaliVersion}" }
+  val smaliUtil by lazy { "com.android.tools.smali:smali-util:${Versions.smaliVersion}" }
 }
 
 object ThirdPartyDeps {
diff --git a/d8_r8/commonBuildSrc/src/main/kotlin/TestConfigurationHelper.kt b/d8_r8/commonBuildSrc/src/main/kotlin/TestConfigurationHelper.kt
index eb432eb..766bcf8 100644
--- a/d8_r8/commonBuildSrc/src/main/kotlin/TestConfigurationHelper.kt
+++ b/d8_r8/commonBuildSrc/src/main/kotlin/TestConfigurationHelper.kt
@@ -3,7 +3,10 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import java.io.File
+import java.io.PrintStream
 import java.util.Date
+import java.util.concurrent.TimeUnit
+import org.gradle.api.Project
 import org.gradle.api.tasks.testing.Test
 import org.gradle.api.tasks.testing.TestDescriptor
 import org.gradle.api.tasks.testing.TestListener
@@ -13,9 +16,39 @@
 
   companion object {
 
-    fun setupTestTask(test: Test) {
+    fun retrace(project: Project, r8jar: File?, exception: Throwable): String {
+      val out = StringBuilder()
+      val header = "RETRACED STACKTRACE";
+      out.append("\n--------------------------------------\n")
+      out.append("${header}\n")
+      out.append("--------------------------------------\n")
+      val retracePath = project.getRoot().resolveAll("tools", "retrace.py")
+      val command = mutableListOf("python3", retracePath.toString(), "--quiet")
+      if (r8jar != null) {
+        command.addAll(arrayOf("--r8jar", r8jar.toString()))
+      }
+      val process = ProcessBuilder(command).start()
+      process.outputStream.use { exception.printStackTrace(PrintStream(it)) }
+      process.outputStream.close()
+      val processCompleted = process.waitFor(10L, TimeUnit.SECONDS)
+        && process.exitValue() == 0
+      out.append(process.inputStream.bufferedReader().use { it.readText() })
+      if (!processCompleted) {
+        out.append(command.joinToString(" ") + "\n")
+        out.append("ERROR DURING RETRACING\n")
+        out.append(process.errorStream.bufferedReader().use { it.readText() })
+      }
+      if (project.hasProperty("print_obfuscated_stacktraces") || !processCompleted) {
+        out.append("\n\n--------------------------------------\n")
+        out.append("OBFUSCATED STACKTRACE\n")
+        out.append("--------------------------------------\n")
+      }
+      return out.toString()
+    }
+
+    fun setupTestTask(test: Test, isR8Lib: Boolean = false, r8Jar: File? = null) {
       val project = test.project
-      test.systemProperty("USE_NEW_GRADLE_SETUP", "true")
+      test.environment("USE_NEW_GRADLE_SETUP", "true")
       if (project.hasProperty("kotlin_compiler_dev")) {
         test.systemProperty("com.android.tools.r8.kotlincompilerdev", "1")
       }
@@ -74,7 +107,8 @@
         test.maxHeapSize = "4G"
       }
 
-      if (project.hasProperty("one_line_per_test")
+      if (isR8Lib
+        || project.hasProperty("one_line_per_test")
         || project.hasProperty("update_test_timestamp")) {
         test.addTestListener(object : TestListener {
           override fun beforeSuite(desc: TestDescriptor?) {}
@@ -93,6 +127,11 @@
               File(project.property("update_test_timestamp")!!.toString())
                 .writeText(Date().getTime().toString())
             }
+            if (isR8Lib
+              && result?.resultType == TestResult.ResultType.FAILURE
+              && result.exception != null) {
+              println(retrace(project, r8Jar, result.exception as Throwable))
+            }
           }
         })
       }
diff --git a/d8_r8/main/build.gradle.kts b/d8_r8/main/build.gradle.kts
index 4f2e1e4..ca51e8e 100644
--- a/d8_r8/main/build.gradle.kts
+++ b/d8_r8/main/build.gradle.kts
@@ -68,7 +68,7 @@
     dependsOn(thirdPartyResourceDependenciesTask)
   }
 
-  val consolidatedLicense by registering() {
+  val consolidatedLicense by registering {
     val root = getRoot()
     val r8License = root.resolve("LICENSE")
     val libraryLicense = root.resolve("LIBRARY-LICENSE")
@@ -78,7 +78,7 @@
       libraryLicenseFiles,
       mainJarDependencies().map(::zipTree))
 
-    val license = rootProject.buildDir.resolveAll("generatedLicense", "LICENSE")
+    val license = rootProject.layout.buildDirectory.file("generatedLicense/LICENSE").get().asFile
     outputs.files(license)
 
     doLast {
@@ -149,7 +149,6 @@
     exclude("META-INF/MANIFEST.MF")
     exclude("META-INF/maven/**")
     exclude("META-INF/proguard/**")
-    exclude("META-INF/services/**")
     exclude("META-INF/versions/**")
     exclude("**/*.xml")
     exclude("com/android/version.properties")
diff --git a/d8_r8/r8lib/build.gradle.kts b/d8_r8/r8lib/build.gradle.kts
deleted file mode 100644
index 5b81050..0000000
--- a/d8_r8/r8lib/build.gradle.kts
+++ /dev/null
@@ -1,116 +0,0 @@
-// 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.
-
-import java.nio.file.Paths
-
-plugins {
-  `kotlin-dsl`
-  id("dependencies-plugin")
-}
-
-java {
-  sourceCompatibility = JvmCompatibility.sourceCompatibility
-  targetCompatibility = JvmCompatibility.targetCompatibility
-}
-
-dependencies { }
-
-val r8WithRelocatedDepsTask = projectTask("main", "r8WithRelocatedDeps")
-val r8Jar = projectTask("main", "jar")
-val depsJarTask = projectTask("main", "depsJar")
-val allTestsJarRelocatedTask = projectTask("test", "allTestsJarRelocated")
-val allDepsJarTask = projectTask("test", "allDepsJar")
-
-tasks {
-  withType<Exec> {
-    doFirst {
-      println("Executing command: ${commandLine.joinToString(" ")}")
-    }
-  }
-
-  val generateKeepRules by registering(Exec::class) {
-    dependsOn(r8WithRelocatedDepsTask)
-    dependsOn(depsJarTask)
-    dependsOn(allTestsJarRelocatedTask)
-    dependsOn(allDepsJarTask)
-    val r8 = r8WithRelocatedDepsTask.outputs.files.getSingleFile()
-    val deps = depsJarTask.outputs.files.getSingleFile()
-    val tests = allTestsJarRelocatedTask.outputs.files.getSingleFile()
-    val testDeps = allDepsJarTask.outputs.files.getSingleFile()
-    inputs.files(listOf(r8, deps, tests, testDeps))
-    val output = file(Paths.get("build", "libs", "generated-keep-rules.txt"))
-    outputs.file(output)
-    commandLine = baseCompilerCommandLine(
-      r8,
-      "tracereferences",
-      listOf(
-        "--keep-rules",
-        "--allowobfuscation",
-        "--lib",
-        "${getRoot().resolveAll("third_party", "openjdk", "openjdk-rt-1.8", "rt.jar")}",
-        "--lib",
-        "${deps}",
-        "--lib",
-        "$testDeps",
-        "--target",
-        "$r8",
-        "--source",
-        "$tests",
-        "--output",
-        "$output"))
-  }
-
-  val r8LibWithRelocatedDeps by registering(Exec::class) {
-    dependsOn(generateKeepRules)
-    dependsOn(r8WithRelocatedDepsTask)
-    val r8 = r8WithRelocatedDepsTask.outputs.files.getSingleFile()
-    val generatedKeepRules = generateKeepRules.get().outputs.files.getSingleFile()
-    val keepTxt = getRoot().resolveAll("src", "main", "keep.txt")
-    // TODO(b/294351878): Remove once enum issue is fixed
-    val keepResourceShrinkerTxt = getRoot().resolveAll("src", "main", "keep_r8resourceshrinker.txt")
-    inputs.files(listOf(r8, generatedKeepRules, keepTxt, keepResourceShrinkerTxt))
-    val output = file(Paths.get("build", "libs", "r8lib-deps-relocated.jar"))
-    outputs.file(output)
-    commandLine = createR8LibCommandLine(
-      r8,
-      r8,
-      output,
-      listOf(keepTxt, generatedKeepRules, keepResourceShrinkerTxt),
-      false)
-  }
-
-  val r8LibNoDeps by registering(Exec::class) {
-    dependsOn(depsJarTask)
-    dependsOn(r8WithRelocatedDepsTask)
-    val r8Compiler = r8WithRelocatedDepsTask.outputs.files.getSingleFile()
-    val r8Jar = r8Jar.outputs.files.getSingleFile()
-    val deps = depsJarTask.outputs.files.getSingleFile()
-    inputs.files(listOf(r8Compiler, r8Jar, deps))
-    val output = file(Paths.get("build", "libs", "r8lib-no-deps.jar"))
-    outputs.file(output)
-    commandLine = createR8LibCommandLine(
-      r8Compiler,
-      r8Jar,
-      output,
-      listOf(getRoot().resolveAll("src", "main", "keep.txt")),
-      true,
-      listOf(deps))
-  }
-
-  val resourceshrinkercli by registering(Exec::class) {
-    dependsOn(r8WithRelocatedDepsTask)
-    val r8 = r8WithRelocatedDepsTask.outputs.files.getSingleFile()
-    val keepTxt = getRoot().resolveAll("src", "main", "resourceshrinker_cli.txt")
-    val cliKeep = getRoot().resolveAll("src", "main", "keep_r8resourceshrinker.txt")
-    inputs.files(listOf(keepTxt, cliKeep))
-    val output = file(Paths.get("build", "libs", "resourceshrinkercli.jar"))
-    outputs.file(output)
-    commandLine = createR8LibCommandLine(
-      r8,
-      r8,
-      output,
-      listOf(keepTxt, cliKeep),
-      false)
-  }
-}
diff --git a/d8_r8/r8lib/gradle.properties b/d8_r8/r8lib/gradle.properties
deleted file mode 100644
index a82d85e..0000000
--- a/d8_r8/r8lib/gradle.properties
+++ /dev/null
@@ -1,18 +0,0 @@
-# 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.
-
-org.gradle.jvmargs=-Xmx2048M -Dfile.encoding=UTF-8
-kotlin.daemon.jvmargs=-Xmx3g -Dkotlin.js.compiler.legacy.force_enabled=true
-systemProp.file.encoding=UTF-8
-
-# Enable new incremental compilation
-kotlin.incremental.useClasspathSnapshot=true
-
-org.gradle.parallel=true
-org.gradle.caching=false
-org.gradle.configuration-cache=true
-
-# Do not download any jdks or detect them. We provide them.
-org.gradle.java.installations.auto-detect=false
-org.gradle.java.installations.auto-download=false
diff --git a/d8_r8/r8lib/settings.gradle.kts b/d8_r8/r8lib/settings.gradle.kts
deleted file mode 100644
index cb9fc2e..0000000
--- a/d8_r8/r8lib/settings.gradle.kts
+++ /dev/null
@@ -1,31 +0,0 @@
-// 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.
-
-pluginManagement {
-  repositories {
-    maven {
-      url = uri("file:../../third_party/dependencies")
-    }
-    maven {
-      url = uri("file:../../third_party/dependencies_new")
-    }
-  }
-}
-
-dependencyResolutionManagement {
-  repositories {
-    maven {
-      url = uri("file:../../third_party/dependencies")
-    }
-    maven {
-      url = uri("file:../../third_party/dependencies_new")
-    }
-  }
-}
-
-rootProject.name = "r8lib"
-
-val root = rootProject.projectDir.parentFile
-includeBuild(root.resolve("main"))
-includeBuild(root.resolve("test"))
diff --git a/d8_r8/settings.gradle.kts b/d8_r8/settings.gradle.kts
index 9abecbf..c3c86b7 100644
--- a/d8_r8/settings.gradle.kts
+++ b/d8_r8/settings.gradle.kts
@@ -88,7 +88,3 @@
 includeBuild(root.resolve("main"))
 includeBuild(root.resolve("library_desugar"))
 includeBuild(root.resolve("test"))
-
-// Include r8lib as standalone to have a nice separation between source artifacts and r8 compiled
-// artifacts
-includeBuild(root.resolve("r8lib"))
diff --git a/d8_r8/test/build.gradle.kts b/d8_r8/test/build.gradle.kts
index 2a84bfa..ceafdfa 100644
--- a/d8_r8/test/build.gradle.kts
+++ b/d8_r8/test/build.gradle.kts
@@ -20,16 +20,19 @@
 
 dependencies { }
 
+val keepAnnoCompileTask = projectTask("keepanno", "compileJava")
+val mainDepsJarTask = projectTask("main", "depsJar")
+val r8Jar = projectTask("main", "jar")
 val r8WithRelocatedDepsTask = projectTask("main", "r8WithRelocatedDeps")
 val java8TestJarTask = projectTask("tests_java_8", "testJar")
 val java8TestsDepsJarTask = projectTask("tests_java_8", "depsJar")
 val bootstrapTestsDepsJarTask = projectTask("tests_bootstrap", "depsJar")
 
 tasks {
-  withType<JavaCompile> {
-    options.setFork(true)
-    options.forkOptions.executable = getCompilerPath(Jdk.JDK_17)
-    options.forkOptions.javaHome = getJavaHome(Jdk.JDK_17)
+  withType<Exec> {
+    doFirst {
+      println("Executing command: ${commandLine.joinToString(" ")}")
+    }
   }
 
   withType<KotlinCompile> {
@@ -40,7 +43,7 @@
 
   val allTestsJar by registering(Jar::class) {
     dependsOn(java8TestJarTask)
-    from(java8TestJarTask.outputs.getFiles().map(::zipTree))
+    from(java8TestJarTask.outputs.files.map(::zipTree))
     exclude("META-INF/*.kotlin_module")
     exclude("**/*.kotlin_metadata")
     archiveFileName.set("all-tests.jar")
@@ -76,7 +79,141 @@
              "kotlinx.metadata.**->com.android.tools.r8.jetbrains.kotlinx.metadata"))
   }
 
-  withType<Test> {
+  val r8LibNoDeps by registering(Exec::class) {
+    dependsOn(mainDepsJarTask)
+    dependsOn(r8WithRelocatedDepsTask)
+    val r8Compiler = r8WithRelocatedDepsTask.outputs.files.getSingleFile()
+    val r8Jar = r8Jar.outputs.files.getSingleFile()
+    val deps = mainDepsJarTask.outputs.files.getSingleFile()
+    inputs.files(listOf(r8Compiler, r8Jar, deps))
+    val output = file(Paths.get("build", "libs", "r8lib-exclude-deps.jar"))
+    outputs.file(output)
+    commandLine = createR8LibCommandLine(
+      r8Compiler,
+      r8Jar,
+      output,
+      listOf(getRoot().resolveAll("src", "main", "keep.txt")),
+      true,
+      listOf(deps))
+  }
+
+  val generateKeepRules by registering(Exec::class) {
+    dependsOn(r8WithRelocatedDepsTask)
+    dependsOn(mainDepsJarTask)
+    dependsOn(allTestsJarRelocated)
+    dependsOn(allDepsJar)
+    val r8 = r8WithRelocatedDepsTask.outputs.files.getSingleFile()
+    val deps = mainDepsJarTask.outputs.files.getSingleFile()
+    val tests = allTestsJarRelocated.get().outputs.files.getSingleFile()
+    val testDeps = allDepsJar.get().outputs.files.getSingleFile()
+    inputs.files(listOf(r8, deps, tests, testDeps))
+    val output = file(Paths.get("build", "libs", "generated-keep-rules.txt"))
+    outputs.file(output)
+    commandLine = baseCompilerCommandLine(
+      r8,
+      "tracereferences",
+      listOf(
+        "--keep-rules",
+        "--allowobfuscation",
+        "--lib",
+        "${getRoot().resolveAll("third_party", "openjdk", "openjdk-rt-1.8", "rt.jar")}",
+        "--lib",
+        "${deps}",
+        "--lib",
+        "$testDeps",
+        "--target",
+        "$r8",
+        "--source",
+        "$tests",
+        "--output",
+        "$output"))
+  }
+
+  val r8LibWithRelocatedDeps by registering(Exec::class) {
+    dependsOn(generateKeepRules)
+    dependsOn(r8WithRelocatedDepsTask)
+    val r8 = r8WithRelocatedDepsTask.outputs.files.getSingleFile()
+    val generatedKeepRules = generateKeepRules.get().outputs.files.getSingleFile()
+    val keepTxt = getRoot().resolveAll("src", "main", "keep.txt")
+    // TODO(b/294351878): Remove once enum issue is fixed
+    val keepResourceShrinkerTxt = getRoot().resolveAll("src", "main", "keep_r8resourceshrinker.txt")
+    inputs.files(listOf(r8, generatedKeepRules, keepTxt, keepResourceShrinkerTxt))
+    val output = getRoot().resolveAll("build", "libs", "r8lib.jar")
+    outputs.files(output)
+    commandLine = createR8LibCommandLine(
+      r8,
+      r8,
+      output,
+      listOf(keepTxt, generatedKeepRules, keepResourceShrinkerTxt),
+      false)
+  }
+
+  val resourceshrinkercli by registering(Exec::class) {
+    dependsOn(r8WithRelocatedDepsTask)
+    val r8 = r8WithRelocatedDepsTask.outputs.files.getSingleFile()
+    val keepTxt = getRoot().resolveAll("src", "main", "resourceshrinker_cli.txt")
+    val cliKeep = getRoot().resolveAll("src", "main", "keep_r8resourceshrinker.txt")
+    inputs.files(listOf(keepTxt, cliKeep))
+    val output = file(Paths.get("build", "libs", "resourceshrinkercli.jar"))
+    outputs.file(output)
+    commandLine = createR8LibCommandLine(
+      r8,
+      r8,
+      output,
+      listOf(keepTxt, cliKeep),
+      false)
+  }
+
+  val allTestWithApplyMappingProguardConfiguration by registering {
+    dependsOn(r8LibWithRelocatedDeps)
+    val license = rootProject.buildDir.resolveAll("libs", "r8tests-keep.txt")
+    outputs.files(license)
+    doLast {
+      // TODO(b/299065371): We should be able to take in the partition map output.
+      license.writeText(
+        """-keep class ** { *; }
+-dontshrink
+-dontoptimize
+-keepattributes *
+-applymapping ${r8LibWithRelocatedDeps.get().outputs.files.singleFile}.map
+""")
+    }
+  }
+
+  val allTestsWithApplyMapping by registering(Exec::class) {
+    dependsOn(allDepsJar)
+    dependsOn(allTestsJarRelocated)
+    dependsOn(r8WithRelocatedDepsTask)
+    dependsOn(allTestWithApplyMappingProguardConfiguration)
+    val r8 = r8WithRelocatedDepsTask.outputs.files.singleFile
+    val allTests = allTestsJarRelocated.get().outputs.files.singleFile
+    val pgConf = allTestWithApplyMappingProguardConfiguration.get().outputs.files.singleFile
+    val lib = resolve(ThirdPartyDeps.java8Runtime, "rt.jar").getSingleFile()
+    val main = r8WithRelocatedDepsTask.outputs.files.singleFile
+    val testDeps = allDepsJar.get().outputs.files.singleFile
+    inputs.files(listOf(r8, allTests, pgConf, lib, main, testDeps))
+    val output = file(Paths.get("build", "libs", "all-tests-relocated-applymapping.jar"))
+    outputs.file(output)
+    commandLine = baseCompilerCommandLine(
+      r8,
+      "r8",
+      listOf(
+        "--classfile",
+        "--debug",
+        "--lib",
+        "$lib",
+        "--classpath",
+        "$main",
+        "--classpath",
+        "$testDeps",
+        "--output",
+        "$output",
+        "--pg-conf",
+        "$pgConf",
+        "$allTests"))
+  }
+
+  test {
     println("NOTE: Number of processors " + Runtime.getRuntime().availableProcessors())
     println("NOTE: Max parallel forks " + maxParallelForks)
     val os = DefaultNativePlatform.getCurrentOperatingSystem()
@@ -91,7 +228,7 @@
           "tests requiring Art will be skipped")
     } else if (!os.isLinux) {
       logger.log(
-        LogLevel.ERROR,
+        ERROR,
         "Testing in not supported on your platform. Testing is only fully supported on " +
           "Linux and partially supported on Mac OS and Windows. Art does not run on other " +
           "platforms.")
@@ -99,4 +236,63 @@
     dependsOn(gradle.includedBuild("tests_java_8").task(":test"))
     dependsOn(gradle.includedBuild("tests_bootstrap").task(":test"))
   }
+
+  val unzipTests by registering(Copy::class) {
+    dependsOn(allTestsJar)
+    val outputDir = file("${buildDir}/unpacked/test")
+    from(zipTree(allTestsJar.get().outputs.files.singleFile))
+    into(outputDir)
+  }
+
+  val unzipRewrittenTests by registering(Copy::class) {
+    dependsOn(allTestsWithApplyMapping)
+    val outputDir = file("${buildDir}/unpacked/rewrittentest")
+    from(zipTree(allTestsWithApplyMapping.get().outputs.files.singleFile))
+    into(outputDir)
+  }
+
+  val r8LibTest by registering(Test::class) {
+    println("NOTE: Number of processors " + Runtime.getRuntime().availableProcessors())
+    println("NOTE: Max parallel forks " + maxParallelForks)
+    dependsOn(allDepsJar)
+    dependsOn(r8LibWithRelocatedDeps)
+    dependsOn(unzipTests)
+    dependsOn(unzipRewrittenTests)
+    val r8LibJar = r8LibWithRelocatedDeps.get().outputs.files.singleFile
+    this.configure(isR8Lib = true, r8Jar = r8LibJar)
+
+    // R8lib should be used instead of the main output and all the tests in r8 should be mapped and
+    // exists in r8LibTestPath.
+    classpath = files(
+      allDepsJar.get().outputs.files,
+      r8LibJar,
+      unzipRewrittenTests.get().outputs.files)
+    testClassesDirs = unzipRewrittenTests.get().outputs.files
+
+    environment.put("TEST_CLASSES_LOCATIONS", unzipTests.get().outputs.files.singleFile)
+    systemProperty("KEEP_ANNO_JAVAC_BUILD_DIR", keepAnnoCompileTask.outputs.files.getAsPath())
+    systemProperty("EXAMPLES_JAVA_11_JAVAC_BUILD_DIR",
+                   getRoot().resolveAll("build", "test", "examplesJava11", "classes"))
+    systemProperty("R8_RUNTIME_PATH", r8LibJar)
+    // TODO(b/270105162): This should change if running with retrace lib/r8lib.
+    systemProperty("RETRACE_RUNTIME_PATH", r8LibJar)
+    systemProperty("R8_DEPS", mainDepsJarTask.outputs.files.singleFile)
+
+    // TODO(b/291198792): Remove this exclusion when desugared library runs correctly.
+    exclude("com/android/tools/r8/desugar/desugaredlibrary/**")
+    exclude("com/android/tools/r8/desugar/InvokeSuperToRewrittenDefaultMethodTest**")
+    exclude("com/android/tools/r8/desugar/InvokeSuperToEmulatedDefaultMethodTest**")
+    exclude("com/android/tools/r8/desugar/backports/ThreadLocalBackportWithDesugaredLibraryTest**")
+    exclude("com/android/tools/r8/L8CommandTest**")
+    exclude("com/android/tools/r8/MarkersTest**")
+    exclude("com/android/tools/r8/apimodel/ApiModelDesugaredLibraryReferenceTest**")
+    exclude("com/android/tools/r8/apimodel/ApiModelNoDesugaredLibraryReferenceTest**")
+    exclude("com/android/tools/r8/benchmarks/desugaredlib/**")
+    exclude("com/android/tools/r8/classmerging/vertical/ForceInlineConstructorWithRetargetedLibMemberTest**")
+    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**")
+    exclude("com/android/tools/r8/shaking/serviceloader/ServiceLoaderDesugaredLibraryTest**")
+ }
 }
\ No newline at end of file
diff --git a/d8_r8/test/settings.gradle.kts b/d8_r8/test/settings.gradle.kts
index ccdc169..5df668c 100644
--- a/d8_r8/test/settings.gradle.kts
+++ b/d8_r8/test/settings.gradle.kts
@@ -27,6 +27,7 @@
 rootProject.name = "r8-tests"
 
 val root = rootProject.projectDir.parentFile
+includeBuild(root.resolve("keepanno"))
 includeBuild(root.resolve("main"))
 includeBuild(root.resolve("test_modules").resolve("tests_java_8"))
 includeBuild(root.resolve("test_modules").resolve("tests_bootstrap"))
diff --git a/d8_r8/test_modules/tests_bootstrap/build.gradle.kts b/d8_r8/test_modules/tests_bootstrap/build.gradle.kts
index 3c0dfa1..1a8ff99 100644
--- a/d8_r8/test_modules/tests_bootstrap/build.gradle.kts
+++ b/d8_r8/test_modules/tests_bootstrap/build.gradle.kts
@@ -69,9 +69,10 @@
     TestingState.setUpTestingState(this)
 
     environment.put("USE_NEW_GRADLE_SETUP", "true")
+    environment.put("TEST_CLASSES_LOCATIONS", "$buildDir/classes/java/test")
     dependsOn(mainR8RelocatedTask)
-    environment.put("R8_WITH_RELOCATED_DEPS", mainR8RelocatedTask.outputs.files.getSingleFile())
-    environment.put("R8_RUNTIME_PATH", mainR8RelocatedTask.outputs.files.getSingleFile())
+    systemProperty("R8_WITH_RELOCATED_DEPS", mainR8RelocatedTask.outputs.files.getSingleFile())
+    systemProperty("R8_RUNTIME_PATH", mainR8RelocatedTask.outputs.files.getSingleFile())
 
     // TODO(b/291198792): Remove this exclusion when desugared library runs correctly.
     exclude("com/android/tools/r8/bootstrap/HelloWorldCompiledOnArtTest**")
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 1a1f801..dd1bfbd 100644
--- a/d8_r8/test_modules/tests_java_8/build.gradle.kts
+++ b/d8_r8/test_modules/tests_java_8/build.gradle.kts
@@ -55,6 +55,7 @@
   implementation(resolve(ThirdPartyDeps.jdwpTests,"apache-harmony-jdwp-tests-host.jar"))
   implementation(Deps.fastUtil)
   implementation(Deps.smali)
+  implementation(Deps.smaliUtil)
 }
 
 val thirdPartyCompileDependenciesTask = ensureThirdPartyDependencies(
@@ -133,11 +134,9 @@
     .get()
     .compileClasspath
     .filter {
-      "$it".contains("keepanno")
-        || "$it".contains("resourceshrinker")
-        || ("$it".contains("third_party")
-              && !"$it".contains("errorprone")
-              && !"$it".contains("third_party/gradle"))
+        "$it".contains("third_party")
+          && !"$it".contains("errorprone")
+          && !"$it".contains("third_party/gradle")
     }
 }
 
@@ -159,29 +158,27 @@
 
   withType<Test> {
     TestingState.setUpTestingState(this)
-
     environment.put("USE_NEW_GRADLE_SETUP", "true")
+    environment.put("TEST_CLASSES_LOCATIONS", "$buildDir/classes/java/test")
     dependsOn(mainDepsJarTask)
     dependsOn(thirdPartyRuntimeDependenciesTask)
     if (!project.hasProperty("no_internal")) {
       dependsOn(thirdPartyRuntimeInternalDependenciesTask)
     }
     dependsOn(*sourceSetDependenciesTasks)
-    environment.put("KEEP_ANNO_JAVAC_BUILD_DIR", keepAnnoCompileTask.outputs.files.getAsPath())
+    systemProperty("KEEP_ANNO_JAVAC_BUILD_DIR", keepAnnoCompileTask.outputs.files.getAsPath())
     // This path is set when compiling examples jar task in DependenciesPlugin.
-    environment.put("EXAMPLES_JAVA_11_JAVAC_BUILD_DIR",
+    systemProperty("EXAMPLES_JAVA_11_JAVAC_BUILD_DIR",
                     getRoot().resolveAll("build", "test", "examplesJava11", "classes"))
-    // TODO(b/270105162): This should change if running with r8lib.
-    environment.put(
+    systemProperty(
       "R8_RUNTIME_PATH",
       mainCompileTask.outputs.files.getAsPath().split(File.pathSeparator)[0] +
         File.pathSeparator + mainDepsJarTask.outputs.files.singleFile)
-    // TODO(b/270105162): This should change if running with retrace lib/r8lib.
-    environment.put(
+    systemProperty(
       "RETRACE_RUNTIME_PATH",
       mainCompileTask.outputs.files.getAsPath().split(File.pathSeparator)[0] +
         File.pathSeparator + mainDepsJarTask.outputs.files.singleFile)
-    environment.put("R8_DEPS", mainDepsJarTask.outputs.files.singleFile)
+    systemProperty("R8_DEPS", mainDepsJarTask.outputs.files.singleFile)
 
     // TODO(b/291198792): Remove this exclusion when desugared library runs correctly.
     exclude("com/android/tools/r8/desugar/desugaredlibrary/**")
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java
index a376f4a..615cd59 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java
@@ -131,7 +131,10 @@
               // Use the concrete getNoKotlinInfo() instead of isNoKotlinInformation() to handle
               // invalid kotlin info as well.
               assert hasKotlinClassMetadataAnnotation(clazz, definitionsForContext(clazz))
-                  == (clazz.getKotlinInfo() != getNoKotlinInfo());
+                      == (clazz.getKotlinInfo() != getNoKotlinInfo())
+                  : clazz.toSourceString()
+                      + " "
+                      + (clazz.getKotlinInfo() == getNoKotlinInfo() ? "no info" : "has info");
             }
           });
     }
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 63bf83a..d9558e4 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -100,13 +100,13 @@
 
   public static String getProjectRoot() {
     String current = System.getProperty("user.dir");
-    if (!current.contains("test_modules")) {
+    if (!current.contains("d8_r8")) {
       return "";
     }
-    while (current.contains("test_modules")) {
+    while (current.contains("d8_r8")) {
       current = Paths.get(current).getParent().toString();
     }
-    return Paths.get(current).getParent().toString() + "/";
+    return current + "/";
   }
 
   public static final String SOURCE_DIR = getProjectRoot() + "src/";
@@ -141,7 +141,8 @@
   public static String getExamplesJava11BuildDir() {
     // TODO(b/270105162): This changes when new gradle setup is default.
     if (ToolHelper.isNewGradleSetup()) {
-      return System.getenv("EXAMPLES_JAVA_11_JAVAC_BUILD_DIR");
+      assert System.getProperty("EXAMPLES_JAVA_11_JAVAC_BUILD_DIR") != null;
+      return System.getProperty("EXAMPLES_JAVA_11_JAVAC_BUILD_DIR");
     } else {
       return BUILD_DIR + "classes/java/examplesJava11/";
     }
@@ -150,7 +151,8 @@
   public static Path getR8MainPath() {
     // TODO(b/270105162): This changes when new gradle setup is default.
     if (ToolHelper.isNewGradleSetup()) {
-      return Paths.get(System.getenv("R8_RUNTIME_PATH"));
+      assert System.getProperty("R8_RUNTIME_PATH") != null;
+      return Paths.get(System.getProperty("R8_RUNTIME_PATH"));
     } else {
       return isTestingR8Lib() ? R8LIB_JAR : R8_JAR_OLD;
     }
@@ -159,7 +161,8 @@
   public static Path getRetracePath() {
     // TODO(b/270105162): This changes when new gradle setup is default.
     if (ToolHelper.isNewGradleSetup()) {
-      return Paths.get(System.getenv("RETRACE_RUNTIME_PATH"));
+      assert System.getProperty("RETRACE_RUNTIME_PATH") != null;
+      return Paths.get(System.getProperty("RETRACE_RUNTIME_PATH"));
     } else {
       return isTestingR8Lib() ? ToolHelper.R8_RETRACE_JAR : ToolHelper.R8_JAR_OLD;
     }
@@ -234,7 +237,7 @@
 
   public static Path getDeps() {
     if (isNewGradleSetup()) {
-      return Paths.get(System.getenv("R8_DEPS"));
+      return Paths.get(System.getProperty("R8_DEPS"));
     } else {
       return Paths.get(LIBS_DIR, "deps_all.jar");
     }
@@ -242,7 +245,7 @@
 
   public static Path getR8WithRelocatedDeps() {
     if (isNewGradleSetup()) {
-      return Paths.get(System.getenv("R8_WITH_RELOCATED_DEPS"));
+      return Paths.get(System.getProperty("R8_WITH_RELOCATED_DEPS"));
     } else {
       return Paths.get(LIBS_DIR, "r8_with_relocated_deps.jar");
     }
@@ -1156,7 +1159,7 @@
   public static Path getAndroidJar(AndroidApiLevel apiLevel) {
     Path path = getAndroidJarPath(apiLevel);
     assert Files.exists(path)
-        : "Expected android jar to exist for API level " + apiLevel;
+        : "Expected android jar to exist for API level " + apiLevel + " at " + path;
     return path;
   }
 
@@ -1405,7 +1408,8 @@
 
   public static Path getClassPathForTests() {
     if (isNewGradleSetup()) {
-      return Paths.get(TEST_MODULE_DIR, "tests_java_8", "build", "classes", "java", "test");
+      assert System.getenv("TEST_CLASSES_LOCATIONS") != null;
+      return Paths.get(System.getenv("TEST_CLASSES_LOCATIONS"));
     } else {
       return Paths.get(BUILD_DIR, "classes", "java", "test");
     }
@@ -1454,7 +1458,12 @@
 
   public static Path getClassFileForTestClass(Class<?> clazz) {
     List<String> parts = getNamePartsForTestClass(clazz);
-    return getClassPathForTests().resolve(Paths.get("", parts.toArray(StringUtils.EMPTY_ARRAY)));
+    Path resolve =
+        getClassPathForTests().resolve(Paths.get("", parts.toArray(StringUtils.EMPTY_ARRAY)));
+    if (!Files.exists(resolve)) {
+      throw new RuntimeException("Could not find: " + resolve.toString());
+    }
+    return resolve;
   }
 
   public static Collection<Path> getClassFilesForInnerClasses(Path path) throws IOException {
diff --git a/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTest.java b/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTest.java
index 34cd179..bb72b7a 100644
--- a/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTest.java
+++ b/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTest.java
@@ -107,9 +107,17 @@
         "-keep class " + clazz.getName() + " { public static void main(java.lang.String[]); }");
   }
 
+  public boolean isNewGradleSetup() {
+    return "true".equals(System.getenv("USE_NEW_GRADLE_SETUP"));
+  }
+
   public Path getPathForClass(Class<?> clazz) {
     String file = clazz.getName().replace('.', '/') + ".class";
-    return Paths.get("build", "classes", "java", "test", file);
+    if (isNewGradleSetup()) {
+      return Paths.get(System.getenv("TEST_CLASSES_LOCATIONS"), file);
+    } else {
+      return Paths.get("build", "classes", "java", "test", file);
+    }
   }
 
   public byte[] getBytesForClass(Class<?> clazz) throws IOException {
diff --git a/src/test/java/com/android/tools/r8/debug/SmaliDebugTest.java b/src/test/java/com/android/tools/r8/debug/SmaliDebugTest.java
index 126cbac..087b7ae 100644
--- a/src/test/java/com/android/tools/r8/debug/SmaliDebugTest.java
+++ b/src/test/java/com/android/tools/r8/debug/SmaliDebugTest.java
@@ -198,7 +198,7 @@
 
   private List<Path> buildAndRun(SmaliBuilder builder) throws Throwable {
     byte[] bytes = builder.compile();
-    Path out = temp.getRoot().toPath().resolve("classes.dex");
+    Path out = temp.newFolder().toPath().resolve("classes.dex");
     Files.write(out, bytes);
     ToolHelper.runArtNoVerificationErrors(out.toString(), CLASS);
     return Collections.singletonList(out);
diff --git a/src/test/java/com/android/tools/r8/keepanno/KeepEdgeAnnotationsTest.java b/src/test/java/com/android/tools/r8/keepanno/KeepEdgeAnnotationsTest.java
index 21b1ea6..5c22e9f 100644
--- a/src/test/java/com/android/tools/r8/keepanno/KeepEdgeAnnotationsTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/KeepEdgeAnnotationsTest.java
@@ -71,7 +71,8 @@
   public static Path getKeepAnnoPath() {
     // TODO(b/270105162): This changes when new gradle setup is default.
     if (ToolHelper.isNewGradleSetup()) {
-      return Paths.get(System.getenv("KEEP_ANNO_JAVAC_BUILD_DIR").split(File.pathSeparator)[0]);
+      return Paths.get(
+          System.getProperty("KEEP_ANNO_JAVAC_BUILD_DIR").split(File.pathSeparator)[0]);
     } else {
       return Paths.get(ToolHelper.BUILD_DIR, "classes", "java", "keepanno");
     }
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceCommandLineTests.java b/src/test/java/com/android/tools/r8/retrace/RetraceCommandLineTests.java
index 7d981a5..2bc2ff9 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceCommandLineTests.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceCommandLineTests.java
@@ -346,7 +346,7 @@
       command.add(ToolHelper.getSystemJavaExecutable());
       command.add("-ea");
       command.add("-cp");
-      command.add(ToolHelper.R8_RETRACE_JAR.toString());
+      command.add(ToolHelper.getRetracePath().toString());
       command.add(mainEntryPointExternal);
       command.addAll(args);
       ProcessBuilder builder = new ProcessBuilder(command);
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceTests.java b/src/test/java/com/android/tools/r8/retrace/RetraceTests.java
index 57ede60..6abc4c7 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceTests.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceTests.java
@@ -537,7 +537,7 @@
       command.add(parameters.getRuntime().asCf().getJavaExecutable().toString());
       command.add("-ea");
       command.add("-cp");
-      command.add(ToolHelper.R8_RETRACE_JAR.toString());
+      command.add(ToolHelper.getRetracePath().toString());
       if (allowExperimentalMapping) {
         command.add("-Dcom.android.tools.r8.experimentalmapping");
       }
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 05012fb..c5a5a05 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 @@
-e8b501b64fea3bfa07cd39d1d62b719c84709c13
\ No newline at end of file
+4b9212d58c7e29b81a49fb67246f945b05c22623
\ No newline at end of file
diff --git a/third_party/retrace/binary_compatibility.tar.gz.sha1 b/third_party/retrace/binary_compatibility.tar.gz.sha1
index 450affa..41a5e04 100644
--- a/third_party/retrace/binary_compatibility.tar.gz.sha1
+++ b/third_party/retrace/binary_compatibility.tar.gz.sha1
@@ -1 +1 @@
-0c79a64372af9813b73dee17ab6f18bc050de3d2
\ No newline at end of file
+c200df1f5305635d3b26f948a15732af5fefcacf
\ 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 3c945f3..500c480 100755
--- a/tools/create_local_maven_with_dependencies.py
+++ b/tools/create_local_maven_with_dependencies.py
@@ -51,6 +51,7 @@
 TEST_DEPENDENCIES = [
   'junit:junit:{version}'.format(version = JUNIT_VERSION),
   'com.android.tools.smali:smali:{version}'.format(version = SMALI_VERSION),
+  'com.android.tools.smali:smali-util:{version}'.format(version = SMALI_VERSION),
   'com.google.errorprone:error_prone_core:{version}'.format(version = ERROR_PRONE_VERSION),
   'org.javassist:javassist:{version}'.format(version = JAVASSIST_VERSION),
   'org.jetbrains.kotlin:kotlin-stdlib:{version}'.format(version = KOTLIN_VERSION),