Merge commit '4cfe51ef79f7be4b8095d70294410ab25095c1e6' into dev-release Change-Id: Ib34bee76fd2af418056373e6c0354160cb1db00f
diff --git a/doc/compilerdump.md b/doc/compilerdump.md index c85a9ff..87976be 100644 --- a/doc/compilerdump.md +++ b/doc/compilerdump.md
@@ -63,6 +63,17 @@ ./gradlew assembleDebug -Dorg.gradle.caching=false -Dcom.android.tools.r8.dumpinputtodirectory=mydumps/ --no-daemon ``` +### Generating a dump in AOSP +For R8 compilations you can generate dumps with the R8_DUMP_DIRECTORY environment variable. +This will put dumps for all R8 compilations leading up to the target that you are building. +For a specific target you can do: + +``` +mkdir /tmp/dumps +R8_DUMP_DIRECTORY=/tmp/dumps m -j77 SystemUI +``` +The actual dump file for SystemUI will be the last dump in /tmp/dumps. + ## Reproducing using a dump @@ -81,3 +92,4 @@ The flags can also be used to override the setting specified in the dump. Doing so allows compiling with other compiler versions, or other settings. +
diff --git a/infra/config/global/generated/cr-buildbucket.cfg b/infra/config/global/generated/cr-buildbucket.cfg index 11b270c..ded5fe1 100644 --- a/infra/config/global/generated/cr-buildbucket.cfg +++ b/infra/config/global/generated/cr-buildbucket.cfg
@@ -27,8 +27,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -56,8 +56,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -85,8 +85,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -114,8 +114,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -152,8 +152,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -186,8 +186,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -218,8 +218,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -250,8 +250,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -288,8 +288,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -326,8 +326,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -364,8 +364,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -402,8 +402,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -440,8 +440,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -478,8 +478,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -516,8 +516,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -554,8 +554,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -592,8 +592,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -630,8 +630,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -668,8 +668,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -706,8 +706,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -744,8 +744,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -782,8 +782,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -820,8 +820,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -858,8 +858,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -896,8 +896,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -934,8 +934,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -972,8 +972,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -1010,8 +1010,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -1048,8 +1048,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -1086,8 +1086,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -1124,8 +1124,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -1162,8 +1162,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -1199,8 +1199,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -1236,8 +1236,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -1273,8 +1273,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -1305,8 +1305,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -1337,8 +1337,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -1374,8 +1374,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -1411,8 +1411,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -1448,8 +1448,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -1485,8 +1485,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -1522,8 +1522,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -1559,8 +1559,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -1596,8 +1596,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -1633,8 +1633,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -1670,8 +1670,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -1707,8 +1707,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -1744,8 +1744,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -1781,8 +1781,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -1818,8 +1818,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -1852,8 +1852,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -1886,8 +1886,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -1915,8 +1915,8 @@ dimensions: "os:Ubuntu-20.04" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -1944,8 +1944,8 @@ dimensions: "os:Windows-10" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties: @@ -1980,8 +1980,8 @@ dimensions: "os:Windows-10" dimensions: "pool:luci.r8.ci" exe { - cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave" - cipd_version: "refs/heads/master" + cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build" + cipd_version: "refs/heads/main" cmd: "luciexe" } properties:
diff --git a/infra/config/global/main.star b/infra/config/global/main.star index f223381..3e642c0 100755 --- a/infra/config/global/main.star +++ b/infra/config/global/main.star
@@ -155,9 +155,8 @@ luci.recipe( name="rex", cipd_package = "infra_internal/recipe_bundles/" + - "chrome-internal.googlesource.com/chrome/" + - "tools/build_limited/scripts/slave", - cipd_version = "refs/heads/master", + "chrome-internal.googlesource.com/chrome/tools/build", + cipd_version = "refs/heads/main", use_bbagent = True )
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java index 24d8545..93926dd 100644 --- a/src/main/java/com/android/tools/r8/R8.java +++ b/src/main/java/com/android/tools/r8/R8.java
@@ -247,7 +247,7 @@ static void runInternal(AndroidApp app, InternalOptions options, ExecutorService executor) throws IOException { - if (options.r8PartialCompilationOptions.enabled) { + if (options.partialCompilationConfiguration.isEnabled()) { try { new R8Partial(options).runInternal(app, executor); } catch (ResourceException e) {
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java index 1077122..6a7475f 100644 --- a/src/main/java/com/android/tools/r8/R8Command.java +++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -51,6 +51,7 @@ import com.android.tools.r8.utils.InternalOptions.LineNumberOptimization; import com.android.tools.r8.utils.InternalOptions.MappingComposeOptions; import com.android.tools.r8.utils.ProgramClassCollection; +import com.android.tools.r8.utils.R8PartialCompilationConfiguration; import com.android.tools.r8.utils.Reporter; import com.android.tools.r8.utils.SemanticVersion; import com.android.tools.r8.utils.SetUtils; @@ -149,6 +150,7 @@ private AndroidResourceConsumer androidResourceConsumer = null; private ResourceShrinkerConfiguration resourceShrinkerConfiguration = ResourceShrinkerConfiguration.DEFAULT_CONFIGURATION; + private R8PartialCompilationConfiguration partialCompilationConfiguration = null; private final ProguardConfigurationParserOptions.Builder parserOptionsBuilder = ProguardConfigurationParserOptions.builder().readEnvironment(); @@ -554,6 +556,43 @@ this.readEmbeddedRulesFromClasspathAndLibrary = enable; } + /** + * Configure partial shrinking in R8, where R8 is only applied to a part of the input. + * + * <p>The patterns in {@code includePatterns} and {@code excludePatterns} are comma separated + * lists of string patterns of fully qualified names of packages/classes. The patterns support + * the wildcards {@code *} and {@code **}. The wildcards are only supported at the end of the + * pattern, so only prefix matching. If the character just before the wildcard is a {@code .} + * (package separator) then the difference between {@code *} and {@code **} is that {@code *} + * only includes classes in the same package, whereas {@code **} includes classes in subpackages + * as well. If the character before the wildcard is not a {@code .} (package separator) then + * {@code *} and {@code **} will both match all classes with that prefix. + * + * <p>If {@code includePatterns} is not specified ({@code null} or an empty string), the default + * is {@code "androidx.**,kotlin.**,kotlinx.**"}. + * + * <p>The include patterns are processed first collecting all possible include classes. Then the + * exclude patterns are applied removing all matching classes from the collected include + * classes. + * + * @param includePatterns patterns for classes to include in R8 shrinking (see above for + * semantics) + * @param excludePatterns patterns for classes to exclude from R8 shrinking (see above for + * semantics) + * @return + */ + @Deprecated + public Builder enableExperimentalPartialShrinking( + String includePatterns, String excludePatterns) { + if (includePatterns == null || includePatterns.isEmpty()) { + includePatterns = "androidx.**,kotlin.**,kotlinx.**"; + } + partialCompilationConfiguration = + R8PartialCompilationConfiguration.fromIncludeExcludePatterns( + includePatterns, excludePatterns); + return self(); + } + @Override protected InternalProgramOutputPathConsumer createProgramOutputConsumer( Path path, @@ -799,7 +838,8 @@ androidResourceConsumer, resourceShrinkerConfiguration, keepSpecifications, - buildMetadataConsumer); + buildMetadataConsumer, + partialCompilationConfiguration); if (inputDependencyGraphConsumer != null) { inputDependencyGraphConsumer.finished(); @@ -1016,6 +1056,7 @@ private final AndroidResourceConsumer androidResourceConsumer; private final ResourceShrinkerConfiguration resourceShrinkerConfiguration; private final Consumer<? super R8BuildMetadata> buildMetadataConsumer; + private final R8PartialCompilationConfiguration partialCompilationConfiguration; /** Get a new {@link R8Command.Builder}. */ public static Builder builder() { @@ -1115,7 +1156,8 @@ AndroidResourceConsumer androidResourceConsumer, ResourceShrinkerConfiguration resourceShrinkerConfiguration, List<KeepSpecificationSource> keepSpecifications, - Consumer<? super R8BuildMetadata> buildMetadataConsumer) { + Consumer<? super R8BuildMetadata> buildMetadataConsumer, + R8PartialCompilationConfiguration partialCompilationConfiguration) { super( inputApp, mode, @@ -1165,6 +1207,7 @@ this.androidResourceConsumer = androidResourceConsumer; this.resourceShrinkerConfiguration = resourceShrinkerConfiguration; this.buildMetadataConsumer = buildMetadataConsumer; + this.partialCompilationConfiguration = partialCompilationConfiguration; } private R8Command(boolean printHelp, boolean printVersion) { @@ -1194,6 +1237,7 @@ androidResourceConsumer = null; resourceShrinkerConfiguration = null; buildMetadataConsumer = null; + partialCompilationConfiguration = null; } public DexItemFactory getDexItemFactory() { @@ -1343,6 +1387,10 @@ } // EXPERIMENTAL flags. + if (partialCompilationConfiguration != null) { + internal.partialCompilationConfiguration = partialCompilationConfiguration; + } + assert !internal.forceProguardCompatibility; internal.forceProguardCompatibility = forceProguardCompatibility;
diff --git a/src/main/java/com/android/tools/r8/R8Partial.java b/src/main/java/com/android/tools/r8/R8Partial.java index e9cb9b8..42b5b5b 100644 --- a/src/main/java/com/android/tools/r8/R8Partial.java +++ b/src/main/java/com/android/tools/r8/R8Partial.java
@@ -21,9 +21,12 @@ import com.android.tools.r8.tracereferences.TraceReferencesKeepRules; import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.AndroidApp; +import com.android.tools.r8.utils.AndroidAppConsumers; import com.android.tools.r8.utils.DumpInputFlags; +import com.android.tools.r8.utils.ExceptionUtils; import com.android.tools.r8.utils.FileUtils; import com.android.tools.r8.utils.InternalOptions; +import com.android.tools.r8.utils.ThreadUtils; import com.android.tools.r8.utils.Timing; import com.android.tools.r8.utils.ZipUtils; import com.android.tools.r8.utils.ZipUtils.ZipBuilder; @@ -34,15 +37,37 @@ import java.util.HashSet; import java.util.Set; import java.util.concurrent.ExecutorService; -import java.util.function.Predicate; +import java.util.function.Consumer; import java.util.stream.Collectors; class R8Partial { private final InternalOptions options; + private final Consumer<AndroidApp> r8InputAppConsumer; + private final Consumer<AndroidApp> d8InputAppConsumer; + private final Consumer<AndroidApp> r8OutputAppConsumer; + private final Consumer<AndroidApp> d8OutputAppConsumer; R8Partial(InternalOptions options) { this.options = options; + this.r8InputAppConsumer = options.partialCompilationConfiguration.r8InputAppConsumer; + this.d8InputAppConsumer = options.partialCompilationConfiguration.d8InputAppConsumer; + this.r8OutputAppConsumer = options.partialCompilationConfiguration.r8OutputAppConsumer; + this.d8OutputAppConsumer = options.partialCompilationConfiguration.d8OutputAppConsumer; + } + + static void runForTesting(AndroidApp app, InternalOptions options) + throws CompilationFailedException { + ExecutorService executor = ThreadUtils.getExecutorService(options); + ExceptionUtils.withR8CompilationHandler( + options.reporter, + () -> { + try { + new R8Partial(options).runInternal(app, executor); + } finally { + executor.shutdown(); + } + }); } void runInternal(AndroidApp app, ExecutorService executor) throws IOException, ResourceException { @@ -51,8 +76,8 @@ ProgramConsumer originalProgramConsumer = options.programConsumer; MapConsumer originalMapConsumer = options.mapConsumer; - Path tmp = options.r8PartialCompilationOptions.getTemp(); - Path dumpFile = options.r8PartialCompilationOptions.getDumpFile(); + Path tmp = options.partialCompilationConfiguration.getTempDir(); + Path dumpFile = options.partialCompilationConfiguration.getDumpFile(); // Create a dump of the compiler input. // TODO(b/309743298): Do not use compiler dump to handle splitting the compilation. This should @@ -94,15 +119,15 @@ AppInfoWithClassHierarchy.createForDesugaring( AppInfo.createInitialAppInfo(dapp, GlobalSyntheticsStrategy.forNonSynthesizing())); - Predicate<String> isR8 = options.r8PartialCompilationOptions.isR8; - Set<String> d8classes = new HashSet<>(); + Set<DexProgramClass> d8classes = new HashSet<>(); appInfo .classes() .forEach( clazz -> { - String key = clazz.toSourceString(); - if (!d8classes.contains(key) && !isR8.test(key)) { - d8classes.add(key); + if (!d8classes.contains(clazz) + && !options.partialCompilationConfiguration.test( + clazz.getType().getDescriptor())) { + d8classes.add(clazz); // TODO(b/309743298): Improve this to only visit each class once and stop at // library boundary. appInfo.forEachSuperType( @@ -111,7 +136,7 @@ DexProgramClass superClass = asProgramClassOrNull(appInfo.definitionFor(superType)); if (superClass != null) { - d8classes.add(superClass.toSourceString()); + d8classes.add(superClass); } }); } @@ -120,7 +145,7 @@ // Filter the program input into the D8 and R8 parts. Set<String> d8ZipEntries = d8classes.stream() - .map(name -> name.replace('.', '/') + ".class") + .map(clazz -> ZipUtils.zipEntryNameForClass(clazz.getClassReference())) .collect(Collectors.toSet()); ZipBuilder d8ProgramBuilder = ZipBuilder.builder(tmp.resolve("d8-program.jar")); ZipBuilder r8ProgramBuilder = ZipBuilder.builder(tmp.resolve("r8-program.jar")); @@ -151,13 +176,23 @@ d8Builder.addDesugaredLibraryConfiguration( Files.readString(dump.getDesugaredLibraryFile(), UTF_8)); } + AndroidAppConsumers d8OutputAppSink = null; + if (d8OutputAppConsumer != null) { + d8OutputAppSink = new AndroidAppConsumers(d8Builder); + } d8Builder.validate(); D8Command d8command = d8Builder.makeCommand(); AndroidApp d8App = d8command.getInputApp(); + if (d8InputAppConsumer != null) { + d8InputAppConsumer.accept(d8App); + } InternalOptions d8Options = d8command.getInternalOptions(); assert d8Options.getMinApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N) : "Default interface methods not yet supported"; D8.runInternal(d8App, d8Options, executor); + if (d8OutputAppConsumer != null) { + d8OutputAppConsumer.accept(d8OutputAppSink.build()); + } // Run trace references to produce keep rules for the D8 compiled part. // TODO(b/309743298): Do not emit keep rules into a file. @@ -192,12 +227,23 @@ r8Builder.addDesugaredLibraryConfiguration( Files.readString(dump.getDesugaredLibraryFile(), UTF_8)); } + AndroidAppConsumers r8OutputAppSink = null; + if (r8Builder != null) { + r8OutputAppSink = new AndroidAppConsumers(r8Builder); + } + r8Builder.validate(); R8Command r8Command = r8Builder.makeCommand(); AndroidApp r8App = r8Command.getInputApp(); + if (r8InputAppConsumer != null) { + r8InputAppConsumer.accept(r8App); + } InternalOptions r8Options = r8Command.getInternalOptions(); r8Options.mapConsumer = originalMapConsumer; r8Options.quiet = true; // Don't write the R8 version. R8.runInternal(r8App, r8Options, executor); + if (r8OutputAppConsumer != null) { + r8OutputAppConsumer.accept(r8OutputAppSink.build()); + } // Emit resources and merged DEX to the output consumer. // TODO(b/309743298): Consider passing the DataResourceConsumer to the R8 invocation above.
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java index 7d9439b..763198e 100644 --- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java +++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -114,14 +114,11 @@ import com.android.tools.r8.verticalclassmerging.VerticallyMergedClasses; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Predicates; -import com.google.common.base.Splitter; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collection; @@ -1022,9 +1019,10 @@ private final ArtProfileOptions artProfileOptions = new ArtProfileOptions(this); private final StartupOptions startupOptions = new StartupOptions(); private final InstrumentationOptions instrumentationOptions; - public final R8PartialCompilationOptions r8PartialCompilationOptions = - new R8PartialCompilationOptions( - System.getProperty("com.android.tools.r8.r8PartialCompilation")); + public R8PartialCompilationConfiguration partialCompilationConfiguration = + R8PartialCompilationConfiguration.fromIncludeExcludePatterns( + System.getProperty("com.android.tools.r8.experimentalPartialShrinkingIncludePatterns"), + System.getProperty("com.android.tools.r8.experimentalPartialShrinkingExcludePatterns")); public final TestingOptions testing = new TestingOptions(); public List<ProguardConfigurationRule> mainDexKeepRules = ImmutableList.of(); @@ -2282,39 +2280,6 @@ } } - public static class R8PartialCompilationOptions { - public boolean enabled; - public Path tempDir = null; - public Predicate<String> isR8 = null; - - R8PartialCompilationOptions(String partialR8) { - this.enabled = partialR8 != null; - if (this.enabled) { - final List<String> prefixes = Splitter.on(",").splitToList(partialR8); - this.isR8 = - name -> { - for (int i = 0; i < prefixes.size(); i++) { - if (name.startsWith(prefixes.get(i))) { - return true; - } - } - return false; - }; - } - } - - public synchronized Path getTemp() throws IOException { - if (tempDir == null) { - tempDir = Files.createTempDirectory("r8PartialCompilation"); - } - return tempDir; - } - - public Path getDumpFile() throws IOException { - return getTemp().resolve("dump.zip"); - } - } - public static class TestingOptions { public boolean enableEmbeddedKeepAnnotations =
diff --git a/src/main/java/com/android/tools/r8/utils/R8PartialCompilationConfiguration.java b/src/main/java/com/android/tools/r8/utils/R8PartialCompilationConfiguration.java new file mode 100644 index 0000000..a1c3b2d --- /dev/null +++ b/src/main/java/com/android/tools/r8/utils/R8PartialCompilationConfiguration.java
@@ -0,0 +1,283 @@ +// Copyright (c) 2024, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +package com.android.tools.r8.utils; + +import com.android.tools.r8.graph.DexString; +import com.google.common.base.Predicates; +import com.google.common.base.Splitter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Predicate; + +public class R8PartialCompilationConfiguration implements Predicate<DexString> { + + private final boolean enabled; + private Path tempDir = null; + private final List<Predicate<DexString>> includePredicates; + private final List<Predicate<DexString>> excludePredicates; + + public Consumer<AndroidApp> r8InputAppConsumer; + public Consumer<AndroidApp> d8InputAppConsumer; + public Consumer<AndroidApp> r8OutputAppConsumer; + public Consumer<AndroidApp> d8OutputAppConsumer; + + private static final R8PartialCompilationConfiguration disabledConfiguration = + new R8PartialCompilationConfiguration(false, null, null); + + private R8PartialCompilationConfiguration( + boolean enabled, + List<Predicate<DexString>> includePredicates, + List<Predicate<DexString>> excludePredicates) { + assert !enabled || !includePredicates.isEmpty(); + assert !enabled || excludePredicates != null; + this.enabled = enabled; + this.includePredicates = includePredicates; + this.excludePredicates = excludePredicates; + } + + @Override + public boolean test(DexString name) { + for (Predicate<DexString> isR8ClassPredicate : includePredicates) { + if (isR8ClassPredicate.test(name)) { + for (Predicate<DexString> isD8ClassPredicate : excludePredicates) { + if (isD8ClassPredicate.test(name)) { + return false; + } + } + return true; + } + } + return false; + } + + public static R8PartialCompilationConfiguration disabledConfiguration() { + return disabledConfiguration; + } + + public static R8PartialCompilationConfiguration fromIncludeExcludePatterns( + String includePatterns, String excludePatterns) { + boolean enabled = includePatterns != null || excludePatterns != null; + if (!enabled) { + return disabledConfiguration(); + } + Builder builder = builder(); + if (includePatterns != null) { + Splitter.on(",").splitToList(includePatterns).forEach(builder::addJavaTypeIncludePattern); + } + if (excludePatterns != null) { + Splitter.on(",").splitToList(excludePatterns).forEach(builder::addJavaTypeExcludePattern); + } + return builder.build(); + } + + public static Builder builder() { + return new Builder(); + } + + public boolean isEnabled() { + return enabled; + } + + public synchronized Path getTempDir() throws IOException { + if (tempDir == null) { + setTempDir(Files.createTempDirectory("r8PartialCompilation")); + } + return tempDir; + } + + public void setTempDir(Path tempDir) { + this.tempDir = tempDir; + } + + public Path getDumpFile() throws IOException { + return getTempDir().resolve("dump.zip"); + } + + public static class Builder { + private final List<Predicate<DexString>> includePredicates = new ArrayList<>(); + private final List<Predicate<DexString>> excludePredicates = new ArrayList<>(); + + private Builder() {} + + public R8PartialCompilationConfiguration build() { + return new R8PartialCompilationConfiguration( + !includePredicates.isEmpty(), includePredicates, excludePredicates); + } + + public Builder includeAll() { + includePredicates.add(Predicates.alwaysTrue()); + return this; + } + + public Builder addJavaTypeIncludePattern(String pattern) { + includePredicates.add( + createMatcher("L" + DescriptorUtils.getBinaryNameFromJavaType(pattern))); + return this; + } + + public Builder addJavaTypeExcludePattern(String pattern) { + excludePredicates.add( + createMatcher("L" + DescriptorUtils.getBinaryNameFromJavaType(pattern))); + return this; + } + + public Builder addDescriptorIncludePattern(String pattern) { + includePredicates.add(createMatcher(pattern)); + return this; + } + + public Builder addDescriptorExcludePattern(String pattern) { + excludePredicates.add(createMatcher(pattern)); + return this; + } + + private Predicate<DexString> createMatcher(String descriptorPrefix) { + assert descriptorPrefix.startsWith("L"); + assert descriptorPrefix.indexOf('.') == -1; + + if (descriptorPrefix.equals("L**")) { + return new AllClassesMatcher(); + } else if (descriptorPrefix.equals("L*")) { + return new UnnamedPackageMatcher(); + } else if (descriptorPrefix.endsWith("/**")) { + return new PackageAndSubpackagePrefixMatcher( + descriptorPrefix.substring(0, descriptorPrefix.length() - 2)); + } else if (descriptorPrefix.endsWith("/*")) { + return new PackagePrefixMatcher( + descriptorPrefix.substring(0, descriptorPrefix.length() - 1)); + } + if (descriptorPrefix.endsWith("*")) { + return new ClassPrefixMatcher(descriptorPrefix.substring(0, descriptorPrefix.length() - 1)); + } else { + return new ClassNameMatcher(descriptorPrefix + ';'); + } + } + + public Builder includeClasses(Class<?>... classes) { + return includeClasses(Arrays.asList(classes)); + } + + public Builder includeClasses(Collection<Class<?>> classes) { + classes.forEach( + clazz -> + includePredicates.add( + descriptor -> + descriptor.toString().equals(DescriptorUtils.javaClassToDescriptor(clazz)))); + return this; + } + + public Builder includeJavaType(Predicate<String> include) { + includePredicates.add( + descriptor -> include.test(DescriptorUtils.descriptorToJavaType(descriptor.toString()))); + return this; + } + + public Builder excludeClasses(Class<?>... classes) { + return excludeClasses(Arrays.asList(classes)); + } + + public Builder excludeClasses(Collection<Class<?>> classes) { + classes.forEach( + clazz -> + excludePredicates.add( + descriptor -> + descriptor.toString().equals(DescriptorUtils.javaClassToDescriptor(clazz)))); + return this; + } + + public Builder excludeJavaType(Predicate<String> exclude) { + excludePredicates.add( + descriptor -> exclude.test(DescriptorUtils.descriptorToJavaType(descriptor.toString()))); + return this; + } + } + + private static class AllClassesMatcher implements Predicate<DexString> { + + AllClassesMatcher() {} + + @Override + public boolean test(DexString descriptor) { + return true; + } + } + + private static class UnnamedPackageMatcher implements Predicate<DexString> { + + UnnamedPackageMatcher() {} + + @Override + public boolean test(DexString descriptor) { + return descriptor.indexOf('/') == -1; + } + } + + private static class PackageAndSubpackagePrefixMatcher implements Predicate<DexString> { + + private final byte[] descriptorPrefix; + + PackageAndSubpackagePrefixMatcher(String descriptorPrefix) { + this.descriptorPrefix = DexString.encodeToMutf8(descriptorPrefix); + } + + @Override + public boolean test(DexString descriptor) { + return descriptor.startsWith(descriptorPrefix); + } + } + + private static class PackagePrefixMatcher implements Predicate<DexString> { + + private final byte[] descriptorPrefix; + private final int descriptorPrefixLength; + + PackagePrefixMatcher(String descriptorPrefix) { + this.descriptorPrefix = DexString.encodeToMutf8(descriptorPrefix); + this.descriptorPrefixLength = descriptorPrefix.length(); + } + + @Override + public boolean test(DexString descriptor) { + return descriptor.startsWith(descriptorPrefix) + && descriptor.lastIndexOf('/') == descriptorPrefixLength - 1; + } + } + + private static class ClassPrefixMatcher implements Predicate<DexString> { + + private final byte[] descriptorPrefix; + private final int descriptorPrefixLength; + + ClassPrefixMatcher(String descriptorPrefix) { + this.descriptorPrefix = DexString.encodeToMutf8(descriptorPrefix); + this.descriptorPrefixLength = descriptorPrefix.length(); + } + + @Override + public boolean test(DexString descriptor) { + return descriptor.startsWith(descriptorPrefix) + && descriptor.lastIndexOf('/') < descriptorPrefixLength - 1; + } + } + + private static class ClassNameMatcher implements Predicate<DexString> { + + private final String descriptor; + + ClassNameMatcher(String descriptor) { + this.descriptor = descriptor; + } + + @Override + public boolean test(DexString descriptor) { + return descriptor.toString().equals(this.descriptor); + } + } +}
diff --git a/src/test/examplesJava9/twraddsuppressed/TestClass.java b/src/test/examplesJava9/twraddsuppressed/TestClass.java index 61285ce..fcf0d6f 100644 --- a/src/test/examplesJava9/twraddsuppressed/TestClass.java +++ b/src/test/examplesJava9/twraddsuppressed/TestClass.java
@@ -20,6 +20,8 @@ } public static void bar() { + // NOTE: The $closeResource helper is _only_ generated by the JDK-9 compiler. + // // Use twr twice to have javac generate a shared $closeResource helper. try (MyClosable closable = new MyClosable()) { foo();
diff --git a/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTestCollection.java b/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTestCollection.java index 5d349fc..bd1aace 100644 --- a/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTestCollection.java +++ b/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTestCollection.java
@@ -36,6 +36,7 @@ import com.android.tools.r8.compilerapi.testsetup.ApiTestingSetUpTest; import com.android.tools.r8.compilerapi.wrappers.CommandLineParserTest; import com.android.tools.r8.compilerapi.wrappers.EnableMissingLibraryApiModelingTest; +import com.android.tools.r8.partial.PartialShrinkingPreviewApiTest; import com.google.common.collect.ImmutableList; import java.nio.file.Path; import java.nio.file.Paths; @@ -79,7 +80,7 @@ MainDexRulesTest.ApiTest.class); private static final List<Class<? extends CompilerApiTest>> CLASSES_PENDING_BINARY_COMPATIBILITY = - ImmutableList.of(); + ImmutableList.of(PartialShrinkingPreviewApiTest.ApiTest.class); private final TemporaryFolder temp;
diff --git a/src/test/java/com/android/tools/r8/desugar/suppressedexceptions/TwrSuppressedExceptionsTest.java b/src/test/java/com/android/tools/r8/desugar/suppressedexceptions/TwrSuppressedExceptionsTest.java index ce7e1a7..6c03e85 100644 --- a/src/test/java/com/android/tools/r8/desugar/suppressedexceptions/TwrSuppressedExceptionsTest.java +++ b/src/test/java/com/android/tools/r8/desugar/suppressedexceptions/TwrSuppressedExceptionsTest.java
@@ -84,6 +84,7 @@ ClassSubject clazz = inspector.clazz(MAIN.typeName()); hasInvokesTo( clazz.uniqueMethodWithOriginalName("bar"), + // NOTE: The $closeResource helper is _only_ generated by the JDK-9 compiler. "$closeResource", apiLevelHasTwrCloseResourceSupport(true) ? 4 : 0); if (apiLevelHasSuppressedExceptionsSupport(true)) { @@ -102,6 +103,7 @@ DesugarTestConfiguration::isNotDesugared, inspector -> { ClassSubject clazz = inspector.clazz(MAIN.typeName()); + // NOTE: The $closeResource helper is _only_ generated by the JDK-9 compiler. hasInvokesTo(clazz.uniqueMethodWithOriginalName("bar"), "$closeResource", 4); hasInvokesTo(clazz.mainMethod(), "getSuppressed", 1); });
diff --git a/src/test/java/com/android/tools/r8/desugar/twr/TwrCloseResourceDuplicationTest.java b/src/test/java/com/android/tools/r8/desugar/twr/TwrCloseResourceDuplicationTest.java index b5b8444..dbea1507 100644 --- a/src/test/java/com/android/tools/r8/desugar/twr/TwrCloseResourceDuplicationTest.java +++ b/src/test/java/com/android/tools/r8/desugar/twr/TwrCloseResourceDuplicationTest.java
@@ -110,6 +110,8 @@ .assertSuccessWithOutput(EXPECTED) .inspect( inspector -> { + // NOTE: The $closeResource helper is _only_ generated by the JDK-9 compiler. + // // There should be two synthetic classes besides the three program classes. // One for the desugar version of TWR $closeResource and one for the // Throwable.addSuppressed that is still present in the original $closeResource.
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/backports/CloseResourceMethod.java b/src/test/java/com/android/tools/r8/ir/desugar/backports/CloseResourceMethod.java index 2059e86..7e18bdb 100644 --- a/src/test/java/com/android/tools/r8/ir/desugar/backports/CloseResourceMethod.java +++ b/src/test/java/com/android/tools/r8/ir/desugar/backports/CloseResourceMethod.java
@@ -8,6 +8,9 @@ public class CloseResourceMethod { + // NOTE: The $closeResource helper is _only_ generated by the JDK-9 compiler. The test + // CheckTwrOutputForJavaCompilersTest will fail if it is generated by other compilers. + // // The following method defines the code of // // public static void $closeResource(Throwable throwable, Object resource)
diff --git a/src/test/java/com/android/tools/r8/partial/ClassHierarchyInterleavedD8AndR8Test.java b/src/test/java/com/android/tools/r8/partial/ClassHierarchyInterleavedD8AndR8Test.java index db45859..32bfa65 100644 --- a/src/test/java/com/android/tools/r8/partial/ClassHierarchyInterleavedD8AndR8Test.java +++ b/src/test/java/com/android/tools/r8/partial/ClassHierarchyInterleavedD8AndR8Test.java
@@ -4,6 +4,7 @@ package com.android.tools.r8.partial; import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; +import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed; import static org.hamcrest.MatcherAssert.assertThat; @@ -13,9 +14,10 @@ import com.android.tools.r8.TestParametersCollection; import com.android.tools.r8.ToolHelper.DexVm; import com.android.tools.r8.utils.AndroidApiLevel; +import com.android.tools.r8.utils.R8PartialCompilationConfiguration; import com.android.tools.r8.utils.ThrowingConsumer; import com.android.tools.r8.utils.codeinspector.CodeInspector; -import java.util.function.Predicate; +import java.util.function.Consumer; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -40,15 +42,18 @@ } private void runTest( - Predicate<String> isR8, ThrowingConsumer<CodeInspector, RuntimeException> inspector) + Consumer<R8PartialCompilationConfiguration.Builder> partialConfigurationBuilderConsumer, + ThrowingConsumer<CodeInspector, RuntimeException> d8Inspector, + ThrowingConsumer<CodeInspector, RuntimeException> inspector) throws Exception { // Path tempDir = temp.newFolder().toPath(); testForR8Partial(parameters.getBackend()) .setMinApi(parameters) .addProgramClasses(A.class, B.class, C.class, Main.class) .addKeepMainRule(Main.class) - .setR8PartialConfigurationPredicate(isR8) + .setR8PartialConfiguration(partialConfigurationBuilderConsumer) .compile() + .inspectD8Input(d8Inspector) .inspect(inspector) .run(parameters.getRuntime(), Main.class) .assertSuccessWithEmptyOutput(); @@ -57,7 +62,13 @@ @Test public void testD8Top() throws Exception { runTest( - name -> !name.equals(A.class.getTypeName()), + partialConfigurationBuilder -> + partialConfigurationBuilder.includeAll().excludeClasses(A.class), + inspector -> { + assertThat(inspector.programClass(A.class), isPresent()); + assertThat(inspector.programClass(B.class), isAbsent()); + assertThat(inspector.programClass(C.class), isAbsent()); + }, inspector -> { assertThat(inspector.clazz(A.class), isPresentAndNotRenamed()); assertThat(inspector.clazz(B.class), isAbsent()); // Merged into C. @@ -68,7 +79,13 @@ @Test public void testD8Middle() throws Exception { runTest( - name -> !name.equals(B.class.getTypeName()), + partialConfigurationBuilder -> + partialConfigurationBuilder.includeAll().excludeClasses(B.class), + inspector -> { + assertThat(inspector.programClass(A.class), isPresent()); + assertThat(inspector.programClass(B.class), isPresent()); + assertThat(inspector.programClass(C.class), isAbsent()); + }, inspector -> { assertThat(inspector.clazz(A.class), isPresentAndNotRenamed()); assertThat(inspector.clazz(B.class), isPresentAndNotRenamed()); @@ -79,7 +96,13 @@ @Test public void testD8Bottom() throws Exception { runTest( - name -> !name.equals(C.class.getTypeName()), + partialConfigurationBuilder -> + partialConfigurationBuilder.includeAll().excludeClasses(C.class), + inspector -> { + assertThat(inspector.programClass(A.class), isPresent()); + assertThat(inspector.programClass(B.class), isPresent()); + assertThat(inspector.programClass(C.class), isPresent()); + }, inspector -> { assertThat(inspector.clazz(A.class), isPresentAndNotRenamed()); assertThat(inspector.clazz(B.class), isPresentAndNotRenamed());
diff --git a/src/test/java/com/android/tools/r8/partial/PartialCompilationBasicPreviewPatternsTest.java b/src/test/java/com/android/tools/r8/partial/PartialCompilationBasicPreviewPatternsTest.java new file mode 100644 index 0000000..b6c55e9 --- /dev/null +++ b/src/test/java/com/android/tools/r8/partial/PartialCompilationBasicPreviewPatternsTest.java
@@ -0,0 +1,286 @@ +// Copyright (c) 2024, 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.partial; + +import static org.junit.Assert.assertTrue; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.ToolHelper.DexVm; +import com.android.tools.r8.partial.pkg1.A1; +import com.android.tools.r8.partial.pkg1.A2; +import com.android.tools.r8.partial.pkg1.subpkg.B; +import com.android.tools.r8.partial.pkg2.C1; +import com.android.tools.r8.partial.pkg2.C2; +import com.android.tools.r8.utils.AndroidApiLevel; +import com.google.common.collect.ImmutableList; +import java.util.List; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class PartialCompilationBasicPreviewPatternsTest extends TestBase { + + private static String PKG1 = getPackageName(A1.class); + private static String SUBPKG = getPackageName(B.class); + private static String PKG2 = getPackageName(C2.class); + + private static String getPackageName(Class<?> clazz) { + return clazz.getTypeName().substring(0, clazz.getTypeName().lastIndexOf('.')); + } + + @Parameter(0) + public TestParameters parameters; + + @Parameters(name = "{0}") + // Test with min API level 24. + public static TestParametersCollection data() { + return getTestParameters() + .withDexRuntime(DexVm.Version.V7_0_0) + .withApiLevel(AndroidApiLevel.N) + .build(); + } + + private static final List<Class<?>> ALL_CLASSES = + ImmutableList.of(A1.class, A2.class, B.class, C1.class, C2.class, Main.class); + private static final String[] ALL_TYPE_NAMES = + new String[] { + A1.class.getTypeName(), + A2.class.getTypeName(), + B.class.getTypeName(), + C1.class.getTypeName(), + C2.class.getTypeName() + }; + + @Test + public void pkg1AndSubpackagesCompiledWithR8() throws Exception { + testForR8Partial(parameters.getBackend()) + .setMinApi(parameters) + .addProgramClasses(ALL_CLASSES) + .setR8PartialConfiguration(builder -> builder.addJavaTypeIncludePattern(PKG1 + ".**")) + .compile() + .inspectD8Input( + inspector -> + assertTrue(inspector.hasExactlyProgramClasses(C1.class, C2.class, Main.class))) + .inspectR8Input( + inspector -> + assertTrue(inspector.hasExactlyProgramClasses(A1.class, A2.class, B.class))) + .inspect( + inspector -> + assertTrue(inspector.hasExactlyProgramClasses(C1.class, C2.class, Main.class))) + .run(parameters.getRuntime(), Main.class, ALL_TYPE_NAMES) + .assertSuccessWithOutputLines( + "Not instantiated", + "Not instantiated", + "Not instantiated", + "Instantiated", + "Instantiated"); + } + + @Test + public void pkg1CompiledWithR8() throws Exception { + testForR8Partial(parameters.getBackend()) + .setMinApi(parameters) + .addProgramClasses(ALL_CLASSES) + .setR8PartialConfiguration(builder -> builder.addJavaTypeIncludePattern(PKG1 + ".*")) + .compile() + .inspectD8Input( + inspector -> + assertTrue( + inspector.hasExactlyProgramClasses(B.class, C1.class, C2.class, Main.class))) + .inspectR8Input( + inspector -> assertTrue(inspector.hasExactlyProgramClasses(A1.class, A2.class))) + .inspect( + inspector -> + assertTrue( + inspector.hasExactlyProgramClasses(B.class, C1.class, C2.class, Main.class))) + .run(parameters.getRuntime(), Main.class, ALL_TYPE_NAMES) + .assertSuccessWithOutputLines( + "Not instantiated", "Not instantiated", "Instantiated", "Instantiated", "Instantiated"); + } + + @Test + public void pkg1AndSubpackagesExcludeSubPkgCompiledWithR8() throws Exception { + testForR8Partial(parameters.getBackend()) + .setMinApi(parameters) + .addProgramClasses(ALL_CLASSES) + .setR8PartialConfiguration( + builder -> + builder + .addJavaTypeIncludePattern(PKG1 + ".**") + .addJavaTypeExcludePattern(SUBPKG + ".*")) + .compile() + .inspectD8Input( + inspector -> + assertTrue( + inspector.hasExactlyProgramClasses(C1.class, C2.class, B.class, Main.class))) + .inspectR8Input( + inspector -> assertTrue(inspector.hasExactlyProgramClasses(A1.class, A2.class))) + .inspect( + inspector -> + assertTrue( + inspector.hasExactlyProgramClasses(B.class, C1.class, C2.class, Main.class))) + .run(parameters.getRuntime(), Main.class, ALL_TYPE_NAMES) + .assertSuccessWithOutputLines( + "Not instantiated", "Not instantiated", "Instantiated", "Instantiated", "Instantiated"); + } + + @Test + public void pkg1AndSubpackagesExcludeAPrefixCompiledWithR8() throws Exception { + testForR8Partial(parameters.getBackend()) + .setMinApi(parameters) + .addProgramClasses(ALL_CLASSES) + .setR8PartialConfiguration( + builder -> + builder + .addJavaTypeIncludePattern(PKG1 + ".**") + .addJavaTypeExcludePattern(PKG1 + ".A*")) + .compile() + .inspectD8Input( + inspector -> + assertTrue( + inspector.hasExactlyProgramClasses( + A1.class, A2.class, C1.class, C2.class, Main.class))) + .inspectR8Input(inspector -> assertTrue(inspector.hasExactlyProgramClasses(B.class))) + .inspect( + inspector -> + assertTrue( + inspector.hasExactlyProgramClasses( + A1.class, A2.class, C1.class, C2.class, Main.class))) + .run(parameters.getRuntime(), Main.class, ALL_TYPE_NAMES) + .assertSuccessWithOutputLines( + "Instantiated", "Instantiated", "Not instantiated", "Instantiated", "Instantiated"); + } + + @Test + public void pkg1AndSubpackagesExcludeA1AndA2CompiledWithR8() throws Exception { + testForR8Partial(parameters.getBackend()) + .setMinApi(parameters) + .addProgramClasses(ALL_CLASSES) + .setR8PartialConfiguration( + builder -> + builder + .addJavaTypeIncludePattern(PKG1 + ".**") + .addJavaTypeExcludePattern(PKG1 + ".A1") + .addJavaTypeExcludePattern(PKG1 + ".A2")) + .compile() + .inspectD8Input( + inspector -> + assertTrue( + inspector.hasExactlyProgramClasses( + A1.class, A2.class, C1.class, C2.class, Main.class))) + .inspectR8Input(inspector -> assertTrue(inspector.hasExactlyProgramClasses(B.class))) + .inspect( + inspector -> + assertTrue( + inspector.hasExactlyProgramClasses( + A1.class, A2.class, C1.class, C2.class, Main.class))) + .run(parameters.getRuntime(), Main.class, ALL_TYPE_NAMES) + .assertSuccessWithOutputLines( + "Instantiated", "Instantiated", "Not instantiated", "Instantiated", "Instantiated"); + } + + @Test + public void allExeptC1CompiledWithR8() throws Exception { + testForR8Partial(parameters.getBackend()) + .setMinApi(parameters) + .addProgramClasses(ALL_CLASSES) + .setR8PartialConfiguration( + builder -> + builder + .addJavaTypeIncludePattern(PKG1 + ".**") + .addJavaTypeIncludePattern(PKG2 + ".**") + .addJavaTypeExcludePattern(PKG2 + ".C1")) + .compile() + .inspectD8Input( + inspector -> assertTrue(inspector.hasExactlyProgramClasses(C1.class, Main.class))) + .inspectR8Input( + inspector -> + assertTrue( + inspector.hasExactlyProgramClasses(A1.class, A2.class, B.class, C2.class))) + .inspect(inspector -> assertTrue(inspector.hasExactlyProgramClasses(C1.class, Main.class))) + .run(parameters.getRuntime(), Main.class, ALL_TYPE_NAMES) + .assertSuccessWithOutputLines( + "Not instantiated", + "Not instantiated", + "Not instantiated", + "Instantiated", + "Not instantiated"); + } + + @Test + public void allExeptA1CompiledWithR8() throws Exception { + testForR8Partial(parameters.getBackend()) + .setMinApi(parameters) + .addProgramClasses(ALL_CLASSES) + .setR8PartialConfiguration( + builder -> + builder + .addJavaTypeIncludePattern(PKG1 + ".*") + .addJavaTypeIncludePattern(SUBPKG + ".*") + .addJavaTypeIncludePattern(PKG2 + ".*") + .addJavaTypeExcludePattern(PKG1 + ".A1")) + .compile() + .inspectD8Input( + inspector -> assertTrue(inspector.hasExactlyProgramClasses(A1.class, Main.class))) + .inspectR8Input( + inspector -> + assertTrue( + inspector.hasExactlyProgramClasses(A2.class, B.class, C1.class, C2.class))) + .inspect(inspector -> assertTrue(inspector.hasExactlyProgramClasses(A1.class, Main.class))) + .run(parameters.getRuntime(), Main.class, ALL_TYPE_NAMES) + .assertSuccessWithOutputLines( + "Instantiated", + "Not instantiated", + "Not instantiated", + "Not instantiated", + "Not instantiated"); + } + + @Test + public void allExeptBCompiledWithR8() throws Exception { + testForR8Partial(parameters.getBackend()) + .setMinApi(parameters) + .addProgramClasses(ALL_CLASSES) + .setR8PartialConfiguration( + builder -> + builder + .addJavaTypeIncludePattern(PKG1 + ".**") + .addJavaTypeIncludePattern(PKG2 + ".**") + .addJavaTypeExcludePattern(SUBPKG + ".*")) + .compile() + .inspectD8Input( + inspector -> assertTrue(inspector.hasExactlyProgramClasses(B.class, Main.class))) + .inspectR8Input( + inspector -> + assertTrue( + inspector.hasExactlyProgramClasses(A1.class, A2.class, C1.class, C2.class))) + .inspect(inspector -> assertTrue(inspector.hasExactlyProgramClasses(B.class, Main.class))) + .run(parameters.getRuntime(), Main.class, ALL_TYPE_NAMES) + .assertSuccessWithOutputLines( + "Not instantiated", + "Not instantiated", + "Instantiated", + "Not instantiated", + "Not instantiated"); + } + + public static class Main { + + public static void main(String[] args) throws Exception { + for (String arg : args) { + try { + Class.forName(arg); + System.out.println("Instantiated"); + } catch (ClassNotFoundException e) { + System.out.println("Not instantiated"); + } + } + } + } +}
diff --git a/src/test/java/com/android/tools/r8/partial/PartialCompilationBasicTest.java b/src/test/java/com/android/tools/r8/partial/PartialCompilationBasicTest.java index 662aa21..e55a8d5 100644 --- a/src/test/java/com/android/tools/r8/partial/PartialCompilationBasicTest.java +++ b/src/test/java/com/android/tools/r8/partial/PartialCompilationBasicTest.java
@@ -39,12 +39,37 @@ .setMinApi(parameters) .addProgramClasses(A.class, B.class, Main.class) .addKeepMainRule(Main.class) - .setR8PartialConfiguration(builder -> builder.includeAll().excludeClasses(A.class).build()) + .setR8PartialConfiguration(builder -> builder.includeAll().excludeClasses(A.class)) .compile() + .inspectR8Input( + inspector -> { + assertThat(inspector.programClass(A.class), isAbsent()); + assertThat(inspector.programClass(B.class), isPresent()); + assertThat(inspector.programClass(Main.class), isPresent()); + }) + .inspectD8Input( + inspector -> { + assertThat(inspector.programClass(A.class), isPresent()); + assertThat(inspector.programClass(B.class), isAbsent()); + assertThat(inspector.programClass(Main.class), isAbsent()); + }) + .inspectR8Output( + inspector -> { + assertThat(inspector.clazz(A.class), isAbsent()); + assertThat(inspector.clazz(B.class), isAbsent()); + assertThat(inspector.clazz(Main.class), isPresent()); + }) + .inspectD8Output( + inspector -> { + assertThat(inspector.clazz(A.class), isPresent()); + assertThat(inspector.clazz(B.class), isAbsent()); + assertThat(inspector.clazz(Main.class), isAbsent()); + }) .inspect( inspector -> { assertThat(inspector.clazz(A.class), isPresent()); assertThat(inspector.clazz(B.class), isAbsent()); + assertThat(inspector.clazz(Main.class), isPresent()); }) .run(parameters.getRuntime(), Main.class, getClass().getTypeName()) .assertSuccessWithOutputLines("Instantiated", "Not instantiated"); @@ -56,12 +81,41 @@ .setMinApi(parameters) .addProgramClasses(A.class, B.class, Main.class) .addKeepMainRule(Main.class) - .setR8PartialConfiguration(builder -> builder.includeAll().excludeClasses(B.class).build()) + .setR8PartialConfiguration(builder -> builder.includeAll().excludeClasses(B.class)) .compile() + .inspectR8Input( + inspector -> { + // TODO(b/309743298): These are all present as inspection currently also look at + // classpath. + assertThat(inspector.programClass(A.class), isPresent()); + assertThat(inspector.programClass(B.class), isAbsent()); + assertThat(inspector.programClass(Main.class), isPresent()); + }) + .inspectD8Input( + inspector -> { + // TODO(b/309743298): These are all present as inspection currently also look at + // classpath. + assertThat(inspector.programClass(A.class), isAbsent()); + assertThat(inspector.programClass(B.class), isPresent()); + assertThat(inspector.programClass(Main.class), isAbsent()); + }) + .inspectR8Output( + inspector -> { + assertThat(inspector.clazz(A.class), isAbsent()); + assertThat(inspector.clazz(B.class), isAbsent()); + assertThat(inspector.clazz(Main.class), isPresent()); + }) + .inspectD8Output( + inspector -> { + assertThat(inspector.clazz(A.class), isAbsent()); + assertThat(inspector.clazz(B.class), isPresent()); + assertThat(inspector.clazz(Main.class), isAbsent()); + }) .inspect( inspector -> { assertThat(inspector.clazz(A.class), isAbsent()); assertThat(inspector.clazz(B.class), isPresent()); + assertThat(inspector.clazz(Main.class), isPresent()); }) .run(parameters.getRuntime(), Main.class, getClass().getTypeName()) .assertSuccessWithOutputLines("Not instantiated", "Instantiated");
diff --git a/src/test/java/com/android/tools/r8/partial/PartialCompilationDemoTest.java b/src/test/java/com/android/tools/r8/partial/PartialCompilationDemoTest.java index 0ccd8ce..43ad334 100644 --- a/src/test/java/com/android/tools/r8/partial/PartialCompilationDemoTest.java +++ b/src/test/java/com/android/tools/r8/partial/PartialCompilationDemoTest.java
@@ -236,10 +236,10 @@ private void runR8Partial(Path tempDir, CompilerDump dump, Path output, Predicate<String> isR8) throws IOException, CompilationFailedException { testForR8Partial(parameters.getBackend()) - .setR8PartialConfigurationPredicate(isR8) + .setR8PartialConfigurationJavaTypePredicate(isR8) .addOptionsModification( options -> { - options.r8PartialCompilationOptions.tempDir = tempDir; + options.partialCompilationConfiguration.setTempDir(tempDir); // For compiling nowonandroid. options.testing.allowUnnecessaryDontWarnWildcards = true;
diff --git a/src/test/java/com/android/tools/r8/partial/PartialShrinkingPreviewApiTest.java b/src/test/java/com/android/tools/r8/partial/PartialShrinkingPreviewApiTest.java new file mode 100644 index 0000000..f5784c5 --- /dev/null +++ b/src/test/java/com/android/tools/r8/partial/PartialShrinkingPreviewApiTest.java
@@ -0,0 +1,78 @@ +// Copyright (c) 2024, 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.partial; + +import static com.android.tools.r8.MarkerMatcher.markerMinApi; +import static com.android.tools.r8.MarkerMatcher.markerR8Mode; +import static org.hamcrest.MatcherAssert.assertThat; + +import com.android.tools.r8.DexIndexedConsumer; +import com.android.tools.r8.ProgramConsumer; +import com.android.tools.r8.R8; +import com.android.tools.r8.R8Command; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.compilerapi.CompilerApiTest; +import com.android.tools.r8.compilerapi.CompilerApiTestRunner; +import com.android.tools.r8.origin.Origin; +import com.android.tools.r8.utils.AndroidApiLevel; +import com.android.tools.r8.utils.ThrowingConsumer; +import com.android.tools.r8.utils.codeinspector.CodeInspector; +import java.nio.file.Path; +import org.hamcrest.CoreMatchers; +import org.junit.Test; + +public class PartialShrinkingPreviewApiTest extends CompilerApiTestRunner { + + public static final int MIN_API_LEVEL = 31; + + public PartialShrinkingPreviewApiTest(TestParameters parameters) { + super(parameters); + } + + @Override + public Class<? extends CompilerApiTest> binaryTestClass() { + return ApiTest.class; + } + + @Test + public void testR8() throws Exception { + ApiTest test = new ApiTest(ApiTest.PARAMETERS); + runTest(test::runR8); + } + + private void runTest(ThrowingConsumer<ProgramConsumer, Exception> test) throws Exception { + Path output = temp.newFolder().toPath().resolve("out.jar"); + test.accept(new DexIndexedConsumer.ArchiveConsumer(output)); + assertThat( + new CodeInspector(output).getMarkers(), + CoreMatchers.everyItem( + CoreMatchers.allOf( + markerMinApi(AndroidApiLevel.getAndroidApiLevel(MIN_API_LEVEL)), + markerR8Mode("full")))); + } + + public static class ApiTest extends CompilerApiTest { + + public ApiTest(Object parameters) { + super(parameters); + } + + public void runR8(ProgramConsumer programConsumer) throws Exception { + R8.run( + R8Command.builder() + .addClassProgramData(getBytesForClass(getMockClass()), Origin.unknown()) + .addProguardConfiguration(getKeepMainRules(getMockClass()), Origin.unknown()) + .addLibraryFiles(getJava8RuntimeJar()) + .setProgramConsumer(programConsumer) + .enableExperimentalPartialShrinking("**", null) + .setMinApiLevel(MIN_API_LEVEL) + .build()); + } + + @Test + public void testR8() throws Exception { + runR8(DexIndexedConsumer.emptyConsumer()); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/partial/pkg1/A1.java b/src/test/java/com/android/tools/r8/partial/pkg1/A1.java new file mode 100644 index 0000000..e435721 --- /dev/null +++ b/src/test/java/com/android/tools/r8/partial/pkg1/A1.java
@@ -0,0 +1,6 @@ +// Copyright (c) 2024, 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.partial.pkg1; + +public class A1 {}
diff --git a/src/test/java/com/android/tools/r8/partial/pkg1/A2.java b/src/test/java/com/android/tools/r8/partial/pkg1/A2.java new file mode 100644 index 0000000..7cac5c2 --- /dev/null +++ b/src/test/java/com/android/tools/r8/partial/pkg1/A2.java
@@ -0,0 +1,6 @@ +// Copyright (c) 2024, 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.partial.pkg1; + +public class A2 {}
diff --git a/src/test/java/com/android/tools/r8/partial/pkg1/subpkg/B.java b/src/test/java/com/android/tools/r8/partial/pkg1/subpkg/B.java new file mode 100644 index 0000000..ee4cb46 --- /dev/null +++ b/src/test/java/com/android/tools/r8/partial/pkg1/subpkg/B.java
@@ -0,0 +1,6 @@ +// Copyright (c) 2024, 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.partial.pkg1.subpkg; + +public class B {}
diff --git a/src/test/java/com/android/tools/r8/partial/pkg2/C1.java b/src/test/java/com/android/tools/r8/partial/pkg2/C1.java new file mode 100644 index 0000000..a6225c1 --- /dev/null +++ b/src/test/java/com/android/tools/r8/partial/pkg2/C1.java
@@ -0,0 +1,6 @@ +// Copyright (c) 2024, 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.partial.pkg2; + +public class C1 {}
diff --git a/src/test/java/com/android/tools/r8/partial/pkg2/C2.java b/src/test/java/com/android/tools/r8/partial/pkg2/C2.java new file mode 100644 index 0000000..139666a --- /dev/null +++ b/src/test/java/com/android/tools/r8/partial/pkg2/C2.java
@@ -0,0 +1,6 @@ +// Copyright (c) 2024, 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.partial.pkg2; + +public class C2 {}
diff --git a/src/test/java/com/android/tools/r8/profile/art/completeness/TwrCloseResourceDuplicationProfileRewritingTest.java b/src/test/java/com/android/tools/r8/profile/art/completeness/TwrCloseResourceDuplicationProfileRewritingTest.java index f840c33f..3bb5e4c 100644 --- a/src/test/java/com/android/tools/r8/profile/art/completeness/TwrCloseResourceDuplicationProfileRewritingTest.java +++ b/src/test/java/com/android/tools/r8/profile/art/completeness/TwrCloseResourceDuplicationProfileRewritingTest.java
@@ -98,6 +98,7 @@ ImmutableList.of(Reference.classFromClass(String.class)), null)) .addMethodRule( + // NOTE: The $closeResource helper is _only_ generated by the JDK-9 compiler. Reference.method( FOO.getClassReference(), "$closeResource", closeResourceFormalParameters, null)) .addMethodRule( @@ -107,6 +108,7 @@ ImmutableList.of(Reference.classFromClass(String.class)), null)) .addMethodRule( + // NOTE: The $closeResource helper is _only_ generated by the JDK-9 compiler. Reference.method( BAR.getClassReference(), "$closeResource", closeResourceFormalParameters, null)) .build();
diff --git a/src/test/testbase/java/com/android/tools/r8/R8PartialTestBuilder.java b/src/test/testbase/java/com/android/tools/r8/R8PartialTestBuilder.java index 319b633..3dacb92 100644 --- a/src/test/testbase/java/com/android/tools/r8/R8PartialTestBuilder.java +++ b/src/test/testbase/java/com/android/tools/r8/R8PartialTestBuilder.java
@@ -10,23 +10,17 @@ import com.android.tools.r8.utils.AndroidApp; import com.android.tools.r8.utils.Box; import com.android.tools.r8.utils.InternalOptions; -import com.google.common.base.Predicates; -import com.google.common.collect.ImmutableList; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; +import com.android.tools.r8.utils.R8PartialCompilationConfiguration; import java.util.List; import java.util.function.Consumer; -import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; -import java.util.stream.Collectors; public class R8PartialTestBuilder extends R8TestBuilder<R8PartialTestCompileResult, R8TestRunResult, R8PartialTestBuilder> { - private R8PartialConfiguration r8PartialConfiguration = - R8PartialConfiguration.defaultConfiguration(); + private R8PartialCompilationConfiguration r8PartialConfiguration = + R8PartialCompilationConfiguration.disabledConfiguration(); private R8PartialTestBuilder(TestState state, Builder builder, Backend backend) { super(state, builder, backend); @@ -52,106 +46,30 @@ return this; } - public static class R8PartialConfiguration implements Predicate<String> { - private static final R8PartialConfiguration defaultConfiguration = - new R8PartialConfiguration(ImmutableList.of(), ImmutableList.of()); - private final List<Predicate<String>> includePredicates; - private final List<Predicate<String>> excludePredicates; - - public R8PartialConfiguration( - List<Predicate<String>> includePredicates, List<Predicate<String>> excludePredicates) { - this.includePredicates = includePredicates; - this.excludePredicates = excludePredicates; - } - - private static R8PartialConfiguration defaultConfiguration() { - return defaultConfiguration; - } - - public static Builder builder() { - return new Builder(); - } - - public boolean test(String name) { - for (Predicate<String> isR8ClassPredicate : includePredicates) { - if (isR8ClassPredicate.test(name)) { - for (Predicate<String> isD8ClassPredicate : excludePredicates) { - if (isD8ClassPredicate.test(name)) { - return false; - } - } - return true; - } - } - return false; - } - - public static class Builder { - private final List<Predicate<String>> includePredicates = new ArrayList<>(); - private final List<Predicate<String>> excludePredicates = new ArrayList<>(); - - public R8PartialConfiguration build() { - return new R8PartialConfiguration(includePredicates, excludePredicates); - } - - public Builder includeAll() { - includePredicates.add(Predicates.alwaysTrue()); - return this; - } - - public Builder includeClasses(Class<?>... classes) { - return includeClasses(Arrays.asList(classes)); - } - - public Builder includeClasses(Collection<Class<?>> classes) { - Collection<String> typeNames = - classes.stream().map(Class::getTypeName).collect(Collectors.toList()); - includePredicates.add(typeNames::contains); - return this; - } - - public Builder include(Predicate<String> include) { - includePredicates.add(include); - return this; - } - - public Builder excludeClasses(Class<?>... classes) { - return excludeClasses(Arrays.asList(classes)); - } - - public Builder excludeClasses(Collection<Class<?>> classes) { - Collection<String> typeNames = - classes.stream().map(Class::getTypeName).collect(Collectors.toList()); - excludePredicates.add(typeNames::contains); - return this; - } - - public Builder exclude(Predicate<String> exclude) { - excludePredicates.add(exclude); - return this; - } - } - } - - public R8PartialTestBuilder setR8PartialConfigurationPredicate(Predicate<String> include) { - assert r8PartialConfiguration == R8PartialConfiguration.defaultConfiguration() + public R8PartialTestBuilder setR8PartialConfigurationJavaTypePredicate( + Predicate<String> include) { + assert r8PartialConfiguration.equals(R8PartialCompilationConfiguration.disabledConfiguration()) : "Overwriting configuration...?"; - r8PartialConfiguration = R8PartialConfiguration.builder().include(include).build(); + r8PartialConfiguration = + R8PartialCompilationConfiguration.builder().includeJavaType(include).build(); return self(); } - public R8PartialTestBuilder setR8PartialConfiguration(R8PartialConfiguration configuration) { - assert r8PartialConfiguration == R8PartialConfiguration.defaultConfiguration() + public R8PartialTestBuilder setR8PartialConfiguration( + R8PartialCompilationConfiguration configuration) { + assert r8PartialConfiguration.equals(R8PartialCompilationConfiguration.disabledConfiguration()) : "Overwriting configuration...?"; r8PartialConfiguration = configuration; return self(); } public R8PartialTestBuilder setR8PartialConfiguration( - Function<R8PartialConfiguration.Builder, R8PartialConfiguration> fn) { - assert r8PartialConfiguration == R8PartialConfiguration.defaultConfiguration() + Consumer<R8PartialCompilationConfiguration.Builder> consumer) { + assert r8PartialConfiguration.equals(R8PartialCompilationConfiguration.disabledConfiguration()) : "Overwriting configuration...?"; - r8PartialConfiguration = fn.apply(R8PartialConfiguration.builder()); + R8PartialCompilationConfiguration.Builder builder = R8PartialCompilationConfiguration.builder(); + consumer.accept(builder); + r8PartialConfiguration = builder.build(); return self(); } @@ -165,12 +83,19 @@ Box<List<ProguardConfigurationRule>> syntheticProguardRulesConsumer, StringBuilder proguardMapBuilder) throws CompilationFailedException { + Box<AndroidApp> r8InputAppBox = new Box<>(); + Box<AndroidApp> d8InputAppBox = new Box<>(); + Box<AndroidApp> r8OutputAppBox = new Box<>(); + Box<AndroidApp> d8OutputAppBox = new Box<>(); Consumer<InternalOptions> configureR8PartialCompilation = options -> { - options.r8PartialCompilationOptions.enabled = true; - options.r8PartialCompilationOptions.isR8 = r8PartialConfiguration; + options.partialCompilationConfiguration = r8PartialConfiguration; + options.partialCompilationConfiguration.r8InputAppConsumer = r8InputAppBox::set; + options.partialCompilationConfiguration.d8InputAppConsumer = d8InputAppBox::set; + options.partialCompilationConfiguration.r8OutputAppConsumer = r8OutputAppBox::set; + options.partialCompilationConfiguration.d8OutputAppConsumer = d8OutputAppBox::set; }; - ToolHelper.runAndBenchmarkR8WithoutResult( + ToolHelper.runAndBenchmarkR8PartialWithoutResult( builder, configureR8PartialCompilation.andThen(optionsConsumer), benchmarkResults); return new R8PartialTestCompileResult( getState(), @@ -186,6 +111,10 @@ residualArtProfiles, resourceShrinkerOutput, resourceShrinkerOutputForFeatures, - buildMetadata != null ? buildMetadata.get() : null); + buildMetadata != null ? buildMetadata.get() : null, + r8InputAppBox.get(), + d8InputAppBox.get(), + r8OutputAppBox.get(), + d8OutputAppBox.get()); } }
diff --git a/src/test/testbase/java/com/android/tools/r8/R8PartialTestCompileResult.java b/src/test/testbase/java/com/android/tools/r8/R8PartialTestCompileResult.java index 18f75fb..2ff5569 100644 --- a/src/test/testbase/java/com/android/tools/r8/R8PartialTestCompileResult.java +++ b/src/test/testbase/java/com/android/tools/r8/R8PartialTestCompileResult.java
@@ -8,13 +8,23 @@ import com.android.tools.r8.shaking.CollectingGraphConsumer; import com.android.tools.r8.shaking.ProguardConfigurationRule; import com.android.tools.r8.utils.AndroidApp; +import com.android.tools.r8.utils.InternalOptions; +import com.android.tools.r8.utils.ThrowingConsumer; +import com.android.tools.r8.utils.codeinspector.CodeInspector; +import java.io.IOException; import java.nio.file.Path; import java.util.HashMap; import java.util.List; +import java.util.function.Consumer; public class R8PartialTestCompileResult extends R8TestCompileResultBase<R8PartialTestCompileResult> { + private final AndroidApp r8InputApp; + private final AndroidApp d8InputApp; + private final AndroidApp r8OutputApp; + private final AndroidApp d8OutputApp; + R8PartialTestCompileResult( TestState state, OutputMode outputMode, @@ -29,7 +39,11 @@ List<ExternalArtProfile> residualArtProfiles, Path resourceShrinkerOutput, HashMap<String, Path> resourceShrinkerOutputForFeatures, - R8BuildMetadata buildMetadata) { + R8BuildMetadata buildMetadata, + AndroidApp r8InputApp, + AndroidApp d8InputApp, + AndroidApp r8OutputApp, + AndroidApp d8OutputApp) { super( state, outputMode, @@ -45,10 +59,74 @@ resourceShrinkerOutput, resourceShrinkerOutputForFeatures, buildMetadata); + this.r8InputApp = r8InputApp; + this.d8InputApp = d8InputApp; + this.r8OutputApp = r8OutputApp; + this.d8OutputApp = d8OutputApp; } @Override public R8PartialTestCompileResult self() { return this; } + + public CodeInspector inspectorR8Input() throws IOException { + return new CodeInspector(r8InputApp); + } + + public CodeInspector inspectorR8Input(Consumer<InternalOptions> debugOptionsConsumer) + throws IOException { + return new CodeInspector(r8InputApp, debugOptionsConsumer); + } + + public <E extends Throwable> R8PartialTestCompileResult inspectR8Input( + ThrowingConsumer<CodeInspector, E> consumer) throws IOException, E { + consumer.accept(inspectorR8Input()); + return self(); + } + + public CodeInspector inspectorD8Input() throws IOException { + return new CodeInspector(d8InputApp); + } + + public CodeInspector inspectorD8Input(Consumer<InternalOptions> debugOptionsConsumer) + throws IOException { + return new CodeInspector(d8InputApp, debugOptionsConsumer); + } + + public <E extends Throwable> R8PartialTestCompileResult inspectD8Input( + ThrowingConsumer<CodeInspector, E> consumer) throws IOException, E { + consumer.accept(inspectorD8Input()); + return self(); + } + + public CodeInspector inspectorR8Output() throws IOException { + return new CodeInspector(r8OutputApp); + } + + public CodeInspector inspectorR8Output(Consumer<InternalOptions> debugOptionsConsumer) + throws IOException { + return new CodeInspector(r8OutputApp, debugOptionsConsumer); + } + + public <E extends Throwable> R8PartialTestCompileResult inspectR8Output( + ThrowingConsumer<CodeInspector, E> consumer) throws IOException, E { + consumer.accept(inspectorR8Output()); + return self(); + } + + public CodeInspector inspectorD8Output() throws IOException { + return new CodeInspector(d8OutputApp); + } + + public CodeInspector inspectorD8Output(Consumer<InternalOptions> debugOptionsConsumer) + throws IOException { + return new CodeInspector(d8OutputApp, debugOptionsConsumer); + } + + public <E extends Throwable> R8PartialTestCompileResult inspectD8Output( + ThrowingConsumer<CodeInspector, E> consumer) throws IOException, E { + consumer.accept(inspectorD8Output()); + return self(); + } }
diff --git a/src/test/testbase/java/com/android/tools/r8/ToolHelper.java b/src/test/testbase/java/com/android/tools/r8/ToolHelper.java index 1a8a049..0608acb 100644 --- a/src/test/testbase/java/com/android/tools/r8/ToolHelper.java +++ b/src/test/testbase/java/com/android/tools/r8/ToolHelper.java
@@ -1807,6 +1807,28 @@ } } + public static void runAndBenchmarkR8PartialWithoutResult( + R8Command.Builder commandBuilder, + Consumer<InternalOptions> optionsConsumer, + BenchmarkResults benchmarkResults) + throws CompilationFailedException { + long start = 0; + if (benchmarkResults != null) { + start = System.nanoTime(); + } + R8Command command = commandBuilder.build(); + InternalOptions internalOptions = command.getInternalOptions(); + optionsConsumer.accept(internalOptions); + try { + R8Partial.runForTesting(command.getInputApp(), internalOptions); + } finally { + if (benchmarkResults != null) { + long end = System.nanoTime(); + benchmarkResults.addRuntimeResult(end - start); + } + } + } + public static AndroidApp runR8WithFullResult( R8Command command, Consumer<InternalOptions> optionsConsumer) throws CompilationFailedException {
diff --git a/src/test/testbase/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java b/src/test/testbase/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java index 7c06d42..d9af1e0 100644 --- a/src/test/testbase/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java +++ b/src/test/testbase/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
@@ -4,6 +4,8 @@ package com.android.tools.r8.utils.codeinspector; import static com.android.tools.r8.utils.ConsumerUtils.emptyConsumer; +import static com.android.tools.r8.utils.codeinspector.CodeInspector.ClassType.ANY; +import static com.android.tools.r8.utils.codeinspector.CodeInspector.ClassType.PROGRAM; import com.android.tools.r8.DexIndexedConsumer; import com.android.tools.r8.StringResource; @@ -45,6 +47,7 @@ import com.android.tools.r8.synthesis.SyntheticItemsTestUtils; import com.android.tools.r8.utils.AndroidApp; import com.android.tools.r8.utils.BiMapContainer; +import com.android.tools.r8.utils.BooleanBox; import com.android.tools.r8.utils.DescriptorUtils; import com.android.tools.r8.utils.InternalOptions; import com.android.tools.r8.utils.Timing; @@ -61,6 +64,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Consumer; @@ -78,6 +82,11 @@ final Map<String, String> obfuscatedToOriginalMapping; private Retracer lazyRetracer = null; + public enum ClassType { + PROGRAM, + ANY + } + public static MethodSignature MAIN = new MethodSignature("main", "void", new String[] {"java.lang.String[]"}); @@ -293,6 +302,10 @@ return rewriter.getSignature(); } + public ClassSubject clazz(Class<?> clazz, ClassType classType) { + return clazz(Reference.classFromClass(clazz), classType); + } + public ClassSubject clazz(Class<?> clazz) { return clazz(Reference.classFromClass(clazz)); } @@ -302,6 +315,10 @@ return clazz(Reference.classFromTypeName(name)); } + public ClassSubject programClass(Class<?> clazz) { + return clazz(Reference.classFromClass(clazz), PROGRAM); + } + public ClassNameMapper getMapping() { return mapping; } @@ -355,7 +372,7 @@ } } - public ClassSubject clazz(ClassReference reference) { + public ClassSubject clazz(ClassReference reference, ClassType classType) { String descriptor = reference.getDescriptor(); String name = DescriptorUtils.descriptorToJavaType(descriptor); ClassNamingForNameMapper naming = null; @@ -374,13 +391,20 @@ } } } - DexClass clazz = application.definitionFor(toDexTypeIgnorePrimitives(name)); + DexClass clazz = + classType == ANY + ? application.definitionFor(toDexTypeIgnorePrimitives(name)) + : application.programDefinitionFor(toDexTypeIgnorePrimitives(name)); if (clazz == null) { return new AbsentClassSubject(this, reference); } return new FoundClassSubject(this, clazz, MappingWrapper.create(mapping, naming), reference); } + public ClassSubject clazz(ClassReference reference) { + return clazz(reference, ANY); + } + public ClassSubject companionClassFor(Class<?> clazz) { return clazz(SyntheticItemsTestUtils.syntheticCompanionClass(clazz)); } @@ -402,6 +426,18 @@ return builder.build(); } + public boolean hasExactlyProgramClasses(Class<?>... classes) { + return hasExactlyProgramClasses(Arrays.asList(classes)); + } + + public boolean hasExactlyProgramClasses(Collection<Class<?>> classes) { + Set<ClassReference> descriptors = + classes.stream().map(Reference::classFromClass).collect(Collectors.toSet()); + BooleanBox allFound = new BooleanBox(true); + forAllClasses(clazz -> allFound.and(descriptors.remove(clazz.reference))); + return descriptors.isEmpty() && allFound.get(); + } + public Stream<InstructionSubject> streamInstructions() { return allClasses().stream() .flatMap(cls -> cls.allMethods(MethodSubject::hasCode).stream())