Merge commit 'e88c5d81' into dev-release
diff --git a/infra/config/global/generated/cr-buildbucket.cfg b/infra/config/global/generated/cr-buildbucket.cfg
index 31f7a57..9dae144 100644
--- a/infra/config/global/generated/cr-buildbucket.cfg
+++ b/infra/config/global/generated/cr-buildbucket.cfg
@@ -26,13 +26,17 @@
       dimensions: "cpu:x86-64"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_wrapper:\"tools/archive.py\""
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_wrapper": "tools/archive.py"'
+        '}'
       priority: 25
       execution_timeout_secs: 1800
       expiration_secs: 126000
@@ -55,13 +59,17 @@
       dimensions: "cpu:x86-64"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_wrapper:\"tools/archive.py\""
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_wrapper": "tools/archive.py"'
+        '}'
       priority: 25
       execution_timeout_secs: 1800
       expiration_secs: 126000
@@ -84,13 +92,21 @@
       dimensions: "cpu:x86-64"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--no_internal\",\"--desugared-library\",\"HEAD\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--no_internal",'
+        '    "--desugared-library",'
+        '    "HEAD"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 43200
       expiration_secs: 126000
@@ -113,13 +129,23 @@
       dimensions: "cpu:x86-64"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--no_internal\",\"--desugared-library\",\"HEAD\",\"--desugared-library-configuration\",\"jdk11\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--no_internal",'
+        '    "--desugared-library",'
+        '    "HEAD",'
+        '    "--desugared-library-configuration",'
+        '    "jdk11"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 43200
       expiration_secs: 126000
@@ -142,13 +168,17 @@
       dimensions: "cpu:x86-64"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_wrapper:\"tools/archive_desugar_jdk_libs.py\""
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_wrapper": "tools/archive_desugar_jdk_libs.py"'
+        '}'
       priority: 25
       execution_timeout_secs: 3600
       expiration_secs: 126000
@@ -172,13 +202,24 @@
       dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--dex_vm=10.0.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--dex_vm=10.0.0",'
+        '    "--all_tests",'
+        '    "--tool=r8",'
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
@@ -202,13 +243,24 @@
       dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--dex_vm=10.0.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--dex_vm=10.0.0",'
+        '    "--all_tests",'
+        '    "--tool=r8",'
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
@@ -232,13 +284,24 @@
       dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--dex_vm=12.0.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--dex_vm=12.0.0",'
+        '    "--all_tests",'
+        '    "--tool=r8",'
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
@@ -262,13 +325,24 @@
       dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--dex_vm=12.0.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--dex_vm=12.0.0",'
+        '    "--all_tests",'
+        '    "--tool=r8",'
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
@@ -292,13 +366,24 @@
       dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--dex_vm=4.0.4\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--dex_vm=4.0.4",'
+        '    "--all_tests",'
+        '    "--tool=r8",'
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
@@ -322,13 +407,24 @@
       dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--dex_vm=4.0.4\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--dex_vm=4.0.4",'
+        '    "--all_tests",'
+        '    "--tool=r8",'
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
@@ -352,13 +448,24 @@
       dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--dex_vm=4.4.4\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--dex_vm=4.4.4",'
+        '    "--all_tests",'
+        '    "--tool=r8",'
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
@@ -382,13 +489,24 @@
       dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--dex_vm=4.4.4\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--dex_vm=4.4.4",'
+        '    "--all_tests",'
+        '    "--tool=r8",'
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
@@ -412,13 +530,24 @@
       dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--dex_vm=5.1.1\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--dex_vm=5.1.1",'
+        '    "--all_tests",'
+        '    "--tool=r8",'
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
@@ -442,13 +571,24 @@
       dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--dex_vm=5.1.1\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--dex_vm=5.1.1",'
+        '    "--all_tests",'
+        '    "--tool=r8",'
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
@@ -472,13 +612,24 @@
       dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--dex_vm=6.0.1\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--dex_vm=6.0.1",'
+        '    "--all_tests",'
+        '    "--tool=r8",'
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
@@ -502,13 +653,24 @@
       dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--dex_vm=6.0.1\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--dex_vm=6.0.1",'
+        '    "--all_tests",'
+        '    "--tool=r8",'
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
@@ -532,13 +694,24 @@
       dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--dex_vm=7.0.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--dex_vm=7.0.0",'
+        '    "--all_tests",'
+        '    "--tool=r8",'
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
@@ -562,13 +735,24 @@
       dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--dex_vm=7.0.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--dex_vm=7.0.0",'
+        '    "--all_tests",'
+        '    "--tool=r8",'
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
@@ -592,13 +776,24 @@
       dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--dex_vm=8.1.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--dex_vm=8.1.0",'
+        '    "--all_tests",'
+        '    "--tool=r8",'
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
@@ -622,13 +817,24 @@
       dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--dex_vm=8.1.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--dex_vm=8.1.0",'
+        '    "--all_tests",'
+        '    "--tool=r8",'
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
@@ -652,13 +858,24 @@
       dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--dex_vm=9.0.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--dex_vm=9.0.0",'
+        '    "--all_tests",'
+        '    "--tool=r8",'
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
@@ -682,13 +899,24 @@
       dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--dex_vm=9.0.0\",\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--dex_vm=9.0.0",'
+        '    "--all_tests",'
+        '    "--tool=r8",'
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
@@ -712,13 +940,24 @@
       dimensions: "jctf:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\",\"--dex_vm=all\",\"--tool=d8\",\"--only_jctf\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures",'
+        '    "--dex_vm=all",'
+        '    "--tool=d8",'
+        '    "--only_jctf"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 43200
       expiration_secs: 126000
@@ -742,13 +981,24 @@
       dimensions: "jctf:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\",\"--dex_vm=all\",\"--tool=d8\",\"--only_jctf\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures",'
+        '    "--dex_vm=all",'
+        '    "--tool=d8",'
+        '    "--only_jctf"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 43200
       expiration_secs: 126000
@@ -772,13 +1022,23 @@
       dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--runtimes=dex-default\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--runtimes=dex-default",'
+        '    "--tool=r8",'
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
@@ -802,13 +1062,23 @@
       dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--runtimes=dex-default\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--runtimes=dex-default",'
+        '    "--tool=r8",'
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
@@ -832,14 +1102,20 @@
       dimensions: "internal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--bot\"]"
-        properties_j: "test_wrapper:\"tools/internal_test.py\""
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--bot"'
+        '  ],'
+        '  "test_wrapper": "tools/internal_test.py"'
+        '}'
       priority: 25
       execution_timeout_secs: 43200
       expiration_secs: 126000
@@ -863,14 +1139,20 @@
       dimensions: "internal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--bot\"]"
-        properties_j: "test_wrapper:\"tools/internal_test.py\""
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--bot"'
+        '  ],'
+        '  "test_wrapper": "tools/internal_test.py"'
+        '}'
       priority: 25
       execution_timeout_secs: 43200
       expiration_secs: 126000
@@ -894,13 +1176,23 @@
       dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--runtimes=jdk11\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--runtimes=jdk11",'
+        '    "--tool=r8",'
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
@@ -924,13 +1216,23 @@
       dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--runtimes=jdk11\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--runtimes=jdk11",'
+        '    "--tool=r8",'
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
@@ -954,13 +1256,23 @@
       dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--runtimes=jdk8\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--runtimes=jdk8",'
+        '    "--tool=r8",'
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
@@ -984,13 +1296,23 @@
       dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--runtimes=jdk8\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--runtimes=jdk8",'
+        '    "--tool=r8",'
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
@@ -1014,13 +1336,23 @@
       dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--runtimes=jdk9\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--runtimes=jdk9",'
+        '    "--tool=r8",'
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
@@ -1044,13 +1376,23 @@
       dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--runtimes=jdk9\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--runtimes=jdk9",'
+        '    "--tool=r8",'
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
@@ -1073,13 +1415,25 @@
       dimensions: "cpu:x86-64"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--runtimes=dex-default:jdk11\",\"--kotlin-compiler-dev\",\"--one_line_per_test\",\"--archive_failures\",\"--no-internal\",\"*kotlin*\",\"*debug*\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--runtimes=dex-default:jdk11",'
+        '    "--kotlin-compiler-dev",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures",'
+        '    "--no-internal",'
+        '    "*kotlin*",'
+        '    "*debug*"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 43200
       expiration_secs: 126000
@@ -1102,13 +1456,25 @@
       dimensions: "cpu:x86-64"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--runtimes=dex-default:jdk11\",\"--kotlin-compiler-old\",\"--one_line_per_test\",\"--archive_failures\",\"--no-internal\",\"*kotlin*\",\"*debug*\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--runtimes=dex-default:jdk11",'
+        '    "--kotlin-compiler-old",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures",'
+        '    "--no-internal",'
+        '    "*kotlin*",'
+        '    "*debug*"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 43200
       expiration_secs: 126000
@@ -1132,13 +1498,23 @@
       dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--runtimes=none\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--runtimes=none",'
+        '    "--tool=r8",'
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
@@ -1162,13 +1538,23 @@
       dimensions: "normal:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--runtimes=none\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--runtimes=none",'
+        '    "--tool=r8",'
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
@@ -1192,13 +1578,24 @@
       dimensions: "jctf:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\",\"--dex_vm=all\",\"--tool=r8cf\",\"--only_jctf\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures",'
+        '    "--dex_vm=all",'
+        '    "--tool=r8cf",'
+        '    "--only_jctf"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 43200
       expiration_secs: 126000
@@ -1222,13 +1619,24 @@
       dimensions: "jctf:true"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\",\"--dex_vm=all\",\"--tool=r8cf\",\"--only_jctf\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures",'
+        '    "--dex_vm=all",'
+        '    "--tool=r8cf",'
+        '    "--only_jctf"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 43200
       expiration_secs: 126000
@@ -1251,14 +1659,20 @@
       dimensions: "cpu:x86-64"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--bot\"]"
-        properties_j: "test_wrapper:\"tools/run_on_app_dump.py\""
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--bot"'
+        '  ],'
+        '  "test_wrapper": "tools/run_on_app_dump.py"'
+        '}'
       priority: 26
       execution_timeout_secs: 43200
       expiration_secs: 126000
@@ -1281,14 +1695,20 @@
       dimensions: "cpu:x86-64"
       dimensions: "os:Ubuntu-16.04"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--bot\"]"
-        properties_j: "test_wrapper:\"tools/run_on_app_dump.py\""
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--bot"'
+        '  ],'
+        '  "test_wrapper": "tools/run_on_app_dump.py"'
+        '}'
       priority: 26
       execution_timeout_secs: 43200
       expiration_secs: 126000
@@ -1311,13 +1731,23 @@
       dimensions: "cpu:x86-64"
       dimensions: "os:Windows-10"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--all_tests",'
+        '    "--tool=r8",'
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
@@ -1340,13 +1770,23 @@
       dimensions: "cpu:x86-64"
       dimensions: "os:Windows-10"
       dimensions: "pool:luci.r8.ci"
-      recipe {
-        name: "rex"
+      exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
         cipd_version: "refs/heads/master"
-        properties_j: "builder_group:\"internal.client.r8\""
-        properties_j: "test_options:[\"--all_tests\",\"--tool=r8\",\"--no_internal\",\"--one_line_per_test\",\"--archive_failures\"]"
+        cmd: "luciexe"
       }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--all_tests",'
+        '    "--tool=r8",'
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures"'
+        '  ]'
+        '}'
       priority: 26
       execution_timeout_secs: 21600
       expiration_secs: 126000
diff --git a/infra/config/global/main.star b/infra/config/global/main.star
index 6d178eb..a438dbc 100755
--- a/infra/config/global/main.star
+++ b/infra/config/global/main.star
@@ -136,8 +136,9 @@
       name="rex",
       cipd_package = "infra_internal/recipe_bundles/" +
           "chrome-internal.googlesource.com/chrome/" +
-	  "tools/build_limited/scripts/slave",
-      cipd_version = "refs/heads/master"
+          "tools/build_limited/scripts/slave",
+      cipd_version = "refs/heads/master",
+      use_bbagent = True
 )
 
 common_test_options = [
diff --git a/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java b/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java
index 61caf95..bce73f0 100644
--- a/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java
+++ b/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java
@@ -4,8 +4,8 @@
 package com.android.tools.r8;
 
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfiguration;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfigurationParser;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecificationParser;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
@@ -41,7 +41,7 @@
   private final boolean printVersion;
   private final Reporter reporter;
   private final int minApiLevel;
-  private final DesugaredLibraryConfiguration desugaredLibraryConfiguration;
+  private final LegacyDesugaredLibrarySpecification desugaredLibrarySpecification;
   private final AndroidApp app;
   private final StringConsumer backportedMethodListConsumer;
   private final DexItemFactory factory;
@@ -62,8 +62,8 @@
     return minApiLevel;
   }
 
-  public DesugaredLibraryConfiguration getDesugaredLibraryConfiguration() {
-    return desugaredLibraryConfiguration;
+  public LegacyDesugaredLibrarySpecification getDesugaredLibraryConfiguration() {
+    return desugaredLibrarySpecification;
   }
 
   public StringConsumer getBackportedMethodListConsumer() {
@@ -79,7 +79,7 @@
     this.printVersion = printVersion;
     this.reporter = new Reporter();
     this.minApiLevel = -1;
-    this.desugaredLibraryConfiguration = null;
+    this.desugaredLibrarySpecification = null;
     this.app = null;
     this.backportedMethodListConsumer = null;
     this.factory = null;
@@ -88,7 +88,7 @@
   private BackportedMethodListCommand(
       Reporter reporter,
       int minApiLevel,
-      DesugaredLibraryConfiguration desugaredLibraryConfiguration,
+      LegacyDesugaredLibrarySpecification desugaredLibrarySpecification,
       AndroidApp app,
       StringConsumer backportedMethodListConsumer,
       DexItemFactory factory) {
@@ -96,7 +96,7 @@
     this.printVersion = false;
     this.reporter = reporter;
     this.minApiLevel = minApiLevel;
-    this.desugaredLibraryConfiguration = desugaredLibraryConfiguration;
+    this.desugaredLibrarySpecification = desugaredLibrarySpecification;
     this.app = app;
     this.backportedMethodListConsumer = backportedMethodListConsumer;
     this.factory = factory;
@@ -105,7 +105,7 @@
   InternalOptions getInternalOptions() {
     InternalOptions options = new InternalOptions(factory, getReporter());
     options.setMinApiLevel(AndroidApiLevel.getAndroidApiLevel(minApiLevel));
-    options.desugaredLibraryConfiguration = desugaredLibraryConfiguration;
+    options.desugaredLibrarySpecification = desugaredLibrarySpecification;
     return options;
   }
 
@@ -178,7 +178,7 @@
 
     private final Reporter reporter;
     private int minApiLevel = AndroidApiLevel.B.getLevel();
-    private List<StringResource> desugaredLibraryConfigurationResources = new ArrayList<>();
+    private List<StringResource> desugaredLibrarySpecificationResources = new ArrayList<>();
     private final AndroidApp.Builder app;
     private StringConsumer backportedMethodListConsumer;
     private boolean printHelp = false;
@@ -215,7 +215,7 @@
 
     /** Desugared library configuration */
     public Builder addDesugaredLibraryConfiguration(StringResource configuration) {
-      desugaredLibraryConfigurationResources.add(configuration);
+      desugaredLibrarySpecificationResources.add(configuration);
       return this;
     }
 
@@ -245,18 +245,18 @@
       return this;
     }
 
-    DesugaredLibraryConfiguration getDesugaredLibraryConfiguration(DexItemFactory factory) {
-      if (desugaredLibraryConfigurationResources.isEmpty()) {
-        return DesugaredLibraryConfiguration.empty();
+    LegacyDesugaredLibrarySpecification getDesugaredLibraryConfiguration(DexItemFactory factory) {
+      if (desugaredLibrarySpecificationResources.isEmpty()) {
+        return LegacyDesugaredLibrarySpecification.empty();
       }
-      if (desugaredLibraryConfigurationResources.size() > 1) {
+      if (desugaredLibrarySpecificationResources.size() > 1) {
         reporter.fatalError("Only one desugared library configuration is supported.");
       }
-      StringResource desugaredLibraryConfigurationResource =
-          desugaredLibraryConfigurationResources.get(0);
-      DesugaredLibraryConfigurationParser libraryParser =
-          new DesugaredLibraryConfigurationParser(factory, null, false, getMinApiLevel());
-      return libraryParser.parse(desugaredLibraryConfigurationResource);
+      StringResource desugaredLibrarySpecificationResource =
+          desugaredLibrarySpecificationResources.get(0);
+      LegacyDesugaredLibrarySpecificationParser libraryParser =
+          new LegacyDesugaredLibrarySpecificationParser(factory, null, false, getMinApiLevel());
+      return libraryParser.parse(desugaredLibrarySpecificationResource);
     }
 
     /** Output file for the backported method list */
@@ -306,7 +306,7 @@
 
     public BackportedMethodListCommand build() {
       AndroidApp library = app.build();
-      if (!desugaredLibraryConfigurationResources.isEmpty()
+      if (!desugaredLibrarySpecificationResources.isEmpty()
           && library.getLibraryResourceProviders().isEmpty()) {
         reporter.error(
             new StringDiagnostic("With desugared library configuration a library is required"));
diff --git a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
index 4af2547..18b7c02 100644
--- a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
+++ b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
@@ -7,8 +7,8 @@
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.inspector.Inspector;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfiguration;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfigurationParser;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecificationParser;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
@@ -224,7 +224,7 @@
     private int minApiLevel = 0;
     private int threadCount = ThreadUtils.NOT_SPECIFIED;
     protected DesugarState desugarState = DesugarState.ON;
-    private List<StringResource> desugaredLibraryConfigurationResources = new ArrayList<>();
+    private List<StringResource> desugaredLibrarySpecificationResources = new ArrayList<>();
     private boolean includeClassesChecksum = false;
     private boolean lookupLibraryBeforeProgram = true;
     private boolean optimizeMultidexForLinearAlloc = false;
@@ -562,35 +562,35 @@
     /** Desugared library configuration */
     // Configuration "default" is for testing only and support will be dropped.
     public B addDesugaredLibraryConfiguration(String configuration) {
-      this.desugaredLibraryConfigurationResources.add(
+      this.desugaredLibrarySpecificationResources.add(
           StringResource.fromString(configuration, Origin.unknown()));
       return self();
     }
 
     /** Desugared library configuration */
     public B addDesugaredLibraryConfiguration(StringResource configuration) {
-      this.desugaredLibraryConfigurationResources.add(configuration);
+      this.desugaredLibrarySpecificationResources.add(configuration);
       return self();
     }
 
-    DesugaredLibraryConfiguration getDesugaredLibraryConfiguration(
+    LegacyDesugaredLibrarySpecification getDesugaredLibraryConfiguration(
         DexItemFactory factory, boolean libraryCompilation) {
-      if (desugaredLibraryConfigurationResources.isEmpty()) {
-        return DesugaredLibraryConfiguration.empty();
+      if (desugaredLibrarySpecificationResources.isEmpty()) {
+        return LegacyDesugaredLibrarySpecification.empty();
       }
-      if (desugaredLibraryConfigurationResources.size() > 1) {
+      if (desugaredLibrarySpecificationResources.size() > 1) {
         throw new CompilationError("Only one desugared library configuration is supported.");
       }
-      StringResource desugaredLibraryConfigurationResource =
-          desugaredLibraryConfigurationResources.get(0);
-      DesugaredLibraryConfigurationParser libraryParser =
-          new DesugaredLibraryConfigurationParser(
+      StringResource desugaredLibrarySpecificationResource =
+          desugaredLibrarySpecificationResources.get(0);
+      LegacyDesugaredLibrarySpecificationParser libraryParser =
+          new LegacyDesugaredLibrarySpecificationParser(
               factory, getReporter(), libraryCompilation, getMinApiLevel());
-      return libraryParser.parse(desugaredLibraryConfigurationResource);
+      return libraryParser.parse(desugaredLibrarySpecificationResource);
     }
 
     boolean hasDesugaredLibraryConfiguration() {
-      return !desugaredLibraryConfigurationResources.isEmpty();
+      return !desugaredLibrarySpecificationResources.isEmpty();
     }
 
     /** Encodes checksum for each class when generating dex files. */
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index 58753de..3b3e48e 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -28,10 +28,8 @@
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
 import com.android.tools.r8.jar.CfApplicationWriter;
 import com.android.tools.r8.kotlin.KotlinMetadataRewriter;
-import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.naming.PrefixRewritingNamingLens;
-import com.android.tools.r8.naming.ProguardMapSupplier;
 import com.android.tools.r8.naming.RecordRewritingNamingLens;
 import com.android.tools.r8.naming.signature.GenericSignatureRewriter;
 import com.android.tools.r8.origin.CommandLineOrigin;
@@ -44,7 +42,6 @@
 import com.android.tools.r8.utils.ExceptionUtils;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.InternalOptions.DesugarState;
-import com.android.tools.r8.utils.LineNumberOptimizer;
 import com.android.tools.r8.utils.StringDiagnostic;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.ThreadUtils;
@@ -172,7 +169,7 @@
       AndroidApp inputApp, InternalOptions options, ExecutorService executor, Timing timing)
       throws IOException {
     PrefixRewritingMapper rewritePrefix =
-        options.desugaredLibraryConfiguration.getPrefixRewritingMapper();
+        options.desugaredLibrarySpecification.getPrefixRewritingMapper();
     ApplicationReader applicationReader = new ApplicationReader(inputApp, options, timing);
     LazyLoadedDexApplication app = applicationReader.read(executor);
     AppInfo appInfo = AppInfo.createInitialAppInfo(app, applicationReader.readMainDexClasses(app));
@@ -269,11 +266,9 @@
       namingLens = RecordRewritingNamingLens.createRecordRewritingNamingLens(appView, namingLens);
 
       if (options.isGeneratingClassFiles()) {
-        ProguardMapSupplier proguardMapSupplier =
-            finalizeApplication(inputApp, appView, executor, namingLens);
-        new CfApplicationWriter(
-                appView, marker, GraphLens.getIdentityLens(), namingLens, proguardMapSupplier)
-            .write(options.getClassFileConsumer());
+        finalizeApplication(inputApp, appView, executor, namingLens);
+        new CfApplicationWriter(appView, marker, GraphLens.getIdentityLens(), namingLens)
+            .write(options.getClassFileConsumer(), inputApp);
       } else {
         if (!hasDexResources || !hasClassResources || !appView.rewritePrefix.isRewriting()) {
           // All inputs are either dex or cf, or there is nothing to rewrite.
@@ -314,17 +309,15 @@
                       executor, appView.appInfo().app(), appView.appInfo().getMainDexInfo());
           appView.setAppInfo(appView.appInfo().rebuildWithMainDexInfo(mainDexInfo));
         }
-        ProguardMapSupplier proguardMapSupplier =
-            finalizeApplication(inputApp, appView, executor, namingLens);
+        finalizeApplication(inputApp, appView, executor, namingLens);
 
         new ApplicationWriter(
                 appView,
                 marker == null ? null : ImmutableList.copyOf(markers),
                 appView.graphLens(),
                 InitClassLens.getThrowingInstance(),
-                namingLens,
-                proguardMapSupplier)
-            .write(executor);
+                namingLens)
+            .write(executor, inputApp);
       }
       options.printWarnings();
     } catch (ExecutionException e) {
@@ -338,19 +331,13 @@
     }
   }
 
-  private static ProguardMapSupplier finalizeApplication(
+  private static void finalizeApplication(
       AndroidApp inputApp,
       AppView<AppInfo> appView,
       ExecutorService executorService,
       NamingLens namingLens)
       throws ExecutionException {
     SyntheticFinalization.finalize(appView, executorService);
-    if (appView.options().proguardMapConsumer == null) {
-      return null;
-    }
-    ClassNameMapper classNameMapper =
-        LineNumberOptimizer.run(appView, appView.appInfo().app(), inputApp, namingLens);
-    return ProguardMapSupplier.create(classNameMapper, appView.options());
   }
 
   private static DexApplication rewriteNonDexInputs(
@@ -395,7 +382,6 @@
             GraphLens.getIdentityLens(),
             InitClassLens.getThrowingInstance(),
             desugaringLens,
-            null,
             convertedCfFiles)
         .write(executor);
     AndroidApp.Builder builder = AndroidApp.builder(inputApp);
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index 8d0f357..d667575 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -12,7 +12,7 @@
 import com.android.tools.r8.horizontalclassmerging.HorizontalClassMerger;
 import com.android.tools.r8.inspector.Inspector;
 import com.android.tools.r8.inspector.internal.InspectorImpl;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfiguration;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.shaking.ProguardConfigurationParser;
 import com.android.tools.r8.shaking.ProguardConfigurationRule;
@@ -288,7 +288,7 @@
       intermediate |= getProgramConsumer() instanceof DexFilePerClassFileConsumer;
 
       DexItemFactory factory = new DexItemFactory();
-      DesugaredLibraryConfiguration libraryConfiguration =
+      LegacyDesugaredLibrarySpecification desugaredLibrarySpecification =
           getDesugaredLibraryConfiguration(factory, false);
 
       ImmutableList<ProguardConfigurationRule> mainDexKeepRules =
@@ -308,7 +308,7 @@
           getDexClassChecksumFilter(),
           getDesugarGraphConsumer(),
           desugaredLibraryKeepRuleConsumer,
-          libraryConfiguration,
+          desugaredLibrarySpecification,
           getAssertionsConfiguration(),
           getOutputInspections(),
           synthesizedClassPrefix,
@@ -328,7 +328,7 @@
   private final boolean intermediate;
   private final DesugarGraphConsumer desugarGraphConsumer;
   private final StringConsumer desugaredLibraryKeepRuleConsumer;
-  private final DesugaredLibraryConfiguration libraryConfiguration;
+  private final LegacyDesugaredLibrarySpecification desugaredLibrarySpecification;
   private final String synthesizedClassPrefix;
   private final boolean skipDump;
   private final boolean enableMainDexListCheck;
@@ -390,7 +390,7 @@
       BiPredicate<String, Long> dexClassChecksumFilter,
       DesugarGraphConsumer desugarGraphConsumer,
       StringConsumer desugaredLibraryKeepRuleConsumer,
-      DesugaredLibraryConfiguration libraryConfiguration,
+      LegacyDesugaredLibrarySpecification desugaredLibrarySpecification,
       List<AssertionsConfiguration> assertionsConfiguration,
       List<Consumer<Inspector>> outputInspections,
       String synthesizedClassPrefix,
@@ -422,7 +422,7 @@
     this.intermediate = intermediate;
     this.desugarGraphConsumer = desugarGraphConsumer;
     this.desugaredLibraryKeepRuleConsumer = desugaredLibraryKeepRuleConsumer;
-    this.libraryConfiguration = libraryConfiguration;
+    this.desugaredLibrarySpecification = desugaredLibrarySpecification;
     this.synthesizedClassPrefix = synthesizedClassPrefix;
     this.skipDump = skipDump;
     this.enableMainDexListCheck = enableMainDexListCheck;
@@ -436,7 +436,7 @@
     intermediate = false;
     desugarGraphConsumer = null;
     desugaredLibraryKeepRuleConsumer = null;
-    libraryConfiguration = null;
+    desugaredLibrarySpecification = null;
     synthesizedClassPrefix = null;
     skipDump = false;
     enableMainDexListCheck = true;
@@ -500,7 +500,7 @@
     internal.dexClassChecksumFilter = getDexClassChecksumFilter();
     internal.enableInheritanceClassInDexDistributor = isOptimizeMultidexForLinearAlloc();
 
-    internal.desugaredLibraryConfiguration = libraryConfiguration;
+    internal.desugaredLibrarySpecification = desugaredLibrarySpecification;
     internal.synthesizedClassPrefix = synthesizedClassPrefix;
     internal.desugaredLibraryKeepRuleConsumer = desugaredLibraryKeepRuleConsumer;
 
@@ -528,7 +528,7 @@
     dumpBaseCommandOptions(builder);
     return builder
         .setIntermediate(intermediate)
-        .setDesugaredLibraryConfiguration(libraryConfiguration)
+        .setDesugaredLibraryConfiguration(desugaredLibrarySpecification)
         .setMainDexKeepRules(mainDexKeepRules)
         .build();
   }
diff --git a/src/main/java/com/android/tools/r8/DexFileMergerHelper.java b/src/main/java/com/android/tools/r8/DexFileMergerHelper.java
index f51d700..d8e8e69 100644
--- a/src/main/java/com/android/tools/r8/DexFileMergerHelper.java
+++ b/src/main/java/com/android/tools/r8/DexFileMergerHelper.java
@@ -107,8 +107,7 @@
                 markers,
                 GraphLens.getIdentityLens(),
                 InitClassLens.getThrowingInstance(),
-                NamingLens.getIdentityLens(),
-                null);
+                NamingLens.getIdentityLens());
         writer.write(executor);
         options.printWarnings();
       } catch (ExecutionException e) {
diff --git a/src/main/java/com/android/tools/r8/DexSplitterHelper.java b/src/main/java/com/android/tools/r8/DexSplitterHelper.java
index 875635f..fdcdaf2 100644
--- a/src/main/java/com/android/tools/r8/DexSplitterHelper.java
+++ b/src/main/java/com/android/tools/r8/DexSplitterHelper.java
@@ -115,7 +115,6 @@
                   GraphLens.getIdentityLens(),
                   InitClassLens.getThrowingInstance(),
                   NamingLens.getIdentityLens(),
-                  null,
                   consumer)
               .write(executor);
           options.printWarnings();
diff --git a/src/main/java/com/android/tools/r8/DumpOptions.java b/src/main/java/com/android/tools/r8/DumpOptions.java
index 14ae9c6..c7f3345 100644
--- a/src/main/java/com/android/tools/r8/DumpOptions.java
+++ b/src/main/java/com/android/tools/r8/DumpOptions.java
@@ -7,7 +7,7 @@
 import com.android.tools.r8.dex.Marker.Tool;
 import com.android.tools.r8.experimental.startup.StartupConfiguration;
 import com.android.tools.r8.features.FeatureSplitConfiguration;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfiguration;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
 import com.android.tools.r8.shaking.ProguardConfiguration;
 import com.android.tools.r8.shaking.ProguardConfigurationRule;
 import com.android.tools.r8.utils.InternalOptions.DesugarState;
@@ -50,7 +50,7 @@
   private final Optional<Boolean> forceProguardCompatibility;
 
   // Dump if present.
-  private final DesugaredLibraryConfiguration desugaredLibraryConfiguration;
+  private final LegacyDesugaredLibrarySpecification desugaredLibrarySpecification;
   private final FeatureSplitConfiguration featureSplitConfiguration;
   private final ProguardConfiguration proguardConfiguration;
   private final List<ProguardConfigurationRule> mainDexKeepRules;
@@ -62,7 +62,7 @@
       Tool tool,
       CompilationMode compilationMode,
       int minAPI,
-      DesugaredLibraryConfiguration desugaredLibraryConfiguration,
+      LegacyDesugaredLibrarySpecification desugaredLibrarySpecification,
       boolean optimizeMultidexForLinearAlloc,
       int threadCount,
       DesugarState desugarState,
@@ -78,7 +78,7 @@
     this.tool = tool;
     this.compilationMode = compilationMode;
     this.minApi = minAPI;
-    this.desugaredLibraryConfiguration = desugaredLibraryConfiguration;
+    this.desugaredLibrarySpecification = desugaredLibrarySpecification;
     this.optimizeMultidexForLinearAlloc = optimizeMultidexForLinearAlloc;
     this.threadCount = threadCount;
     this.desugarState = desugarState;
@@ -133,13 +133,13 @@
   }
 
   private boolean hasDesugaredLibraryConfiguration() {
-    return desugaredLibraryConfiguration != null
-        && !desugaredLibraryConfiguration.isEmptyConfiguration();
+    return desugaredLibrarySpecification != null
+        && !desugaredLibrarySpecification.isEmptyConfiguration();
   }
 
   public String getDesugaredLibraryJsonSource() {
     if (hasDesugaredLibraryConfiguration()) {
-      return desugaredLibraryConfiguration.getJsonSource();
+      return desugaredLibrarySpecification.getJsonSource();
     }
     return null;
   }
@@ -186,7 +186,7 @@
     private Optional<Boolean> minification = Optional.empty();
     private Optional<Boolean> forceProguardCompatibility = Optional.empty();
     // Dump if present.
-    private DesugaredLibraryConfiguration desugaredLibraryConfiguration;
+    private LegacyDesugaredLibrarySpecification desugaredLibrarySpecification;
     private FeatureSplitConfiguration featureSplitConfiguration;
     private ProguardConfiguration proguardConfiguration;
     private List<ProguardConfigurationRule> mainDexKeepRules;
@@ -209,8 +209,8 @@
     }
 
     public Builder setDesugaredLibraryConfiguration(
-        DesugaredLibraryConfiguration desugaredLibraryConfiguration) {
-      this.desugaredLibraryConfiguration = desugaredLibraryConfiguration;
+        LegacyDesugaredLibrarySpecification desugaredLibrarySpecification) {
+      this.desugaredLibrarySpecification = desugaredLibrarySpecification;
       return this;
     }
 
@@ -280,7 +280,7 @@
           tool,
           compilationMode,
           minApi,
-          desugaredLibraryConfiguration,
+          desugaredLibrarySpecification,
           optimizeMultidexForLinearAlloc,
           threadCount,
           desugarState,
diff --git a/src/main/java/com/android/tools/r8/GenerateLintFiles.java b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
index 68b9354..660b1ef 100644
--- a/src/main/java/com/android/tools/r8/GenerateLintFiles.java
+++ b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
@@ -34,8 +34,8 @@
 import com.android.tools.r8.graph.LazyLoadedDexApplication;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfiguration;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfigurationParser;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecificationParser;
 import com.android.tools.r8.jar.CfApplicationWriter;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.origin.Origin;
@@ -73,7 +73,7 @@
   private final Reporter reporter = new Reporter();
   private final InternalOptions options = new InternalOptions(factory, reporter);
 
-  private final DesugaredLibraryConfiguration desugaredLibraryConfiguration;
+  private final LegacyDesugaredLibrarySpecification desugaredLibrarySpecification;
   private final Path desugaredLibraryImplementation;
   private final Path outputDirectory;
 
@@ -82,7 +82,7 @@
   public GenerateLintFiles(
       String desugarConfigurationPath, String desugarImplementationPath, String outputDirectory)
       throws Exception {
-    this.desugaredLibraryConfiguration =
+    this.desugaredLibrarySpecification =
         readDesugaredLibraryConfiguration(desugarConfigurationPath);
     this.desugaredLibraryImplementation = Paths.get(desugarImplementationPath);
     this.outputDirectory = Paths.get(outputDirectory);
@@ -119,9 +119,9 @@
     return Paths.get(jar);
   }
 
-  private DesugaredLibraryConfiguration readDesugaredLibraryConfiguration(
+  private LegacyDesugaredLibrarySpecification readDesugaredLibraryConfiguration(
       String desugarConfigurationPath) {
-    return new DesugaredLibraryConfigurationParser(
+    return new LegacyDesugaredLibrarySpecificationParser(
             factory, reporter, false, AndroidApiLevel.B.getLevel())
         .parse(StringResource.fromFile(Paths.get(desugarConfigurationPath)));
   }
@@ -230,7 +230,7 @@
     for (DexProgramClass clazz : dexApplication.classes()) {
       String className = clazz.toSourceString();
       // All the methods with the rewritten prefix are supported.
-      for (String prefix : desugaredLibraryConfiguration.getRewritePrefix().keySet()) {
+      for (String prefix : desugaredLibrarySpecification.getRewritePrefix().keySet()) {
         if (clazz.accessFlags.isPublic() && className.startsWith(prefix)) {
           DexProgramClass implementationClass =
               implementationApplication.programDefinitionFor(clazz.getType());
@@ -259,11 +259,11 @@
 
       // All retargeted methods are supported.
       for (DexEncodedMethod method : clazz.methods()) {
-        if (desugaredLibraryConfiguration
+        if (desugaredLibrarySpecification
             .getRetargetCoreLibMember()
             .keySet()
             .contains(method.getReference().name)) {
-          if (desugaredLibraryConfiguration
+          if (desugaredLibrarySpecification
               .getRetargetCoreLibMember()
               .get(method.getReference().name)
               .containsKey(clazz.type)) {
@@ -275,7 +275,7 @@
       }
 
       // All emulated interfaces static and default methods are supported.
-      if (desugaredLibraryConfiguration.getEmulateLibraryInterface().containsKey(clazz.type)) {
+      if (desugaredLibrarySpecification.getEmulateLibraryInterface().containsKey(clazz.type)) {
         assert clazz.isInterface();
         for (DexEncodedMethod method : clazz.methods()) {
           if (!method.isDefaultMethod() && !method.isStatic()) {
@@ -352,8 +352,7 @@
             appView,
             options.getMarker(Tool.L8),
             GraphLens.getIdentityLens(),
-            NamingLens.getIdentityLens(),
-            null);
+            NamingLens.getIdentityLens());
     ClassFileConsumer consumer =
         new ClassFileConsumer.ArchiveConsumer(
             lintFile(compilationApiLevel, minApiLevel, FileUtils.JAR_EXTENSION));
@@ -385,7 +384,7 @@
   private void run() throws Exception {
     // Run over all the API levels that the desugared library can be compiled with.
     for (int apiLevel = AndroidApiLevel.LATEST.getLevel();
-        apiLevel >= desugaredLibraryConfiguration.getRequiredCompilationApiLevel().getLevel();
+        apiLevel >= desugaredLibrarySpecification.getRequiredCompilationApiLevel().getLevel();
         apiLevel--) {
       System.out.println("Generating lint files for compile API " + apiLevel);
       run(apiLevel);
diff --git a/src/main/java/com/android/tools/r8/L8.java b/src/main/java/com/android/tools/r8/L8.java
index b0eec1a..c3bf91f 100644
--- a/src/main/java/com/android/tools/r8/L8.java
+++ b/src/main/java/com/android/tools/r8/L8.java
@@ -19,6 +19,7 @@
 import com.android.tools.r8.naming.PrefixRewritingNamingLens;
 import com.android.tools.r8.naming.signature.GenericSignatureRewriter;
 import com.android.tools.r8.origin.CommandLineOrigin;
+import com.android.tools.r8.shaking.AnnotationRemover;
 import com.android.tools.r8.shaking.L8TreePruner;
 import com.android.tools.r8.synthesis.SyntheticFinalization;
 import com.android.tools.r8.utils.AndroidApp;
@@ -134,6 +135,10 @@
 
       AppView<AppInfo> appView = readApp(inputApp, options, executor, timing);
 
+      if (!options.disableL8AnnotationRemoval) {
+        AnnotationRemover.clearAnnotations(appView);
+      }
+
       new IRConverter(appView, timing).convert(appView, executor);
 
       SyntheticFinalization.finalize(appView, executor);
@@ -141,8 +146,7 @@
       NamingLens namingLens = PrefixRewritingNamingLens.createPrefixRewritingNamingLens(appView);
       new GenericSignatureRewriter(appView, namingLens).run(appView.appInfo().classes(), executor);
 
-      new CfApplicationWriter(
-              appView, options.getMarker(Tool.L8), appView.graphLens(), namingLens, null)
+      new CfApplicationWriter(appView, options.getMarker(Tool.L8), appView.graphLens(), namingLens)
           .write(options.getClassFileConsumer());
       options.printWarnings();
     } catch (ExecutionException e) {
@@ -163,7 +167,7 @@
         new ApplicationReader(inputApp, options, timing).read(executor);
 
     PrefixRewritingMapper rewritePrefix =
-        options.desugaredLibraryConfiguration.getPrefixRewritingMapper();
+        options.desugaredLibrarySpecification.getPrefixRewritingMapper();
 
     DexApplication app = new L8TreePruner(options).prune(lazyApp, rewritePrefix);
     return AppView.createForL8(AppInfo.createInitialAppInfo(app), rewritePrefix);
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java
index 51ea781..c39a041 100644
--- a/src/main/java/com/android/tools/r8/L8Command.java
+++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -12,7 +12,7 @@
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.horizontalclassmerging.HorizontalClassMerger;
 import com.android.tools.r8.inspector.Inspector;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfiguration;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
@@ -42,7 +42,7 @@
 
   private final D8Command d8Command;
   private final R8Command r8Command;
-  private final DesugaredLibraryConfiguration libraryConfiguration;
+  private final LegacyDesugaredLibrarySpecification desugaredLibrarySpecification;
   private final DexItemFactory factory;
 
   boolean isShrinking() {
@@ -95,7 +95,7 @@
       Reporter diagnosticsHandler,
       boolean encodeChecksum,
       BiPredicate<String, Long> dexClassChecksumFilter,
-      DesugaredLibraryConfiguration libraryConfiguration,
+      LegacyDesugaredLibrarySpecification desugaredLibrarySpecification,
       List<AssertionsConfiguration> assertionsConfiguration,
       List<Consumer<Inspector>> outputInspections,
       int threadCount,
@@ -121,7 +121,7 @@
         null);
     this.d8Command = d8Command;
     this.r8Command = r8Command;
-    this.libraryConfiguration = libraryConfiguration;
+    this.desugaredLibrarySpecification = desugaredLibrarySpecification;
     this.factory = factory;
   }
 
@@ -129,7 +129,7 @@
     super(printHelp, printVersion);
     r8Command = null;
     d8Command = null;
-    libraryConfiguration = null;
+    desugaredLibrarySpecification = null;
     factory = null;
   }
 
@@ -194,10 +194,10 @@
     assert internal.enableInheritanceClassInDexDistributor;
     internal.enableInheritanceClassInDexDistributor = false;
 
-    assert libraryConfiguration != null;
-    internal.desugaredLibraryConfiguration = libraryConfiguration;
+    assert desugaredLibrarySpecification != null;
+    internal.desugaredLibrarySpecification = desugaredLibrarySpecification;
     internal.synthesizedClassPrefix =
-        libraryConfiguration.getSynthesizedLibraryClassesPackagePrefix();
+        desugaredLibrarySpecification.getSynthesizedLibraryClassesPackagePrefix();
 
     // Default is to remove all javac generated assertion code when generating dex.
     assert internal.assertionsConfiguration == null;
@@ -332,7 +332,7 @@
       }
 
       DexItemFactory factory = new DexItemFactory();
-      DesugaredLibraryConfiguration libraryConfiguration =
+      LegacyDesugaredLibrarySpecification desugaredLibrarySpecification =
           getDesugaredLibraryConfiguration(factory, true);
 
       R8Command r8Command = null;
@@ -346,7 +346,7 @@
             R8Command.builder(getReporter())
                 .addProgramResourceProvider((ProgramResourceProvider) l8CfConsumer)
                 .setSynthesizedClassesPrefix(
-                    libraryConfiguration.getSynthesizedLibraryClassesPackagePrefix())
+                    desugaredLibrarySpecification.getSynthesizedLibraryClassesPackagePrefix())
                 .setMinApiLevel(getMinApiLevel())
                 .setMode(getMode())
                 .setIncludeClassesChecksum(getIncludeClassesChecksum())
@@ -363,7 +363,7 @@
           r8Builder.setProguardMapConsumer(proguardMapConsumer);
         }
         r8Builder.addProguardConfiguration(
-            libraryConfiguration.getExtraKeepRules(), Origin.unknown());
+            desugaredLibrarySpecification.getExtraKeepRules(), Origin.unknown());
         // TODO(b/180903899): Remove rule when -dontwarn sun.misc.Unsafe is part of config.
         r8Builder.addProguardConfiguration(
             ImmutableList.of("-dontwarn sun.misc.Unsafe"), Origin.unknown());
@@ -377,7 +377,7 @@
             D8Command.builder(getReporter())
                 .addProgramResourceProvider((ProgramResourceProvider) l8CfConsumer)
                 .setSynthesizedClassesPrefix(
-                    libraryConfiguration.getSynthesizedLibraryClassesPackagePrefix())
+                    desugaredLibrarySpecification.getSynthesizedLibraryClassesPackagePrefix())
                 .setMinApiLevel(getMinApiLevel())
                 .setMode(getMode())
                 .setIncludeClassesChecksum(getIncludeClassesChecksum())
@@ -406,7 +406,7 @@
           getReporter(),
           getIncludeClassesChecksum(),
           getDexClassChecksumFilter(),
-          libraryConfiguration,
+          desugaredLibrarySpecification,
           getAssertionsConfiguration(),
           getOutputInspections(),
           getThreadCount(),
@@ -444,6 +444,6 @@
     if (r8Command != null) {
       builder.setProguardConfiguration(r8Command.getInternalOptions().getProguardConfiguration());
     }
-    return builder.setDesugaredLibraryConfiguration(libraryConfiguration).build();
+    return builder.setDesugaredLibraryConfiguration(desugaredLibrarySpecification).build();
   }
 }
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 722ae3e..171d1bc 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -7,6 +7,7 @@
 import static com.android.tools.r8.utils.AssertionUtils.forTesting;
 import static com.android.tools.r8.utils.ExceptionUtils.unwrapExecutionException;
 
+import com.android.tools.r8.androidapi.ApiReferenceStubber;
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.cf.code.CfPosition;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryKeepRuleGenerator;
@@ -48,7 +49,7 @@
 import com.android.tools.r8.ir.desugar.BackportedMethodRewriter;
 import com.android.tools.r8.ir.desugar.CfClassSynthesizerDesugaringCollection;
 import com.android.tools.r8.ir.desugar.CfClassSynthesizerDesugaringEventConsumer;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterLibraryTypeSynthesizer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeterLibraryTypeSynthesizer;
 import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
 import com.android.tools.r8.ir.desugar.records.RecordDesugaring;
 import com.android.tools.r8.ir.desugar.records.RecordFieldValuesRewriter;
@@ -62,12 +63,10 @@
 import com.android.tools.r8.jar.CfApplicationWriter;
 import com.android.tools.r8.kotlin.KotlinMetadataRewriter;
 import com.android.tools.r8.kotlin.KotlinMetadataUtils;
-import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.naming.Minifier;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.naming.PrefixRewritingNamingLens;
 import com.android.tools.r8.naming.ProguardMapMinifier;
-import com.android.tools.r8.naming.ProguardMapSupplier;
 import com.android.tools.r8.naming.RecordRewritingNamingLens;
 import com.android.tools.r8.naming.signature.GenericSignatureRewriter;
 import com.android.tools.r8.optimize.ClassAndMemberPublicizer;
@@ -109,7 +108,6 @@
 import com.android.tools.r8.utils.CollectionUtils;
 import com.android.tools.r8.utils.ExceptionUtils;
 import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.LineNumberOptimizer;
 import com.android.tools.r8.utils.SelfRetraceTest;
 import com.android.tools.r8.utils.StringDiagnostic;
 import com.android.tools.r8.utils.StringUtils;
@@ -217,7 +215,7 @@
       InitClassLens initClassLens,
       NamingLens namingLens,
       InternalOptions options,
-      ProguardMapSupplier proguardMapSupplier)
+      AndroidApp inputApp)
       throws ExecutionException {
     InspectorImpl.runInspections(options.outputInspections, appView.appInfo().classes());
     try {
@@ -228,8 +226,8 @@
       Set<Marker> markers = new HashSet<>(options.itemFactory.extractMarkers());
       markers.remove(marker);
       if (options.isGeneratingClassFiles()) {
-        new CfApplicationWriter(appView, marker, graphLens, namingLens, proguardMapSupplier)
-            .write(options.getClassFileConsumer());
+        new CfApplicationWriter(appView, marker, graphLens, namingLens)
+            .write(options.getClassFileConsumer(), inputApp);
       } else {
         new ApplicationWriter(
                 appView,
@@ -237,9 +235,8 @@
                 ImmutableList.<Marker>builder().add(marker).addAll(markers).build(),
                 graphLens,
                 initClassLens,
-                namingLens,
-                proguardMapSupplier)
-            .write(executorService);
+                namingLens)
+            .write(executorService, inputApp);
       }
     } catch (IOException e) {
       throw new RuntimeException("Cannot write application", e);
@@ -313,7 +310,7 @@
       if (!options.mainDexKeepRules.isEmpty()) {
         MainDexListBuilder.checkForAssumedLibraryTypes(appView.appInfo());
       }
-      if (!options.desugaredLibraryConfiguration.getRetargetCoreLibMember().isEmpty()) {
+      if (!options.desugaredLibrarySpecification.getRetargetCoreLibMember().isEmpty()) {
         DesugaredLibraryRetargeterLibraryTypeSynthesizer.checkForAssumedLibraryTypes(appView);
         DesugaredLibraryRetargeterLibraryTypeSynthesizer.amendLibraryWithRetargetedMembers(appView);
       }
@@ -786,14 +783,6 @@
 
       assert verifyMovedMethodsHaveOriginalMethodPosition(appView, getDirectApp(appView));
 
-      timing.begin("Line number remapping");
-      // When line number optimization is turned off the identity mapping for line numbers is
-      // used. We still run the line number optimizer to collect line numbers and inline frame
-      // information for the mapping file.
-      ClassNameMapper classNameMapper =
-          LineNumberOptimizer.run(appView, getDirectApp(appView), inputApp, namingLens);
-      timing.end();
-
       // If a method filter is present don't produce output since the application is likely partial.
       if (options.hasMethodsFilter()) {
         System.out.println("Finished compilation with method filter: ");
@@ -827,6 +816,8 @@
       namingLens = PrefixRewritingNamingLens.createPrefixRewritingNamingLens(appView, namingLens);
       namingLens = RecordRewritingNamingLens.createRecordRewritingNamingLens(appView, namingLens);
 
+      new ApiReferenceStubber(appView).run(executorService);
+
       timing.begin("MinifyKotlinMetadata");
       new KotlinMetadataRewriter(appView, namingLens).runForR8(executorService);
       timing.end();
@@ -853,7 +844,7 @@
           appView.initClassLens(),
           namingLens,
           options,
-          ProguardMapSupplier.create(classNameMapper, options));
+          inputApp);
 
       assert appView.getDontWarnConfiguration().validate(options);
 
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 4b53393..b51ee2e 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -15,7 +15,7 @@
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.inspector.Inspector;
 import com.android.tools.r8.inspector.internal.InspectorImpl;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfiguration;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
 import com.android.tools.r8.naming.SourceFileRewriter;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.origin.PathOrigin;
@@ -475,7 +475,7 @@
       List<ProguardConfigurationRule> mainDexKeepRules =
           ProguardConfigurationParser.parse(mainDexRules, factory, reporter);
 
-      DesugaredLibraryConfiguration libraryConfiguration =
+      LegacyDesugaredLibrarySpecification desugaredLibrarySpecification =
           getDesugaredLibraryConfiguration(factory, false);
 
       ProguardConfigurationParser parser =
@@ -585,7 +585,7 @@
               getIncludeClassesChecksum(),
               getDexClassChecksumFilter(),
               desugaredLibraryKeepRuleConsumer,
-              libraryConfiguration,
+              desugaredLibrarySpecification,
               featureSplitConfiguration,
               getAssertionsConfiguration(),
               getOutputInspections(),
@@ -669,7 +669,7 @@
   private final GraphConsumer mainDexKeptGraphConsumer;
   private final Consumer<List<ProguardConfigurationRule>> syntheticProguardRulesConsumer;
   private final StringConsumer desugaredLibraryKeepRuleConsumer;
-  private final DesugaredLibraryConfiguration libraryConfiguration;
+  private final LegacyDesugaredLibrarySpecification desugaredLibrarySpecification;
   private final FeatureSplitConfiguration featureSplitConfiguration;
   private final String synthesizedClassPrefix;
   private final boolean skipDump;
@@ -747,7 +747,7 @@
       boolean encodeChecksum,
       BiPredicate<String, Long> dexClassChecksumFilter,
       StringConsumer desugaredLibraryKeepRuleConsumer,
-      DesugaredLibraryConfiguration libraryConfiguration,
+      LegacyDesugaredLibrarySpecification desugaredLibrarySpecification,
       FeatureSplitConfiguration featureSplitConfiguration,
       List<AssertionsConfiguration> assertionsConfiguration,
       List<Consumer<Inspector>> outputInspections,
@@ -791,7 +791,7 @@
     this.mainDexKeptGraphConsumer = mainDexKeptGraphConsumer;
     this.syntheticProguardRulesConsumer = syntheticProguardRulesConsumer;
     this.desugaredLibraryKeepRuleConsumer = desugaredLibraryKeepRuleConsumer;
-    this.libraryConfiguration = libraryConfiguration;
+    this.desugaredLibrarySpecification = desugaredLibrarySpecification;
     this.featureSplitConfiguration = featureSplitConfiguration;
     this.synthesizedClassPrefix = synthesizedClassPrefix;
     this.skipDump = skipDump;
@@ -814,7 +814,7 @@
     mainDexKeptGraphConsumer = null;
     syntheticProguardRulesConsumer = null;
     desugaredLibraryKeepRuleConsumer = null;
-    libraryConfiguration = null;
+    desugaredLibrarySpecification = null;
     featureSplitConfiguration = null;
     synthesizedClassPrefix = null;
     skipDump = false;
@@ -942,7 +942,7 @@
 
     internal.enableInheritanceClassInDexDistributor = isOptimizeMultidexForLinearAlloc();
 
-    internal.desugaredLibraryConfiguration = libraryConfiguration;
+    internal.desugaredLibrarySpecification = desugaredLibrarySpecification;
     internal.synthesizedClassPrefix = synthesizedClassPrefix;
     internal.desugaredLibraryKeepRuleConsumer = desugaredLibraryKeepRuleConsumer;
 
@@ -1000,7 +1000,7 @@
         .setFeatureSplitConfiguration(featureSplitConfiguration)
         .setProguardConfiguration(proguardConfiguration)
         .setMainDexKeepRules(mainDexKeepRules)
-        .setDesugaredLibraryConfiguration(libraryConfiguration)
+        .setDesugaredLibraryConfiguration(desugaredLibrarySpecification)
         .build();
   }
 }
diff --git a/src/main/java/com/android/tools/r8/androidapi/AndroidApiLevelCompute.java b/src/main/java/com/android/tools/r8/androidapi/AndroidApiLevelCompute.java
index 4afafc1..fec4b65 100644
--- a/src/main/java/com/android/tools/r8/androidapi/AndroidApiLevelCompute.java
+++ b/src/main/java/com/android/tools/r8/androidapi/AndroidApiLevelCompute.java
@@ -54,14 +54,10 @@
     return new NoAndroidApiLevelCompute();
   }
 
-  public static ComputedApiLevel computeInitialMinApiLevel(InternalOptions options) {
-    if (options.apiModelingOptions().enableApiCallerIdentification) {
+  public ComputedApiLevel computeInitialMinApiLevel(InternalOptions options) {
       return options.getMinApiLevel() == AndroidApiLevel.ANDROID_PLATFORM
           ? ComputedApiLevel.platform()
           : new KnownApiLevel(options.getMinApiLevel());
-    } else {
-      return ComputedApiLevel.unknown();
-    }
   }
 
   public ComputedApiLevel getPlatformApiLevelOrUnknown(AppView<?> appView) {
@@ -84,6 +80,11 @@
         DexReference reference, ComputedApiLevel unknownValue) {
       return unknownValue;
     }
+
+    @Override
+    public ComputedApiLevel computeInitialMinApiLevel(InternalOptions options) {
+      return ComputedApiLevel.unknown();
+    }
   }
 
   public static class DefaultAndroidApiLevelCompute extends AndroidApiLevelCompute {
diff --git a/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java b/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java
index 27fbc38..b4609ce 100644
--- a/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java
+++ b/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java
@@ -9,14 +9,14 @@
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexReference;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfiguration;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.google.common.collect.ImmutableList;
 import java.util.List;
 
 public class AndroidApiReferenceLevelCache {
 
-  private final DesugaredLibraryConfiguration desugaredLibraryConfiguration;
+  private final LegacyDesugaredLibrarySpecification desugaredLibrarySpecification;
   private final AndroidApiLevelCompute apiLevelCompute;
   private final AndroidApiLevelDatabase androidApiLevelDatabase;
   private final AppView<?> appView;
@@ -31,7 +31,7 @@
     factory = appView.dexItemFactory();
     androidApiLevelDatabase =
         new AndroidApiLevelHashingDatabaseImpl(predefinedApiTypeLookupForHashing);
-    desugaredLibraryConfiguration = appView.options().desugaredLibraryConfiguration;
+    desugaredLibrarySpecification = appView.options().desugaredLibrarySpecification;
   }
 
   public static AndroidApiReferenceLevelCache create(
@@ -69,7 +69,7 @@
     if (reference.getContextType() == factory.objectType) {
       return appView.computedMinApiLevel();
     }
-    if (desugaredLibraryConfiguration.isSupported(reference, appView)) {
+    if (desugaredLibrarySpecification.isSupported(reference, appView)) {
       // If we end up desugaring the reference, the library classes is bridged by j$ which is part
       // of the program.
       return appView.computedMinApiLevel();
diff --git a/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java b/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
new file mode 100644
index 0000000..5071174
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
@@ -0,0 +1,298 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.androidapi;
+
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexLibraryClass;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexReference;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.MethodAccessFlags;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.ThrowExceptionCode;
+import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.synthesis.CommittedItems;
+import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
+import com.android.tools.r8.utils.ThreadUtils;
+import com.android.tools.r8.utils.WorkList;
+import com.google.common.collect.Sets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+
+public class ApiReferenceStubber {
+
+  private class ReferencesToApiLevelUseRegistry extends UseRegistry<ProgramMethod> {
+
+    public ReferencesToApiLevelUseRegistry(ProgramMethod context) {
+      super(appView, context);
+    }
+
+    @Override
+    public void registerInitClass(DexType type) {
+      checkReferenceToLibraryClass(type);
+    }
+
+    @Override
+    public void registerInvokeVirtual(DexMethod method) {
+      checkReferenceToLibraryClass(method);
+    }
+
+    @Override
+    public void registerInvokeDirect(DexMethod method) {
+      checkReferenceToLibraryClass(method);
+    }
+
+    @Override
+    public void registerInvokeStatic(DexMethod method) {
+      checkReferenceToLibraryClass(method);
+    }
+
+    @Override
+    public void registerInvokeInterface(DexMethod method) {
+      checkReferenceToLibraryClass(method);
+    }
+
+    @Override
+    public void registerInvokeSuper(DexMethod method) {
+      checkReferenceToLibraryClass(method);
+    }
+
+    @Override
+    public void registerInstanceFieldRead(DexField field) {
+      checkReferenceToLibraryClass(field.type);
+    }
+
+    @Override
+    public void registerInstanceFieldWrite(DexField field) {
+      checkReferenceToLibraryClass(field.type);
+    }
+
+    @Override
+    public void registerStaticFieldRead(DexField field) {
+      checkReferenceToLibraryClass(field.type);
+    }
+
+    @Override
+    public void registerStaticFieldWrite(DexField field) {
+      checkReferenceToLibraryClass(field.type);
+    }
+
+    @Override
+    public void registerTypeReference(DexType type) {
+      checkReferenceToLibraryClass(type);
+    }
+
+    private void checkReferenceToLibraryClass(DexReference reference) {
+      if (reference.isDexMember()) {
+        reference
+            .asDexMember()
+            .getReferencedBaseTypes(appView.dexItemFactory())
+            .forEach(
+                refType -> findReferencedLibraryClasses(appView.graphLens().lookupType(refType)));
+      }
+      DexType rewrittenType = appView.graphLens().lookupType(reference.getContextType());
+      findReferencedLibraryClasses(rewrittenType);
+      if (reference.isDexMethod()) {
+        findReferencedLibraryMethod(reference.asDexMethod());
+      }
+    }
+  }
+
+  private final AppView<? extends AppInfoWithClassHierarchy> appView;
+  private final Map<DexLibraryClass, Set<DexMethod>> libraryClassesToMock =
+      new ConcurrentHashMap<>();
+  private final Set<DexType> seenTypes = Sets.newConcurrentHashSet();
+  private final AndroidApiLevelCompute apiLevelCompute;
+  private final LegacyDesugaredLibrarySpecification desugaredLibraryConfiguration;
+
+  public ApiReferenceStubber(AppView<? extends AppInfoWithClassHierarchy> appView) {
+    this.appView = appView;
+    apiLevelCompute = AndroidApiLevelCompute.create(appView);
+    desugaredLibraryConfiguration = appView.options().desugaredLibrarySpecification;
+  }
+
+  public void run(ExecutorService executorService) throws ExecutionException {
+    if (appView.options().isGeneratingClassFiles()
+        || !appView.options().apiModelingOptions().enableStubbingOfClasses) {
+      return;
+    }
+    ThreadUtils.processItems(appView.appInfo().classes(), this::processClass, executorService);
+    if (libraryClassesToMock.isEmpty()) {
+      return;
+    }
+    libraryClassesToMock.forEach(
+        (clazz, methods) ->
+            mockMissingLibraryClass(
+                clazz,
+                methods,
+                ThrowExceptionCode.create(appView.dexItemFactory().noClassDefFoundErrorType)));
+    // Commit the synthetic items.
+    CommittedItems committedItems = appView.getSyntheticItems().commit(appView.appInfo().app());
+    if (appView.hasLiveness()) {
+      AppView<AppInfoWithLiveness> appInfoWithLivenessAppView = appView.withLiveness();
+      appInfoWithLivenessAppView.setAppInfo(
+          appInfoWithLivenessAppView.appInfo().rebuildWithLiveness(committedItems));
+    } else {
+      appView
+          .withClassHierarchy()
+          .setAppInfo(appView.appInfo().rebuildWithClassHierarchy(committedItems));
+    }
+  }
+
+  public void processClass(DexProgramClass clazz) {
+    findReferencedLibraryClasses(clazz.type);
+    clazz.forEachProgramMethodMatching(
+        DexEncodedMethod::hasCode,
+        method -> method.registerCodeReferences(new ReferencesToApiLevelUseRegistry(method)));
+  }
+
+  private void findReferencedLibraryMethod(DexMethod method) {
+    DexType holderType = method.getHolderType();
+    if (!holderType.isClassType()) {
+      return;
+    }
+    DexType rewrittenType = appView.graphLens().lookupType(holderType);
+    DexClass clazz = appView.definitionFor(rewrittenType);
+    if (clazz == null || !clazz.isLibraryClass()) {
+      return;
+    }
+    ComputedApiLevel apiLevel =
+        apiLevelCompute.computeApiLevelForLibraryReference(method, ComputedApiLevel.unknown());
+    if (apiLevel.isGreaterThan(appView.computedMinApiLevel())) {
+      ComputedApiLevel holderApiLevel =
+          apiLevelCompute.computeApiLevelForLibraryReference(
+              rewrittenType, ComputedApiLevel.unknown());
+      if (holderApiLevel.isUnknownApiLevel()) {
+        // Do not mock methods or classes where the holder is unknown.
+        return;
+      }
+      if (holderApiLevel.isGreaterThan(appView.computedMinApiLevel())) {
+        libraryClassesToMock
+            .computeIfAbsent(clazz.asLibraryClass(), ignored -> Sets.newConcurrentHashSet())
+            .add(method);
+      }
+    }
+  }
+
+  private void findReferencedLibraryClasses(DexType type) {
+    if (!type.isClassType()) {
+      return;
+    }
+    WorkList<DexType> workList = WorkList.newIdentityWorkList(type, seenTypes);
+    while (workList.hasNext()) {
+      DexClass clazz = appView.definitionFor(workList.next());
+      if (clazz == null) {
+        continue;
+      }
+      if (clazz.isLibraryClass()) {
+        ComputedApiLevel androidApiLevel =
+            apiLevelCompute.computeApiLevelForLibraryReference(
+                clazz.type, ComputedApiLevel.unknown());
+        if (androidApiLevel.isGreaterThan(appView.computedMinApiLevel())
+            && !androidApiLevel.isUnknownApiLevel()) {
+          libraryClassesToMock.computeIfAbsent(
+              clazz.asLibraryClass(), ignored -> Sets.newConcurrentHashSet());
+        }
+      }
+      workList.addIfNotSeen(clazz.allImmediateSupertypes());
+    }
+  }
+
+  private void mockMissingLibraryClass(
+      DexLibraryClass libraryClass,
+      Set<DexMethod> methodsToStub,
+      ThrowExceptionCode throwExceptionCode) {
+    if (libraryClass.getType() == appView.dexItemFactory().objectType
+        || libraryClass.getType().toDescriptorString().startsWith("Ljava/")) {
+      return;
+    }
+    if (desugaredLibraryConfiguration.isSupported(libraryClass.getType(), appView)) {
+      return;
+    }
+    appView
+        .appInfo()
+        .getSyntheticItems()
+        .addSyntheticClassWithLibraryContext(
+            appView,
+            libraryClass,
+            SyntheticKind.API_MODEL_STUB,
+            libraryClass.getType(),
+            classBuilder -> {
+              classBuilder
+                  .setSuperType(libraryClass.getSuperType())
+                  .setInterfaces(Arrays.asList(libraryClass.getInterfaces().values))
+                  .setVirtualMethods(
+                      buildLibraryMethodsForProgram(
+                          libraryClass, libraryClass.virtualMethods(), methodsToStub));
+              // Based on b/138781768#comment57 there is no significant reason to synthesize fields.
+              if (libraryClass.isInterface()) {
+                classBuilder.setInterface();
+              }
+              if (!libraryClass.isFinal()) {
+                classBuilder.unsetFinal();
+              }
+              List<DexEncodedMethod> directMethods =
+                  (!libraryClass.isInterface()
+                          || appView.options().canUseDefaultAndStaticInterfaceMethods())
+                      ? buildLibraryMethodsForProgram(
+                          libraryClass, libraryClass.directMethods(), methodsToStub)
+                      : new ArrayList<>();
+              // Add throwing static initializer
+              directMethods.add(
+                  DexEncodedMethod.syntheticBuilder()
+                      .setMethod(
+                          appView.dexItemFactory().createClassInitializer(libraryClass.getType()))
+                      .setAccessFlags(MethodAccessFlags.createForClassInitializer())
+                      .setCode(throwExceptionCode)
+                      .build());
+              classBuilder.setDirectMethods(directMethods);
+            });
+  }
+
+  private List<DexEncodedMethod> buildLibraryMethodsForProgram(
+      DexLibraryClass clazz, Iterable<DexEncodedMethod> methods, Set<DexMethod> methodsToMock) {
+    List<DexEncodedMethod> newMethods = new ArrayList<>();
+    methods.forEach(
+        method -> {
+          if (methodsToMock.contains(method.getReference())) {
+            DexEncodedMethod newMethod = buildLibraryMethodForProgram(clazz, method);
+            if (newMethod != null) {
+              newMethods.add(newMethod);
+            }
+          }
+        });
+    return newMethods;
+  }
+
+  private DexEncodedMethod buildLibraryMethodForProgram(
+      DexLibraryClass clazz, DexEncodedMethod method) {
+    assert !clazz.isInterface()
+        || !method.isStatic()
+        || appView.options().canUseDefaultAndStaticInterfaceMethods();
+    DexMethod newMethod = method.getReference().withHolder(clazz.type, appView.dexItemFactory());
+    boolean isVirtualInterfaceMethod = method.isVirtualMethod() && clazz.isInterface();
+    return DexEncodedMethod.syntheticBuilder(method)
+        .setMethod(newMethod)
+        .modifyAccessFlags(MethodAccessFlags::setSynthetic)
+        .applyIf(isVirtualInterfaceMethod, b -> b.modifyAccessFlags(MethodAccessFlags::setAbstract))
+        .applyIf(
+            !isVirtualInterfaceMethod && !method.isAbstract(),
+            b -> b.modifyAccessFlags(MethodAccessFlags::setNative))
+        .build();
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/bisect/Bisect.java b/src/main/java/com/android/tools/r8/bisect/Bisect.java
index 7406a28..262300f 100644
--- a/src/main/java/com/android/tools/r8/bisect/Bisect.java
+++ b/src/main/java/com/android/tools/r8/bisect/Bisect.java
@@ -194,8 +194,7 @@
             null,
             GraphLens.getIdentityLens(),
             InitClassLens.getThrowingInstance(),
-            NamingLens.getIdentityLens(),
-            null);
+            NamingLens.getIdentityLens());
     writer.write(executor);
     options.signalFinishedToConsumers();
     compatSink.build().writeToDirectory(output, OutputMode.DexIndexed);
diff --git a/src/main/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryKeepRuleGenerator.java b/src/main/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryKeepRuleGenerator.java
index c7c920b..a720021 100644
--- a/src/main/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryKeepRuleGenerator.java
+++ b/src/main/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryKeepRuleGenerator.java
@@ -13,7 +13,7 @@
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfiguration;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.references.ArrayReference;
 import com.android.tools.r8.references.ClassReference;
@@ -71,7 +71,7 @@
       return false;
     }
     return namingLens.hasPrefixRewritingLogic()
-        || options.desugaredLibraryConfiguration.hasEmulatedLibraryInterfaces();
+        || options.desugaredLibrarySpecification.hasEmulatedLibraryInterfaces();
   }
 
   private void run() {
@@ -80,15 +80,15 @@
   }
 
   private Predicate<DexType> createTargetPredicate() {
-    DesugaredLibraryConfiguration desugaredLibraryConfiguration =
-        options.desugaredLibraryConfiguration;
+    LegacyDesugaredLibrarySpecification desugaredLibrarySpecification =
+        options.desugaredLibrarySpecification;
     Set<DexType> potentialTypesToKeep =
         SetUtils.newIdentityHashSet(
-            desugaredLibraryConfiguration.getCustomConversions().values(),
-            desugaredLibraryConfiguration.getEmulateLibraryInterface().values());
+            desugaredLibrarySpecification.getCustomConversions().values(),
+            desugaredLibrarySpecification.getEmulateLibraryInterface().values());
     byte[] synthesizedLibraryClassesPackageDescriptorPrefix =
         DexString.encodeToMutf8(
-            "L" + desugaredLibraryConfiguration.getSynthesizedLibraryClassesPackagePrefix());
+            "L" + desugaredLibrarySpecification.getSynthesizedLibraryClassesPackagePrefix());
     return type ->
         namingLens.prefixRewrittenType(type) != null
             || potentialTypesToKeep.contains(type)
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
index 3acd908..f99eee5 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.dex;
 
+import static com.android.tools.r8.utils.LineNumberOptimizer.runAndWriteMap;
+
 import com.android.tools.r8.ByteBufferProvider;
 import com.android.tools.r8.ByteDataView;
 import com.android.tools.r8.DataDirectoryResource;
@@ -41,15 +43,16 @@
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ParameterAnnotationsList;
 import com.android.tools.r8.naming.NamingLens;
-import com.android.tools.r8.naming.ProguardMapSupplier;
 import com.android.tools.r8.naming.ProguardMapSupplier.ProguardMapId;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.shaking.MainDexInfo;
+import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.ArrayUtils;
 import com.android.tools.r8.utils.Box;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.ExceptionUtils;
 import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.OriginalSourceFiles;
 import com.android.tools.r8.utils.PredicateUtils;
 import com.android.tools.r8.utils.StringDiagnostic;
 import com.android.tools.r8.utils.StringUtils;
@@ -63,8 +66,10 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
@@ -84,7 +89,6 @@
   public List<DexString> markerStrings;
 
   public DexIndexedConsumer programConsumer;
-  public final ProguardMapSupplier proguardMapSupplier;
 
   private static class SortAnnotations extends MixedSectionCollection {
 
@@ -154,15 +158,13 @@
       List<Marker> markers,
       GraphLens graphLens,
       InitClassLens initClassLens,
-      NamingLens namingLens,
-      ProguardMapSupplier proguardMapSupplier) {
+      NamingLens namingLens) {
     this(
         appView,
         markers,
         graphLens,
         initClassLens,
         namingLens,
-        proguardMapSupplier,
         null);
   }
 
@@ -172,7 +174,6 @@
       GraphLens graphLens,
       InitClassLens initClassLens,
       NamingLens namingLens,
-      ProguardMapSupplier proguardMapSupplier,
       DexIndexedConsumer consumer) {
     this.appView = appView;
     this.options = appView.options();
@@ -181,7 +182,6 @@
     this.graphLens = graphLens;
     this.initClassLens = initClassLens;
     this.namingLens = namingLens;
-    this.proguardMapSupplier = proguardMapSupplier;
     this.programConsumer = consumer;
     this.isTypeMissing =
         PredicateUtils.isNull(appView.appInfo()::definitionForWithoutExistenceAssert);
@@ -228,17 +228,26 @@
   }
 
   private boolean willComputeProguardMap() {
-    return proguardMapSupplier != null && options.proguardMapConsumer != null;
+    return options.proguardMapConsumer != null;
   }
 
+  /** Writer that never needs the input app to deal with mapping info for kotlin. */
   public void write(ExecutorService executorService) throws IOException, ExecutionException {
+    assert !willComputeProguardMap();
+    write(executorService, null);
+  }
+
+  public void write(ExecutorService executorService, AndroidApp inputApp)
+      throws IOException, ExecutionException {
     Timing timing = appView.appInfo().app().timing;
+
     timing.begin("DexApplication.write");
 
     Box<ProguardMapId> delayedProguardMapId = new Box<>();
     List<LazyDexString> lazyDexStrings = new ArrayList<>();
     computeMarkerStrings(delayedProguardMapId, lazyDexStrings);
-    computeSourceFileString(delayedProguardMapId, lazyDexStrings);
+    OriginalSourceFiles originalSourceFiles =
+        computeSourceFileString(delayedProguardMapId, lazyDexStrings);
 
     try {
       timing.begin("Insert Attribute Annotations");
@@ -295,11 +304,9 @@
       }
 
       // Now code offsets are fixed, compute the mapping file content.
-      // TODO(b/207765416): Move the line number optimizer to this point so PC info can be used.
       if (willComputeProguardMap()) {
-        timing.begin("Write proguard map");
-        delayedProguardMapId.set(proguardMapSupplier.writeProguardMap());
-        timing.end();
+        delayedProguardMapId.set(
+            runAndWriteMap(inputApp, appView, namingLens, timing, originalSourceFiles));
       }
 
       // With the mapping id/hash known, it is safe to compute the remaining dex strings.
@@ -366,17 +373,25 @@
     }
   }
 
-  private void computeSourceFileString(
+  private OriginalSourceFiles computeSourceFileString(
       Box<ProguardMapId> delayedProguardMapId, List<LazyDexString> lazyDexStrings) {
     if (options.sourceFileProvider == null) {
-      return;
+      return OriginalSourceFiles.fromClasses();
     }
     if (!willComputeProguardMap()) {
       rewriteSourceFile(null);
-      return;
+      return OriginalSourceFiles.unreachable();
     }
     // Clear all source files so as not to collect the original files.
-    appView.appInfo().classes().forEach(clazz -> clazz.setSourceFile(null));
+    List<DexProgramClass> classes = appView.appInfo().classes();
+    Map<DexType, DexString> originalSourceFiles = new HashMap<>(classes.size());
+    for (DexProgramClass clazz : classes) {
+      DexString originalSourceFile = clazz.getSourceFile();
+      if (originalSourceFile != null) {
+        originalSourceFiles.put(clazz.getType(), originalSourceFile);
+        clazz.setSourceFile(null);
+      }
+    }
     // Add a lazy dex string computation to defer construction of the actual string.
     lazyDexStrings.add(
         new LazyDexString() {
@@ -385,6 +400,8 @@
             return rewriteSourceFile(delayedProguardMapId.get());
           }
         });
+
+    return OriginalSourceFiles.fromMap(originalSourceFiles);
   }
 
   public static SourceFileEnvironment createSourceFileEnvironment(ProguardMapId proguardMapId) {
diff --git a/src/main/java/com/android/tools/r8/dex/CodeToKeep.java b/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
index 44affb4..cc05c31 100644
--- a/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
+++ b/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
@@ -25,7 +25,7 @@
 
   static CodeToKeep createCodeToKeep(InternalOptions options, NamingLens namingLens) {
     if ((!namingLens.hasPrefixRewritingLogic()
-            && !options.desugaredLibraryConfiguration.hasEmulatedLibraryInterfaces())
+            && !options.desugaredLibrarySpecification.hasEmulatedLibraryInterfaces())
         || options.isDesugaredLibraryCompilation()
         || options.testing.enableExperimentalDesugaredLibraryKeepRuleGenerator) {
       return new NopCodeToKeep();
@@ -65,9 +65,9 @@
       this.namingLens = namingLens;
       this.options = options;
       potentialTypesToKeep.addAll(
-          options.desugaredLibraryConfiguration.getEmulateLibraryInterface().values());
+          options.desugaredLibrarySpecification.getEmulateLibraryInterface().values());
       potentialTypesToKeep.addAll(
-          options.desugaredLibraryConfiguration.getCustomConversions().values());
+          options.desugaredLibrarySpecification.getCustomConversions().values());
     }
 
     private boolean shouldKeep(DexType type) {
@@ -77,7 +77,7 @@
           || type.toDescriptorString()
               .startsWith(
                   "L"
-                      + options.desugaredLibraryConfiguration
+                      + options.desugaredLibrarySpecification
                           .getSynthesizedLibraryClassesPackagePrefix());
     }
 
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java
index 303eaf8e..c2316e4 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -119,6 +119,7 @@
 
   private final Thread mainThread = Thread.currentThread();
 
+  private final AndroidApiLevelCompute apiLevelCompute;
   private final ComputedApiLevel computedMinApiLevel;
 
   private AppView(
@@ -143,7 +144,8 @@
     this.libraryMemberOptimizer = new LibraryMemberOptimizer(this);
     this.protoShrinker = ProtoShrinker.create(withLiveness());
 
-    this.computedMinApiLevel = AndroidApiLevelCompute.computeInitialMinApiLevel(appInfo.options());
+    this.apiLevelCompute = AndroidApiLevelCompute.create(this);
+    this.computedMinApiLevel = apiLevelCompute.computeInitialMinApiLevel(options());
   }
 
   public boolean verifyMainThread() {
@@ -158,7 +160,7 @@
 
   private static <T extends AppInfo> PrefixRewritingMapper defaultPrefixRewritingMapper(T appInfo) {
     InternalOptions options = appInfo.options();
-    return options.desugaredLibraryConfiguration.getPrefixRewritingMapper();
+    return options.desugaredLibrarySpecification.getPrefixRewritingMapper();
   }
 
   public static <T extends AppInfo> AppView<T> createForD8(T appInfo) {
@@ -843,6 +845,10 @@
     return testing().enableTestAssertions ? test.get() : true;
   }
 
+  public AndroidApiLevelCompute apiLevelCompute() {
+    return apiLevelCompute;
+  }
+
   public ComputedApiLevel computedMinApiLevel() {
     return computedMinApiLevel;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/Code.java b/src/main/java/com/android/tools/r8/graph/Code.java
index 6e41fa0..be9507d 100644
--- a/src/main/java/com/android/tools/r8/graph/Code.java
+++ b/src/main/java/com/android/tools/r8/graph/Code.java
@@ -94,10 +94,18 @@
     return false;
   }
 
+  public boolean isThrowExceptionCode() {
+    return false;
+  }
+
   public ThrowNullCode asThrowNullCode() {
     return null;
   }
 
+  public ThrowExceptionCode asThrowExceptionCode() {
+    return null;
+  }
+
   /** Estimate the number of IR instructions emitted by buildIR(). */
   public int estimatedSizeForInlining() {
     return Integer.MAX_VALUE;
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
index 6952bf7..366ad9c 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
@@ -114,9 +114,10 @@
     if (options.retainCompileTimeAnnotations) {
       return true;
     }
-    if (annotation == options.itemFactory.dalvikFastNativeAnnotation
-        || annotation == options.itemFactory.dalvikCriticalNativeAnnotation
-        || annotation == options.itemFactory.annotationSynthesizedClass) {
+    if (annotation == options.itemFactory.annotationSynthesizedClass
+        || annotation
+            .getDescriptor()
+            .startsWith(options.itemFactory.dalvikAnnotationOptimizationPrefix)) {
       return true;
     }
     if (options.processCovariantReturnTypeAnnotations) {
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 2a9e275..4b5152b 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -1332,7 +1332,7 @@
     return new Builder(true);
   }
 
-  private static Builder syntheticBuilder(DexEncodedMethod from) {
+  public static Builder syntheticBuilder(DexEncodedMethod from) {
     return new Builder(true, from);
   }
 
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index c108238..c064992 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -74,6 +74,8 @@
   public static final String dalvikAnnotationSignatureString = "Ldalvik/annotation/Signature;";
   public static final String recordTagDescriptorString = "Lcom/android/tools/r8/RecordTag;";
   public static final String recordDescriptorString = "Ljava/lang/Record;";
+  public static final String dalvikAnnotationOptimizationPrefixString =
+      "Ldalvik/annotation/optimization/";
 
   /** Set of types that may be synthesized during compilation. */
   private final Set<DexType> possibleCompilerSynthesizedTypes = Sets.newIdentityHashSet();
@@ -334,6 +336,10 @@
   public final DexString valueString = createString("value");
   public final DexString kindString = createString("kind");
 
+  // Prefix for runtime affecting yet potential class-retained annotations.
+  public final DexString dalvikAnnotationOptimizationPrefix =
+      createString(dalvikAnnotationOptimizationPrefixString);
+
   public final DexType booleanType = createStaticallyKnownType(booleanDescriptor);
   public final DexType byteType = createStaticallyKnownType(byteDescriptor);
   public final DexType charType = createStaticallyKnownType(charDescriptor);
@@ -680,12 +686,6 @@
   public final DexType annotationReachabilitySensitive =
       createStaticallyKnownType("Ldalvik/annotation/optimization/ReachabilitySensitive;");
 
-  // Runtime affecting yet class-retained annotations.
-  public final DexType dalvikFastNativeAnnotation =
-      createStaticallyKnownType("Ldalvik/annotation/optimization/FastNative;");
-  public final DexType dalvikCriticalNativeAnnotation =
-      createStaticallyKnownType("Ldalvik/annotation/optimization/CriticalNative;");
-
   private static final String METAFACTORY_METHOD_NAME = "metafactory";
   private static final String METAFACTORY_ALT_METHOD_NAME = "altMetafactory";
 
diff --git a/src/main/java/com/android/tools/r8/graph/DexWritableCode.java b/src/main/java/com/android/tools/r8/graph/DexWritableCode.java
index fffff66..ef6bd3b 100644
--- a/src/main/java/com/android/tools/r8/graph/DexWritableCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexWritableCode.java
@@ -20,9 +20,14 @@
   enum DexWritableCodeKind {
     DEFAULT,
     DEFAULT_INSTANCE_INITIALIZER,
-    THROW_NULL
+    THROW_NULL,
+    THROW_EXCEPTION
   }
 
+  boolean isThrowExceptionCode();
+
+  ThrowExceptionCode asThrowExceptionCode();
+
   default int acceptCompareTo(DexWritableCode code, CompareToVisitor visitor) {
     DexWritableCodeKind kind = getDexWritableCodeKind();
     DexWritableCodeKind otherKind = code.getDexWritableCodeKind();
@@ -36,6 +41,9 @@
         return 0;
       case THROW_NULL:
         return 0;
+      case THROW_EXCEPTION:
+        assert isThrowExceptionCode();
+        return asThrowExceptionCode().acceptCompareTo(code.asThrowExceptionCode(), visitor);
       default:
         throw new Unreachable();
     }
diff --git a/src/main/java/com/android/tools/r8/graph/ThrowExceptionCode.java b/src/main/java/com/android/tools/r8/graph/ThrowExceptionCode.java
new file mode 100644
index 0000000..8928361
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/ThrowExceptionCode.java
@@ -0,0 +1,237 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph;
+
+import com.android.tools.r8.code.InvokeDirect;
+import com.android.tools.r8.code.NewInstance;
+import com.android.tools.r8.code.Throw;
+import com.android.tools.r8.dex.CodeToKeep;
+import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.dex.MixedSectionCollection;
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexCode.Try;
+import com.android.tools.r8.graph.DexCode.TryHandler;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.NumberGenerator;
+import com.android.tools.r8.ir.code.Position;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.structural.HashingVisitor;
+import java.nio.ShortBuffer;
+import java.util.Objects;
+
+public class ThrowExceptionCode extends Code implements DexWritableCode {
+
+  private final DexType exceptionType;
+
+  private ThrowExceptionCode(DexType exceptionType) {
+    this.exceptionType = exceptionType;
+  }
+
+  public static ThrowExceptionCode create(DexType exceptionType) {
+    return new ThrowExceptionCode(exceptionType);
+  }
+
+  @Override
+  public Code asCode() {
+    return this;
+  }
+
+  @Override
+  public void acceptHashing(HashingVisitor visitor) {
+    visitor.visitInt(getDexWritableCodeKind().hashCode());
+    visitor.visitDexType(exceptionType);
+  }
+
+  @Override
+  public IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
+    throw new Unreachable("Should not be called");
+  }
+
+  @Override
+  public IRCode buildInliningIR(
+      ProgramMethod context,
+      ProgramMethod method,
+      AppView<?> appView,
+      GraphLens codeLens,
+      NumberGenerator valueNumberGenerator,
+      Position callerPosition,
+      Origin origin,
+      RewrittenPrototypeDescription protoChanges) {
+    throw new Unreachable("Should not be called");
+  }
+
+  @Override
+  public int codeSizeInBytes() {
+    return NewInstance.SIZE + InvokeDirect.SIZE + Throw.SIZE;
+  }
+
+  @Override
+  public void collectIndexedItems(
+      IndexedItemCollection indexedItems,
+      ProgramMethod context,
+      GraphLens graphLens,
+      LensCodeRewriterUtils rewriter) {
+    rewriter
+        .dexItemFactory()
+        .createInstanceInitializer(exceptionType)
+        .collectIndexedItems(indexedItems);
+  }
+
+  @Override
+  public void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+    // Intentionally empty.
+  }
+
+  @Override
+  protected int computeHashCode() {
+    return Objects.hash(DexWritableCodeKind.THROW_EXCEPTION, exceptionType.hashCode());
+  }
+
+  @Override
+  protected boolean computeEquals(Object other) {
+    if (this == other) {
+      return true;
+    }
+    if (!(other instanceof ThrowExceptionCode)) {
+      return false;
+    }
+    ThrowExceptionCode that = (ThrowExceptionCode) other;
+    return Objects.equals(exceptionType, that.exceptionType);
+  }
+
+  @Override
+  public int estimatedDexCodeSizeUpperBoundInBytes() {
+    return codeSizeInBytes();
+  }
+
+  @Override
+  public DexWritableCodeKind getDexWritableCodeKind() {
+    return DexWritableCodeKind.THROW_EXCEPTION;
+  }
+
+  @Override
+  public DexDebugInfoForWriting getDebugInfoForWriting() {
+    return null;
+  }
+
+  @Override
+  public TryHandler[] getHandlers() {
+    return new TryHandler[0];
+  }
+
+  @Override
+  public DexString getHighestSortingString() {
+    return null;
+  }
+
+  @Override
+  public int getIncomingRegisterSize(ProgramMethod method) {
+    return 0;
+  }
+
+  @Override
+  public int getOutgoingRegisterSize() {
+    return 1;
+  }
+
+  @Override
+  public int getRegisterSize(ProgramMethod method) {
+    return 1;
+  }
+
+  @Override
+  public Try[] getTries() {
+    return new Try[0];
+  }
+
+  @Override
+  public boolean isDexWritableCode() {
+    return true;
+  }
+
+  @Override
+  public DexWritableCode asDexWritableCode() {
+    return this;
+  }
+
+  @Override
+  public boolean isEmptyVoidMethod() {
+    return false;
+  }
+
+  @Override
+  public boolean isSharedCodeObject() {
+    return true;
+  }
+
+  @Override
+  public boolean isThrowExceptionCode() {
+    return true;
+  }
+
+  @Override
+  public ThrowExceptionCode asThrowExceptionCode() {
+    return this;
+  }
+
+  @Override
+  public void registerCodeReferences(ProgramMethod method, UseRegistry registry) {
+    throw new Unreachable("Should not be called");
+  }
+
+  @Override
+  public void registerCodeReferencesForDesugaring(ClasspathMethod method, UseRegistry registry) {
+    throw new Unreachable("Should not be called");
+  }
+
+  @Override
+  public DexWritableCode rewriteCodeWithJumboStrings(
+      ProgramMethod method, ObjectToOffsetMapping mapping, DexItemFactory factory, boolean force) {
+    // Intentionally empty. This piece of code does not have any const-string instructions.
+    return this;
+  }
+
+  @Override
+  public void setCallSiteContexts(ProgramMethod method) {
+    // Intentionally empty.
+  }
+
+  @Override
+  public void writeDex(
+      ShortBuffer shortBuffer,
+      ProgramMethod context,
+      GraphLens graphLens,
+      LensCodeRewriterUtils lensCodeRewriter,
+      ObjectToOffsetMapping mapping) {
+    int register = 0;
+    int notUsed = 0;
+    int argumentCount = 1;
+    new NewInstance(register, exceptionType)
+        .write(shortBuffer, context, graphLens, mapping, lensCodeRewriter);
+    DexMethod instanceInitializer =
+        lensCodeRewriter.dexItemFactory().createInstanceInitializer(exceptionType);
+    new InvokeDirect(
+            argumentCount, instanceInitializer, register, notUsed, notUsed, notUsed, notUsed)
+        .write(shortBuffer, context, graphLens, mapping, lensCodeRewriter);
+    new Throw(register).write(shortBuffer, context, graphLens, mapping, lensCodeRewriter);
+  }
+
+  @Override
+  public void writeKeepRulesForDesugaredLibrary(CodeToKeep codeToKeep) {
+    // Intentionally empty.
+  }
+
+  @Override
+  public String toString() {
+    return "ThrowExceptionCode";
+  }
+
+  @Override
+  public String toString(DexEncodedMethod method, ClassNameMapper naming) {
+    return "ThrowExceptionCode";
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
index 45e2065..86c7e2d 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
@@ -21,9 +21,9 @@
   private final AndroidApiLevelCompute apiCompute;
   private final ComputedApiLevel minApiLevel;
 
-  public ApiModelAnalysis(AppView<?> appView, AndroidApiLevelCompute apiCompute) {
+  public ApiModelAnalysis(AppView<?> appView) {
     this.appView = appView;
-    this.apiCompute = apiCompute;
+    this.apiCompute = appView.apiLevelCompute();
     this.minApiLevel = appView.computedMinApiLevel();
   }
 
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/GetArrayOfMissingTypeVerifyErrorWorkaround.java b/src/main/java/com/android/tools/r8/graph/analysis/GetArrayOfMissingTypeVerifyErrorWorkaround.java
index 01b6d96..74817d0 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/GetArrayOfMissingTypeVerifyErrorWorkaround.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/GetArrayOfMissingTypeVerifyErrorWorkaround.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.graph.analysis;
 
+import com.android.tools.r8.androidapi.AndroidApiLevelCompute;
 import com.android.tools.r8.androidapi.ComputedApiLevel;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
@@ -35,11 +36,13 @@
 
   private final DexItemFactory dexItemFactory;
   private final Enqueuer enqueuer;
+  private final AndroidApiLevelCompute apiLevelCompute;
 
   public GetArrayOfMissingTypeVerifyErrorWorkaround(
       AppView<? extends AppInfoWithClassHierarchy> appView, Enqueuer enqueuer) {
     this.dexItemFactory = appView.dexItemFactory();
     this.enqueuer = enqueuer;
+    this.apiLevelCompute = appView.apiLevelCompute();
   }
 
   public static void register(
@@ -82,9 +85,7 @@
       return false;
     }
     ComputedApiLevel baseTypeApiLevel =
-        enqueuer
-            .getApiLevelCompute()
-            .computeApiLevelForLibraryReference(baseType, ComputedApiLevel.unknown());
+        apiLevelCompute.computeApiLevelForLibraryReference(baseType, ComputedApiLevel.unknown());
     return !baseTypeApiLevel.isKnownApiLevel()
         || baseTypeApiLevel
             .asKnownApiLevel()
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoDifferentApiReferenceLevel.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoDifferentApiReferenceLevel.java
index 6a083f0..992f73c 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoDifferentApiReferenceLevel.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoDifferentApiReferenceLevel.java
@@ -20,8 +20,8 @@
   private final boolean enableApiCallerIdentification;
 
   public NoDifferentApiReferenceLevel(AppView<?> appView) {
-    apiLevelCompute = AndroidApiLevelCompute.create(appView);
     this.appView = appView;
+    apiLevelCompute = appView.apiLevelCompute();
     enableApiCallerIdentification =
         appView.options().apiModelingOptions().enableApiCallerIdentification;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 1250ada..dc97590 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -6,7 +6,6 @@
 import static com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.Flavor.ExcludeDexResources;
 import static com.android.tools.r8.ir.desugar.lambda.D8LambdaDesugaring.rewriteEnclosingLambdaMethodAttributes;
 
-import com.android.tools.r8.androidapi.AndroidApiLevelCompute;
 import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.errors.Unreachable;
@@ -56,7 +55,7 @@
 import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer.D8CfPostProcessingDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.CovariantReturnTypeAnnotationTransformer;
 import com.android.tools.r8.ir.desugar.ProgramAdditions;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter;
 import com.android.tools.r8.ir.desugar.itf.EmulatedInterfaceApplicationRewriter;
 import com.android.tools.r8.ir.desugar.itf.InterfaceMethodProcessorFacade;
 import com.android.tools.r8.ir.desugar.itf.InterfaceProcessor;
@@ -204,7 +203,6 @@
             .map(prefix -> "L" + DescriptorUtils.getPackageBinaryNameFromJavaType(prefix))
             .map(options.itemFactory::createString)
             .collect(Collectors.toList());
-    AndroidApiLevelCompute apiLevelCompute = AndroidApiLevelCompute.create(appView);
     if (options.isDesugaredLibraryCompilation()) {
       // Specific L8 Settings, performs all desugaring including L8 specific desugaring.
       //
@@ -223,7 +221,7 @@
       // - invoke-special desugaring.
       assert options.desugarState.isOn();
       this.instructionDesugaring =
-          CfInstructionDesugaringCollection.create(appView, apiLevelCompute);
+          CfInstructionDesugaringCollection.create(appView, appView.apiLevelCompute());
       this.covariantReturnTypeAnnotationTransformer = null;
       this.dynamicTypeOptimization = null;
       this.classInliner = null;
@@ -248,7 +246,7 @@
     this.instructionDesugaring =
         appView.enableWholeProgramOptimizations()
             ? CfInstructionDesugaringCollection.empty()
-            : CfInstructionDesugaringCollection.create(appView, apiLevelCompute);
+            : CfInstructionDesugaringCollection.create(appView, appView.apiLevelCompute());
     this.covariantReturnTypeAnnotationTransformer =
         options.processCovariantReturnTypeAnnotations
             ? new CovariantReturnTypeAnnotationTransformer(this, appView.dexItemFactory())
@@ -287,7 +285,7 @@
       this.typeChecker = new TypeChecker(appViewWithLiveness, VerifyTypesHelper.create(appView));
       this.serviceLoaderRewriter =
           options.enableServiceLoaderRewriting
-              ? new ServiceLoaderRewriter(appViewWithLiveness, apiLevelCompute)
+              ? new ServiceLoaderRewriter(appViewWithLiveness, appView.apiLevelCompute())
               : null;
       this.enumValueOptimizer =
           options.enableEnumValueOptimization ? new EnumValueOptimizer(appViewWithLiveness) : null;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
index ed1260e..8cd6162 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
@@ -32,7 +32,7 @@
 import com.android.tools.r8.ir.desugar.backports.ObjectsMethodRewrites;
 import com.android.tools.r8.ir.desugar.backports.OptionalMethodRewrites;
 import com.android.tools.r8.ir.desugar.backports.SparseArrayMethodRewrites;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeter;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeter;
 import com.android.tools.r8.synthesis.SyntheticNaming;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
@@ -97,7 +97,7 @@
       AndroidApp androidApp, InternalOptions options, ExecutorService executor) throws IOException {
     List<DexMethod> methods = new ArrayList<>();
     PrefixRewritingMapper rewritePrefix =
-        options.desugaredLibraryConfiguration.getPrefixRewritingMapper();
+        options.desugaredLibrarySpecification.getPrefixRewritingMapper();
     AppInfo appInfo = null;
     if (androidApp != null) {
       DexApplication app =
@@ -135,13 +135,13 @@
         && appView.options().isDesugaredLibraryCompilation()
         && appView
             .options()
-            .desugaredLibraryConfiguration
+            .desugaredLibrarySpecification
             .getBackportCoreLibraryMember()
             .containsKey(method.holder)) {
       DexType newHolder =
           appView
               .options()
-              .desugaredLibraryConfiguration
+              .desugaredLibrarySpecification
               .getBackportCoreLibraryMember()
               .get(method.holder);
       DexMethod backportedMethod =
@@ -1366,7 +1366,7 @@
     }
 
     private void addProvider(MethodProvider generator) {
-      if (appView.options().desugaredLibraryConfiguration.isSupported(generator.method, appView)) {
+      if (appView.options().desugaredLibrarySpecification.isSupported(generator.method, appView)) {
         // TODO(b/174453232): Remove this after the configuration file format has bee updated
         // with the "rewrite_method" section.
         if (generator.method.getHolderType() == appView.dexItemFactory().objectsType) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfClassSynthesizerDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/CfClassSynthesizerDesugaringCollection.java
index dbd3de8..c54f7ec 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfClassSynthesizerDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfClassSynthesizerDesugaringCollection.java
@@ -4,9 +4,9 @@
 package com.android.tools.r8.ir.desugar;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterL8Synthesizer;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizer;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.RetargetingInfo;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryWrapperSynthesizer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeterL8Synthesizer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.RetargetingInfo;
 import com.android.tools.r8.ir.desugar.itf.ProgramEmulatedInterfaceSynthesizer;
 import com.android.tools.r8.ir.desugar.records.RecordDesugaring;
 import com.android.tools.r8.utils.ThreadUtils;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfClassSynthesizerDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/CfClassSynthesizerDesugaringEventConsumer.java
index 8b8b2e3..8a9a016 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfClassSynthesizerDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfClassSynthesizerDesugaringEventConsumer.java
@@ -5,8 +5,8 @@
 package com.android.tools.r8.ir.desugar;
 
 import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterL8SynthesizerEventConsumer;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterL8SynthesizerEventConsumer;
 import com.android.tools.r8.ir.desugar.itf.EmulatedInterfaceSynthesizerEventConsumer.L8ProgramEmulatedInterfaceSynthesizerEventConsumer;
 import com.android.tools.r8.ir.desugar.records.RecordDesugaringEventConsumer;
 import com.google.common.collect.Sets;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringCollection.java
index 2257925..de491c7 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringCollection.java
@@ -9,8 +9,8 @@
 import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.RetargetingInfo;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.RetargetingInfo;
 import com.android.tools.r8.ir.desugar.itf.InterfaceMethodProcessorFacade;
 import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.Flavor;
 import com.android.tools.r8.ir.desugar.itf.InterfaceProcessor;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
index 42212fd..de940f8 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
@@ -16,8 +16,8 @@
 import com.android.tools.r8.ir.desugar.backports.BackportedMethodDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.constantdynamic.ConstantDynamicClass;
 import com.android.tools.r8.ir.desugar.constantdynamic.ConstantDynamicDesugaringEventConsumer;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterInstructionEventConsumer;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryAPIConverterEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryAPIConverterEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterInstructionEventConsumer;
 import com.android.tools.r8.ir.desugar.invokespecial.InvokeSpecialBridgeInfo;
 import com.android.tools.r8.ir.desugar.invokespecial.InvokeSpecialToSelfDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.itf.EmulatedInterfaceSynthesizerEventConsumer.ClasspathEmulatedInterfaceSynthesizerEventConsumer;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringCollection.java
index 064e82d..1fd0ad0 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringCollection.java
@@ -6,9 +6,9 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPICallbackSynthesizer;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterPostProcessor;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.RetargetingInfo;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPICallbackSynthesizer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeterPostProcessor;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.RetargetingInfo;
 import com.android.tools.r8.ir.desugar.itf.InterfaceMethodProcessorFacade;
 import com.android.tools.r8.ir.desugar.records.RecordDesugaring;
 import java.util.ArrayList;
@@ -57,7 +57,7 @@
         InterfaceMethodProcessorFacade interfaceMethodProcessorFacade,
         RetargetingInfo retargetingInfo) {
       ArrayList<CfPostProcessingDesugaring> desugarings = new ArrayList<>();
-      if (!appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember().isEmpty()
+      if (!appView.options().desugaredLibrarySpecification.getRetargetCoreLibMember().isEmpty()
           && !appView.options().isDesugaredLibraryCompilation()) {
         desugarings.add(new DesugaredLibraryRetargeterPostProcessor(appView, retargetingInfo));
       }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringEventConsumer.java
index 496cef9..8cb11ed 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringEventConsumer.java
@@ -9,8 +9,8 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.conversion.D8MethodProcessor;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterPostProcessingEventConsumer;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryAPICallbackSynthesizorEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryAPICallbackSynthesizorEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterPostProcessingEventConsumer;
 import com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringSyntheticHelper;
 import com.android.tools.r8.ir.desugar.itf.InterfaceProcessingDesugaringEventConsumer;
 import com.android.tools.r8.shaking.Enqueuer.SyntheticAdditions;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/EmptyCfInstructionDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/EmptyCfInstructionDesugaringCollection.java
index 27b646f..1e4d6f8 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/EmptyCfInstructionDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/EmptyCfInstructionDesugaringCollection.java
@@ -7,8 +7,8 @@
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
 import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.RetargetingInfo;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.RetargetingInfo;
 import com.android.tools.r8.ir.desugar.itf.InterfaceMethodProcessorFacade;
 import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.Flavor;
 import com.android.tools.r8.ir.desugar.itf.InterfaceProcessor;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
index f722159..a8d8b14 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
@@ -16,9 +16,9 @@
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.desugar.apimodel.ApiInvokeOutlinerDesugaring;
 import com.android.tools.r8.ir.desugar.constantdynamic.ConstantDynamicInstructionDesugaring;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeter;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.RetargetingInfo;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeter;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.RetargetingInfo;
 import com.android.tools.r8.ir.desugar.icce.AlwaysThrowingInstructionDesugaring;
 import com.android.tools.r8.ir.desugar.invokespecial.InvokeSpecialToSelfDesugaring;
 import com.android.tools.r8.ir.desugar.itf.InterfaceMethodProcessorFacade;
@@ -79,7 +79,7 @@
     this.nestBasedAccessDesugaring = NestBasedAccessDesugaring.create(appView);
     BackportedMethodRewriter backportedMethodRewriter = null;
     desugaredLibraryRetargeter =
-        appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember().isEmpty()
+        appView.options().desugaredLibrarySpecification.getRetargetCoreLibMember().isEmpty()
             ? null
             : new DesugaredLibraryRetargeter(appView);
     if (desugaredLibraryRetargeter != null) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/PrefixRewritingMapper.java b/src/main/java/com/android/tools/r8/ir/desugar/PrefixRewritingMapper.java
index b03cab4..eb4f662 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/PrefixRewritingMapper.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/PrefixRewritingMapper.java
@@ -63,6 +63,7 @@
 
     public DesugarPrefixRewritingMapper(
         Map<String, String> prefixes, DexItemFactory itemFactory, boolean libraryCompilation) {
+      assert itemFactory != null || prefixes.isEmpty();
       this.factory = itemFactory;
       this.l8Compilation = libraryCompilation;
       ImmutableMap.Builder<DexString, DexString> builder = ImmutableMap.builder();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryConfiguration.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryConfiguration.java
deleted file mode 100644
index 326b3c9..0000000
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryConfiguration.java
+++ /dev/null
@@ -1,467 +0,0 @@
-// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.ir.desugar.desugaredlibrary;
-
-import com.android.tools.r8.errors.CompilationError;
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexClassAndMethod;
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexReference;
-import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.desugar.PrefixRewritingMapper;
-import com.android.tools.r8.ir.desugar.PrefixRewritingMapper.DesugarPrefixRewritingMapper;
-import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.DescriptorUtils;
-import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.Pair;
-import com.android.tools.r8.utils.Reporter;
-import com.android.tools.r8.utils.StringDiagnostic;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
-import com.google.common.collect.Sets.SetView;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.IdentityHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-public class DesugaredLibraryConfiguration {
-  public static final String FALL_BACK_SYNTHESIZED_CLASSES_PACKAGE_PREFIX = "j$/";
-  public static final boolean FALL_BACK_SUPPORT_ALL_CALLBACKS_FROM_LIBRARY = true;
-  private final AndroidApiLevel requiredCompilationAPILevel;
-  private final boolean libraryCompilation;
-  private final String synthesizedLibraryClassesPackagePrefix;
-  private final String identifier;
-  private final String jsonSource;
-  // Setting supportAllCallbacksFromLibrary reduces the number of generated call-backs,
-  // more specifically:
-  // - no call-back is generated for emulated interface method overrides (forEach, etc.)
-  // - no call-back is generated inside the desugared library itself.
-  // Such setting decreases significantly the desugared library dex file, but virtual calls from
-  // within the library to desugared library classes instances as receiver may be incorrect, for
-  // example the method forEach in Iterable may be executed over a concrete implementation.
-  public final boolean supportAllCallbacksFromLibrary;
-  private final Map<String, String> rewritePrefix;
-  private final Map<DexType, DexType> emulateLibraryInterface;
-  private final Map<DexString, Map<DexType, DexType>> retargetCoreLibMember;
-  private final Map<DexType, DexType> backportCoreLibraryMember;
-  private final Map<DexType, DexType> customConversions;
-  private final List<Pair<DexType, DexString>> dontRewriteInvocation;
-  private final Set<DexType> dontRetargetLibMember;
-  private final List<String> extraKeepRules;
-  private final Set<DexType> wrapperConversions;
-  private final PrefixRewritingMapper prefixRewritingMapper;
-
-  public static Builder builder(DexItemFactory dexItemFactory, Reporter reporter, Origin origin) {
-    return new Builder(dexItemFactory, reporter, origin);
-  }
-
-  public static DesugaredLibraryConfiguration withOnlyRewritePrefixForTesting(
-      Map<String, String> prefix, InternalOptions options) {
-    return new DesugaredLibraryConfiguration(
-        AndroidApiLevel.B,
-        true,
-        FALL_BACK_SYNTHESIZED_CLASSES_PACKAGE_PREFIX,
-        "testingOnlyVersion",
-        null,
-        FALL_BACK_SUPPORT_ALL_CALLBACKS_FROM_LIBRARY,
-        prefix,
-        ImmutableMap.of(),
-        ImmutableMap.of(),
-        ImmutableMap.of(),
-        ImmutableMap.of(),
-        ImmutableSet.of(),
-        ImmutableList.of(),
-        ImmutableSet.of(),
-        ImmutableList.of(),
-        new DesugarPrefixRewritingMapper(prefix, options.itemFactory, true));
-  }
-
-  public static DesugaredLibraryConfiguration empty() {
-    return new DesugaredLibraryConfiguration(
-        AndroidApiLevel.B,
-        false,
-        FALL_BACK_SYNTHESIZED_CLASSES_PACKAGE_PREFIX,
-        null,
-        null,
-        FALL_BACK_SUPPORT_ALL_CALLBACKS_FROM_LIBRARY,
-        ImmutableMap.of(),
-        ImmutableMap.of(),
-        ImmutableMap.of(),
-        ImmutableMap.of(),
-        ImmutableMap.of(),
-        ImmutableSet.of(),
-        ImmutableList.of(),
-        ImmutableSet.of(),
-        ImmutableList.of(),
-        PrefixRewritingMapper.empty()) {
-
-      @Override
-      public boolean isSupported(DexReference reference, AppView<?> appView) {
-        return false;
-      }
-
-      @Override
-      public boolean isEmptyConfiguration() {
-        return true;
-      }
-    };
-  }
-
-  private DesugaredLibraryConfiguration(
-      AndroidApiLevel requiredCompilationAPILevel,
-      boolean libraryCompilation,
-      String packagePrefix,
-      String identifier,
-      String jsonSource,
-      boolean supportAllCallbacksFromLibrary,
-      Map<String, String> rewritePrefix,
-      Map<DexType, DexType> emulateLibraryInterface,
-      Map<DexString, Map<DexType, DexType>> retargetCoreLibMember,
-      Map<DexType, DexType> backportCoreLibraryMember,
-      Map<DexType, DexType> customConversions,
-      Set<DexType> wrapperConversions,
-      List<Pair<DexType, DexString>> dontRewriteInvocation,
-      Set<DexType> dontRetargetLibMember,
-      List<String> extraKeepRules,
-      PrefixRewritingMapper prefixRewritingMapper) {
-    this.requiredCompilationAPILevel = requiredCompilationAPILevel;
-    this.libraryCompilation = libraryCompilation;
-    this.synthesizedLibraryClassesPackagePrefix = packagePrefix;
-    this.identifier = identifier;
-    this.jsonSource = jsonSource;
-    this.supportAllCallbacksFromLibrary = supportAllCallbacksFromLibrary;
-    this.rewritePrefix = rewritePrefix;
-    this.emulateLibraryInterface = emulateLibraryInterface;
-    this.retargetCoreLibMember = retargetCoreLibMember;
-    this.backportCoreLibraryMember = backportCoreLibraryMember;
-    this.customConversions = customConversions;
-    this.wrapperConversions = wrapperConversions;
-    this.dontRewriteInvocation = dontRewriteInvocation;
-    this.dontRetargetLibMember = dontRetargetLibMember;
-    this.extraKeepRules = extraKeepRules;
-    this.prefixRewritingMapper = prefixRewritingMapper;
-  }
-
-  public PrefixRewritingMapper getPrefixRewritingMapper() {
-    return prefixRewritingMapper;
-  }
-
-  public AndroidApiLevel getRequiredCompilationApiLevel() {
-    return requiredCompilationAPILevel;
-  }
-
-  public boolean isLibraryCompilation() {
-    return libraryCompilation;
-  }
-
-  public String getSynthesizedLibraryClassesPackagePrefix() {
-    return synthesizedLibraryClassesPackagePrefix;
-  }
-
-  // TODO(b/183918843): We are currently computing a new name for the class by replacing the
-  //  initial package prefix by the synthesized library class package prefix, it would be better
-  //  to make the rewriting explicit in the desugared library json file.
-  public String convertJavaNameToDesugaredLibrary(DexType type) {
-    String prefix =
-        DescriptorUtils.getJavaTypeFromBinaryName(getSynthesizedLibraryClassesPackagePrefix());
-    String interfaceType = type.toString();
-    int firstPackage = interfaceType.indexOf('.');
-    return prefix + interfaceType.substring(firstPackage + 1);
-  }
-
-  public String getIdentifier() {
-    return identifier;
-  }
-
-  public Map<String, String> getRewritePrefix() {
-    return rewritePrefix;
-  }
-
-  public boolean hasEmulatedLibraryInterfaces() {
-    return !getEmulateLibraryInterface().isEmpty();
-  }
-
-  public Map<DexType, DexType> getEmulateLibraryInterface() {
-    return emulateLibraryInterface;
-  }
-
-  public boolean isSupported(DexReference reference, AppView<?> appView) {
-    return prefixRewritingMapper.hasRewrittenType(reference.getContextType(), appView);
-  }
-
-  // If the method is retargeted, answers the retargeted method, else null.
-  public DexMethod retargetMethod(DexEncodedMethod method, AppView<?> appView) {
-    Map<DexType, DexType> typeMap = retargetCoreLibMember.get(method.getName());
-    if (typeMap != null && typeMap.containsKey(method.getHolderType())) {
-      return appView
-          .dexItemFactory()
-          .createMethod(
-              typeMap.get(method.getHolderType()),
-              appView.dexItemFactory().prependHolderToProto(method.getReference()),
-              method.getName());
-    }
-    return null;
-  }
-
-  public DexMethod retargetMethod(DexClassAndMethod method, AppView<?> appView) {
-    return retargetMethod(method.getDefinition(), appView);
-  }
-
-  public Map<DexString, Map<DexType, DexType>> getRetargetCoreLibMember() {
-    return retargetCoreLibMember;
-  }
-
-  public Map<DexType, DexType> getBackportCoreLibraryMember() {
-    return backportCoreLibraryMember;
-  }
-
-  public Map<DexType, DexType> getCustomConversions() {
-    return customConversions;
-  }
-
-  public Set<DexType> getWrapperConversions() {
-    return wrapperConversions;
-  }
-
-  public List<Pair<DexType, DexString>> getDontRewriteInvocation() {
-    return dontRewriteInvocation;
-  }
-
-  public Set<DexType> getDontRetargetLibMember() {
-    return dontRetargetLibMember;
-  }
-
-  public List<String> getExtraKeepRules() {
-    return extraKeepRules;
-  }
-
-  public String getJsonSource() {
-    return jsonSource;
-  }
-
-  public boolean isEmptyConfiguration() {
-    return false;
-  }
-
-  public static class Builder {
-    private final DexItemFactory factory;
-    private final Reporter reporter;
-    private final Origin origin;
-    private AndroidApiLevel requiredCompilationAPILevel;
-    private boolean libraryCompilation = false;
-    private String synthesizedLibraryClassesPackagePrefix =
-        FALL_BACK_SYNTHESIZED_CLASSES_PACKAGE_PREFIX;
-    private String identifier;
-    private String jsonSource;
-    private Map<String, String> rewritePrefix = new HashMap<>();
-    private Map<DexType, DexType> emulateLibraryInterface = new IdentityHashMap<>();
-    private Map<DexString, Map<DexType, DexType>> retargetCoreLibMember = new IdentityHashMap<>();
-    private Map<DexType, DexType> backportCoreLibraryMember = new IdentityHashMap<>();
-    private Map<DexType, DexType> customConversions = new IdentityHashMap<>();
-    private Set<DexType> wrapperConversions = Sets.newIdentityHashSet();
-    private List<Pair<DexType, DexString>> dontRewriteInvocation = new ArrayList<>();
-    private Set<DexType> dontRetargetLibMember = Sets.newIdentityHashSet();
-    ;
-    private List<String> extraKeepRules = Collections.emptyList();
-    private boolean supportAllCallbacksFromLibrary = FALL_BACK_SUPPORT_ALL_CALLBACKS_FROM_LIBRARY;
-
-    private Builder(DexItemFactory dexItemFactory, Reporter reporter, Origin origin) {
-      this.factory = dexItemFactory;
-      this.reporter = reporter;
-      this.origin = origin;
-    }
-    // Utility to set values. Currently assumes the key is fresh.
-    private <K, V> void put(Map<K, V> map, K key, V value, String desc) {
-      if (map.containsKey(key)) {
-        throw reporter.fatalError(
-            new StringDiagnostic(
-                "Invalid desugared library configuration. "
-                    + " Duplicate assignment of key: '"
-                    + key
-                    + "' in sections for '"
-                    + desc
-                    + "'",
-                origin));
-      }
-      map.put(key, value);
-    }
-
-    public Builder setSynthesizedLibraryClassesPackagePrefix(String prefix) {
-      this.synthesizedLibraryClassesPackagePrefix = prefix.replace('.', '/');
-      return this;
-    }
-
-    public Builder setDesugaredLibraryIdentifier(String identifier) {
-      this.identifier = identifier;
-      return this;
-    }
-
-    public Builder setJsonSource(String jsonSource) {
-      this.jsonSource = jsonSource;
-      return this;
-    }
-
-    public Builder setRequiredCompilationAPILevel(AndroidApiLevel requiredCompilationAPILevel) {
-      this.requiredCompilationAPILevel = requiredCompilationAPILevel;
-      return this;
-    }
-
-    public Builder setProgramCompilation() {
-      libraryCompilation = false;
-      return this;
-    }
-
-    public Builder setLibraryCompilation() {
-      libraryCompilation = true;
-      return this;
-    }
-
-    public Builder setExtraKeepRules(List<String> rules) {
-      extraKeepRules = rules;
-      return this;
-    }
-
-    public Builder putRewritePrefix(String prefix, String rewrittenPrefix) {
-      put(
-          rewritePrefix,
-          prefix,
-          rewrittenPrefix,
-          DesugaredLibraryConfigurationParser.REWRITE_PREFIX_KEY);
-      return this;
-    }
-
-    public Builder putEmulateLibraryInterface(
-        String emulateLibraryItf, String rewrittenEmulateLibraryItf) {
-      DexType interfaceType = stringClassToDexType(emulateLibraryItf);
-      DexType rewrittenType = stringClassToDexType(rewrittenEmulateLibraryItf);
-      put(
-          emulateLibraryInterface,
-          interfaceType,
-          rewrittenType,
-          DesugaredLibraryConfigurationParser.EMULATE_INTERFACE_KEY);
-      return this;
-    }
-
-    public Builder putCustomConversion(String type, String conversionHolder) {
-      DexType dexType = stringClassToDexType(type);
-      DexType conversionType = stringClassToDexType(conversionHolder);
-      put(
-          customConversions,
-          dexType,
-          conversionType,
-          DesugaredLibraryConfigurationParser.CUSTOM_CONVERSION_KEY);
-      return this;
-    }
-
-    public Builder addWrapperConversion(String type) {
-      DexType dexType = stringClassToDexType(type);
-      wrapperConversions.add(dexType);
-      return this;
-    }
-
-    public Builder putRetargetCoreLibMember(String retarget, String rewrittenRetarget) {
-      int index = sharpIndex(retarget, "retarget core library member");
-      DexString methodName = factory.createString(retarget.substring(index + 1));
-      retargetCoreLibMember.putIfAbsent(methodName, new IdentityHashMap<>());
-      Map<DexType, DexType> typeMap = retargetCoreLibMember.get(methodName);
-      DexType originalType = stringClassToDexType(retarget.substring(0, index));
-      DexType finalType = stringClassToDexType(rewrittenRetarget);
-      assert !typeMap.containsKey(originalType);
-      put(
-          typeMap,
-          originalType,
-          finalType,
-          DesugaredLibraryConfigurationParser.RETARGET_LIB_MEMBER_KEY);
-      return this;
-    }
-
-    public Builder putBackportCoreLibraryMember(String backport, String rewrittenBackport) {
-      DexType backportType = stringClassToDexType(backport);
-      DexType rewrittenBackportType = stringClassToDexType(rewrittenBackport);
-      put(
-          backportCoreLibraryMember,
-          backportType,
-          rewrittenBackportType,
-          DesugaredLibraryConfigurationParser.BACKPORT_KEY);
-      return this;
-    }
-
-    public Builder addDontRewriteInvocation(String dontRewriteInvocation) {
-      int index = sharpIndex(dontRewriteInvocation, "don't rewrite");
-      this.dontRewriteInvocation.add(
-          new Pair<>(
-              stringClassToDexType(dontRewriteInvocation.substring(0, index)),
-              factory.createString(dontRewriteInvocation.substring(index + 1))));
-      return this;
-    }
-
-    public Builder addDontRetargetLibMember(String dontRetargetLibMember) {
-      this.dontRetargetLibMember.add(stringClassToDexType(dontRetargetLibMember));
-      return this;
-    }
-
-    private int sharpIndex(String typeAndSelector, String descr) {
-      int index = typeAndSelector.lastIndexOf('#');
-      if (index <= 0 || index >= typeAndSelector.length() - 1) {
-        throw new CompilationError(
-            "Invalid " + descr + " specification (# position) in " + typeAndSelector + ".");
-      }
-      return index;
-    }
-
-    private DexType stringClassToDexType(String stringClass) {
-      return factory.createType(DescriptorUtils.javaTypeToDescriptor(stringClass));
-    }
-
-    public void setSupportAllCallbacksFromLibrary(boolean supportAllCallbacksFromLibrary) {
-      this.supportAllCallbacksFromLibrary = supportAllCallbacksFromLibrary;
-    }
-
-    public DesugaredLibraryConfiguration build() {
-      validate();
-      return new DesugaredLibraryConfiguration(
-          requiredCompilationAPILevel,
-          libraryCompilation,
-          synthesizedLibraryClassesPackagePrefix,
-          identifier,
-          jsonSource,
-          supportAllCallbacksFromLibrary,
-          ImmutableMap.copyOf(rewritePrefix),
-          ImmutableMap.copyOf(emulateLibraryInterface),
-          ImmutableMap.copyOf(retargetCoreLibMember),
-          ImmutableMap.copyOf(backportCoreLibraryMember),
-          ImmutableMap.copyOf(customConversions),
-          ImmutableSet.copyOf(wrapperConversions),
-          ImmutableList.copyOf(dontRewriteInvocation),
-          ImmutableSet.copyOf(dontRetargetLibMember),
-          ImmutableList.copyOf(extraKeepRules),
-          rewritePrefix.isEmpty()
-              ? PrefixRewritingMapper.empty()
-              : new DesugarPrefixRewritingMapper(rewritePrefix, factory, libraryCompilation));
-    }
-
-    private void validate() {
-      SetView<DexType> dups = Sets.intersection(customConversions.keySet(), wrapperConversions);
-      if (!dups.isEmpty()) {
-        throw reporter.fatalError(
-            new StringDiagnostic(
-                "Invalid desugared library configuration. "
-                    + "Duplicate types in custom conversions and wrapper conversions: "
-                    + String.join(
-                        ", ", dups.stream().map(DexType::toString).collect(Collectors.toSet())),
-                origin));
-      }
-    }
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPICallbackSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPICallbackSynthesizer.java
similarity index 90%
rename from src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPICallbackSynthesizer.java
rename to src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPICallbackSynthesizer.java
index 92d7b92..0795a4e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPICallbackSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPICallbackSynthesizer.java
@@ -2,11 +2,11 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-package com.android.tools.r8.ir.desugar.desugaredlibrary;
+package com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion;
 
-import static com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter.generateTrackDesugaredAPIWarnings;
-import static com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter.isAPIConversionSyntheticType;
-import static com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter.methodWithVivifiedTypeInSignature;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter.generateTrackDesugaredAPIWarnings;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter.isAPIConversionSyntheticType;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter.methodWithVivifiedTypeInSignature;
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
@@ -19,7 +19,7 @@
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaring;
 import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryAPICallbackSynthesizorEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryAPICallbackSynthesizorEventConsumer;
 import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APICallbackWrapperCfCodeProvider;
 import com.android.tools.r8.utils.OptionalBool;
 import com.android.tools.r8.utils.WorkList;
@@ -109,7 +109,7 @@
     if (!appView.rewritePrefix.hasRewrittenTypeInSignature(definition.getProto(), appView)
         || appView
             .options()
-            .desugaredLibraryConfiguration
+            .desugaredLibrarySpecification
             .getEmulateLibraryInterface()
             .containsKey(method.getHolderType())) {
       return false;
@@ -127,7 +127,7 @@
         return false;
       }
     }
-    if (!appView.options().desugaredLibraryConfiguration.supportAllCallbacksFromLibrary
+    if (!appView.options().desugaredLibrarySpecification.supportAllCallbacksFromLibrary()
         && appView.options().isDesugaredLibraryCompilation()) {
       return false;
     }
@@ -178,11 +178,11 @@
   }
 
   private boolean shouldGenerateCallbacksForEmulateInterfaceAPIs(DexClass dexClass) {
-    if (appView.options().desugaredLibraryConfiguration.supportAllCallbacksFromLibrary) {
+    if (appView.options().desugaredLibrarySpecification.supportAllCallbacksFromLibrary()) {
       return true;
     }
     Map<DexType, DexType> emulateLibraryInterfaces =
-        appView.options().desugaredLibraryConfiguration.getEmulateLibraryInterface();
+        appView.options().desugaredLibrarySpecification.getEmulateLibraryInterface();
     return !(emulateLibraryInterfaces.containsKey(dexClass.type)
         || emulateLibraryInterfaces.containsValue(dexClass.type));
   }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java
similarity index 98%
rename from src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverter.java
rename to src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java
index 460c350..558faf7 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAPIConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-package com.android.tools.r8.ir.desugar.desugaredlibrary;
+package com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion;
 
 import com.android.tools.r8.cf.code.CfArrayLoad;
 import com.android.tools.r8.cf.code.CfArrayStore;
@@ -34,7 +34,7 @@
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.FreshLocalProvider;
 import com.android.tools.r8.ir.desugar.LocalStackAllocator;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryClasspathWrapperSynthesizeEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryClasspathWrapperSynthesizeEventConsumer;
 import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APIConversionCfCodeProvider;
 import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
 import com.android.tools.r8.utils.DescriptorUtils;
@@ -181,7 +181,7 @@
     return interfaceResult != null
         && appView
             .options()
-            .desugaredLibraryConfiguration
+            .desugaredLibrarySpecification
             .getEmulateLibraryInterface()
             .containsKey(interfaceResult.getHolderType());
   }
@@ -209,6 +209,7 @@
     DexProto newProto = appView.dexItemFactory().createProto(newReturnType, newParameters);
     return appView.dexItemFactory().createMethod(holder, newProto, originalMethod.name);
   }
+
   public void generateTrackingWarnings() {
     generateTrackDesugaredAPIWarnings(trackedAPIs, "", appView);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryEnumConversionSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryEnumConversionSynthesizer.java
similarity index 93%
rename from src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryEnumConversionSynthesizer.java
rename to src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryEnumConversionSynthesizer.java
index c97d2ab..e71ec21 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryEnumConversionSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryEnumConversionSynthesizer.java
@@ -2,9 +2,9 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-package com.android.tools.r8.ir.desugar.desugaredlibrary;
+package com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion;
 
-import static com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter.vivifiedTypeFor;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter.vivifiedTypeFor;
 
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.graph.AppView;
@@ -16,7 +16,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.ir.desugar.CfClassSynthesizerDesugaringEventConsumer;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryClasspathWrapperSynthesizeEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryClasspathWrapperSynthesizeEventConsumer;
 import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.EnumArrayConversionCfCodeProvider;
 import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.EnumConversionCfCodeProvider;
 import com.android.tools.r8.synthesis.SyntheticClasspathClassBuilder;
@@ -172,7 +172,7 @@
             programContext,
             appView,
             builder -> buildEnumMethodsWithCode(builder, enumFields, type, vivifiedType),
-            eventConsumer::acceptWrapperProgramClass);
+            eventConsumer::acceptEnumConversionProgramClass);
   }
 
   private DexClass ensureEnumConversionClass(
@@ -192,6 +192,6 @@
             context.asClasspathOrLibraryClass(),
             appView,
             builder -> buildEnumMethodsWithoutCode(builder, type, vivifiedType),
-            eventConsumer::acceptWrapperClasspathClass);
+            eventConsumer::acceptEnumConversionClasspathClass);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryWrapperSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java
similarity index 96%
rename from src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryWrapperSynthesizer.java
rename to src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java
index 14240a6..55d61b9 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryWrapperSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-package com.android.tools.r8.ir.desugar.desugaredlibrary;
+package com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion;
 
 import com.android.tools.r8.androidapi.ComputedApiLevel;
 import com.android.tools.r8.dex.Constants;
@@ -25,8 +25,9 @@
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.desugar.CfClassSynthesizerDesugaring;
 import com.android.tools.r8.ir.desugar.CfClassSynthesizerDesugaringEventConsumer;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryClasspathWrapperSynthesizeEventConsumer;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryClasspathWrapperSynthesizeEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
 import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APIConverterConstructorCfCodeProvider;
 import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APIConverterThrowRuntimeExceptionCfCodeProvider;
 import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APIConverterVivifiedWrapperCfCodeProvider;
@@ -178,7 +179,7 @@
     // ConversionType holds the methods "rewrittenType convert(type)" and the other way around.
     // But everything is going to be rewritten, so we need to use vivifiedType and type".
     DexType conversionHolder =
-        appView.options().desugaredLibraryConfiguration.getCustomConversions().get(type);
+        appView.options().desugaredLibrarySpecification.getCustomConversions().get(type);
     if (conversionHolder != null) {
       return factory.createMethod(
           conversionHolder, factory.createProto(destType, srcType), factory.convertMethodName);
@@ -187,7 +188,7 @@
   }
 
   private boolean canConvert(DexType type) {
-    return appView.options().desugaredLibraryConfiguration.getCustomConversions().containsKey(type)
+    return appView.options().desugaredLibrarySpecification.getCustomConversions().containsKey(type)
         || canGenerateWrapper(type);
   }
 
@@ -215,7 +216,7 @@
   }
 
   private boolean canGenerateWrapper(DexType type) {
-    return appView.options().desugaredLibraryConfiguration.getWrapperConversions().contains(type);
+    return appView.options().desugaredLibrarySpecification.getWrapperConversions().contains(type);
   }
 
   private DexClass getValidClassToWrap(DexType type) {
@@ -476,7 +477,7 @@
       if (holderClass == null) {
         assert appView
             .options()
-            .desugaredLibraryConfiguration
+            .desugaredLibrarySpecification
             .getEmulateLibraryInterface()
             .containsValue(dexEncodedMethod.getHolderType());
         isInterface = true;
@@ -666,10 +667,10 @@
   // conversion methods are present.
   @Override
   public void synthesizeClasses(CfClassSynthesizerDesugaringEventConsumer eventConsumer) {
-    DesugaredLibraryConfiguration conf = appView.options().desugaredLibraryConfiguration;
+    LegacyDesugaredLibrarySpecification spec = appView.options().desugaredLibrarySpecification;
     List<DexProgramClass> validClassesToWrap = new ArrayList<>();
-    for (DexType type : conf.getWrapperConversions()) {
-      assert !conf.getCustomConversions().containsKey(type);
+    for (DexType type : spec.getWrapperConversions()) {
+      assert !spec.getCustomConversions().containsKey(type);
       DexClass validClassToWrap = getValidClassToWrap(type);
       // In broken set-ups we can end up having a json files containing wrappers of non desugared
       // classes. Such wrappers are not required since the class won't be rewritten.
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryWrapperSynthesizerEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizerEventConsumer.java
similarity index 94%
rename from src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryWrapperSynthesizerEventConsumer.java
rename to src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizerEventConsumer.java
index 511e0d2..d6811bc 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryWrapperSynthesizerEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizerEventConsumer.java
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-package com.android.tools.r8.ir.desugar.desugaredlibrary;
+package com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion;
 
 import com.android.tools.r8.graph.DexClasspathClass;
 import com.android.tools.r8.graph.DexProgramClass;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecification.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecification.java
new file mode 100644
index 0000000..6198ce5
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecification.java
@@ -0,0 +1,177 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexReference;
+import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.desugar.PrefixRewritingMapper;
+import com.android.tools.r8.ir.desugar.PrefixRewritingMapper.DesugarPrefixRewritingMapper;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.Pair;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class LegacyDesugaredLibrarySpecification {
+
+  private final boolean libraryCompilation;
+  private final LegacyTopLevelFlags topLevelFlags;
+  private final LegacyRewritingFlags rewritingFlags;
+  private final PrefixRewritingMapper prefixRewritingMapper;
+
+  public static LegacyDesugaredLibrarySpecification withOnlyRewritePrefixForTesting(
+      Map<String, String> prefix, InternalOptions options) {
+    return new LegacyDesugaredLibrarySpecification(
+        LegacyTopLevelFlags.empty(),
+        LegacyRewritingFlags.withOnlyRewritePrefixForTesting(prefix, options),
+        true,
+        options.itemFactory);
+  }
+
+  public static LegacyDesugaredLibrarySpecification empty() {
+    return new LegacyDesugaredLibrarySpecification(
+        LegacyTopLevelFlags.empty(), LegacyRewritingFlags.empty(), false, null) {
+
+      @Override
+      public boolean isSupported(DexReference reference, AppView<?> appView) {
+        return false;
+      }
+
+      @Override
+      public boolean isEmptyConfiguration() {
+        return true;
+      }
+    };
+  }
+
+  public LegacyDesugaredLibrarySpecification(
+      LegacyTopLevelFlags topLevelFlags,
+      LegacyRewritingFlags rewritingFlags,
+      boolean libraryCompilation,
+      DexItemFactory factory) {
+    this.libraryCompilation = libraryCompilation;
+    this.topLevelFlags = topLevelFlags;
+    this.rewritingFlags = rewritingFlags;
+    this.prefixRewritingMapper =
+        rewritingFlags.getRewritePrefix().isEmpty()
+            ? PrefixRewritingMapper.empty()
+            : new DesugarPrefixRewritingMapper(
+                rewritingFlags.getRewritePrefix(), factory, libraryCompilation);
+  }
+
+  public boolean supportAllCallbacksFromLibrary() {
+    return topLevelFlags.supportAllCallbacksFromLibrary();
+  }
+
+  public PrefixRewritingMapper getPrefixRewritingMapper() {
+    return prefixRewritingMapper;
+  }
+
+  public AndroidApiLevel getRequiredCompilationApiLevel() {
+    return topLevelFlags.getRequiredCompilationAPILevel();
+  }
+
+  public boolean isLibraryCompilation() {
+    return libraryCompilation;
+  }
+
+  public String getSynthesizedLibraryClassesPackagePrefix() {
+    return topLevelFlags.getSynthesizedLibraryClassesPackagePrefix();
+  }
+
+  // TODO(b/183918843): We are currently computing a new name for the class by replacing the
+  //  initial package prefix by the synthesized library class package prefix, it would be better
+  //  to make the rewriting explicit in the desugared library json file.
+  public String convertJavaNameToDesugaredLibrary(DexType type) {
+    String prefix =
+        DescriptorUtils.getJavaTypeFromBinaryName(getSynthesizedLibraryClassesPackagePrefix());
+    String interfaceType = type.toString();
+    int firstPackage = interfaceType.indexOf('.');
+    return prefix + interfaceType.substring(firstPackage + 1);
+  }
+
+  public String getIdentifier() {
+    return topLevelFlags.getIdentifier();
+  }
+
+  public Map<String, String> getRewritePrefix() {
+    return rewritingFlags.getRewritePrefix();
+  }
+
+  public boolean hasEmulatedLibraryInterfaces() {
+    return !getEmulateLibraryInterface().isEmpty();
+  }
+
+  public Map<DexType, DexType> getEmulateLibraryInterface() {
+    return rewritingFlags.getEmulateLibraryInterface();
+  }
+
+  public boolean isSupported(DexReference reference, AppView<?> appView) {
+    return prefixRewritingMapper.hasRewrittenType(reference.getContextType(), appView);
+  }
+
+  // If the method is retargeted, answers the retargeted method, else null.
+  public DexMethod retargetMethod(DexEncodedMethod method, AppView<?> appView) {
+    Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
+        rewritingFlags.getRetargetCoreLibMember();
+    Map<DexType, DexType> typeMap = retargetCoreLibMember.get(method.getName());
+    if (typeMap != null && typeMap.containsKey(method.getHolderType())) {
+      return appView
+          .dexItemFactory()
+          .createMethod(
+              typeMap.get(method.getHolderType()),
+              appView.dexItemFactory().prependHolderToProto(method.getReference()),
+              method.getName());
+    }
+    return null;
+  }
+
+  public DexMethod retargetMethod(DexClassAndMethod method, AppView<?> appView) {
+    return retargetMethod(method.getDefinition(), appView);
+  }
+
+  public Map<DexString, Map<DexType, DexType>> getRetargetCoreLibMember() {
+    return rewritingFlags.getRetargetCoreLibMember();
+  }
+
+  public Map<DexType, DexType> getBackportCoreLibraryMember() {
+    return rewritingFlags.getBackportCoreLibraryMember();
+  }
+
+  public Map<DexType, DexType> getCustomConversions() {
+    return rewritingFlags.getCustomConversions();
+  }
+
+  public Set<DexType> getWrapperConversions() {
+    return rewritingFlags.getWrapperConversions();
+  }
+
+  public List<Pair<DexType, DexString>> getDontRewriteInvocation() {
+    return rewritingFlags.getDontRewriteInvocation();
+  }
+
+  public Set<DexType> getDontRetargetLibMember() {
+    return rewritingFlags.getDontRetargetLibMember();
+  }
+
+  public List<String> getExtraKeepRules() {
+    return topLevelFlags.getExtraKeepRules();
+  }
+
+  public String getJsonSource() {
+    return topLevelFlags.getJsonSource();
+  }
+
+  public boolean isEmptyConfiguration() {
+    return false;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryConfigurationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecificationParser.java
similarity index 70%
rename from src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryConfigurationParser.java
rename to src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecificationParser.java
index f8b69f6..7cece17 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecificationParser.java
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-package com.android.tools.r8.ir.desugar.desugaredlibrary;
+package com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification;
 
 import com.android.tools.r8.StringResource;
 import com.android.tools.r8.graph.DexItemFactory;
@@ -21,7 +21,7 @@
 import java.util.Map;
 import java.util.function.Consumer;
 
-public class DesugaredLibraryConfigurationParser {
+public class LegacyDesugaredLibrarySpecificationParser {
 
   public static final int MAX_SUPPORTED_VERSION = 4;
   public static final SemanticVersion MIN_SUPPORTED_VERSION = new SemanticVersion(1, 0, 9);
@@ -55,10 +55,10 @@
   private final boolean libraryCompilation;
   private final int minAPILevel;
 
-  private DesugaredLibraryConfiguration.Builder configurationBuilder = null;
   private Origin origin;
+  private JsonObject jsonConfig;
 
-  public DesugaredLibraryConfigurationParser(
+  public LegacyDesugaredLibrarySpecificationParser(
       DexItemFactory dexItemFactory,
       Reporter reporter,
       boolean libraryCompilation,
@@ -69,7 +69,24 @@
     this.libraryCompilation = libraryCompilation;
   }
 
-  private JsonElement required(JsonObject json, String key) {
+  public DexItemFactory dexItemFactory() {
+    return dexItemFactory;
+  }
+
+  public Reporter reporter() {
+    return reporter;
+  }
+
+  public JsonObject getJsonConfig() {
+    return jsonConfig;
+  }
+
+  public Origin getOrigin() {
+    assert origin != null;
+    return origin;
+  }
+
+  JsonElement required(JsonObject json, String key) {
     if (!json.has(key)) {
       throw reporter.fatalError(
           new StringDiagnostic(
@@ -79,23 +96,28 @@
     return json.get(key);
   }
 
-  public DesugaredLibraryConfiguration parse(StringResource stringResource) {
+  public LegacyDesugaredLibrarySpecification parse(StringResource stringResource) {
     return parse(stringResource, builder -> {});
   }
 
-  public DesugaredLibraryConfiguration parse(
-      StringResource stringResource,
-      Consumer<DesugaredLibraryConfiguration.Builder> configurationAmender) {
-    origin = stringResource.getOrigin();
-    assert origin != null;
-    configurationBuilder = DesugaredLibraryConfiguration.builder(dexItemFactory, reporter, origin);
-    if (libraryCompilation) {
-      configurationBuilder.setLibraryCompilation();
-    } else {
-      configurationBuilder.setProgramCompilation();
-    }
+  public LegacyDesugaredLibrarySpecification parse(
+      StringResource stringResource, Consumer<LegacyTopLevelFlags.Builder> topLevelFlagAmender) {
+    String jsonConfigString = parseJson(stringResource);
+
+    LegacyTopLevelFlags topLevelFlags = parseTopLevelFlags(jsonConfigString, topLevelFlagAmender);
+
+    LegacyRewritingFlags legacyRewritingFlags = parseRewritingFlags();
+
+    LegacyDesugaredLibrarySpecification config =
+        new LegacyDesugaredLibrarySpecification(
+            topLevelFlags, legacyRewritingFlags, libraryCompilation, dexItemFactory);
+    origin = null;
+    return config;
+  }
+
+  String parseJson(StringResource stringResource) {
+    setOrigin(stringResource);
     String jsonConfigString;
-    JsonObject jsonConfig;
     try {
       jsonConfigString = stringResource.getString();
       JsonParser parser = new JsonParser();
@@ -103,8 +125,32 @@
     } catch (Exception e) {
       throw reporter.fatalError(new ExceptionDiagnostic(e, origin));
     }
+    return jsonConfigString;
+  }
 
-    configurationBuilder.setJsonSource(jsonConfigString);
+  void setOrigin(StringResource stringResource) {
+    origin = stringResource.getOrigin();
+    assert origin != null;
+  }
+
+  private LegacyRewritingFlags parseRewritingFlags() {
+    LegacyRewritingFlags.Builder builder =
+        LegacyRewritingFlags.builder(dexItemFactory, reporter, origin);
+    JsonElement commonFlags = required(jsonConfig, COMMON_FLAGS_KEY);
+    JsonElement libraryFlags = required(jsonConfig, LIBRARY_FLAGS_KEY);
+    JsonElement programFlags = required(jsonConfig, PROGRAM_FLAGS_KEY);
+    parseFlagsList(commonFlags.getAsJsonArray(), builder);
+    parseFlagsList(
+        libraryCompilation ? libraryFlags.getAsJsonArray() : programFlags.getAsJsonArray(),
+        builder);
+    return builder.build();
+  }
+
+  LegacyTopLevelFlags parseTopLevelFlags(
+      String jsonConfigString, Consumer<LegacyTopLevelFlags.Builder> topLevelFlagAmender) {
+    LegacyTopLevelFlags.Builder builder = LegacyTopLevelFlags.builder();
+
+    builder.setJsonSource(jsonConfigString);
 
     JsonElement formatVersionElement = required(jsonConfig, CONFIGURATION_FORMAT_VERSION_KEY);
     int formatVersion = formatVersionElement.getAsInt();
@@ -132,101 +178,90 @@
     String groupID = required(jsonConfig, GROUP_ID_KEY).getAsString();
     String artifactID = required(jsonConfig, ARTIFACT_ID_KEY).getAsString();
     String identifier = String.join(":", groupID, artifactID, version);
-    configurationBuilder.setDesugaredLibraryIdentifier(identifier);
-    configurationBuilder.setSynthesizedLibraryClassesPackagePrefix(
+    builder.setDesugaredLibraryIdentifier(identifier);
+    builder.setSynthesizedLibraryClassesPackagePrefix(
         required(jsonConfig, SYNTHESIZED_LIBRARY_CLASSES_PACKAGE_PREFIX_KEY).getAsString());
 
     int required_compilation_api_level =
         required(jsonConfig, REQUIRED_COMPILATION_API_LEVEL_KEY).getAsInt();
-    configurationBuilder.setRequiredCompilationAPILevel(
+    builder.setRequiredCompilationAPILevel(
         AndroidApiLevel.getAndroidApiLevel(required_compilation_api_level));
-    JsonElement commonFlags = required(jsonConfig, COMMON_FLAGS_KEY);
-    JsonElement libraryFlags = required(jsonConfig, LIBRARY_FLAGS_KEY);
-    JsonElement programFlags = required(jsonConfig, PROGRAM_FLAGS_KEY);
-    parseFlagsList(commonFlags.getAsJsonArray());
-    parseFlagsList(
-        libraryCompilation ? libraryFlags.getAsJsonArray() : programFlags.getAsJsonArray());
     if (jsonConfig.has(SHRINKER_CONFIG_KEY)) {
       JsonArray jsonKeepRules = jsonConfig.get(SHRINKER_CONFIG_KEY).getAsJsonArray();
       List<String> extraKeepRules = new ArrayList<>(jsonKeepRules.size());
       for (JsonElement keepRule : jsonKeepRules) {
         extraKeepRules.add(keepRule.getAsString());
       }
-      configurationBuilder.setExtraKeepRules(extraKeepRules);
+      builder.setExtraKeepRules(extraKeepRules);
     }
 
     if (jsonConfig.has(SUPPORT_ALL_CALLBACKS_FROM_LIBRARY_KEY)) {
       boolean supportAllCallbacksFromLibrary =
           jsonConfig.get(SUPPORT_ALL_CALLBACKS_FROM_LIBRARY_KEY).getAsBoolean();
-      configurationBuilder.setSupportAllCallbacksFromLibrary(supportAllCallbacksFromLibrary);
+      builder.setSupportAllCallbacksFromLibrary(supportAllCallbacksFromLibrary);
     }
-    configurationAmender.accept(configurationBuilder);
-    DesugaredLibraryConfiguration config = configurationBuilder.build();
-    configurationBuilder = null;
-    origin = null;
-    return config;
+
+    topLevelFlagAmender.accept(builder);
+
+    return builder.build();
   }
 
-  private void parseFlagsList(JsonArray jsonFlags) {
+  private void parseFlagsList(JsonArray jsonFlags, LegacyRewritingFlags.Builder builder) {
     for (JsonElement jsonFlagSet : jsonFlags) {
       JsonObject flag = jsonFlagSet.getAsJsonObject();
       int api_level_below_or_equal = required(flag, API_LEVEL_BELOW_OR_EQUAL_KEY).getAsInt();
       if (minAPILevel <= api_level_below_or_equal) {
-        parseFlags(flag);
+        parseFlags(flag, builder);
       }
     }
   }
 
-  private void parseFlags(JsonObject jsonFlagSet) {
+  void parseFlags(JsonObject jsonFlagSet, LegacyRewritingFlags.Builder builder) {
     if (jsonFlagSet.has(REWRITE_PREFIX_KEY)) {
       for (Map.Entry<String, JsonElement> rewritePrefix :
           jsonFlagSet.get(REWRITE_PREFIX_KEY).getAsJsonObject().entrySet()) {
-        configurationBuilder.putRewritePrefix(
-            rewritePrefix.getKey(), rewritePrefix.getValue().getAsString());
+        builder.putRewritePrefix(rewritePrefix.getKey(), rewritePrefix.getValue().getAsString());
       }
     }
     if (jsonFlagSet.has(RETARGET_LIB_MEMBER_KEY)) {
       for (Map.Entry<String, JsonElement> retarget :
           jsonFlagSet.get(RETARGET_LIB_MEMBER_KEY).getAsJsonObject().entrySet()) {
-        configurationBuilder.putRetargetCoreLibMember(
-            retarget.getKey(), retarget.getValue().getAsString());
+        builder.putRetargetCoreLibMember(retarget.getKey(), retarget.getValue().getAsString());
       }
     }
     if (jsonFlagSet.has(BACKPORT_KEY)) {
       for (Map.Entry<String, JsonElement> backport :
           jsonFlagSet.get(BACKPORT_KEY).getAsJsonObject().entrySet()) {
-        configurationBuilder.putBackportCoreLibraryMember(
-            backport.getKey(), backport.getValue().getAsString());
+        builder.putBackportCoreLibraryMember(backport.getKey(), backport.getValue().getAsString());
       }
     }
     if (jsonFlagSet.has(EMULATE_INTERFACE_KEY)) {
       for (Map.Entry<String, JsonElement> itf :
           jsonFlagSet.get(EMULATE_INTERFACE_KEY).getAsJsonObject().entrySet()) {
-        configurationBuilder.putEmulateLibraryInterface(itf.getKey(), itf.getValue().getAsString());
+        builder.putEmulateLibraryInterface(itf.getKey(), itf.getValue().getAsString());
       }
     }
     if (jsonFlagSet.has(CUSTOM_CONVERSION_KEY)) {
       for (Map.Entry<String, JsonElement> conversion :
           jsonFlagSet.get(CUSTOM_CONVERSION_KEY).getAsJsonObject().entrySet()) {
-        configurationBuilder.putCustomConversion(
-            conversion.getKey(), conversion.getValue().getAsString());
+        builder.putCustomConversion(conversion.getKey(), conversion.getValue().getAsString());
       }
     }
     if (jsonFlagSet.has(WRAPPER_CONVERSION_KEY)) {
       for (JsonElement wrapper : jsonFlagSet.get(WRAPPER_CONVERSION_KEY).getAsJsonArray()) {
-        configurationBuilder.addWrapperConversion(wrapper.getAsString());
+        builder.addWrapperConversion(wrapper.getAsString());
       }
     }
     if (jsonFlagSet.has(DONT_REWRITE_KEY)) {
       JsonArray dontRewrite = jsonFlagSet.get(DONT_REWRITE_KEY).getAsJsonArray();
       for (JsonElement rewrite : dontRewrite) {
-        configurationBuilder.addDontRewriteInvocation(rewrite.getAsString());
+        builder.addDontRewriteInvocation(rewrite.getAsString());
       }
     }
     if (jsonFlagSet.has(DONT_RETARGET_LIB_MEMBER_KEY)) {
       JsonArray dontRetarget = jsonFlagSet.get(DONT_RETARGET_LIB_MEMBER_KEY).getAsJsonArray();
       for (JsonElement rewrite : dontRetarget) {
-        configurationBuilder.addDontRetargetLibMember(rewrite.getAsString());
+        builder.addDontRetargetLibMember(rewrite.getAsString());
       }
     }
   }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyRewritingFlags.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyRewritingFlags.java
new file mode 100644
index 0000000..61a2eb8
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyRewritingFlags.java
@@ -0,0 +1,319 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification;
+
+import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.Pair;
+import com.android.tools.r8.utils.Reporter;
+import com.android.tools.r8.utils.StringDiagnostic;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import com.google.common.collect.Sets.SetView;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public class LegacyRewritingFlags {
+
+  private final Map<String, String> rewritePrefix;
+  private final Map<DexType, DexType> emulateLibraryInterface;
+  private final Map<DexString, Map<DexType, DexType>> retargetCoreLibMember;
+  private final Map<DexType, DexType> backportCoreLibraryMember;
+  private final Map<DexType, DexType> customConversions;
+  private final List<Pair<DexType, DexString>> dontRewriteInvocation;
+  private final Set<DexType> dontRetargetLibMember;
+  private final Set<DexType> wrapperConversions;
+
+  LegacyRewritingFlags(
+      Map<String, String> rewritePrefix,
+      Map<DexType, DexType> emulateLibraryInterface,
+      Map<DexString, Map<DexType, DexType>> retargetCoreLibMember,
+      Map<DexType, DexType> backportCoreLibraryMember,
+      Map<DexType, DexType> customConversions,
+      List<Pair<DexType, DexString>> dontRewriteInvocation,
+      Set<DexType> dontRetargetLibMember,
+      Set<DexType> wrapperConversions) {
+    this.rewritePrefix = rewritePrefix;
+    this.emulateLibraryInterface = emulateLibraryInterface;
+    this.retargetCoreLibMember = retargetCoreLibMember;
+    this.backportCoreLibraryMember = backportCoreLibraryMember;
+    this.customConversions = customConversions;
+    this.dontRewriteInvocation = dontRewriteInvocation;
+    this.dontRetargetLibMember = dontRetargetLibMember;
+    this.wrapperConversions = wrapperConversions;
+  }
+
+  public static LegacyRewritingFlags empty() {
+    return new LegacyRewritingFlags(
+        ImmutableMap.of(),
+        ImmutableMap.of(),
+        ImmutableMap.of(),
+        ImmutableMap.of(),
+        ImmutableMap.of(),
+        ImmutableList.of(),
+        ImmutableSet.of(),
+        ImmutableSet.of());
+  }
+
+  public static LegacyRewritingFlags withOnlyRewritePrefixForTesting(
+      Map<String, String> prefix, InternalOptions options) {
+    Builder builder = builder(options.dexItemFactory(), options.reporter, Origin.unknown());
+    prefix.forEach(builder::putRewritePrefix);
+    return builder.build();
+  }
+
+  public static Builder builder(DexItemFactory dexItemFactory, Reporter reporter, Origin origin) {
+    return new Builder(dexItemFactory, reporter, origin);
+  }
+
+  public Builder newBuilder(DexItemFactory dexItemFactory, Reporter reporter, Origin origin) {
+    return new Builder(
+        dexItemFactory,
+        reporter,
+        origin,
+        rewritePrefix,
+        emulateLibraryInterface,
+        retargetCoreLibMember,
+        backportCoreLibraryMember,
+        customConversions,
+        dontRewriteInvocation,
+        dontRetargetLibMember,
+        wrapperConversions);
+  }
+
+  public Map<String, String> getRewritePrefix() {
+    return rewritePrefix;
+  }
+
+  public Map<DexType, DexType> getEmulateLibraryInterface() {
+    return emulateLibraryInterface;
+  }
+
+  public Map<DexString, Map<DexType, DexType>> getRetargetCoreLibMember() {
+    return retargetCoreLibMember;
+  }
+
+  public Map<DexType, DexType> getBackportCoreLibraryMember() {
+    return backportCoreLibraryMember;
+  }
+
+  public Map<DexType, DexType> getCustomConversions() {
+    return customConversions;
+  }
+
+  public List<Pair<DexType, DexString>> getDontRewriteInvocation() {
+    return dontRewriteInvocation;
+  }
+
+  public Set<DexType> getDontRetargetLibMember() {
+    return dontRetargetLibMember;
+  }
+
+  public Set<DexType> getWrapperConversions() {
+    return wrapperConversions;
+  }
+
+  public static class Builder {
+
+    private final DexItemFactory factory;
+    private final Reporter reporter;
+    private final Origin origin;
+
+    private final Map<String, String> rewritePrefix;
+    private final Map<DexType, DexType> emulateLibraryInterface;
+    private final Map<DexString, Map<DexType, DexType>> retargetCoreLibMember;
+    private final Map<DexType, DexType> backportCoreLibraryMember;
+    private final Map<DexType, DexType> customConversions;
+    private final List<Pair<DexType, DexString>> dontRewriteInvocation;
+    private final Set<DexType> dontRetargetLibMember;
+    private final Set<DexType> wrapperConversions;
+
+    Builder(DexItemFactory factory, Reporter reporter, Origin origin) {
+      this(
+          factory,
+          reporter,
+          origin,
+          new HashMap<>(),
+          new IdentityHashMap<>(),
+          new IdentityHashMap<>(),
+          new IdentityHashMap<>(),
+          new IdentityHashMap<>(),
+          new ArrayList<>(),
+          Sets.newIdentityHashSet(),
+          Sets.newIdentityHashSet());
+    }
+
+    Builder(
+        DexItemFactory factory,
+        Reporter reporter,
+        Origin origin,
+        Map<String, String> rewritePrefix,
+        Map<DexType, DexType> emulateLibraryInterface,
+        Map<DexString, Map<DexType, DexType>> retargetCoreLibMember,
+        Map<DexType, DexType> backportCoreLibraryMember,
+        Map<DexType, DexType> customConversions,
+        List<Pair<DexType, DexString>> dontRewriteInvocation,
+        Set<DexType> dontRetargetLibMember,
+        Set<DexType> wrapperConversions) {
+      this.factory = factory;
+      this.reporter = reporter;
+      this.origin = origin;
+      this.rewritePrefix = rewritePrefix;
+      this.emulateLibraryInterface = emulateLibraryInterface;
+      this.retargetCoreLibMember = retargetCoreLibMember;
+      this.backportCoreLibraryMember = backportCoreLibraryMember;
+      this.customConversions = customConversions;
+      this.dontRewriteInvocation = dontRewriteInvocation;
+      this.dontRetargetLibMember = dontRetargetLibMember;
+      this.wrapperConversions = wrapperConversions;
+    }
+
+    // Utility to set values. Currently assumes the key is fresh.
+    private <K, V> void put(Map<K, V> map, K key, V value, String desc) {
+      if (map.containsKey(key)) {
+        throw reporter.fatalError(
+            new StringDiagnostic(
+                "Invalid desugared library configuration. "
+                    + " Duplicate assignment of key: '"
+                    + key
+                    + "' in sections for '"
+                    + desc
+                    + "'",
+                origin));
+      }
+      map.put(key, value);
+    }
+
+    public Builder putRewritePrefix(String prefix, String rewrittenPrefix) {
+      put(
+          rewritePrefix,
+          prefix,
+          rewrittenPrefix,
+          LegacyDesugaredLibrarySpecificationParser.REWRITE_PREFIX_KEY);
+      return this;
+    }
+
+    public Builder putEmulateLibraryInterface(
+        String emulateLibraryItf, String rewrittenEmulateLibraryItf) {
+      DexType interfaceType = stringClassToDexType(emulateLibraryItf);
+      DexType rewrittenType = stringClassToDexType(rewrittenEmulateLibraryItf);
+      put(
+          emulateLibraryInterface,
+          interfaceType,
+          rewrittenType,
+          LegacyDesugaredLibrarySpecificationParser.EMULATE_INTERFACE_KEY);
+      return this;
+    }
+
+    public Builder putCustomConversion(String type, String conversionHolder) {
+      DexType dexType = stringClassToDexType(type);
+      DexType conversionType = stringClassToDexType(conversionHolder);
+      put(
+          customConversions,
+          dexType,
+          conversionType,
+          LegacyDesugaredLibrarySpecificationParser.CUSTOM_CONVERSION_KEY);
+      return this;
+    }
+
+    public Builder addWrapperConversion(String type) {
+      DexType dexType = stringClassToDexType(type);
+      wrapperConversions.add(dexType);
+      return this;
+    }
+
+    public Builder putRetargetCoreLibMember(String retarget, String rewrittenRetarget) {
+      int index = sharpIndex(retarget, "retarget core library member");
+      DexString methodName = factory.createString(retarget.substring(index + 1));
+      retargetCoreLibMember.putIfAbsent(methodName, new IdentityHashMap<>());
+      Map<DexType, DexType> typeMap = retargetCoreLibMember.get(methodName);
+      DexType originalType = stringClassToDexType(retarget.substring(0, index));
+      DexType finalType = stringClassToDexType(rewrittenRetarget);
+      assert !typeMap.containsKey(originalType);
+      put(
+          typeMap,
+          originalType,
+          finalType,
+          LegacyDesugaredLibrarySpecificationParser.RETARGET_LIB_MEMBER_KEY);
+      return this;
+    }
+
+    public Builder putBackportCoreLibraryMember(String backport, String rewrittenBackport) {
+      DexType backportType = stringClassToDexType(backport);
+      DexType rewrittenBackportType = stringClassToDexType(rewrittenBackport);
+      put(
+          backportCoreLibraryMember,
+          backportType,
+          rewrittenBackportType,
+          LegacyDesugaredLibrarySpecificationParser.BACKPORT_KEY);
+      return this;
+    }
+
+    public Builder addDontRewriteInvocation(String dontRewriteInvocation) {
+      int index = sharpIndex(dontRewriteInvocation, "don't rewrite");
+      this.dontRewriteInvocation.add(
+          new Pair<>(
+              stringClassToDexType(dontRewriteInvocation.substring(0, index)),
+              factory.createString(dontRewriteInvocation.substring(index + 1))));
+      return this;
+    }
+
+    public Builder addDontRetargetLibMember(String dontRetargetLibMember) {
+      this.dontRetargetLibMember.add(stringClassToDexType(dontRetargetLibMember));
+      return this;
+    }
+
+    private int sharpIndex(String typeAndSelector, String descr) {
+      int index = typeAndSelector.lastIndexOf('#');
+      if (index <= 0 || index >= typeAndSelector.length() - 1) {
+        throw new CompilationError(
+            "Invalid " + descr + " specification (# position) in " + typeAndSelector + ".");
+      }
+      return index;
+    }
+
+    private DexType stringClassToDexType(String stringClass) {
+      return factory.createType(DescriptorUtils.javaTypeToDescriptor(stringClass));
+    }
+
+    public LegacyRewritingFlags build() {
+      validate();
+      return new LegacyRewritingFlags(
+          ImmutableMap.copyOf(rewritePrefix),
+          ImmutableMap.copyOf(emulateLibraryInterface),
+          ImmutableMap.copyOf(retargetCoreLibMember),
+          ImmutableMap.copyOf(backportCoreLibraryMember),
+          ImmutableMap.copyOf(customConversions),
+          ImmutableList.copyOf(dontRewriteInvocation),
+          ImmutableSet.copyOf(dontRetargetLibMember),
+          ImmutableSet.copyOf(wrapperConversions));
+    }
+
+    private void validate() {
+      SetView<DexType> dups = Sets.intersection(customConversions.keySet(), wrapperConversions);
+      if (!dups.isEmpty()) {
+        throw reporter.fatalError(
+            new StringDiagnostic(
+                "Invalid desugared library configuration. "
+                    + "Duplicate types in custom conversions and wrapper conversions: "
+                    + String.join(
+                        ", ", dups.stream().map(DexType::toString).collect(Collectors.toSet())),
+                origin));
+      }
+    }
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyTopLevelFlags.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyTopLevelFlags.java
new file mode 100644
index 0000000..465d125
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyTopLevelFlags.java
@@ -0,0 +1,145 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification;
+
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+
+public class LegacyTopLevelFlags {
+
+  public static final String FALL_BACK_SYNTHESIZED_CLASSES_PACKAGE_PREFIX = "j$/";
+  public static final boolean FALL_BACK_SUPPORT_ALL_CALLBACKS_FROM_LIBRARY = true;
+
+  private final AndroidApiLevel requiredCompilationAPILevel;
+  private final String synthesizedLibraryClassesPackagePrefix;
+  private final String identifier;
+  private final String jsonSource;
+  // Setting supportAllCallbacksFromLibrary reduces the number of generated call-backs,
+  // more specifically:
+  // - no call-back is generated for emulated interface method overrides (forEach, etc.)
+  // - no call-back is generated inside the desugared library itself.
+  // Such setting decreases significantly the desugared library dex file, but virtual calls from
+  // within the library to desugared library classes instances as receiver may be incorrect, for
+  // example the method forEach in Iterable may be executed over a concrete implementation.
+  private final boolean supportAllCallbacksFromLibrary;
+  private final List<String> extraKeepRules;
+
+  LegacyTopLevelFlags(
+      AndroidApiLevel requiredCompilationAPILevel,
+      String synthesizedLibraryClassesPackagePrefix,
+      String identifier,
+      String jsonSource,
+      boolean supportAllCallbacksFromLibrary,
+      List<String> extraKeepRules) {
+    this.requiredCompilationAPILevel = requiredCompilationAPILevel;
+    this.synthesizedLibraryClassesPackagePrefix = synthesizedLibraryClassesPackagePrefix;
+    this.identifier = identifier;
+    this.jsonSource = jsonSource;
+    this.supportAllCallbacksFromLibrary = supportAllCallbacksFromLibrary;
+    this.extraKeepRules = extraKeepRules;
+  }
+
+  public static LegacyTopLevelFlags empty() {
+    return new LegacyTopLevelFlags(
+        AndroidApiLevel.B,
+        FALL_BACK_SYNTHESIZED_CLASSES_PACKAGE_PREFIX,
+        null,
+        null,
+        FALL_BACK_SUPPORT_ALL_CALLBACKS_FROM_LIBRARY,
+        ImmutableList.of());
+  }
+
+  public static LegacyTopLevelFlags testing() {
+    return new LegacyTopLevelFlags(
+        AndroidApiLevel.B,
+        FALL_BACK_SYNTHESIZED_CLASSES_PACKAGE_PREFIX,
+        "testing",
+        null,
+        FALL_BACK_SUPPORT_ALL_CALLBACKS_FROM_LIBRARY,
+        ImmutableList.of());
+  }
+
+  public static Builder builder() {
+    return new Builder();
+  }
+
+  public AndroidApiLevel getRequiredCompilationAPILevel() {
+    return requiredCompilationAPILevel;
+  }
+
+  public String getSynthesizedLibraryClassesPackagePrefix() {
+    return synthesizedLibraryClassesPackagePrefix;
+  }
+
+  public String getIdentifier() {
+    return identifier;
+  }
+
+  public String getJsonSource() {
+    return jsonSource;
+  }
+
+  public boolean supportAllCallbacksFromLibrary() {
+    return supportAllCallbacksFromLibrary;
+  }
+
+  public List<String> getExtraKeepRules() {
+    return extraKeepRules;
+  }
+
+  public static class Builder {
+
+    private AndroidApiLevel requiredCompilationAPILevel;
+    private String synthesizedLibraryClassesPackagePrefix =
+        FALL_BACK_SYNTHESIZED_CLASSES_PACKAGE_PREFIX;
+    private String identifier;
+    private String jsonSource;
+    private boolean supportAllCallbacksFromLibrary = FALL_BACK_SUPPORT_ALL_CALLBACKS_FROM_LIBRARY;
+    private List<String> extraKeepRules;
+
+    Builder() {}
+
+    public Builder setRequiredCompilationAPILevel(AndroidApiLevel requiredCompilationAPILevel) {
+      this.requiredCompilationAPILevel = requiredCompilationAPILevel;
+      return this;
+    }
+
+    public Builder setSynthesizedLibraryClassesPackagePrefix(String prefix) {
+      this.synthesizedLibraryClassesPackagePrefix = prefix.replace('.', '/');
+      return this;
+    }
+
+    public Builder setDesugaredLibraryIdentifier(String identifier) {
+      this.identifier = identifier;
+      return this;
+    }
+
+    public Builder setJsonSource(String jsonSource) {
+      this.jsonSource = jsonSource;
+      return this;
+    }
+
+    public Builder setSupportAllCallbacksFromLibrary(boolean supportAllCallbacksFromLibrary) {
+      this.supportAllCallbacksFromLibrary = supportAllCallbacksFromLibrary;
+      return this;
+    }
+
+    public Builder setExtraKeepRules(List<String> rules) {
+      extraKeepRules = rules;
+      return this;
+    }
+
+    public LegacyTopLevelFlags build() {
+      return new LegacyTopLevelFlags(
+          requiredCompilationAPILevel,
+          synthesizedLibraryClassesPackagePrefix,
+          identifier,
+          jsonSource,
+          supportAllCallbacksFromLibrary,
+          extraKeepRules);
+    }
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/MultiAPILevelLegacyDesugaredLibrarySpecification.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/MultiAPILevelLegacyDesugaredLibrarySpecification.java
new file mode 100644
index 0000000..76a0b07
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/MultiAPILevelLegacyDesugaredLibrarySpecification.java
@@ -0,0 +1,26 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification;
+
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+
+public class MultiAPILevelLegacyDesugaredLibrarySpecification {
+
+  private final LegacyTopLevelFlags topLevelFlags;
+  private final Int2ObjectMap<LegacyRewritingFlags> commonFlags;
+  private final Int2ObjectMap<LegacyRewritingFlags> libraryFlags;
+  private final Int2ObjectMap<LegacyRewritingFlags> programFlags;
+
+  public MultiAPILevelLegacyDesugaredLibrarySpecification(
+      LegacyTopLevelFlags topLevelFlags,
+      Int2ObjectMap<LegacyRewritingFlags> commonFlags,
+      Int2ObjectMap<LegacyRewritingFlags> libraryFlags,
+      Int2ObjectMap<LegacyRewritingFlags> programFlags) {
+    this.topLevelFlags = topLevelFlags;
+    this.commonFlags = commonFlags;
+    this.libraryFlags = libraryFlags;
+    this.programFlags = programFlags;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/MultiAPILevelLegacyDesugaredLibrarySpecificationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/MultiAPILevelLegacyDesugaredLibrarySpecificationParser.java
new file mode 100644
index 0000000..708b300
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/MultiAPILevelLegacyDesugaredLibrarySpecificationParser.java
@@ -0,0 +1,55 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification;
+
+import com.android.tools.r8.StringResource;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.utils.Reporter;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+
+public class MultiAPILevelLegacyDesugaredLibrarySpecificationParser
+    extends LegacyDesugaredLibrarySpecificationParser {
+
+  public MultiAPILevelLegacyDesugaredLibrarySpecificationParser(
+      DexItemFactory dexItemFactory, Reporter reporter) {
+    super(dexItemFactory, reporter, false, 1);
+  }
+
+  public MultiAPILevelLegacyDesugaredLibrarySpecification parseMultiLevelConfiguration(
+      StringResource stringResource) {
+
+    String jsonConfigString = parseJson(stringResource);
+
+    LegacyTopLevelFlags topLevelFlags = parseTopLevelFlags(jsonConfigString, builder -> {});
+
+    Int2ObjectMap<LegacyRewritingFlags> commonFlags = parseAllFlags(COMMON_FLAGS_KEY);
+    Int2ObjectMap<LegacyRewritingFlags> libraryFlags = parseAllFlags(LIBRARY_FLAGS_KEY);
+    Int2ObjectMap<LegacyRewritingFlags> programFlags = parseAllFlags(PROGRAM_FLAGS_KEY);
+
+    return new MultiAPILevelLegacyDesugaredLibrarySpecification(
+        topLevelFlags, commonFlags, libraryFlags, programFlags);
+  }
+
+  private Int2ObjectMap<LegacyRewritingFlags> parseAllFlags(String flagKey) {
+    JsonElement jsonFlags = required(getJsonConfig(), flagKey);
+    Int2ObjectMap<LegacyRewritingFlags> flags = new Int2ObjectArrayMap<>();
+    for (JsonElement jsonFlagSet : jsonFlags.getAsJsonArray()) {
+      JsonObject flag = jsonFlagSet.getAsJsonObject();
+      int api_level_below_or_equal = required(flag, API_LEVEL_BELOW_OR_EQUAL_KEY).getAsInt();
+      LegacyRewritingFlags.Builder builder =
+          flags.containsKey(api_level_below_or_equal)
+              ? flags
+                  .get(api_level_below_or_equal)
+                  .newBuilder(dexItemFactory(), reporter(), getOrigin())
+              : LegacyRewritingFlags.builder(dexItemFactory(), reporter(), getOrigin());
+      parseFlags(flag, builder);
+      flags.put(api_level_below_or_equal, builder.build());
+    }
+    return flags;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
similarity index 94%
rename from src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeter.java
rename to src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
index 01c504c..c4a01f6 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
@@ -2,9 +2,9 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-package com.android.tools.r8.ir.desugar.desugaredlibrary;
+package com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter;
 
-import static com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeter.InvokeRetargetingResult.NO_REWRITING;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeter.InvokeRetargetingResult.NO_REWRITING;
 
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.cf.code.CfInvoke;
@@ -24,7 +24,7 @@
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.FreshLocalProvider;
 import com.android.tools.r8.ir.desugar.LocalStackAllocator;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterInstructionEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterInstructionEventConsumer;
 import com.android.tools.r8.utils.collections.DexClassAndMethodSet;
 import java.util.Collection;
 import java.util.Collections;
@@ -130,7 +130,7 @@
     }
     if (appView
         .options()
-        .desugaredLibraryConfiguration
+        .desugaredLibrarySpecification
         .getDontRetargetLibMember()
         .contains(context.getContextType())) {
       return NO_REWRITING;
@@ -149,7 +149,7 @@
       // Final methods can be rewritten as a normal invoke.
       if (superTarget != null && !superTarget.getAccessFlags().isFinal()) {
         return InvokeRetargetingResult.createInvokeRetargetingResult(
-            appView.options().desugaredLibraryConfiguration.retargetMethod(superTarget, appView));
+            appView.options().desugaredLibrarySpecification.retargetMethod(superTarget, appView));
       }
     }
     return retarget;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterL8Synthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterL8Synthesizer.java
similarity index 93%
rename from src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterL8Synthesizer.java
rename to src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterL8Synthesizer.java
index 73cbd3d..d757c94 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterL8Synthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterL8Synthesizer.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.ir.desugar.desugaredlibrary;
+package com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter;
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClassAndMethod;
@@ -19,7 +19,7 @@
       AppView<?> appView, RetargetingInfo retargetingInfo) {
     assert appView.options().isDesugaredLibraryCompilation();
     if (retargetingInfo == null || retargetingInfo.getEmulatedDispatchMethods().isEmpty()) {
-      assert appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember().isEmpty();
+      assert appView.options().desugaredLibrarySpecification.getRetargetCoreLibMember().isEmpty();
       return null;
     }
     return new DesugaredLibraryRetargeterL8Synthesizer(appView, retargetingInfo);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterLibraryTypeSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterLibraryTypeSynthesizer.java
similarity index 97%
rename from src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterLibraryTypeSynthesizer.java
rename to src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterLibraryTypeSynthesizer.java
index faa5857..bbaa4cf 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterLibraryTypeSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterLibraryTypeSynthesizer.java
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-package com.android.tools.r8.ir.desugar.desugaredlibrary;
+package com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter;
 
 import com.android.tools.r8.ProgramResource.Kind;
 import com.android.tools.r8.dex.Constants;
@@ -40,7 +40,7 @@
 
   public static void checkForAssumedLibraryTypes(AppView<?> appView) {
     Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
-        appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember();
+        appView.options().desugaredLibrarySpecification.getRetargetCoreLibMember();
     for (DexString methodName : retargetCoreLibMember.keySet()) {
       for (DexType inType : retargetCoreLibMember.get(methodName).keySet()) {
         DexClass typeClass = appView.definitionFor(inType);
@@ -53,7 +53,7 @@
 
   public static void amendLibraryWithRetargetedMembers(AppView<AppInfoWithClassHierarchy> appView) {
     Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
-        appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember();
+        appView.options().desugaredLibrarySpecification.getRetargetCoreLibMember();
     Map<DexType, DexLibraryClass> synthesizedLibraryClasses =
         synthesizeLibraryClassesForRetargetedMembers(appView, retargetCoreLibMember);
     Map<DexLibraryClass, Set<DexEncodedMethod>> synthesizedLibraryMethods =
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterPostProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java
similarity index 95%
rename from src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterPostProcessor.java
rename to src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java
index 1a2adfb..aae08a7 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterPostProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.ir.desugar.desugaredlibrary;
+package com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter;
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
@@ -15,7 +15,7 @@
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaring;
 import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterPostProcessingEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterPostProcessingEventConsumer;
 import com.android.tools.r8.utils.OptionalBool;
 import com.android.tools.r8.utils.collections.DexClassAndMethodSet;
 import com.google.common.collect.Maps;
@@ -123,7 +123,7 @@
       }
       if (appView
           .options()
-          .desugaredLibraryConfiguration
+          .desugaredLibrarySpecification
           .getDontRetargetLibMember()
           .contains(clazz.getType())) {
         continue;
@@ -144,7 +144,7 @@
     // even if this results in invalid code, these classes are never desugared.
     // In desugared library, emulated interface methods can be overridden by retarget lib members.
     DexMethod forwardMethod =
-        appView.options().desugaredLibraryConfiguration.retargetMethod(target, appView);
+        appView.options().desugaredLibrarySpecification.retargetMethod(target, appView);
     assert forwardMethod != null && forwardMethod != target.getReference();
     DexEncodedMethod desugaringForwardingMethod =
         DexEncodedMethod.createDesugaringForwardingMethod(
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterSynthesizerEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterSynthesizerEventConsumer.java
similarity index 93%
rename from src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterSynthesizerEventConsumer.java
rename to src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterSynthesizerEventConsumer.java
index fab6f10..7785430 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterSynthesizerEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterSynthesizerEventConsumer.java
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-package com.android.tools.r8.ir.desugar.desugaredlibrary;
+package com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter;
 
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexClasspathClass;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterSyntheticHelper.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterSyntheticHelper.java
similarity index 93%
rename from src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterSyntheticHelper.java
rename to src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterSyntheticHelper.java
index 5dde56e..b1e77cd 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterSyntheticHelper.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterSyntheticHelper.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.ir.desugar.desugaredlibrary;
+package com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter;
 
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.graph.AppView;
@@ -11,8 +11,8 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.MethodAccessFlags;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterInstructionEventConsumer;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterL8SynthesizerEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterInstructionEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterL8SynthesizerEventConsumer;
 import com.android.tools.r8.ir.synthetic.EmulateInterfaceSyntheticCfCodeProvider;
 import com.android.tools.r8.synthesis.SyntheticClassBuilder;
 import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
@@ -151,7 +151,7 @@
           DexMethod desugarMethod =
               appView
                   .options()
-                  .desugaredLibraryConfiguration
+                  .desugaredLibrarySpecification
                   .retargetMethod(emulatedDispatchMethod, appView);
           assert desugarMethod
               != null; // This method is reached only for retarget core lib members.
@@ -178,7 +178,7 @@
 
   private void rewriteType(DexType type) {
     String newName =
-        appView.options().desugaredLibraryConfiguration.convertJavaNameToDesugaredLibrary(type);
+        appView.options().desugaredLibrarySpecification.convertJavaNameToDesugaredLibrary(type);
     DexType newType =
         appView.dexItemFactory().createType(DescriptorUtils.javaTypeToDescriptor(newName));
     appView.rewritePrefix.rewriteType(type, newType);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/RetargetingInfo.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/RetargetingInfo.java
similarity index 94%
rename from src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/RetargetingInfo.java
rename to src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/RetargetingInfo.java
index 525801f..d9656fe 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/RetargetingInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/RetargetingInfo.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.ir.desugar.desugaredlibrary;
+package com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter;
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
@@ -11,6 +11,7 @@
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
 import com.android.tools.r8.utils.WorkList;
 import com.android.tools.r8.utils.collections.DexClassAndMethodSet;
 import com.google.common.collect.ImmutableMap;
@@ -66,10 +67,10 @@
     }
 
     private RetargetingInfo computeRetargetingInfo() {
-      DesugaredLibraryConfiguration desugaredLibraryConfiguration =
-          appView.options().desugaredLibraryConfiguration;
+      LegacyDesugaredLibrarySpecification desugaredLibrarySpecification =
+          appView.options().desugaredLibrarySpecification;
       Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
-          desugaredLibraryConfiguration.getRetargetCoreLibMember();
+          desugaredLibrarySpecification.getRetargetCoreLibMember();
       if (retargetCoreLibMember.isEmpty()) {
         return new RetargetingInfo(
             ImmutableMap.of(), ImmutableMap.of(), DexClassAndMethodSet.empty());
@@ -108,7 +109,7 @@
           }
         }
       }
-      if (desugaredLibraryConfiguration.isLibraryCompilation()) {
+      if (desugaredLibrarySpecification.isLibraryCompilation()) {
         // TODO(b/177977763): This is only a workaround rewriting invokes of j.u.Arrays.deepEquals0
         // to j.u.DesugarArrays.deepEquals0.
         DexItemFactory itemFactory = appView.options().dexItemFactory();
@@ -152,7 +153,7 @@
     private boolean isEmulatedInterfaceDispatch(DexClassAndMethod method) {
       // Answers true if this method is already managed through emulated interface dispatch.
       Map<DexType, DexType> emulateLibraryInterface =
-          appView.options().desugaredLibraryConfiguration.getEmulateLibraryInterface();
+          appView.options().desugaredLibrarySpecification.getEmulateLibraryInterface();
       if (emulateLibraryInterface.isEmpty()) {
         return false;
       }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
index 36519f8..0d79ac1 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
@@ -376,10 +376,10 @@
     this.dexItemFactory = appView.dexItemFactory();
     this.helper = new InterfaceDesugaringSyntheticHelper(appView);
     needsLibraryInfo =
-        !appView.options().desugaredLibraryConfiguration.getEmulateLibraryInterface().isEmpty()
+        !appView.options().desugaredLibrarySpecification.getEmulateLibraryInterface().isEmpty()
             || !appView
                 .options()
-                .desugaredLibraryConfiguration
+                .desugaredLibrarySpecification
                 .getRetargetCoreLibMember()
                 .isEmpty();
     this.isLiveMethod = isLiveMethod;
@@ -510,7 +510,7 @@
       DexClass iface = appView.definitionFor(emulatedInterface);
       if (iface != null) {
         assert iface.isLibraryClass()
-            || appView.options().desugaredLibraryConfiguration.isLibraryCompilation();
+            || appView.options().desugaredLibrarySpecification.isLibraryCompilation();
         workList.addIfNotSeen(iface.getInterfaces());
       }
     }
@@ -761,7 +761,7 @@
     assert needsLibraryInfo();
     assert method.getDefinition().isNonPrivateVirtualMethod();
     return !method.getAccessFlags().isFinal()
-        && appView.options().desugaredLibraryConfiguration.retargetMethod(method, appView) != null;
+        && appView.options().desugaredLibrarySpecification.retargetMethod(method, appView) != null;
   }
 
   private boolean dontRewrite(DexClassAndMethod method) {
@@ -850,7 +850,7 @@
     DexMethod forwardMethod =
         target.getHolder().isInterface()
             ? helper.ensureDefaultAsMethodOfCompanionClassStub(target).getReference()
-            : appView.options().desugaredLibraryConfiguration.retargetMethod(target, appView);
+            : appView.options().desugaredLibrarySpecification.retargetMethod(target, appView);
     DexEncodedMethod desugaringForwardingMethod =
         DexEncodedMethod.createDesugaringForwardingMethod(
             target, clazz, forwardMethod, dexItemFactory);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceApplicationRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceApplicationRewriter.java
index af7fb9f..74d94e3 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceApplicationRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceApplicationRewriter.java
@@ -26,7 +26,7 @@
   public EmulatedInterfaceApplicationRewriter(AppView<?> appView) {
     this.appView = appView;
     this.emulatedInterfaces =
-        appView.options().desugaredLibraryConfiguration.getEmulateLibraryInterface();
+        appView.options().desugaredLibrarySpecification.getEmulateLibraryInterface();
   }
 
   public void rewriteApplication(DexApplication.Builder<?> builder) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java
index 0dc7375..a4800c3 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java
@@ -69,7 +69,7 @@
   public InterfaceDesugaringSyntheticHelper(AppView<?> appView) {
     this.appView = appView;
     emulatedInterfaces =
-        appView.options().desugaredLibraryConfiguration.getEmulateLibraryInterface();
+        appView.options().desugaredLibrarySpecification.getEmulateLibraryInterface();
 
     this.shouldIgnoreFromReportsPredicate = getShouldIgnoreFromReportsPredicate(appView);
   }
@@ -100,7 +100,7 @@
 
   boolean dontRewrite(DexClassAndMethod method) {
     for (Pair<DexType, DexString> dontRewrite :
-        appView.options().desugaredLibraryConfiguration.getDontRewriteInvocation()) {
+        appView.options().desugaredLibrarySpecification.getDontRewriteInvocation()) {
       if (method.getHolderType() == dontRewrite.getFirst()
           && method.getName() == dontRewrite.getSecond()) {
         return true;
@@ -515,7 +515,7 @@
       return appView.rewritePrefix.hasRewrittenType(type, appView)
           || descriptor.endsWith(companionClassNameDescriptorSuffix)
           || isRewrittenEmulatedInterface(type)
-          || options.desugaredLibraryConfiguration.getCustomConversions().containsValue(type)
+          || options.desugaredLibrarySpecification.getCustomConversions().containsValue(type)
           || appView.getDontWarnConfiguration().matches(type);
     };
   }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
index 2152ef0..a40d69a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
@@ -35,7 +35,7 @@
 import com.android.tools.r8.ir.desugar.DesugarDescription;
 import com.android.tools.r8.ir.desugar.FreshLocalProvider;
 import com.android.tools.r8.ir.desugar.LocalStackAllocator;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfiguration;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
 import com.android.tools.r8.ir.desugar.icce.AlwaysThrowingInstructionDesugaring;
 import com.android.tools.r8.ir.desugar.lambda.LambdaInstructionDesugaring;
 import com.android.tools.r8.ir.desugar.stringconcat.StringConcatInstructionDesugaring;
@@ -120,11 +120,11 @@
   }
 
   public static void checkForAssumedLibraryTypes(AppInfo appInfo, InternalOptions options) {
-    DesugaredLibraryConfiguration config = options.desugaredLibraryConfiguration;
+    LegacyDesugaredLibrarySpecification spec = options.desugaredLibrarySpecification;
     BiConsumer<DexType, DexType> registerEntry = registerMapEntry(appInfo);
-    config.getEmulateLibraryInterface().forEach(registerEntry);
-    config.getCustomConversions().forEach(registerEntry);
-    config.getRetargetCoreLibMember().forEach((method, types) -> types.forEach(registerEntry));
+    spec.getEmulateLibraryInterface().forEach(registerEntry);
+    spec.getCustomConversions().forEach(registerEntry);
+    spec.getRetargetCoreLibMember().forEach((method, types) -> types.forEach(registerEntry));
   }
 
   private static BiConsumer<DexType, DexType> registerMapEntry(AppInfo appInfo) {
@@ -158,7 +158,7 @@
 
   private void initializeEmulatedInterfaceVariables() {
     Map<DexType, DexType> emulateLibraryInterface =
-        options.desugaredLibraryConfiguration.getEmulateLibraryInterface();
+        options.desugaredLibrarySpecification.getEmulateLibraryInterface();
     for (DexType interfaceType : emulateLibraryInterface.keySet()) {
       addRewriteRulesForEmulatedInterface(
           interfaceType, emulateLibraryInterface.get(interfaceType).toSourceString());
@@ -776,7 +776,7 @@
       // method (method is on desugared library). Find out if it needs to be
       // retargeted or if it just calls a companion class method and rewrite.
       DexMethod retargetMethod =
-          options.desugaredLibraryConfiguration.retargetMethod(superTarget, appView);
+          options.desugaredLibrarySpecification.retargetMethod(superTarget, appView);
       if (retargetMethod != null) {
         return DesugarDescription.builder()
             .setDesugarRewrite(
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/ProgramEmulatedInterfaceSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/ProgramEmulatedInterfaceSynthesizer.java
index d68dec8..5c2ec42 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/ProgramEmulatedInterfaceSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/ProgramEmulatedInterfaceSynthesizer.java
@@ -41,7 +41,7 @@
 
   public static ProgramEmulatedInterfaceSynthesizer create(AppView<?> appView) {
     if (!appView.options().isDesugaredLibraryCompilation()
-        || appView.options().desugaredLibraryConfiguration.getEmulateLibraryInterface().isEmpty()) {
+        || appView.options().desugaredLibrarySpecification.getEmulateLibraryInterface().isEmpty()) {
       return null;
     }
     return new ProgramEmulatedInterfaceSynthesizer(appView);
@@ -166,7 +166,7 @@
     // In practice, there is usually a single case (except for tests),
     // so we do not bother to make the following loop more clever.
     Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
-        appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember();
+        appView.options().desugaredLibrarySpecification.getRetargetCoreLibMember();
     for (DexString methodName : retargetCoreLibMember.keySet()) {
       if (method.getName() == methodName) {
         for (DexType inType : retargetCoreLibMember.get(methodName).keySet()) {
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java
index 1a1cf0a..dfe017a 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java
@@ -46,9 +46,9 @@
 import com.android.tools.r8.ir.code.MemberType;
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.code.ValueType;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizer;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryClasspathWrapperSynthesizeEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryWrapperSynthesizer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryClasspathWrapperSynthesizeEventConsumer;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.collections.ImmutableDeque;
 import com.android.tools.r8.utils.collections.ImmutableInt2ReferenceSortedMap;
diff --git a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
index b10c36a..bdda2fe 100644
--- a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.jar;
 
 import static com.android.tools.r8.utils.InternalOptions.ASM_VERSION;
+import static com.android.tools.r8.utils.LineNumberOptimizer.runAndWriteMap;
 
 import com.android.tools.r8.ByteDataView;
 import com.android.tools.r8.ClassFileConsumer;
@@ -40,14 +41,15 @@
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.naming.NamingLens;
-import com.android.tools.r8.naming.ProguardMapSupplier;
 import com.android.tools.r8.naming.ProguardMapSupplier.ProguardMapId;
 import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.synthesis.SyntheticNaming;
+import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.AsmUtils;
 import com.android.tools.r8.utils.ComparatorUtils;
 import com.android.tools.r8.utils.ExceptionUtils;
 import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.OriginalSourceFiles;
 import com.android.tools.r8.utils.PredicateUtils;
 import com.android.tools.r8.utils.structural.Ordered;
 import com.google.common.collect.ImmutableMap;
@@ -90,16 +92,10 @@
   private final Marker marker;
   private final Predicate<DexType> isTypeMissing;
 
-  public final ProguardMapSupplier proguardMapSupplier;
-
   private static final CfVersion MIN_VERSION_FOR_COMPILER_GENERATED_CODE = CfVersion.V1_6;
 
   public CfApplicationWriter(
-      AppView<?> appView,
-      Marker marker,
-      GraphLens graphLens,
-      NamingLens namingLens,
-      ProguardMapSupplier proguardMapSupplier) {
+      AppView<?> appView, Marker marker, GraphLens graphLens, NamingLens namingLens) {
     this.application = appView.appInfo().app();
     this.appView = appView;
     this.graphLens = graphLens;
@@ -107,15 +103,19 @@
     this.options = appView.options();
     assert marker != null;
     this.marker = marker;
-    this.proguardMapSupplier = proguardMapSupplier;
     this.isTypeMissing =
         PredicateUtils.isNull(appView.appInfo()::definitionForWithoutExistenceAssert);
   }
 
   public void write(ClassFileConsumer consumer) {
+    assert options.proguardMapConsumer == null;
+    write(consumer, null);
+  }
+
+  public void write(ClassFileConsumer consumer, AndroidApp inputApp) {
     application.timing.begin("CfApplicationWriter.write");
     try {
-      writeApplication(consumer);
+      writeApplication(inputApp, consumer);
     } finally {
       application.timing.end();
     }
@@ -132,12 +132,12 @@
     return true;
   }
 
-  private void writeApplication(ClassFileConsumer consumer) {
-    ProguardMapId proguardMapId =
-        (proguardMapSupplier != null && options.proguardMapConsumer != null)
-            ? proguardMapSupplier.writeProguardMap()
-            : null;
-    if (proguardMapId != null) {
+  private void writeApplication(AndroidApp inputApp, ClassFileConsumer consumer) {
+    ProguardMapId proguardMapId = null;
+    if (options.proguardMapConsumer != null) {
+      proguardMapId =
+          runAndWriteMap(
+              inputApp, appView, namingLens, application.timing, OriginalSourceFiles.fromClasses());
       marker.setPgMapId(proguardMapId.getId());
     }
     Optional<String> markerString =
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
index a198bb7..834e879 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
@@ -55,7 +55,7 @@
 
   public MemberRebindingAnalysis(AppView<AppInfoWithLiveness> appView) {
     assert appView.graphLens().isContextFreeForMethods();
-    this.androidApiLevelCompute = AndroidApiLevelCompute.create(appView);
+    this.androidApiLevelCompute = appView.apiLevelCompute();
     this.appView = appView;
     this.options = appView.options();
     this.lensBuilder = MemberRebindingLens.builder(appView);
diff --git a/src/main/java/com/android/tools/r8/relocator/Relocator.java b/src/main/java/com/android/tools/r8/relocator/Relocator.java
index bf2bfe8..d0836d7 100644
--- a/src/main/java/com/android/tools/r8/relocator/Relocator.java
+++ b/src/main/java/com/android/tools/r8/relocator/Relocator.java
@@ -89,11 +89,7 @@
       new GenericSignatureRewriter(appView, namingLens).run(appInfo.classes(), executor);
 
       new CfApplicationWriter(
-              appView,
-              new Marker(Tool.Relocator),
-              GraphLens.getIdentityLens(),
-              namingLens,
-              null)
+              appView, new Marker(Tool.Relocator), GraphLens.getIdentityLens(), namingLens)
           .write(command.getConsumer());
       options.printWarnings();
     } catch (ExecutionException e) {
diff --git a/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java b/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
index 244257a..1b2e03c 100644
--- a/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
+++ b/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
@@ -9,6 +9,7 @@
 import com.android.tools.r8.graph.DexAnnotation.AnnotatedKind;
 import com.android.tools.r8.graph.DexAnnotationElement;
 import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexDefinition;
 import com.android.tools.r8.graph.DexEncodedAnnotation;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -136,6 +137,12 @@
         return isAnnotationTypeLive;
 
       case DexAnnotation.VISIBILITY_BUILD:
+        if (annotation
+            .getAnnotationType()
+            .getDescriptor()
+            .startsWith(options.itemFactory.dalvikAnnotationOptimizationPrefix)) {
+          return true;
+        }
         if (kind.isParameter()) {
           if (!options.isKeepRuntimeInvisibleParameterAnnotationsEnabled()) {
             return false;
@@ -384,6 +391,13 @@
     }
   }
 
+  public static void clearAnnotations(AppView<?> appView) {
+    for (DexProgramClass clazz : appView.appInfo().classes()) {
+      clazz.clearAnnotations();
+      clazz.members().forEach(DexDefinition::clearAnnotations);
+    }
+  }
+
   public static class Builder {
 
     /**
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index c34f7f3..cde8896 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -50,7 +50,7 @@
 import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
 import com.android.tools.r8.ir.code.Invoke.Type;
 import com.android.tools.r8.ir.desugar.LambdaDescriptor;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter;
 import com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringSyntheticHelper;
 import com.android.tools.r8.naming.SeedMapper;
 import com.android.tools.r8.shaking.KeepInfo.Joiner;
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 351815d..7765953 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -14,7 +14,6 @@
 import static java.util.Collections.emptySet;
 
 import com.android.tools.r8.Diagnostic;
-import com.android.tools.r8.androidapi.AndroidApiLevelCompute;
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.cf.code.CfInvoke;
 import com.android.tools.r8.code.CfOrDexInstruction;
@@ -107,7 +106,7 @@
 import com.android.tools.r8.ir.desugar.LambdaDescriptor;
 import com.android.tools.r8.ir.desugar.ProgramAdditions;
 import com.android.tools.r8.ir.desugar.constantdynamic.ConstantDynamicClass;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter;
 import com.android.tools.r8.ir.desugar.itf.InterfaceMethodProcessorFacade;
 import com.android.tools.r8.ir.desugar.itf.InterfaceProcessor;
 import com.android.tools.r8.kotlin.KotlinMetadataEnqueuerExtension;
@@ -266,8 +265,6 @@
 
   private final Set<DexMember<?, ?>> identifierNameStrings = Sets.newIdentityHashSet();
 
-  private final AndroidApiLevelCompute apiLevelCompute;
-
   /**
    * Tracks the dependency between a method and the super-method it calls, if any. Used to make
    * super methods become live when they become reachable from a live sub-method.
@@ -500,9 +497,8 @@
     failedFieldResolutionTargets = SetUtils.newIdentityHashSet(0);
     liveMethods = new LiveMethodsSet(graphReporter::registerMethod);
     liveFields = new LiveFieldsSet(graphReporter::registerField);
-    apiLevelCompute = AndroidApiLevelCompute.create(appView);
     if (mode.isInitialTreeShaking()) {
-      desugaring = CfInstructionDesugaringCollection.create(appView, apiLevelCompute);
+      desugaring = CfInstructionDesugaringCollection.create(appView, appView.apiLevelCompute());
       interfaceProcessor = new InterfaceProcessor(appView);
     } else {
       desugaring = CfInstructionDesugaringCollection.empty();
@@ -517,10 +513,6 @@
     return appView.appInfo();
   }
 
-  public AndroidApiLevelCompute getApiLevelCompute() {
-    return apiLevelCompute;
-  }
-
   public Mode getMode() {
     return mode;
   }
@@ -3190,7 +3182,7 @@
         && appView.options().getProguardConfiguration().getKeepAttributes().signature) {
       registerAnalysis(new GenericSignatureEnqueuerAnalysis(enqueuerDefinitionSupplier));
     }
-    registerAnalysis(new ApiModelAnalysis(appView, apiLevelCompute));
+    registerAnalysis(new ApiModelAnalysis(appView));
 
     // Transfer the minimum keep info from the root set into the Enqueuer state.
     includeMinimumKeepInfo(rootSet);
@@ -4305,7 +4297,7 @@
 
   void traceCode(ProgramMethod method) {
     DefaultEnqueuerUseRegistry registry =
-        useRegistryFactory.create(appView, method, this, apiLevelCompute);
+        useRegistryFactory.create(appView, method, this, appView.apiLevelCompute());
     method.registerCodeReferences(registry);
     // Notify analyses.
     analyses.forEach(analysis -> analysis.processTracedCode(method, registry));
diff --git a/src/main/java/com/android/tools/r8/shaking/L8TreePruner.java b/src/main/java/com/android/tools/r8/shaking/L8TreePruner.java
index c42b3e0..960ccd5 100644
--- a/src/main/java/com/android/tools/r8/shaking/L8TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/L8TreePruner.java
@@ -28,9 +28,9 @@
 
   public L8TreePruner(InternalOptions options) {
     this.options = options;
-    backports.addAll(options.desugaredLibraryConfiguration.getBackportCoreLibraryMember().keySet());
+    backports.addAll(options.desugaredLibrarySpecification.getBackportCoreLibraryMember().keySet());
     emulatedInterfaces.addAll(
-        options.desugaredLibraryConfiguration.getEmulateLibraryInterface().keySet());
+        options.desugaredLibrarySpecification.getEmulateLibraryInterface().keySet());
   }
 
   public DexApplication prune(DexApplication app, PrefixRewritingMapper rewritePrefix) {
diff --git a/src/main/java/com/android/tools/r8/shaking/MissingClasses.java b/src/main/java/com/android/tools/r8/shaking/MissingClasses.java
index 5e33712..823c59c 100644
--- a/src/main/java/com/android/tools/r8/shaking/MissingClasses.java
+++ b/src/main/java/com/android/tools/r8/shaking/MissingClasses.java
@@ -4,7 +4,7 @@
 
 package com.android.tools.r8.shaking;
 
-import static com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter.DESCRIPTOR_VIVIFIED_PREFIX;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter.DESCRIPTOR_VIVIFIED_PREFIX;
 import static com.android.tools.r8.utils.collections.IdentityHashSetFromMap.newProgramDerivedContextSet;
 
 import com.android.tools.r8.diagnostic.MissingDefinitionsDiagnostic;
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
index 3155b54..2a06ead 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -262,7 +262,7 @@
     this.executorService = executorService;
     this.methodPoolCollection = new MethodPoolCollection(appView, subtypingInfo);
     this.lensBuilder = new VerticalClassMergerGraphLens.Builder(appView.dexItemFactory());
-    this.apiLevelCompute = AndroidApiLevelCompute.create(appView);
+    this.apiLevelCompute = appView.apiLevelCompute();
     this.timing = timing;
 
     Iterable<DexProgramClass> classes = application.classesWithDeterministicOrder();
diff --git a/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java b/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java
index 9fe1fb9..bbf4258 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java
@@ -132,7 +132,7 @@
     DexType rewrittenContext =
         appView
             .options()
-            .desugaredLibraryConfiguration
+            .desugaredLibrarySpecification
             .getEmulateLibraryInterface()
             .get(synthesizingContextType);
     if (rewrittenContext == null) {
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java
index 6a6aef4..598dc4f 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java
@@ -38,6 +38,7 @@
   private final Origin origin;
 
   private boolean isAbstract = false;
+  private boolean isFinal = true;
   private boolean isInterface = false;
   private Kind originKind;
   private DexType superType;
@@ -89,6 +90,12 @@
 
   public B setAbstract() {
     isAbstract = true;
+    isFinal = false;
+    return self();
+  }
+
+  public B unsetFinal() {
+    isFinal = false;
     return self();
   }
 
@@ -155,12 +162,13 @@
   }
 
   public C build() {
-    int flag = isAbstract ? Constants.ACC_ABSTRACT : Constants.ACC_FINAL;
+    int abstractFlag = isAbstract ? Constants.ACC_ABSTRACT : 0;
+    int finalFlag = isFinal ? Constants.ACC_FINAL : 0;
     int itfFlag = isInterface ? Constants.ACC_INTERFACE : 0;
     assert !isInterface || isAbstract;
     ClassAccessFlags accessFlags =
         ClassAccessFlags.fromSharedAccessFlags(
-            flag | itfFlag | Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC);
+            abstractFlag | finalFlag | itfFlag | Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC);
     NestHostClassAttribute nestHost = null;
     List<NestMemberClassAttribute> nestMembers = Collections.emptyList();
     EnclosingMethodAttribute enclosingMembers = null;
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
index 2d16065..a29bfcf 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
@@ -17,6 +17,7 @@
 import com.android.tools.r8.graph.DexClasspathClass;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexLibraryClass;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexProto;
@@ -397,6 +398,25 @@
     return SynthesizingContext.fromNonSyntheticInputContext(context, featureSplit);
   }
 
+  public DexProgramClass addSyntheticClassWithLibraryContext(
+      AppView<?> appView,
+      DexLibraryClass context,
+      SyntheticKind syntheticKind,
+      DexType type,
+      Consumer<SyntheticProgramClassBuilder> programClassBuilderConsumer) {
+    SynthesizingContext synthesizingContext =
+        SynthesizingContext.fromNonSyntheticInputContext(context);
+    SyntheticProgramClassBuilder syntheticProgramClassBuilder =
+        new SyntheticProgramClassBuilder(
+                type, syntheticKind, synthesizingContext, appView.dexItemFactory())
+            .setUseSortedMethodBacking(true);
+    programClassBuilderConsumer.accept(syntheticProgramClassBuilder);
+    DexProgramClass newSyntheticClass = syntheticProgramClassBuilder.build();
+    addPendingDefinition(
+        new SyntheticProgramClassDefinition(syntheticKind, synthesizingContext, newSyntheticClass));
+    return newSyntheticClass;
+  }
+
   // Addition and creation of synthetic items.
 
   private DexProgramClass internalEnsureDexProgramClass(
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
index 1bc77c4..fc487f7 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
@@ -57,7 +57,8 @@
     EMULATED_INTERFACE_MARKER_CLASS("", 29, false, true, true),
     CONST_DYNAMIC("$Condy", 30, false),
     ENUM_CONVERSION("$EnumConversion", 31, false, true),
-    API_MODEL_OUTLINE("ApiModelOutline", 32, true, false, false);
+    API_MODEL_OUTLINE("ApiModelOutline", 32, true, false, false),
+    API_MODEL_STUB("ApiModelStub", 33, false, true, true);
 
     static {
       assert verifyNoOverlappingIds();
diff --git a/src/main/java/com/android/tools/r8/tracereferences/Tracer.java b/src/main/java/com/android/tools/r8/tracereferences/Tracer.java
index 205ee03..43bdb0f 100644
--- a/src/main/java/com/android/tools/r8/tracereferences/Tracer.java
+++ b/src/main/java/com/android/tools/r8/tracereferences/Tracer.java
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.tracereferences;
 
-
 import com.android.tools.r8.DiagnosticsHandler;
 import com.android.tools.r8.dex.ApplicationReader;
 import com.android.tools.r8.diagnostic.DefinitionContext;
@@ -84,7 +83,9 @@
     UseCollector useCollector = new UseCollector(appView, consumer, diagnostics, targetPredicate);
     for (DexProgramClass clazz : appView.appInfo().classes()) {
       DefinitionContext classContext = DefinitionContextUtils.create(clazz);
-      useCollector.registerSuperType(clazz, clazz.superType, classContext);
+      if (clazz.superType != null) {
+        useCollector.registerSuperType(clazz, clazz.superType, classContext);
+      }
       for (DexType implementsType : clazz.getInterfaces()) {
         useCollector.registerSuperType(clazz, implementsType, classContext);
       }
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 c1fbc42..7db36b3 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -53,7 +53,7 @@
 import com.android.tools.r8.horizontalclassmerging.Policy;
 import com.android.tools.r8.inspector.internal.InspectorImpl;
 import com.android.tools.r8.ir.code.IRCode;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfiguration;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
 import com.android.tools.r8.ir.desugar.nest.Nest;
 import com.android.tools.r8.ir.optimize.Inliner;
 import com.android.tools.r8.ir.optimize.enums.EnumDataMap;
@@ -294,6 +294,8 @@
   public boolean cfToCfDesugar = false;
   public boolean forceAnnotateSynthetics = false;
   public boolean readDebugSetFileEvent = false;
+  public boolean disableL8AnnotationRemoval =
+      System.getProperty("com.android.tools.r8.disableL8AnnotationRemoval") != null;
 
   public int callGraphLikelySpuriousCallEdgeThreshold = 50;
 
@@ -385,8 +387,8 @@
     if (isGeneratingDex() || desugarState == DesugarState.ON) {
       marker.setMinApi(getMinApiLevel().getLevel());
     }
-    if (desugaredLibraryConfiguration.getIdentifier() != null) {
-      marker.setDesugaredLibraryIdentifiers(desugaredLibraryConfiguration.getIdentifier());
+    if (desugaredLibrarySpecification.getIdentifier() != null) {
+      marker.setDesugaredLibraryIdentifiers(desugaredLibrarySpecification.getIdentifier());
     }
     if (Version.isDevelopmentVersion()) {
       marker.setSha1(VersionProperties.INSTANCE.getSha());
@@ -433,7 +435,7 @@
   }
 
   public boolean isDesugaredLibraryCompilation() {
-    return desugaredLibraryConfiguration.isLibraryCompilation();
+    return desugaredLibrarySpecification.isLibraryCompilation();
   }
 
   public boolean isRelocatorCompilation() {
@@ -737,9 +739,6 @@
 
   public LineNumberOptimization lineNumberOptimization = LineNumberOptimization.ON;
 
-  // TODO(b/207765416): Enable and remove this once fixed.
-  public boolean enablePcBasedMappingFile = false;
-
   public CallSiteOptimizationOptions callSiteOptimizationOptions() {
     return callSiteOptimizationOptions;
   }
@@ -882,8 +881,8 @@
 
   // If null, no desugaring of library is performed.
   // If non null it contains flags describing library desugaring.
-  public DesugaredLibraryConfiguration desugaredLibraryConfiguration =
-      DesugaredLibraryConfiguration.empty();
+  public LegacyDesugaredLibrarySpecification desugaredLibrarySpecification =
+      LegacyDesugaredLibrarySpecification.empty();
 
   public boolean relocatorCompilation = false;
 
@@ -1872,10 +1871,17 @@
     return !isDesugaring() || hasMinApi(AndroidApiLevel.N);
   }
 
+  // Debug entries may be dropped only if the source file content allows being omitted from
+  // stack traces, or if the VM will report the source file even with a null valued debug info.
+  public boolean allowDiscardingResidualDebugInfo() {
+    // TODO(b/146565491): We can drop debug info once fixed at a known min-api.
+    return sourceFileProvider != null && sourceFileProvider.allowDiscardingSourceFile();
+  }
+
   public boolean canUseDexPcAsDebugInformation() {
-    return enablePcBasedMappingFile
-        && lineNumberOptimization == LineNumberOptimization.ON
-        && hasMinApi(AndroidApiLevel.O);
+    return lineNumberOptimization == LineNumberOptimization.ON
+        && hasMinApi(AndroidApiLevel.O)
+        && allowDiscardingResidualDebugInfo();
   }
 
   public boolean isInterfaceMethodDesugaringEnabled() {
diff --git a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
index 2e9c933..71da5cc 100644
--- a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
+++ b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
@@ -54,6 +54,8 @@
 import com.android.tools.r8.naming.MemberNaming.FieldSignature;
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.naming.ProguardMapSupplier;
+import com.android.tools.r8.naming.ProguardMapSupplier.ProguardMapId;
 import com.android.tools.r8.naming.Range;
 import com.android.tools.r8.naming.mappinginformation.CompilerSynthesizedMappingInformation;
 import com.android.tools.r8.naming.mappinginformation.FileNameInformation;
@@ -323,8 +325,32 @@
     }
   }
 
+  public static ProguardMapId runAndWriteMap(
+      AndroidApp inputApp,
+      AppView<?> appView,
+      NamingLens namingLens,
+      Timing timing,
+      OriginalSourceFiles originalSourceFiles) {
+    assert appView.options().proguardMapConsumer != null;
+    // When line number optimization is turned off the identity mapping for line numbers is
+    // used. We still run the line number optimizer to collect line numbers and inline frame
+    // information for the mapping file.
+    timing.begin("Line number remapping");
+    ClassNameMapper mapper =
+        run(appView, appView.appInfo().app(), inputApp, namingLens, originalSourceFiles);
+    timing.end();
+    timing.begin("Write proguard map");
+    ProguardMapId mapId = ProguardMapSupplier.create(mapper, appView.options()).writeProguardMap();
+    timing.end();
+    return mapId;
+  }
+
   public static ClassNameMapper run(
-      AppView<?> appView, DexApplication application, AndroidApp inputApp, NamingLens namingLens) {
+      AppView<?> appView,
+      DexApplication application,
+      AndroidApp inputApp,
+      NamingLens namingLens,
+      OriginalSourceFiles originalSourceFiles) {
     // For finding methods in kotlin files based on SourceDebugExtensions, we use a line method map.
     // We create it here to ensure it is only reading class files once.
     CfLineToMethodMapper cfLineToMethodMapper = new CfLineToMethodMapper(inputApp);
@@ -353,8 +379,9 @@
                       com.android.tools.r8.position.Position.UNKNOWN));
 
       // Check if source file should be added to the map
-      if (clazz.sourceFile != null) {
-        String sourceFile = clazz.sourceFile.toString();
+      DexString originalSourceFile = originalSourceFiles.getOriginalSourceFile(clazz);
+      if (originalSourceFile != null) {
+        String sourceFile = originalSourceFile.toString();
         if (!RetraceUtils.hasPredictableSourceFileName(clazz.toSourceString(), sourceFile)) {
           onDemandClassNamingBuilder
               .get()
@@ -362,10 +389,6 @@
         }
       }
 
-      boolean canStripDebugInfo =
-          appView.options().sourceFileProvider != null
-              && appView.options().sourceFileProvider.allowDiscardingSourceFile();
-
       if (isSyntheticClass) {
         onDemandClassNamingBuilder
             .get()
@@ -417,9 +440,7 @@
           List<MappedPosition> mappedPositions;
           Code code = method.getCode();
           boolean canUseDexPc =
-              canStripDebugInfo
-                  && appView.options().canUseDexPcAsDebugInformation()
-                  && methods.size() == 1;
+              appView.options().canUseDexPcAsDebugInformation() && methods.size() == 1;
           if (code != null) {
             if (code.isDexCode() && doesContainPositions(code.asDexCode())) {
               if (canUseDexPc) {
@@ -458,6 +479,9 @@
               && methodMappingInfo.isEmpty()
               && obfuscatedNameDexString == originalMethod.name
               && originalMethod.holder == originalType) {
+            assert appView.options().lineNumberOptimization == LineNumberOptimization.OFF
+                || !doesContainPositions(method)
+                || appView.isCfByteCodePassThrough(method);
             continue;
           }
 
@@ -588,10 +612,10 @@
             }
             i = j;
           }
-          if (canStripDebugInfo
-              && method.getCode().isDexCode()
+          if (method.getCode().isDexCode()
               && method.getCode().asDexCode().getDebugInfo()
                   == DexDebugInfoForSingleLineMethod.getInstance()) {
+            assert appView.options().allowDiscardingResidualDebugInfo();
             method.getCode().asDexCode().setDebugInfo(null);
           }
         } // for each method of the group
@@ -919,6 +943,7 @@
         && !hasOverloads
         && !appView.options().debug
         && appView.options().lineNumberOptimization != LineNumberOptimization.OFF
+        && appView.options().allowDiscardingResidualDebugInfo()
         && (mappedPositions.isEmpty() || !mappedPositions.get(0).isOutlineCaller())) {
       dexCode.setDebugInfo(DexDebugInfoForSingleLineMethod.getInstance());
       return mappedPositions;
diff --git a/src/main/java/com/android/tools/r8/utils/ListUtils.java b/src/main/java/com/android/tools/r8/utils/ListUtils.java
index c5326b3..cd62dc2 100644
--- a/src/main/java/com/android/tools/r8/utils/ListUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/ListUtils.java
@@ -54,7 +54,7 @@
     return result;
   }
 
-  public static <T> List<T> filter(List<T> list, Predicate<? super T> predicate) {
+  public static <T> List<T> filter(Collection<T> list, Predicate<? super T> predicate) {
     ArrayList<T> filtered = new ArrayList<>(list.size());
     list.forEach(
         t -> {
@@ -96,6 +96,14 @@
     return -1;
   }
 
+  public static <S, T> List<T> map(S[] list, Function<S, T> fn) {
+    List<T> result = new ArrayList<>();
+    for (S element : list) {
+      result.add(fn.apply(element));
+    }
+    return result;
+  }
+
   public static <S, T> List<T> map(Iterable<S> list, Function<S, T> fn) {
     List<T> result = new ArrayList<>();
     for (S element : list) {
diff --git a/src/main/java/com/android/tools/r8/utils/OriginalSourceFiles.java b/src/main/java/com/android/tools/r8/utils/OriginalSourceFiles.java
new file mode 100644
index 0000000..7eca4e7
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/OriginalSourceFiles.java
@@ -0,0 +1,52 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.utils;
+
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexType;
+import java.util.Map;
+
+/** Abstraction to allow removal of the source file content prior to collecting DEX items. */
+public abstract class OriginalSourceFiles {
+
+  private static final OriginalSourceFiles UNREACHABLE =
+      new OriginalSourceFiles() {
+        @Override
+        public DexString getOriginalSourceFile(DexProgramClass clazz) {
+          throw new Unreachable();
+        }
+      };
+
+  private static final OriginalSourceFiles FROM_CLASSES =
+      new OriginalSourceFiles() {
+        @Override
+        public DexString getOriginalSourceFile(DexProgramClass clazz) {
+          return clazz.getSourceFile();
+        }
+      };
+
+  /** For compilations where original source files should never be needed. */
+  public static OriginalSourceFiles unreachable() {
+    return UNREACHABLE;
+  }
+
+  /** For compilations where the original source files is still valid on the classes. */
+  public static OriginalSourceFiles fromClasses() {
+    return FROM_CLASSES;
+  }
+
+  /** Saved mapping of original source files prior to mutating the file on classes. */
+  public static OriginalSourceFiles fromMap(Map<DexType, DexString> map) {
+    return new OriginalSourceFiles() {
+      @Override
+      public DexString getOriginalSourceFile(DexProgramClass clazz) {
+        return map.get(clazz.getType());
+      }
+    };
+  }
+
+  public abstract DexString getOriginalSourceFile(DexProgramClass clazz);
+}
diff --git a/src/test/java/com/android/tools/r8/D8CommandTest.java b/src/test/java/com/android/tools/r8/D8CommandTest.java
index cd1ee66..9740064 100644
--- a/src/test/java/com/android/tools/r8/D8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/D8CommandTest.java
@@ -634,7 +634,7 @@
   public void desugaredLibrary() throws CompilationFailedException {
     D8Command d8Command = parse("--desugared-lib", "src/library_desugar/desugar_jdk_libs.json");
     assertFalse(
-        d8Command.getInternalOptions().desugaredLibraryConfiguration.getRewritePrefix().isEmpty());
+        d8Command.getInternalOptions().desugaredLibrarySpecification.getRewritePrefix().isEmpty());
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/D8TestBuilder.java b/src/test/java/com/android/tools/r8/D8TestBuilder.java
index b2bf2e8..1c74df5 100644
--- a/src/test/java/com/android/tools/r8/D8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/D8TestBuilder.java
@@ -90,8 +90,8 @@
   public D8TestBuilder enableCoreLibraryDesugaring(
       AndroidApiLevel minApiLevel,
       KeepRuleConsumer keepRuleConsumer,
-      StringResource desugaredLibraryConfiguration) {
-    super.enableCoreLibraryDesugaring(minApiLevel, keepRuleConsumer, desugaredLibraryConfiguration);
+      StringResource desugaredLibrarySpecification) {
+    super.enableCoreLibraryDesugaring(minApiLevel, keepRuleConsumer, desugaredLibrarySpecification);
     return self();
   }
 
diff --git a/src/test/java/com/android/tools/r8/KotlinTestParameters.java b/src/test/java/com/android/tools/r8/KotlinTestParameters.java
index 0ddd80e..d5a943f 100644
--- a/src/test/java/com/android/tools/r8/KotlinTestParameters.java
+++ b/src/test/java/com/android/tools/r8/KotlinTestParameters.java
@@ -32,6 +32,10 @@
     return kotlinc;
   }
 
+  public KotlinCompilerVersion getCompilerVersion() {
+    return kotlinc.getCompilerVersion();
+  }
+
   public KotlinTargetVersion getTargetVersion() {
     return targetVersion;
   }
@@ -48,6 +52,10 @@
     return kotlinc.getCompilerVersion().isGreaterThanOrEqualTo(otherVersion);
   }
 
+  public boolean isNewerThan(KotlinCompilerVersion otherVersion) {
+    return kotlinc.getCompilerVersion().isGreaterThan(otherVersion);
+  }
+
   public boolean isOlderThan(KotlinCompilerVersion otherVersion) {
     return !isNewerThanOrEqualTo(otherVersion);
   }
diff --git a/src/test/java/com/android/tools/r8/L8CommandTest.java b/src/test/java/com/android/tools/r8/L8CommandTest.java
index eb44743..e1902f4 100644
--- a/src/test/java/com/android/tools/r8/L8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/L8CommandTest.java
@@ -246,7 +246,7 @@
   }
 
   @Test(expected = CompilationFailedException.class)
-  public void desugaredLibraryConfigurationRequired() throws Throwable {
+  public void desugaredLibrarySpecificationRequired() throws Throwable {
     DiagnosticsChecker.checkErrorsContains(
         "L8 requires a desugared library configuration",
         (handler) ->
@@ -357,7 +357,7 @@
     L8Command l8Command =
         parse("--desugared-lib", ToolHelper.getDesugarLibJsonForTesting().toString());
     assertFalse(
-        l8Command.getInternalOptions().desugaredLibraryConfiguration.getRewritePrefix().isEmpty());
+        l8Command.getInternalOptions().desugaredLibrarySpecification.getRewritePrefix().isEmpty());
   }
 
   private void checkSingleForceAllAssertion(
diff --git a/src/test/java/com/android/tools/r8/L8TestBuilder.java b/src/test/java/com/android/tools/r8/L8TestBuilder.java
index e672f87..44202c6 100644
--- a/src/test/java/com/android/tools/r8/L8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/L8TestBuilder.java
@@ -40,7 +40,7 @@
   private Consumer<InternalOptions> optionsModifier = ConsumerUtils.emptyConsumer();
   private Path desugarJDKLibs = ToolHelper.getDesugarJDKLibs();
   private Path desugarJDKLibsConfiguration = null;
-  private StringResource desugaredLibraryConfiguration =
+  private StringResource desugaredLibrarySpecification =
       StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting());
   private List<Path> libraryFiles = new ArrayList<>();
 
@@ -130,15 +130,20 @@
   }
 
   public L8TestBuilder setDesugaredLibraryConfiguration(Path path) {
-    this.desugaredLibraryConfiguration = StringResource.fromFile(path);
+    this.desugaredLibrarySpecification = StringResource.fromFile(path);
     return this;
   }
 
   public L8TestBuilder setDesugaredLibraryConfiguration(StringResource configuration) {
-    this.desugaredLibraryConfiguration = configuration;
+    this.desugaredLibrarySpecification = configuration;
     return this;
   }
 
+  public L8TestBuilder setDisableL8AnnotationRemoval(boolean disableL8AnnotationRemoval) {
+    return addOptionsModifier(
+        options -> options.disableL8AnnotationRemoval = disableL8AnnotationRemoval);
+  }
+
   public L8TestCompileResult compile()
       throws IOException, CompilationFailedException, ExecutionException {
     // We wrap exceptions in a RuntimeException to call this from a lambda.
@@ -148,7 +153,7 @@
             .addProgramFiles(getProgramFiles())
             .addLibraryFiles(getLibraryFiles())
             .setMode(mode)
-            .addDesugaredLibraryConfiguration(desugaredLibraryConfiguration)
+            .addDesugaredLibraryConfiguration(desugaredLibrarySpecification)
             .setMinApiLevel(apiLevel.getLevel())
             .setProgramConsumer(
                 backend.isCf()
diff --git a/src/test/java/com/android/tools/r8/LibraryDesugaringTestConfiguration.java b/src/test/java/com/android/tools/r8/LibraryDesugaringTestConfiguration.java
index d79f4af..0758bf7 100644
--- a/src/test/java/com/android/tools/r8/LibraryDesugaringTestConfiguration.java
+++ b/src/test/java/com/android/tools/r8/LibraryDesugaringTestConfiguration.java
@@ -66,7 +66,7 @@
   private final AndroidApiLevel minApiLevel;
   private final Path desugarJdkLibs;
   private final Path customConversions;
-  private final List<StringResource> desugaredLibraryConfigurationResources;
+  private final List<StringResource> desugaredLibrarySpecificationResources;
   private final boolean withKeepRuleConsumer;
   private final KeepRuleConsumer keepRuleConsumer;
   private final CompilationMode mode;
@@ -81,7 +81,7 @@
     this.customConversions = null;
     this.keepRuleConsumer = null;
     this.withKeepRuleConsumer = false;
-    this.desugaredLibraryConfigurationResources = null;
+    this.desugaredLibrarySpecificationResources = null;
     this.mode = null;
     this.addRunClassPath = false;
   }
@@ -90,7 +90,7 @@
       AndroidApiLevel minApiLevel,
       Path desugarJdkLibs,
       Path customConversions,
-      List<StringResource> desugaredLibraryConfigurationResources,
+      List<StringResource> desugaredLibrarySpecificationResources,
       boolean withKeepRuleConsumer,
       KeepRuleConsumer keepRuleConsumer,
       CompilationMode mode,
@@ -98,7 +98,7 @@
     this.minApiLevel = minApiLevel;
     this.desugarJdkLibs = desugarJdkLibs;
     this.customConversions = customConversions;
-    this.desugaredLibraryConfigurationResources = desugaredLibraryConfigurationResources;
+    this.desugaredLibrarySpecificationResources = desugaredLibrarySpecificationResources;
     this.withKeepRuleConsumer = withKeepRuleConsumer;
     this.keepRuleConsumer = keepRuleConsumer;
     this.mode = mode;
@@ -110,7 +110,7 @@
     AndroidApiLevel minApiLevel;
     private Path desugarJdkLibs;
     private Path customConversions;
-    private final List<StringResource> desugaredLibraryConfigurationResources = new ArrayList<>();
+    private final List<StringResource> desugaredLibrarySpecificationResources = new ArrayList<>();
     boolean withKeepRuleConsumer = false;
     KeepRuleConsumer keepRuleConsumer;
     private CompilationMode mode = CompilationMode.DEBUG;
@@ -126,8 +126,8 @@
     public Builder setConfiguration(Configuration configuration) {
       desugarJdkLibs = configuration.desugarJdkLibs;
       customConversions = configuration.customConversions;
-      desugaredLibraryConfigurationResources.clear();
-      desugaredLibraryConfigurationResources.add(
+      desugaredLibrarySpecificationResources.clear();
+      desugaredLibrarySpecificationResources.add(
           StringResource.fromFile(configuration.configuration));
       return this;
     }
@@ -147,8 +147,8 @@
       return this;
     }
 
-    public Builder addDesugaredLibraryConfiguration(StringResource desugaredLibraryConfiguration) {
-      desugaredLibraryConfigurationResources.add(desugaredLibraryConfiguration);
+    public Builder addDesugaredLibraryConfiguration(StringResource desugaredLibrarySpecification) {
+      desugaredLibrarySpecificationResources.add(desugaredLibrarySpecification);
       return this;
     }
 
@@ -163,8 +163,8 @@
     }
 
     public LibraryDesugaringTestConfiguration build() {
-      if (desugaredLibraryConfigurationResources.isEmpty()) {
-        desugaredLibraryConfigurationResources.add(
+      if (desugaredLibrarySpecificationResources.isEmpty()) {
+        desugaredLibrarySpecificationResources.add(
             StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()));
       }
       if (withKeepRuleConsumer) {
@@ -174,7 +174,7 @@
           minApiLevel,
           desugarJdkLibs != null ? desugarJdkLibs : DEFAULT.desugarJdkLibs,
           customConversions != null ? customConversions : DEFAULT.customConversions,
-          desugaredLibraryConfigurationResources,
+          desugaredLibrarySpecificationResources,
           withKeepRuleConsumer,
           keepRuleConsumer,
           mode,
@@ -205,7 +205,7 @@
     if (keepRuleConsumer != null) {
       builder.setDesugaredLibraryKeepRuleConsumer(keepRuleConsumer);
     }
-    desugaredLibraryConfigurationResources.forEach(builder::addDesugaredLibraryConfiguration);
+    desugaredLibrarySpecificationResources.forEach(builder::addDesugaredLibraryConfiguration);
   }
 
   public void configure(R8Command.Builder builder) {
@@ -215,7 +215,7 @@
     if (keepRuleConsumer != null) {
       builder.setDesugaredLibraryKeepRuleConsumer(keepRuleConsumer);
     }
-    desugaredLibraryConfigurationResources.forEach(builder::addDesugaredLibraryConfiguration);
+    desugaredLibrarySpecificationResources.forEach(builder::addDesugaredLibraryConfiguration);
   }
 
   public Path buildDesugaredLibrary(TestState state) {
@@ -230,12 +230,12 @@
     }
     String finalGeneratedKeepRules = generatedKeepRules;
     try {
-      assert desugaredLibraryConfigurationResources.size() == 1 : "There can be only one";
+      assert desugaredLibrarySpecificationResources.size() == 1 : "There can be only one";
       return L8TestBuilder.create(minApiLevel, Backend.DEX, state)
           .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
           .setDesugarJDKLibs(desugarJdkLibs)
           .setDesugarJDKLibsConfiguration(customConversions)
-          .setDesugaredLibraryConfiguration(desugaredLibraryConfigurationResources.get(0))
+          .setDesugaredLibraryConfiguration(desugaredLibrarySpecificationResources.get(0))
           .applyIf(
               mode == CompilationMode.RELEASE,
               builder -> {
diff --git a/src/test/java/com/android/tools/r8/R8CommandTest.java b/src/test/java/com/android/tools/r8/R8CommandTest.java
index 03f13ec..0b48fc2 100644
--- a/src/test/java/com/android/tools/r8/R8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/R8CommandTest.java
@@ -765,7 +765,7 @@
   public void desugaredLibrary() throws CompilationFailedException {
     R8Command r8Command = parse("--desugared-lib", "src/library_desugar/desugar_jdk_libs.json");
     assertFalse(
-        r8Command.getInternalOptions().desugaredLibraryConfiguration.getRewritePrefix().isEmpty());
+        r8Command.getInternalOptions().desugaredLibrarySpecification.getRewritePrefix().isEmpty());
   }
 
   @Test
@@ -778,7 +778,7 @@
             "--desugared-lib-pg-conf-output",
             pgout.toString());
     assertFalse(
-        r8Command.getInternalOptions().desugaredLibraryConfiguration.getRewritePrefix().isEmpty());
+        r8Command.getInternalOptions().desugaredLibrarySpecification.getRewritePrefix().isEmpty());
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/R8TestBuilder.java b/src/test/java/com/android/tools/r8/R8TestBuilder.java
index 92270ae..1fa7630 100644
--- a/src/test/java/com/android/tools/r8/R8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/R8TestBuilder.java
@@ -666,8 +666,8 @@
   public T enableCoreLibraryDesugaring(
       AndroidApiLevel minApiLevel,
       KeepRuleConsumer keepRuleConsumer,
-      StringResource desugaredLibraryConfiguration) {
-    super.enableCoreLibraryDesugaring(minApiLevel, keepRuleConsumer, desugaredLibraryConfiguration);
+      StringResource desugaredLibrarySpecification) {
+    super.enableCoreLibraryDesugaring(minApiLevel, keepRuleConsumer, desugaredLibrarySpecification);
     return self();
   }
 
diff --git a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
index 4a6db32..a66a4b2 100644
--- a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
@@ -484,12 +484,12 @@
   public T enableCoreLibraryDesugaring(
       AndroidApiLevel minApiLevel,
       KeepRuleConsumer keepRuleConsumer,
-      StringResource desugaredLibraryConfiguration) {
+      StringResource desugaredLibrarySpecification) {
     return enableLibraryDesugaring(
         LibraryDesugaringTestConfiguration.builder()
             .setMinApi(minApiLevel)
             .setKeepRuleConsumer(keepRuleConsumer)
-            .addDesugaredLibraryConfiguration(desugaredLibraryConfiguration)
+            .addDesugaredLibraryConfiguration(desugaredLibrarySpecification)
             .dontAddRunClasspath()
             .build());
   }
diff --git a/src/test/java/com/android/tools/r8/annotations/DalvikAnnotationOptimizationTest.java b/src/test/java/com/android/tools/r8/annotations/DalvikAnnotationOptimizationTest.java
new file mode 100644
index 0000000..59e8923
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/annotations/DalvikAnnotationOptimizationTest.java
@@ -0,0 +1,201 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.annotations;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assume.assumeTrue;
+import static org.objectweb.asm.Opcodes.ASM7;
+
+import com.android.tools.r8.ClassFileResourceProvider;
+import com.android.tools.r8.ProgramResource;
+import com.android.tools.r8.ProgramResource.Kind;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.transformers.MethodTransformer;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableSet;
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+import org.objectweb.asm.AnnotationVisitor;
+
+@RunWith(Parameterized.class)
+public class DalvikAnnotationOptimizationTest extends TestBase {
+
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameter(1)
+  public boolean optimizationPackage;
+
+  @Parameter(2)
+  public boolean addAnnotationsOnLibraryPath;
+
+  @Parameters(name = "{0}, optimizationPackage = {1}, addAnnotationsOnLibraryPath = {2}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withAllRuntimes().withAllApiLevels().build(),
+        BooleanUtils.values(),
+        BooleanUtils.values());
+  }
+
+  private static final String dalvikOptimizationPrefix =
+      DexItemFactory.dalvikAnnotationOptimizationPrefixString;
+  private static final String dalvikCodegenPrefix = "Ldalvik/annotation/codegen/";
+  private static final String ourClassName =
+      DescriptorUtils.javaTypeToDescriptor(DalvikAnnotationOptimizationTest.class.getTypeName());
+  private static final String innerClassPrefix =
+      ourClassName.substring(0, ourClassName.length() - 1) + "$";
+
+  private static String changePackage(boolean optimizationPackage, String descriptor) {
+    return (optimizationPackage ? dalvikOptimizationPrefix : dalvikCodegenPrefix)
+        + descriptor.substring(innerClassPrefix.length());
+  }
+
+  private void checkExpectedAnnotations(CodeInspector inspector) {
+    Set<String> expected =
+        optimizationPackage
+            ? ImmutableSet.of(
+                dalvikOptimizationPrefix + "CriticalNative;",
+                dalvikOptimizationPrefix + "FastNative;",
+                dalvikOptimizationPrefix + "NeverCompile;",
+                dalvikOptimizationPrefix + "AndAnotherOne;")
+            : ImmutableSet.of();
+    assertEquals(
+        expected,
+        inspector.clazz(TestClass.class).uniqueMethodWithName("main").annotations().stream()
+            .map(s -> s.getAnnotation().type.getDescriptor().toSourceString())
+            .collect(Collectors.toSet()));
+  }
+
+  @Test
+  public void testD8() throws Exception {
+    assumeTrue(parameters.isDexRuntime());
+    testForD8(parameters.getBackend())
+        .addProgramClassFileData(
+            transformer(TestClass.class).addMethodTransformer(getMethodTransformer()).transform())
+        .setMinApi(parameters.getApiLevel())
+        .applyIf(
+            addAnnotationsOnLibraryPath,
+            b -> {
+              b.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.LATEST));
+              b.addLibraryProvider(new ClassPathProviderForAnnotations(optimizationPackage));
+            })
+        .compile()
+        .inspect(this::checkExpectedAnnotations);
+  }
+
+  private MethodTransformer getMethodTransformer() {
+    return new MethodTransformer() {
+      @Override
+      public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
+        assert descriptor.startsWith(innerClassPrefix);
+        return new AnnotationVisitor(
+            ASM7,
+            super.visitAnnotation(changePackage(optimizationPackage, descriptor), visible)) {};
+      }
+    };
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
+        .addProgramClassFileData(
+            transformer(TestClass.class).addMethodTransformer(getMethodTransformer()).transform())
+        .applyIf(
+            addAnnotationsOnLibraryPath,
+            b -> {
+              b.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.LATEST));
+              b.addLibraryProvider(new ClassPathProviderForAnnotations(optimizationPackage));
+            },
+            b ->
+                b.addDontWarn(
+                    optimizationPackage
+                        ? "dalvik.annotation.optimization.*"
+                        : "dalvik.annotation.codegen.*"))
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(TestClass.class)
+        .compile()
+        .inspect(this::checkExpectedAnnotations);
+  }
+
+  static class ClassPathProviderForAnnotations implements ClassFileResourceProvider {
+    private final boolean optimizationPackage;
+    private final Map<String, byte[]> resources = new HashMap<>();
+
+    ClassPathProviderForAnnotations(boolean optimizationPackage) throws IOException {
+      this.optimizationPackage = optimizationPackage;
+      for (Class<?> clazz :
+          new Class<?>[] {
+            CriticalNative.class, FastNative.class, NeverCompile.class, AndAnotherOne.class
+          }) {
+        resources.put(
+            changePackage(
+                optimizationPackage, DescriptorUtils.javaTypeToDescriptor(clazz.getTypeName())),
+            transformPackageName(clazz));
+      }
+    }
+
+    @Override
+    public Set<String> getClassDescriptors() {
+      return resources.keySet();
+    }
+
+    @Override
+    public ProgramResource getProgramResource(String descriptor) {
+      byte[] bytes = resources.get(descriptor);
+      return bytes == null
+          ? null
+          : ProgramResource.fromBytes(
+              Origin.unknown(), Kind.CF, bytes, Collections.singleton(descriptor));
+    }
+
+    private byte[] transformPackageName(Class<?> clazz) throws IOException {
+      return transformer(clazz)
+          .setClassDescriptor(
+              changePackage(
+                  optimizationPackage, DescriptorUtils.javaTypeToDescriptor(clazz.getTypeName())))
+          .transform();
+    }
+  }
+
+  // Keep all CLASS retention annotations in the dalvik.annotation.optimization package.
+  // See b/209701182
+  @Retention(RetentionPolicy.CLASS)
+  @interface CriticalNative {}
+
+  @Retention(RetentionPolicy.CLASS)
+  @interface FastNative {}
+
+  @Retention(RetentionPolicy.CLASS)
+  @interface NeverCompile {}
+
+  @Retention(RetentionPolicy.CLASS)
+  @interface AndAnotherOne {}
+
+  static class TestClass {
+    @CriticalNative
+    @FastNative
+    @NeverCompile
+    @AndAnotherOne
+    public static void main(String[] args) {}
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingTest.java
new file mode 100644
index 0000000..ad0961d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingTest.java
@@ -0,0 +1,71 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.apimodel;
+
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer;
+import static org.junit.Assume.assumeFalse;
+
+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.Version;
+import com.android.tools.r8.utils.AndroidApiLevel;
+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 ApiModelMockClassLoadingTest extends TestBase {
+
+  private final AndroidApiLevel mockLevel = AndroidApiLevel.M;
+
+  @Parameter() public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    // TODO(b/197078995): Make this work on 12.
+    assumeFalse(
+        parameters.isDexRuntime() && parameters.getDexRuntimeVersion().isEqualTo(Version.V12_0_0));
+    boolean isLibraryOnBootClassPath =
+        parameters.isDexRuntime()
+            && parameters.getRuntime().maxSupportedApiLevel().isGreaterThanOrEqualTo(mockLevel);
+    testForR8(parameters.getBackend())
+        .addProgramClasses(Main.class)
+        .addLibraryClasses(LibraryClass.class)
+        .addDefaultRuntimeLibrary(parameters)
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(Main.class)
+        .apply(ApiModelingTestHelper::enableStubbingOfClasses)
+        .apply(setMockApiLevelForClass(LibraryClass.class, mockLevel))
+        .apply(setMockApiLevelForDefaultInstanceInitializer(LibraryClass.class, mockLevel))
+        .compile()
+        .applyIf(isLibraryOnBootClassPath, b -> b.addBootClasspathClasses(LibraryClass.class))
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLinesIf(isLibraryOnBootClassPath, "Hello World");
+  }
+
+  // Only present form api level 23.
+  public static class LibraryClass {
+
+    public static void foo() {
+      System.out.println("Hello World");
+    }
+  }
+
+  public static class Main {
+
+    public static void main(String[] args) {
+      LibraryClass.foo();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassTest.java
index 4125cc2..3c5ad21 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassTest.java
@@ -6,16 +6,16 @@
 
 import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
 import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer;
-import static org.hamcrest.MatcherAssert.assertThat;
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
 import static org.junit.Assume.assumeFalse;
 
+import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.ToolHelper.DexVm.Version;
 import com.android.tools.r8.testing.AndroidBuildVersion;
 import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.codeinspector.Matchers;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -42,14 +42,16 @@
     boolean isMockApiLevel =
         parameters.isDexRuntime() && parameters.getApiLevel().isGreaterThanOrEqualTo(mockLevel);
     testForR8(parameters.getBackend())
-        .addProgramClasses(Main.class)
+        .addProgramClasses(Main.class, TestClass.class)
         .addLibraryClasses(LibraryClass.class)
         .addDefaultRuntimeLibrary(parameters)
         .setMinApi(parameters.getApiLevel())
         .addKeepMainRule(Main.class)
         .addAndroidBuildVersion()
+        .apply(ApiModelingTestHelper::enableStubbingOfClasses)
         .apply(setMockApiLevelForClass(LibraryClass.class, mockLevel))
         .apply(setMockApiLevelForDefaultInstanceInitializer(LibraryClass.class, mockLevel))
+        .enableInliningAnnotations()
         .compile()
         .applyIf(
             parameters.isDexRuntime()
@@ -58,10 +60,7 @@
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLinesIf(isMockApiLevel, "LibraryClass::foo")
         .assertSuccessWithOutputLinesIf(!isMockApiLevel, "Hello World")
-        .inspect(
-            inspector ->
-                // TODO(b/204982782): These should be stubbed for api-level 1-23.
-                assertThat(inspector.clazz(LibraryClass.class), Matchers.isAbsent()));
+        .inspect(verifyThat(parameters, LibraryClass.class).stubbedUntil(mockLevel));
   }
 
   // Only present from api level 23.
@@ -72,9 +71,10 @@
     }
   }
 
-  public static class Main {
+  public static class TestClass {
 
-    public static void main(String[] args) {
+    @NeverInline
+    public static void test() {
       if (AndroidBuildVersion.VERSION >= 23) {
         new LibraryClass().foo();
       } else {
@@ -82,4 +82,11 @@
       }
     }
   }
+
+  public static class Main {
+
+    public static void main(String[] args) {
+      TestClass.test();
+    }
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java
index 46a9fe8..2268036 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java
@@ -6,7 +6,7 @@
 
 import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
 import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer;
-import static org.hamcrest.MatcherAssert.assertThat;
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
 import static org.junit.Assume.assumeFalse;
 
 import com.android.tools.r8.TestBase;
@@ -15,7 +15,6 @@
 import com.android.tools.r8.ToolHelper.DexVm.Version;
 import com.android.tools.r8.testing.AndroidBuildVersion;
 import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.codeinspector.Matchers;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -49,6 +48,7 @@
         .addKeepMainRule(Main.class)
         .addKeepClassRules(ProgramClass.class)
         .addAndroidBuildVersion()
+        .apply(ApiModelingTestHelper::enableStubbingOfClasses)
         .apply(setMockApiLevelForClass(LibraryClass.class, mockLevel))
         .apply(setMockApiLevelForDefaultInstanceInitializer(LibraryClass.class, mockLevel))
         .compile()
@@ -59,10 +59,7 @@
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLinesIf(isMockApiLevel, "ProgramClass::foo")
         .assertSuccessWithOutputLinesIf(!isMockApiLevel, "Hello World")
-        .inspect(
-            inspector ->
-                // TODO(b/204982782): These should be stubbed for api-level 1-23.
-                assertThat(inspector.clazz(LibraryClass.class), Matchers.isAbsent()));
+        .inspect(verifyThat(parameters, LibraryClass.class).stubbedUntil(mockLevel));
   }
 
   // Only present from api level 23.
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java
index 285f3d0..a5f30c2 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java
@@ -6,8 +6,7 @@
 
 import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
 import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer;
-import static org.hamcrest.CoreMatchers.not;
-import static org.hamcrest.MatcherAssert.assertThat;
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
 import static org.junit.Assume.assumeFalse;
 
 import com.android.tools.r8.TestBase;
@@ -16,7 +15,6 @@
 import com.android.tools.r8.ToolHelper.DexVm.Version;
 import com.android.tools.r8.testing.AndroidBuildVersion;
 import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.codeinspector.Matchers;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -51,6 +49,7 @@
         .addKeepMainRule(Main.class)
         .addKeepClassRules(ProgramClass.class)
         .addAndroidBuildVersion()
+        .apply(ApiModelingTestHelper::enableStubbingOfClasses)
         .apply(setMockApiLevelForClass(LibraryClass.class, lowerMockApiLevel))
         .apply(setMockApiLevelForDefaultInstanceInitializer(LibraryClass.class, lowerMockApiLevel))
         .apply(setMockApiLevelForClass(OtherLibraryClass.class, mockApiLevel))
@@ -74,14 +73,9 @@
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLinesIf(isMockApiLevel, "ProgramClass::foo")
         .assertSuccessWithOutputLinesIf(!isMockApiLevel, "Hello World")
-        .inspect(
-            inspector -> {
-              // TODO(b/204982782): These should be stubbed out for api-level 1-23.
-              assertThat(inspector.clazz(LibraryClass.class), not(Matchers.isPresent()));
-              assertThat(inspector.clazz(LibraryInterface.class), not(Matchers.isPresent()));
-              // TODO(b/204982782): This should be stubbed out for api-level 1-24.
-              assertThat(inspector.clazz(OtherLibraryClass.class), not(Matchers.isPresent()));
-            });
+        .inspect(verifyThat(parameters, LibraryClass.class).stubbedUntil(lowerMockApiLevel))
+        .inspect(verifyThat(parameters, LibraryInterface.class).stubbedUntil(lowerMockApiLevel))
+        .inspect(verifyThat(parameters, OtherLibraryClass.class).stubbedUntil(mockApiLevel));
   }
 
   // Only present from api level 23.
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java
index a5c2487..c109def 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.apimodel;
 
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.notIf;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertTrue;
@@ -143,10 +144,36 @@
     };
   }
 
+  static ApiModelingClassVerificationHelper verifyThat(TestParameters parameters, Class<?> clazz) {
+    return new ApiModelingClassVerificationHelper(parameters, clazz);
+  }
+
   static ApiModelingMethodVerificationHelper verifyThat(TestParameters parameters, Method method) {
     return new ApiModelingMethodVerificationHelper(parameters, Reference.methodFromMethod(method));
   }
 
+  public static class ApiModelingClassVerificationHelper {
+
+    private final Class<?> classOfInterest;
+    private final TestParameters parameters;
+
+    public ApiModelingClassVerificationHelper(TestParameters parameters, Class<?> classOfInterest) {
+      this.parameters = parameters;
+      this.classOfInterest = classOfInterest;
+    }
+
+    public ThrowingConsumer<CodeInspector, Exception> stubbedUntil(AndroidApiLevel finalApiLevel) {
+      return inspector -> {
+        assertThat(
+            inspector.clazz(classOfInterest),
+            notIf(
+                isPresent(),
+                parameters.isCfRuntime()
+                    || parameters.getApiLevel().isGreaterThanOrEqualTo(finalApiLevel)));
+      };
+    }
+  }
+
   public static class ApiModelingMethodVerificationHelper {
 
     private final MethodReference methodOfInterest;
diff --git a/src/test/java/com/android/tools/r8/debug/KotlinInlineTest.java b/src/test/java/com/android/tools/r8/debug/KotlinInlineTest.java
index 4d44f78..1a9eff3 100644
--- a/src/test/java/com/android/tools/r8/debug/KotlinInlineTest.java
+++ b/src/test/java/com/android/tools/r8/debug/KotlinInlineTest.java
@@ -338,7 +338,7 @@
         stepInto(),
         // TODO(b/207743106): Remove when resolved.
         applyIf(
-            kotlinParameters.isNewerThanOrEqualTo(KotlinCompilerVersion.KOTLINC_1_6_0),
+            kotlinParameters.getCompilerVersion() == KotlinCompilerVersion.KOTLINC_1_6_0,
             this::stepInto),
         checkMethod(DEBUGGEE_CLASS, "foo"),
         checkLine(SOURCE_FILE, 34),
@@ -391,7 +391,7 @@
         stepInto(),
         // TODO(b/207743106): Remove when resolved.
         applyIf(
-            kotlinParameters.isNewerThanOrEqualTo(KotlinCompilerVersion.KOTLINC_1_6_0),
+            kotlinParameters.getCompilerVersion() == KotlinCompilerVersion.KOTLINC_1_6_0,
             this::stepInto),
         checkMethod(DEBUGGEE_CLASS, "foo"),
         checkLine(SOURCE_FILE, 34),
diff --git a/src/test/java/com/android/tools/r8/debuginfo/CanonicalizeWithInline.java b/src/test/java/com/android/tools/r8/debuginfo/CanonicalizeWithInline.java
index 48b9fc8..a8eb9cc 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/CanonicalizeWithInline.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/CanonicalizeWithInline.java
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.debuginfo;
 
+import static org.junit.Assert.assertNull;
+
 import com.android.tools.r8.AssumeMayHaveSideEffects;
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.OutputMode;
@@ -13,6 +15,8 @@
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.DexParser;
 import com.android.tools.r8.dex.DexSection;
+import com.android.tools.r8.graph.DexDebugInfo;
+import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import java.io.IOException;
 import java.nio.file.Path;
@@ -31,10 +35,8 @@
     return getTestParameters().withNoneRuntime().build();
   }
 
-  private final TestParameters parameters;
-
   public CanonicalizeWithInline(TestParameters parameters) {
-    this.parameters = parameters;
+    parameters.assertNoneRuntime();
   }
 
   private int getNumberOfDebugInfos(Path file) throws IOException {
@@ -58,10 +60,17 @@
             .addProgramClasses(clazzA, clazzB)
             .addKeepRules(
                 "-keepattributes SourceFile,LineNumberTable",
-                "-keep class ** {\n" + "public void call(int);\n" + "}")
+                "-keep class ** { public void call(int); }")
             .enableInliningAnnotations()
             .enableSideEffectAnnotations()
             .compile();
+    result.inspect(
+        inspector -> {
+          DexEncodedMethod method =
+              inspector.clazz(ClassA.class).uniqueMethodWithName("call").getMethod();
+          DexDebugInfo debugInfo = method.getCode().asDexCode().getDebugInfo();
+          assertNull(debugInfo);
+        });
     Path classesPath = temp.getRoot().toPath();
     result.app.write(classesPath, OutputMode.DexIndexed);
     int numberOfDebugInfos =
diff --git a/src/test/java/com/android/tools/r8/debuginfo/DexPcWithDebugInfoForOverloadedMethodsTestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/DexPcWithDebugInfoForOverloadedMethodsTestRunner.java
index f194b99..b3c1c08 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/DexPcWithDebugInfoForOverloadedMethodsTestRunner.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/DexPcWithDebugInfoForOverloadedMethodsTestRunner.java
@@ -23,7 +23,6 @@
 import com.android.tools.r8.ToolHelper.DexVm.Version;
 import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.retrace.RetraceFrameResult;
-import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -68,9 +67,7 @@
         .addKeepMainRule(MAIN)
         .addKeepMethodRules(MAIN, "void overloaded(...)")
         .addKeepAttributeLineNumberTable()
-        .addKeepAttributes(ProguardKeepAttributes.SOURCE_FILE)
         .setMinApi(parameters.getApiLevel())
-        .addOptionsModification(o -> o.enablePcBasedMappingFile = true)
         .run(parameters.getRuntime(), MAIN)
         .assertFailureWithErrorThatMatches(containsString(EXPECTED))
         .inspectOriginalStackTrace(
diff --git a/src/test/java/com/android/tools/r8/debuginfo/EnsureNoDebugInfoEmittedForPcOnlyTestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/EnsureNoDebugInfoEmittedForPcOnlyTestRunner.java
index 14c8504..a5e76eb 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/EnsureNoDebugInfoEmittedForPcOnlyTestRunner.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/EnsureNoDebugInfoEmittedForPcOnlyTestRunner.java
@@ -7,8 +7,8 @@
 import static com.android.tools.r8.naming.retrace.StackTrace.isSameExceptForFileNameAndLineNumber;
 import static com.android.tools.r8.utils.InternalOptions.LineNumberOptimization.ON;
 import static junit.framework.TestCase.assertEquals;
-import static junit.framework.TestCase.assertNull;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
@@ -21,7 +21,6 @@
 import com.android.tools.r8.graph.DexDebugEntryBuilder;
 import com.android.tools.r8.naming.retrace.StackTrace;
 import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine;
-import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
@@ -38,7 +37,6 @@
 
   private static final String FILENAME_MAIN = "EnsureNoDebugInfoEmittedForPcOnlyTest.java";
   private static final Class<?> MAIN = EnsureNoDebugInfoEmittedForPcOnlyTest.class;
-  private static final int INLINED_DEX_PC = 32;
 
   private final TestParameters parameters;
 
@@ -51,8 +49,9 @@
     this.parameters = parameters;
   }
 
-  private boolean apiLevelSupportsPcOutput() {
-    return parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.O);
+  private boolean apiLevelSupportsPcAndSourceFileOutput() {
+    // TODO(b/146565491): Update with API level once fixed.
+    return false;
   }
 
   @Test
@@ -62,7 +61,6 @@
         .addProgramClasses(MAIN)
         .setMinApi(parameters.getApiLevel())
         .internalEnableMappingOutput()
-        .addOptionsModification(o -> o.enablePcBasedMappingFile = true)
         .run(parameters.getRuntime(), MAIN)
         // For a debug build we always expect the output to have actual line information.
         .inspectFailure(this::checkHasLineNumberInfo)
@@ -76,10 +74,9 @@
         .addProgramClasses(MAIN)
         .setMinApi(parameters.getApiLevel())
         .internalEnableMappingOutput()
-        .addOptionsModification(o -> o.enablePcBasedMappingFile = true)
         // TODO(b/191038746): Enable LineNumberOptimization for release builds for DEX PC Output.
         .applyIf(
-            apiLevelSupportsPcOutput(),
+            apiLevelSupportsPcAndSourceFileOutput(),
             builder ->
                 builder.addOptionsModification(
                     options -> {
@@ -100,7 +97,7 @@
         .run(parameters.getRuntime(), MAIN)
         .inspectFailure(
             inspector -> {
-              if (apiLevelSupportsPcOutput()) {
+              if (apiLevelSupportsPcAndSourceFileOutput()) {
                 checkNoDebugInfo(inspector, 5);
               } else {
                 checkHasLineNumberInfo(inspector);
@@ -115,7 +112,6 @@
         .release()
         .addProgramClasses(MAIN)
         .setMinApi(parameters.getApiLevel())
-        .addOptionsModification(o -> o.enablePcBasedMappingFile = true)
         .run(parameters.getRuntime(), MAIN)
         // If compiling without a map output actual debug info should also be retained. Otherwise
         // there would not be any way to obtain the actual lines.
@@ -125,13 +121,12 @@
 
   @Test
   public void testNoEmittedDebugInfoR8() throws Exception {
-    assumeTrue(apiLevelSupportsPcOutput());
+    assumeTrue(apiLevelSupportsPcAndSourceFileOutput());
     testForR8(parameters.getBackend())
         .addProgramClasses(MAIN)
         .addKeepMainRule(MAIN)
         .addKeepAttributeLineNumberTable()
         .setMinApi(parameters.getApiLevel())
-        .addOptionsModification(o -> o.enablePcBasedMappingFile = true)
         .run(parameters.getRuntime(), MAIN)
         .inspectOriginalStackTrace(
             (stackTrace, inspector) -> {
diff --git a/src/test/java/com/android/tools/r8/debuginfo/SingleLineInfoMultipleInlineTest.java b/src/test/java/com/android/tools/r8/debuginfo/SingleLineInfoMultipleInlineTest.java
index 351b1e8..bc0d012 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/SingleLineInfoMultipleInlineTest.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/SingleLineInfoMultipleInlineTest.java
@@ -60,7 +60,6 @@
         .addKeepAttributeSourceFile()
         .addKeepAttributeLineNumberTable()
         .enableInliningAnnotations()
-        .addOptionsModification(o -> o.enablePcBasedMappingFile = true)
         .run(parameters.getRuntime(), Main.class)
         .assertFailureWithErrorThatThrows(NullPointerException.class)
         .inspectStackTrace(
diff --git a/src/test/java/com/android/tools/r8/debuginfo/SingleLineInfoRemoveTest.java b/src/test/java/com/android/tools/r8/debuginfo/SingleLineInfoRemoveTest.java
index 652f401..b881f55 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/SingleLineInfoRemoveTest.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/SingleLineInfoRemoveTest.java
@@ -9,14 +9,18 @@
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.notIf;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.TestRuntime.CfRuntime;
 import com.android.tools.r8.naming.retrace.StackTrace;
+import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine;
+import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import java.util.List;
+import org.hamcrest.CoreMatchers;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -27,14 +31,17 @@
 public class SingleLineInfoRemoveTest extends TestBase {
 
   private final TestParameters parameters;
+  private final boolean customSourceFile;
 
-  @Parameters(name = "{0}")
-  public static TestParametersCollection data() {
-    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  @Parameters(name = "{0}, custom-source-file:{1}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values());
   }
 
-  public SingleLineInfoRemoveTest(TestParameters parameters) {
+  public SingleLineInfoRemoveTest(TestParameters parameters, boolean customSourceFile) {
     this.parameters = parameters;
+    this.customSourceFile = customSourceFile;
   }
 
   public StackTrace expectedStackTrace;
@@ -58,9 +65,27 @@
         .addKeepMainRule(Main.class)
         .addKeepAttributeSourceFile()
         .addKeepAttributeLineNumberTable()
+        .applyIf(
+            customSourceFile,
+            b -> b.getBuilder().setSourceFileProvider(env -> "MyCustomSourceFile"))
         .enableInliningAnnotations()
         .run(parameters.getRuntime(), Main.class)
         .assertFailureWithErrorThatThrows(NullPointerException.class)
+        .inspectOriginalStackTrace(
+            stackTrace -> {
+              for (StackTraceLine line : stackTrace.getStackTraceLines()) {
+                if (customSourceFile) {
+                  assertEquals("MyCustomSourceFile", line.fileName);
+                } else if (parameters.isCfRuntime()) {
+                  assertEquals("SourceFile", line.fileName);
+                } else {
+                  assertThat(
+                      line.fileName,
+                      CoreMatchers.anyOf(
+                          CoreMatchers.is("SourceFile"), CoreMatchers.is("Unknown Source")));
+                }
+              }
+            })
         .inspectStackTrace(
             (stackTrace, inspector) -> {
               assertThat(stackTrace, isSame(expectedStackTrace));
@@ -68,10 +93,14 @@
               assertThat(mainSubject, isPresent());
               assertThat(
                   mainSubject.uniqueMethodWithName("shouldRemoveLineNumber"),
-                  notIf(hasLineNumberTable(), parameters.isDexRuntime()));
+                  notIf(hasLineNumberTable(), canSingleLineDebugInfoBeDiscarded()));
             });
   }
 
+  private boolean canSingleLineDebugInfoBeDiscarded() {
+    return parameters.isDexRuntime() && !customSourceFile;
+  }
+
   public static class Main {
 
     @NeverInline
diff --git a/src/test/java/com/android/tools/r8/debuginfo/pc2pc/DifferentParameterCountMultilineCodeTestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/pc2pc/DifferentParameterCountMultilineCodeTestRunner.java
new file mode 100644
index 0000000..637e1f0
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/debuginfo/pc2pc/DifferentParameterCountMultilineCodeTestRunner.java
@@ -0,0 +1,90 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.debuginfo.pc2pc;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.naming.retrace.StackTrace;
+import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine;
+import com.android.tools.r8.utils.BooleanUtils;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class DifferentParameterCountMultilineCodeTestRunner extends TestBase {
+
+  public static final Class<?> CLASS = DifferentParameterCountMultilineCodeTestSource.class;
+
+  private final TestParameters parameters;
+  private final boolean customSourceFile;
+
+  @Parameterized.Parameters(name = "{0}, custom-source-file:{1}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withDexRuntimes().withAllApiLevels().build(), BooleanUtils.values());
+  }
+
+  public DifferentParameterCountMultilineCodeTestRunner(
+      TestParameters parameters, boolean customSourceFile) {
+    this.parameters = parameters;
+    this.customSourceFile = customSourceFile;
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForR8(parameters.getBackend())
+        .addProgramClasses(CLASS)
+        .addKeepMainRule(CLASS)
+        // Keep all the methods but allow renaming.
+        .noTreeShaking()
+        .addKeepAttributeLineNumberTable()
+        .addKeepAttributeSourceFile()
+        .addKeepRules("-renamesourcefileattribute " + (customSourceFile ? "X" : "SourceFile"))
+        .setMinApi(parameters.getApiLevel())
+        .run(parameters.getRuntime(), CLASS)
+        .assertFailureWithErrorThatThrows(IllegalStateException.class)
+        .inspectOriginalStackTrace(
+            s -> {
+              for (StackTraceLine line : s.getStackTraceLines()) {
+                assertTrue("Expected line number in: " + line, line.hasLineNumber());
+                if (customSourceFile) {
+                  assertEquals("X", line.fileName);
+                } else if (parameters
+                    .getApiLevel()
+                    .isGreaterThanOrEqualTo(apiLevelWithPcAsLineNumberSupport())) {
+                  assertEquals("Unknown Source", line.fileName);
+                } else {
+                  assertEquals("SourceFile", line.fileName);
+                }
+              }
+              assertEquals("Expected 4 stack frames in:\n" + s, 4, s.getStackTraceLines().size());
+            })
+        .inspectStackTrace(
+            retracedStack ->
+                assertThat(
+                    retracedStack,
+                    StackTrace.isSame(
+                        StackTrace.builder()
+                            .add(makeLine("args0", 12))
+                            .add(makeLine("args1", 17))
+                            .add(makeLine("args2", 25))
+                            .add(makeLine("main", 32))
+                            .build())));
+  }
+
+  private StackTraceLine makeLine(String methodName, int lineNumber) {
+    return StackTraceLine.builder()
+        .setClassName(typeName(CLASS))
+        .setFileName(CLASS.getSimpleName() + ".java")
+        .setMethodName(methodName)
+        .setLineNumber(lineNumber)
+        .build();
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/debuginfo/pc2pc/DifferentParameterCountMultilineCodeTestSource.java b/src/test/java/com/android/tools/r8/debuginfo/pc2pc/DifferentParameterCountMultilineCodeTestSource.java
new file mode 100644
index 0000000..221becb
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/debuginfo/pc2pc/DifferentParameterCountMultilineCodeTestSource.java
@@ -0,0 +1,35 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.debuginfo.pc2pc;
+
+class DifferentParameterCountMultilineCodeTestSource {
+
+  public static void args0() {
+    if (System.nanoTime() < 0) {
+      System.out.println("Not hit...");
+    }
+    throw new IllegalStateException("DONE!");
+  }
+
+  public static void args1(String arg1) {
+    if (!arg1.equals("asdf")) {
+      args0();
+    } else {
+      throw new ArithmeticException("WAT");
+    }
+  }
+
+  public static void args2(String arg1, Object arg2) {
+    if (!arg1.equals(arg2)) {
+      args1(arg1);
+    } else {
+      throw new ArithmeticException("NO");
+    }
+  }
+
+  public static void main(String[] args) {
+    args2(System.nanoTime() < 0 ? args[0] : "foo", args.length > 0 ? args[0] : "bar");
+    throw new ArithmeticException("NO AGAIN");
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/debuginfo/pc2pc/DifferentParameterCountSingleLineCodeTestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/pc2pc/DifferentParameterCountSingleLineCodeTestRunner.java
new file mode 100644
index 0000000..398ecb4
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/debuginfo/pc2pc/DifferentParameterCountSingleLineCodeTestRunner.java
@@ -0,0 +1,102 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.debuginfo.pc2pc;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.naming.retrace.StackTrace;
+import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine;
+import com.android.tools.r8.utils.BooleanUtils;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class DifferentParameterCountSingleLineCodeTestRunner extends TestBase {
+
+  private static final Class<?> CLASS = DifferentParameterCountSingleLineCodeTestSource.class;
+
+  private final TestParameters parameters;
+  private final boolean customSourceFile;
+
+  @Parameterized.Parameters(name = "{0}, custom-source-file:{1}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withDexRuntimes().withAllApiLevels().build(), BooleanUtils.values());
+  }
+
+  public DifferentParameterCountSingleLineCodeTestRunner(
+      TestParameters parameters, boolean customSourceFile) {
+    this.parameters = parameters;
+    this.customSourceFile = customSourceFile;
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForR8(parameters.getBackend())
+        .addProgramClasses(CLASS)
+        .addKeepMainRule(CLASS)
+        // Keep all the methods but allow renaming.
+        .noTreeShaking()
+        .addKeepAttributeLineNumberTable()
+        .addKeepAttributeSourceFile()
+        .addKeepRules("-renamesourcefileattribute " + (customSourceFile ? "X" : "SourceFile"))
+        .setMinApi(parameters.getApiLevel())
+        .run(parameters.getRuntime(), CLASS)
+        .assertFailureWithErrorThatThrows(IllegalStateException.class)
+        .inspectOriginalStackTrace(
+            s -> {
+              for (StackTraceLine line : s.getStackTraceLines()) {
+                if (customSourceFile) {
+                  // For a custom source file, all debug info must be present.
+                  assertEquals("X", line.fileName);
+                  assertTrue("Expected line number in: " + line, line.hasLineNumber());
+                } else if (vmHasPcSupport()) {
+                  // Single line debug info is stripped. If running with PC support the PC is
+                  // printed.
+                  assertEquals("Unknown Source", line.fileName);
+                  assertTrue("Expected PC in: " + line, line.hasLineNumber());
+                } else {
+                  // Otherwise, just the bare source file is printed.
+                  assertEquals("SourceFile", line.fileName);
+                  assertFalse("Expected no line number in: " + line, line.hasLineNumber());
+                }
+              }
+              assertEquals("Expected 4 stack frames in:\n" + s, 4, s.getStackTraceLines().size());
+            })
+        .inspectStackTrace(
+            retracedStack ->
+                assertThat(
+                    retracedStack,
+                    StackTrace.isSame(
+                        StackTrace.builder()
+                            .add(makeLine("args0", 9))
+                            .add(makeLine("args1", 13))
+                            .add(makeLine("args2", 17))
+                            .add(makeLine("main", 21))
+                            .build())));
+  }
+
+  private boolean vmHasPcSupport() {
+    return parameters
+        .asDexRuntime()
+        .maxSupportedApiLevel()
+        .isGreaterThanOrEqualTo(apiLevelWithPcAsLineNumberSupport());
+  }
+
+  private StackTraceLine makeLine(String methodName, int lineNumber) {
+    return StackTraceLine.builder()
+        .setClassName(typeName(CLASS))
+        .setFileName(CLASS.getSimpleName() + ".java")
+        .setMethodName(methodName)
+        .setLineNumber(lineNumber)
+        .build();
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/debuginfo/pc2pc/DifferentParameterCountSingleLineCodeTestSource.java b/src/test/java/com/android/tools/r8/debuginfo/pc2pc/DifferentParameterCountSingleLineCodeTestSource.java
new file mode 100644
index 0000000..4f1ea5d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/debuginfo/pc2pc/DifferentParameterCountSingleLineCodeTestSource.java
@@ -0,0 +1,23 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.debuginfo.pc2pc;
+
+class DifferentParameterCountSingleLineCodeTestSource {
+
+  public static RuntimeException args0() {
+    throw System.nanoTime() < 0 ? null : new IllegalStateException("DONE!");
+  }
+
+  public static RuntimeException args1(String arg1) {
+    return !arg1.equals("asdf") ? args0() : null;
+  }
+
+  public static RuntimeException args2(String arg1, Object arg2) {
+    return !arg1.equals(arg2) ? args1(arg1) : null;
+  }
+
+  public static void main(String[] args) {
+    throw args2(System.nanoTime() < 0 ? args[0] : "foo", args.length > 0 ? args[0] : "bar");
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java
index f1ac89f..6b54606 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java
@@ -10,8 +10,8 @@
 import com.android.tools.r8.StringResource;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfiguration;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfigurationParser;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecificationParser;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.InternalOptions;
@@ -60,11 +60,11 @@
             : "Caught j$.io.UncheckedIOException");
   }
 
-  DesugaredLibraryConfiguration configurationAlternative3(
+  LegacyDesugaredLibrarySpecification configurationAlternative3(
       InternalOptions options, boolean libraryCompilation, TestParameters parameters) {
     // Parse the current configuration and amend the configuration for BufferedReader.lines. The
     // configuration is the same for both program and library.
-    return new DesugaredLibraryConfigurationParser(
+    return new LegacyDesugaredLibrarySpecificationParser(
             options.dexItemFactory(),
             options.reporter,
             libraryCompilation,
@@ -73,11 +73,11 @@
   }
 
   private void configurationForProgramCompilation(InternalOptions options) {
-    options.desugaredLibraryConfiguration = configurationAlternative3(options, false, parameters);
+    options.desugaredLibrarySpecification = configurationAlternative3(options, false, parameters);
   }
 
   private void configurationForLibraryCompilation(InternalOptions options) {
-    options.desugaredLibraryConfiguration = configurationAlternative3(options, true, parameters);
+    options.desugaredLibrarySpecification = configurationAlternative3(options, true, parameters);
   }
 
   @Test
@@ -143,7 +143,7 @@
         .addLibraryFiles(getLibraryFile())
         .addOptionsModification(
             options ->
-                options.desugaredLibraryConfiguration =
+                options.desugaredLibrarySpecification =
                     configurationAlternative3(options, false, parameters))
         .addInnerClasses(BufferedReaderTest.class)
         .setMinApi(parameters.getApiLevel())
@@ -172,7 +172,7 @@
         .addLibraryFiles(getLibraryFile())
         .addOptionsModification(
             options ->
-                options.desugaredLibraryConfiguration =
+                options.desugaredLibrarySpecification =
                     configurationAlternative3(options, false, parameters))
         .addInnerClasses(BufferedReaderTest.class)
         .addKeepMainRule(TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryCHMOnlyContentTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryCHMOnlyContentTest.java
index dc995e3..3e7d97d 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryCHMOnlyContentTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryCHMOnlyContentTest.java
@@ -8,8 +8,8 @@
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfiguration;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfigurationParser;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecificationParser;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import java.nio.file.Path;
@@ -44,7 +44,7 @@
             false,
             Collections.emptyList(),
             options -> {
-              options.desugaredLibraryConfiguration =
+              options.desugaredLibrarySpecification =
                   chmOnlyConfiguration(options, true, parameters);
             });
     CodeInspector inspector = new CodeInspector(desugaredLib);
@@ -62,16 +62,16 @@
             true,
             Collections.emptyList(),
             options -> {
-              options.desugaredLibraryConfiguration =
+              options.desugaredLibrarySpecification =
                   chmOnlyConfiguration(options, true, parameters);
             });
     CodeInspector inspector = new CodeInspector(desugaredLib);
     assert inspector.clazz("j$.util.concurrent.ConcurrentHashMap").isPresent();
   }
 
-  DesugaredLibraryConfiguration chmOnlyConfiguration(
+  LegacyDesugaredLibrarySpecification chmOnlyConfiguration(
       InternalOptions options, boolean libraryCompilation, TestParameters parameters) {
-    return new DesugaredLibraryConfigurationParser(
+    return new LegacyDesugaredLibrarySpecificationParser(
             options.dexItemFactory(),
             options.reporter,
             libraryCompilation,
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryConfigurationParsingTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryConfigurationParsingTest.java
index 2ef985e..efc5ce8 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryConfigurationParsingTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryConfigurationParsingTest.java
@@ -20,8 +20,8 @@
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfiguration;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfigurationParser;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecificationParser;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.AbortException;
 import com.android.tools.r8.utils.AndroidApiLevel;
@@ -70,10 +70,11 @@
       ImmutableMap.<String, Object>builder()
           .put(
               "configuration_format_version",
-              DesugaredLibraryConfigurationParser.MAX_SUPPORTED_VERSION)
+              LegacyDesugaredLibrarySpecificationParser.MAX_SUPPORTED_VERSION)
           .put("group_id", "com.tools.android")
           .put("artifact_id", "desugar_jdk_libs")
-          .put("version", DesugaredLibraryConfigurationParser.MIN_SUPPORTED_VERSION.toString())
+          .put(
+              "version", LegacyDesugaredLibrarySpecificationParser.MIN_SUPPORTED_VERSION.toString())
           .put("required_compilation_api_level", 1)
           .put("synthesized_library_classes_package_prefix", "j$.")
           .put("common_flags", Collections.emptyList())
@@ -85,20 +86,20 @@
     return new LinkedHashMap<>(TEMPLATE);
   }
 
-  private DesugaredLibraryConfigurationParser parser(DiagnosticsHandler handler) {
-    return new DesugaredLibraryConfigurationParser(
+  private LegacyDesugaredLibrarySpecificationParser parser(DiagnosticsHandler handler) {
+    return new LegacyDesugaredLibrarySpecificationParser(
         factory, new Reporter(handler), libraryCompilation, minApi.getLevel());
   }
 
-  private DesugaredLibraryConfiguration runPassing(String resource) {
+  private LegacyDesugaredLibrarySpecification runPassing(String resource) {
     return runPassing(StringResource.fromString(resource, origin));
   }
 
-  private DesugaredLibraryConfiguration runPassing(StringResource resource) {
+  private LegacyDesugaredLibrarySpecification runPassing(StringResource resource) {
     TestDiagnosticMessagesImpl handler = new TestDiagnosticMessagesImpl();
-    DesugaredLibraryConfiguration config = parser(handler).parse(resource);
+    LegacyDesugaredLibrarySpecification spec = parser(handler).parse(resource);
     handler.assertNoMessages();
-    return config;
+    return spec;
   }
 
   private void runFailing(String json, Consumer<TestDiagnosticMessages> checker) {
@@ -114,9 +115,9 @@
   @Test
   public void testReference() throws Exception {
     // Just test that the reference file parses without issues.
-    DesugaredLibraryConfiguration config =
+    LegacyDesugaredLibrarySpecification spec =
         runPassing(StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()));
-    assertEquals(libraryCompilation, config.isLibraryCompilation());
+    assertEquals(libraryCompilation, spec.isLibraryCompilation());
   }
 
   @Test
@@ -161,7 +162,7 @@
   @Test
   public void testUnsupportedVersion() {
     LinkedHashMap<String, Object> data = template();
-    SemanticVersion minVersion = DesugaredLibraryConfigurationParser.MIN_SUPPORTED_VERSION;
+    SemanticVersion minVersion = LegacyDesugaredLibrarySpecificationParser.MIN_SUPPORTED_VERSION;
     data.put(
         "version",
         new SemanticVersion(minVersion.getMajor(), minVersion.getMinor(), minVersion.getPatch() - 1)
@@ -255,15 +256,15 @@
                     "java.util.Foo", "j$.util.FooConv1",
                     "java.util.Foo2", "j$.util.FooConv2"))));
     // The gson parser will overwrite the key in order during parsing, thus hiding potential issues.
-    DesugaredLibraryConfiguration config = runPassing(toJson(data).replace("Foo2", "Foo"));
+    LegacyDesugaredLibrarySpecification spec = runPassing(toJson(data).replace("Foo2", "Foo"));
     assertEquals(
         Collections.singletonList("java.util.Foo"),
-        config.getCustomConversions().keySet().stream()
+        spec.getCustomConversions().keySet().stream()
             .map(DexType::toString)
             .collect(Collectors.toList()));
     assertEquals(
         Collections.singletonList("j$.util.FooConv2"),
-        config.getCustomConversions().values().stream()
+        spec.getCustomConversions().values().stream()
             .map(DexType::toString)
             .collect(Collectors.toList()));
   }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryMismatchTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryMismatchTest.java
index 91b87a0..1409ec7 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryMismatchTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryMismatchTest.java
@@ -14,7 +14,7 @@
 import com.android.tools.r8.StringResource;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.errors.DesugaredLibraryMismatchDiagnostic;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfiguration;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.Box;
@@ -193,7 +193,7 @@
   public void testMergeDifferentLibraryDesugarVersions() throws Exception {
     // DEX code with library desugaring using a desugared library configuration with a
     // different identifier.
-    Box<DesugaredLibraryConfiguration> box = new Box<>();
+    Box<LegacyDesugaredLibrarySpecification> box = new Box<>();
     Path libraryDex =
         testForD8(Backend.DEX)
             .addProgramClasses(Library.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java
index e57aaa9..34faa58 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java
@@ -24,8 +24,8 @@
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.DexVm.Version;
 import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfiguration;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfigurationParser;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecificationParser;
 import com.android.tools.r8.tracereferences.TraceReferences;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.FileUtils;
@@ -163,6 +163,10 @@
               L8TestBuilder::setDebug)
           .addOptionsModifier(optionsModifier)
           .setDesugarJDKLibsConfiguration(ToolHelper.DESUGAR_LIB_CONVERSIONS)
+          // If we compile extended library here, it means we use TestNG. TestNG requires
+          // annotations, hence we disable annotation removal. This implies that extra warnings are
+          // generated.
+          .setDisableL8AnnotationRemoval(!additionalProgramFiles.isEmpty())
           .compile()
           .applyIf(
               additionalProgramFiles.isEmpty(),
@@ -227,12 +231,12 @@
     return desugaredLib;
   }
 
-  protected DesugaredLibraryConfiguration configurationWithSupportAllCallbacksFromLibrary(
+  protected LegacyDesugaredLibrarySpecification configurationWithSupportAllCallbacksFromLibrary(
       InternalOptions options,
       boolean libraryCompilation,
       TestParameters parameters,
       boolean supportAllCallbacksFromLibrary) {
-    return new DesugaredLibraryConfigurationParser(
+    return new LegacyDesugaredLibrarySpecificationParser(
             options.dexItemFactory(),
             options.reporter,
             libraryCompilation,
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ExtractWrapperTypesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ExtractWrapperTypesTest.java
index 5c42b95..21dc2f9 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ExtractWrapperTypesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ExtractWrapperTypesTest.java
@@ -16,8 +16,8 @@
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfiguration;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfigurationParser;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecificationParser;
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
 import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.references.MethodReference;
@@ -128,11 +128,11 @@
     CodeInspector desugaredApiJar = getDesugaredApiJar();
     Set<ClassReference> preDesugarTypes = getPreDesugarTypes();
 
-    DesugaredLibraryConfiguration conf = getDesugaredLibraryConfiguration();
+    LegacyDesugaredLibrarySpecification spec = getDesugaredLibraryConfiguration();
     Set<String> wrappersInSpec =
-        conf.getWrapperConversions().stream().map(DexType::toString).collect(Collectors.toSet());
+        spec.getWrapperConversions().stream().map(DexType::toString).collect(Collectors.toSet());
     Set<String> customConversionsInSpec =
-        conf.getCustomConversions().keySet().stream()
+        spec.getCustomConversions().keySet().stream()
             .map(DexType::toString)
             .collect(Collectors.toSet());
     assertEquals(
@@ -191,9 +191,9 @@
     return missingWrappers;
   }
 
-  private DesugaredLibraryConfiguration getDesugaredLibraryConfiguration() {
-    DesugaredLibraryConfigurationParser parser =
-        new DesugaredLibraryConfigurationParser(
+  private LegacyDesugaredLibrarySpecification getDesugaredLibraryConfiguration() {
+    LegacyDesugaredLibrarySpecificationParser parser =
+        new LegacyDesugaredLibrarySpecificationParser(
             new DexItemFactory(), null, true, minApi.getLevel());
     return parser.parse(StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()));
   }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InconsistentPrefixTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InconsistentPrefixTest.java
index 43056e6..b1f57e1 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InconsistentPrefixTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InconsistentPrefixTest.java
@@ -10,7 +10,7 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfiguration;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
 import com.android.tools.r8.jasmin.JasminBuilder;
 import java.nio.file.Path;
 import java.util.HashMap;
@@ -48,8 +48,8 @@
         .addProgramFiles(inputJar)
         .addOptionsModification(
             options ->
-                options.desugaredLibraryConfiguration =
-                    DesugaredLibraryConfiguration.withOnlyRewritePrefixForTesting(x, options))
+                options.desugaredLibrarySpecification =
+                    LegacyDesugaredLibrarySpecification.withOnlyRewritePrefixForTesting(x, options))
         .compileWithExpectedDiagnostics(
             diagnostics -> {
               diagnostics.assertErrorMessageThatMatches(
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java
index 283900e..18af69f 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java
@@ -14,8 +14,8 @@
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfiguration;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfigurationParser;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecificationParser;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.FileUtils;
 import com.android.tools.r8.utils.InternalOptions;
@@ -125,8 +125,8 @@
           directory.toString()
         });
     InternalOptions options = new InternalOptions(new DexItemFactory(), new Reporter());
-    DesugaredLibraryConfiguration desugaredLibraryConfiguration =
-        new DesugaredLibraryConfigurationParser(
+    LegacyDesugaredLibrarySpecification desugaredLibrarySpecification =
+        new LegacyDesugaredLibrarySpecificationParser(
                 options.itemFactory, options.reporter, false, AndroidApiLevel.B.getLevel())
             .parse(StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()));
 
@@ -136,7 +136,7 @@
       }
       Path compileApiLevelDirectory = directory.resolve("compile_api_level_" + apiLevel.getLevel());
       if (apiLevel.getLevel()
-          < desugaredLibraryConfiguration.getRequiredCompilationApiLevel().getLevel()) {
+          < desugaredLibrarySpecification.getRequiredCompilationApiLevel().getLevel()) {
         System.out.println("!Checking " + compileApiLevelDirectory);
         continue;
       }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ObjectsTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ObjectsTest.java
index b2973f5..abdf5c5 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ObjectsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ObjectsTest.java
@@ -15,8 +15,8 @@
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestRuntime.CfVm;
 import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfiguration;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfigurationParser;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecificationParser;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.InternalOptions;
@@ -84,9 +84,9 @@
         ToolHelper.getAndroidJar(Ordered.max(parameters.getApiLevel(), AndroidApiLevel.O));
   }
 
-  DesugaredLibraryConfiguration desugaredLibraryConfiguration(
+  LegacyDesugaredLibrarySpecification desugaredLibrarySpecification(
       InternalOptions options, boolean libraryCompilation, TestParameters parameters) {
-    return new DesugaredLibraryConfigurationParser(
+    return new LegacyDesugaredLibrarySpecificationParser(
             options.dexItemFactory(),
             options.reporter,
             libraryCompilation,
@@ -99,13 +99,13 @@
   }
 
   private void configurationForProgramCompilation(InternalOptions options) {
-    options.desugaredLibraryConfiguration =
-        desugaredLibraryConfiguration(options, false, parameters);
+    options.desugaredLibrarySpecification =
+        desugaredLibrarySpecification(options, false, parameters);
   }
 
   private void configurationForLibraryCompilation(InternalOptions options) {
-    options.desugaredLibraryConfiguration =
-        desugaredLibraryConfiguration(options, true, parameters);
+    options.desugaredLibrarySpecification =
+        desugaredLibrarySpecification(options, true, parameters);
   }
 
   private Matcher<MethodSubject> invokesObjectsCompare(String holder) {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetAndBackportTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetAndBackportTest.java
index 6b29a83..359a18c 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetAndBackportTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetAndBackportTest.java
@@ -7,9 +7,12 @@
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfiguration;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyRewritingFlags;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyTopLevelFlags;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import java.util.List;
 import org.junit.Test;
@@ -35,34 +38,35 @@
     this.backend = backend;
   }
 
+  /**
+   * Add this library desugaring configuration:
+   * "library_flags": [
+   *  {
+   *    "rewrite_prefix":{"java.time.": "j$.time."},
+   *    "backport": {"java.lang.DesugarMath": "java.lang.Math"},
+   *    "retarget_lib_member": {"java.util.Date#toInstant": "java.util.DesugarDate"}
+   *  }
+   * ],
+   */
+  private static void specifyDesugaredLibrary(InternalOptions options) {
+    LegacyRewritingFlags rewritingFlags =
+        LegacyRewritingFlags.builder(options.itemFactory, options.reporter, Origin.unknown())
+            .putRewritePrefix("java.time.", "j$.time.")
+            .putBackportCoreLibraryMember("java.lang.DesugarMath", "java.lang.Math")
+            .putRetargetCoreLibMember("java.util.Date#toInstant", "java.util.DesugarDate")
+            .build();
+    options.desugaredLibrarySpecification =
+        new LegacyDesugaredLibrarySpecification(
+            LegacyTopLevelFlags.testing(), rewritingFlags, true, options.itemFactory);
+  }
+
   @Test
   public void test() throws Exception {
     testForL8(AndroidApiLevel.B, backend)
         .noDefaultDesugarJDKLibs()
         .addProgramClassFileData(dump())
         .addLibraryFiles(getLibraryFile())
-        /*
-         Add this library desugaring configuration:
-         "library_flags": [
-           {
-             "rewrite_prefix": {"java.time.": "j$.time."},
-             "backport": {"java.lang.DesugarMath": "java.lang.Math"},
-             "retarget_lib_member": {"java.util.Date#toInstant": "java.util.DesugarDate"}
-           }
-         ],
-        */
-        .addOptionsModifier(
-            options ->
-                options.desugaredLibraryConfiguration =
-                    DesugaredLibraryConfiguration.builder(
-                            options.dexItemFactory(), options.reporter, Origin.unknown())
-                        .setDesugaredLibraryIdentifier("my-identifier")
-                        .putRewritePrefix("java.time.", "j$.time.")
-                        .putBackportCoreLibraryMember("java.lang.DesugarMath", "java.lang.Math")
-                        .putRetargetCoreLibMember(
-                            "java.util.Date#toInstant", "java.util.DesugarDate")
-                        .setLibraryCompilation()
-                        .build())
+        .addOptionsModifier(RetargetAndBackportTest::specifyDesugaredLibrary)
         .compile()
         .inspect(
             inspector -> {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/AccessModeConversionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/AccessModeConversionTest.java
index d392dd8..6691cb1 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/AccessModeConversionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/AccessModeConversionTest.java
@@ -6,7 +6,9 @@
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfiguration;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyRewritingFlags;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyTopLevelFlags;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
@@ -57,16 +59,15 @@
   }
 
   private void configureDesugaredLibrary(InternalOptions options, boolean l8Compilation) {
-    DesugaredLibraryConfiguration.Builder builder =
-        DesugaredLibraryConfiguration.builder(
-                options.itemFactory, options.reporter, Origin.unknown())
-            .setDesugaredLibraryIdentifier("com.tools.android:desugar_jdk_libs:9.99.99")
+    LegacyRewritingFlags rewritingFlags =
+        LegacyRewritingFlags.builder(options.itemFactory, options.reporter, Origin.unknown())
             .putRewritePrefix("java.nio.file.AccessMode", "j$.nio.file.AccessMode")
-            .addWrapperConversion("java.nio.file.AccessMode");
-    if (l8Compilation) {
-      builder.setLibraryCompilation();
-    }
-    options.desugaredLibraryConfiguration = builder.build();
+            .addWrapperConversion("java.nio.file.AccessMode")
+            .build();
+    LegacyDesugaredLibrarySpecification specification =
+        new LegacyDesugaredLibrarySpecification(
+            LegacyTopLevelFlags.testing(), rewritingFlags, l8Compilation, options.itemFactory);
+    options.desugaredLibrarySpecification = specification;
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java
index a205079..aa97e55 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java
@@ -87,7 +87,7 @@
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
         .addOptionsModification(
             opt ->
-                opt.desugaredLibraryConfiguration =
+                opt.desugaredLibrarySpecification =
                     configurationWithSupportAllCallbacksFromLibrary(
                         opt, false, parameters, supportAllCallbacksFromLibrary))
         .compile()
@@ -151,7 +151,7 @@
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
         .addOptionsModification(
             opt ->
-                opt.desugaredLibraryConfiguration =
+                opt.desugaredLibrarySpecification =
                     configurationWithSupportAllCallbacksFromLibrary(
                         opt, false, parameters, supportAllCallbacksFromLibrary))
         .compile()
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/DuplicateAPIDesugaredLibTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/DuplicateAPIDesugaredLibTest.java
index 1fa4a7c..6b7d86e 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/DuplicateAPIDesugaredLibTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/DuplicateAPIDesugaredLibTest.java
@@ -71,7 +71,7 @@
                         this.buildDesugaredLibrary(
                             api,
                             opt ->
-                                opt.desugaredLibraryConfiguration =
+                                opt.desugaredLibrarySpecification =
                                     configurationWithSupportAllCallbacksFromLibrary(
                                         opt, true, parameters, supportAllCallbacksFromLibrary)));
                     return desugaredLibBox.get();
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
index 05758fd..12fe431 100644
--- a/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
@@ -6,7 +6,7 @@
 
 import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_1_3_72;
 import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_1_5_0;
-import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLIN_DEV;
+import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_1_6_0;
 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.notIf;
@@ -37,7 +37,6 @@
 import java.util.Set;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
-import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -64,8 +63,6 @@
     // SAM interfaces lambdas are implemented by invoke dynamic in kotlin 1.5 unlike 1.4 where a
     // class is generated for each. In CF we leave invokeDynamic but for DEX we desugar the classes
     // and merge them.
-    // TODO(b/208816049): Fix test.
-    Assume.assumeTrue(kotlinParameters.getCompiler().isNot(KOTLIN_DEV));
     boolean hasKotlinCGeneratedLambdaClasses = kotlinParameters.isOlderThan(KOTLINC_1_5_0);
     String mainClassName = "class_inliner_lambda_j_style.MainKt";
     runTest(
@@ -154,10 +151,13 @@
               }
               // TODO(b/173337498): MainKt$testStateless$1 should always be class inlined.
               if (!hasKotlinCGeneratedLambdaClasses) {
+                // Kotlin 1.6.20 and later do not create intrinsics.stringPlus for two argument
+                // string concatination. That allow R8's stringbuilder optimization to reduce the
+                // size of strings and therefore inline the synthetic lambda.
                 assertThat(
                     inspector.clazz(
                         "class_inliner_lambda_j_style.MainKt$$ExternalSyntheticLambda1"),
-                    isPresent());
+                    notIf(isPresent(), kotlinParameters.isNewerThan(KOTLINC_1_6_0)));
               } else {
                 assertThat(
                     inspector.clazz("class_inliner_lambda_j_style.MainKt$testStateless$1"),
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
index 9347e50..ece3111 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -885,8 +885,7 @@
             null,
             GraphLens.getIdentityLens(),
             InitClassLens.getThrowingInstance(),
-            NamingLens.getIdentityLens(),
-            null);
+            NamingLens.getIdentityLens());
     ExecutorService executor = ThreadUtils.getExecutorService(options);
     AndroidAppConsumers compatSink = new AndroidAppConsumers(options);
     try {
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/b135627418/B135627418.java b/src/test/java/com/android/tools/r8/memberrebinding/b135627418/B135627418.java
index 06a87e4..f3103f1 100644
--- a/src/test/java/com/android/tools/r8/memberrebinding/b135627418/B135627418.java
+++ b/src/test/java/com/android/tools/r8/memberrebinding/b135627418/B135627418.java
@@ -12,7 +12,7 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryConfiguration;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
 import com.android.tools.r8.memberrebinding.b135627418.library.Drawable;
 import com.android.tools.r8.memberrebinding.b135627418.library.DrawableWrapper;
 import com.android.tools.r8.memberrebinding.b135627418.library.InsetDrawable;
@@ -76,8 +76,8 @@
             .setMinApi(parameters.getRuntime())
             .addOptionsModification(
                 options ->
-                    options.desugaredLibraryConfiguration =
-                        DesugaredLibraryConfiguration.withOnlyRewritePrefixForTesting(
+                    options.desugaredLibrarySpecification =
+                        LegacyDesugaredLibrarySpecification.withOnlyRewritePrefixForTesting(
                             ImmutableMap.of(packageName + ".runtime", packageName + ".library"),
                             options))
             .compile();
diff --git a/src/test/java/com/android/tools/r8/proguard/configuration/ProguardRuleWithEllipsisForReturnTypeTest.java b/src/test/java/com/android/tools/r8/proguard/configuration/ProguardRuleWithEllipsisForReturnTypeTest.java
index 17b13cf..879786b 100644
--- a/src/test/java/com/android/tools/r8/proguard/configuration/ProguardRuleWithEllipsisForReturnTypeTest.java
+++ b/src/test/java/com/android/tools/r8/proguard/configuration/ProguardRuleWithEllipsisForReturnTypeTest.java
@@ -42,6 +42,7 @@
             "  private static ... unused;",
             "  public static ... main(...);",
             "}")
+        .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), clazz)
         .assertSuccessWithOutput(expectedOutput)
         .inspect(this::inspect);
diff --git a/src/test/java/com/android/tools/r8/regress/b150400371/DebuginfoForInlineFrameRegressionTest.java b/src/test/java/com/android/tools/r8/regress/b150400371/DebuginfoForInlineFrameRegressionTest.java
index 3dc67f0..cc7900e 100644
--- a/src/test/java/com/android/tools/r8/regress/b150400371/DebuginfoForInlineFrameRegressionTest.java
+++ b/src/test/java/com/android/tools/r8/regress/b150400371/DebuginfoForInlineFrameRegressionTest.java
@@ -38,7 +38,6 @@
         .addKeepMainRule(InlineInto.class)
         .addKeepRules("-keepparameternames")
         .setMinApi(parameters.getApiLevel())
-        .addOptionsModification(o -> o.enablePcBasedMappingFile = true)
         .run(parameters.getRuntime(), InlineInto.class)
         .assertSuccessWithOutputLines("42foo")
         .inspect(
diff --git a/src/test/java/com/android/tools/r8/retrace/SourceFileTest.java b/src/test/java/com/android/tools/r8/retrace/SourceFileTest.java
index 5bc7a26..6f533c2 100644
--- a/src/test/java/com/android/tools/r8/retrace/SourceFileTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/SourceFileTest.java
@@ -8,7 +8,7 @@
 import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.R8TestCompileResult;
 import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -85,7 +85,7 @@
 
   private void runTest(boolean addDummyArg, BiConsumer<StackTrace, CodeInspector> consumer)
       throws Exception {
-    R8FullTestBuilder r8FullTestBuilder =
+    R8TestCompileResult compileResult =
         testForR8(parameters.getBackend())
             .addProgramClasses(Main.class, ClassWithoutCustomFileName.class)
             .addProgramClassFileData(
@@ -94,11 +94,12 @@
             .enableInliningAnnotations()
             .addKeepMainRule(Main.class)
             .setMinApi(parameters.getApiLevel())
-            .addKeepAttributeSourceFile();
+            .addKeepAttributeSourceFile()
+            .compile();
     R8TestRunResult runResult =
         addDummyArg
-            ? r8FullTestBuilder.run(parameters.getRuntime(), Main.class, "foo")
-            : r8FullTestBuilder.run(parameters.getRuntime(), Main.class);
+            ? compileResult.run(parameters.getRuntime(), Main.class, "foo")
+            : compileResult.run(parameters.getRuntime(), Main.class);
     runResult.assertFailureWithErrorThatMatches(containsString("Hello World!"));
     StackTrace originalStackTrace = runResult.getOriginalStackTrace();
     StackTrace retracedStackTrace = originalStackTrace.retrace(runResult.proguardMap());
diff --git a/src/test/java/com/android/tools/r8/retrace/StackTraceWithPcAndJumboStringTestRunner.java b/src/test/java/com/android/tools/r8/retrace/StackTraceWithPcAndJumboStringTestRunner.java
index 652de07..a6940a8 100644
--- a/src/test/java/com/android/tools/r8/retrace/StackTraceWithPcAndJumboStringTestRunner.java
+++ b/src/test/java/com/android/tools/r8/retrace/StackTraceWithPcAndJumboStringTestRunner.java
@@ -4,7 +4,6 @@
 package com.android.tools.r8.retrace;
 
 import static com.android.tools.r8.naming.retrace.StackTrace.isSame;
-import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
 
 import com.android.tools.r8.TestBase;
@@ -53,25 +52,11 @@
         .setMinApi(parameters.getApiLevel())
         .addOptionsModification(
             o -> {
-              o.enablePcBasedMappingFile = true;
               o.testing.forceJumboStringProcessing = true;
             })
         .run(parameters.getRuntime(), getTestClass())
         .assertFailureWithErrorThatThrows(RuntimeException.class)
-        .inspectStackTrace(
-            stacktrace -> {
-              if (isApiLevelWithPcSupport()) {
-                // TODO(b/207765416): Remove this when PC support works with jumbo string rewriting.
-                assertThat(stacktrace, not(isSame(getExpectedStackTrace())));
-              } else {
-                assertThat(stacktrace, isSame(getExpectedStackTrace()));
-              }
-            });
-  }
-
-  private boolean isApiLevelWithPcSupport() {
-    return parameters.isDexRuntime()
-        && parameters.getApiLevel().isGreaterThanOrEqualTo(apiLevelWithPcAsLineNumberSupport());
+        .inspectStackTrace(stacktrace -> assertThat(stacktrace, isSame(getExpectedStackTrace())));
   }
 
   private StackTrace getExpectedStackTrace() {
diff --git a/src/test/java/com/android/tools/r8/shaking/TreeShakingSpecificTest.java b/src/test/java/com/android/tools/r8/shaking/TreeShakingSpecificTest.java
index d36489a..f42443d 100644
--- a/src/test/java/com/android/tools/r8/shaking/TreeShakingSpecificTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/TreeShakingSpecificTest.java
@@ -121,7 +121,6 @@
             builder -> builder.addProgramDexFileData(getProgramDexFileData(test)))
         .addKeepRuleFiles(Paths.get(EXAMPLES_DIR, test, "keep-rules.txt"))
         .addOptionsModification(options -> options.inlinerOptions().enableInlining = false)
-        .addOptionsModification(o -> o.enablePcBasedMappingFile = true)
         .setMinApi(minApi)
         .compile()
         .inspectProguardMap(
diff --git a/src/test/java/com/android/tools/r8/shaking/attributes/KeepAttributesTest.java b/src/test/java/com/android/tools/r8/shaking/attributes/KeepAttributesTest.java
index 6413bb8..82bcb21 100644
--- a/src/test/java/com/android/tools/r8/shaking/attributes/KeepAttributesTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/attributes/KeepAttributesTest.java
@@ -119,7 +119,6 @@
         .addKeepRules(keepRules)
         .enableSideEffectAnnotations()
         .setMinApi(parameters.getApiLevel())
-        .addOptionsModification(o -> o.enablePcBasedMappingFile = true)
         .run(parameters.getRuntime(), CLASS)
         .inspector()
         .clazz(CLASS)
diff --git a/src/test/java/com/android/tools/r8/utils/Smali.java b/src/test/java/com/android/tools/r8/utils/Smali.java
index 84099dc..bdeecf4 100644
--- a/src/test/java/com/android/tools/r8/utils/Smali.java
+++ b/src/test/java/com/android/tools/r8/utils/Smali.java
@@ -119,8 +119,7 @@
               null,
               GraphLens.getIdentityLens(),
               InitClassLens.getThrowingInstance(),
-              NamingLens.getIdentityLens(),
-              null);
+              NamingLens.getIdentityLens());
       writer.write(executor);
       return consumer.contents;
     } finally {
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundAnnotationSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundAnnotationSubject.java
index a97f040..d06b289 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundAnnotationSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundAnnotationSubject.java
@@ -6,7 +6,10 @@
 
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.DexAnnotation;
+import com.android.tools.r8.graph.DexAnnotationSet;
 import com.android.tools.r8.graph.DexEncodedAnnotation;
+import com.android.tools.r8.utils.ListUtils;
+import java.util.List;
 
 public class FoundAnnotationSubject extends AnnotationSubject {
 
@@ -16,6 +19,10 @@
     this.annotation = annotation;
   }
 
+  public static List<AnnotationSubject> listFromDex(DexAnnotationSet annotations) {
+    return ListUtils.map(annotations.annotations, FoundAnnotationSubject::new);
+  }
+
   @Override
   public boolean isPresent() {
     return true;
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
index 69ebe80..0d62343 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
@@ -355,11 +355,7 @@
 
   @Override
   public List<AnnotationSubject> annotations() {
-    List<AnnotationSubject> result = new ArrayList<>();
-    for (DexAnnotation annotation : dexClass.annotations().annotations) {
-      result.add(new FoundAnnotationSubject(annotation));
-    }
-    return result;
+    return FoundAnnotationSubject.listFromDex(dexClass.annotations());
   }
 
   @Override
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
index 40fcc0f..813739b 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
@@ -326,7 +326,7 @@
 
   @Override
   public List<AnnotationSubject> annotations() {
-    throw new Unimplemented();
+    return FoundAnnotationSubject.listFromDex(dexMethod.annotations());
   }
 
   @Override
diff --git a/tools/compiledump.py b/tools/compiledump.py
index 98c9489..a810cdc 100755
--- a/tools/compiledump.py
+++ b/tools/compiledump.py
@@ -38,6 +38,24 @@
     help='Compiler to use',
     default=None)
   parser.add_argument(
+    '--minify',
+    help='Force enable/disable minification'
+      ' (defaults to app proguard config)',
+    choices=['default', 'force-enable', 'force-disable'],
+    default='default')
+  parser.add_argument(
+    '--optimize',
+    help='Force enable/disable optimizations'
+      ' (defaults to app proguard config)',
+    choices=['default', 'force-enable', 'force-disable'],
+    default='default')
+  parser.add_argument(
+    '--shrink',
+    help='Force enable/disable shrinking'
+      ' (defaults to app proguard config)',
+    choices=['default', 'force-enable', 'force-disable'],
+    default='default')
+  parser.add_argument(
     '-v',
     '--version',
     help='Compiler version to use (default read from dump version file).'
@@ -281,17 +299,39 @@
   return dest
 
 
-def clean_config(file):
+def clean_config(file, args):
   with open(file) as f:
     lines = f.readlines()
+  minify = args.minify
+  optimize = args.optimize
+  shrink = args.shrink
   with open(file, 'w') as f:
+    if minify == 'force-disable':
+      print('Adding config line: -dontobfuscate')
+      f.write('-dontobfuscate\n')
+    if optimize == 'force-disable':
+      print('Adding config line: -dontoptimize')
+      f.write('-dontoptimize\n')
+    if shrink == 'force-disable':
+      print('Adding config line: -dontshrink')
+      f.write('-dontshrink\n')
     for line in lines:
-      if ('-injars' not in line and '-libraryjars' not in line and
-          '-print' not in line):
-        f.write(line)
-      else:
+      if clean_config_line(line, minify, optimize, shrink):
         print('Removing from config line: \n%s' % line)
+      else:
+        f.write(line)
 
+def clean_config_line(line, minify, optimize, shrink):
+  if ('-injars' in line or '-libraryjars' in line or
+      '-print' in line):
+    return True
+  if minify == 'force-enable' and '-dontobfuscate' in line:
+    return True
+  if optimize == 'force-enable' and '-dontoptimize' in line:
+    return True
+  if shrink == 'force-enable' and '-dontshrink' in line:
+    return True
+  return False
 
 def prepare_wrapper(dist, temp, jdkhome):
   wrapper_file = os.path.join(
@@ -376,7 +416,7 @@
       else:
         # If we get a dump from the wild we can't use -injars, -libraryjars or
         # -print{mapping,usage}
-        clean_config(dump.config_file())
+        clean_config(dump.config_file(), args)
       cmd.extend(['--pg-conf', dump.config_file()])
     if dump.main_dex_rules_resource():
       cmd.extend(['--main-dex-rules', dump.main_dex_rules_resource()])
diff --git a/tools/run_on_app_dump.py b/tools/run_on_app_dump.py
index 6c25a4d..750a877 100755
--- a/tools/run_on_app_dump.py
+++ b/tools/run_on_app_dump.py
@@ -553,10 +553,13 @@
     shrinker))
   print('To compile locally: '
         'tools/run_on_app_dump.py --shrinker {} --r8-compilation-steps {} '
-        '--app {}'.format(
+        '--app {} --minify {} --optimize {} --shrink {}'.format(
     shrinker,
     options.r8_compilation_steps,
-    app.name))
+    app.name,
+    options.minify,
+    options.optimize,
+    options.shrink))
   print('HINT: use --shrinker r8-nolib --no-build if you have a local R8.jar')
   recomp_jar = None
   status = 'success'
@@ -652,6 +655,9 @@
 def build_app_with_shrinker(app, options, temp_dir, app_dir, shrinker,
                             compilation_step_index, compilation_steps,
                             prev_recomp_jar):
+  def config_file_consumer(file):
+    compiledump.clean_config(file, options)
+    remove_print_lines(file)
   args = AttrDict({
     'dump': dump_for_app(app_dir, app),
     'r8_jar': get_r8_jar(options, temp_dir, shrinker),
@@ -662,7 +668,7 @@
     'debug_agent': options.debug_agent,
     'program_jar': prev_recomp_jar,
     'nolib': not is_minified_r8(shrinker),
-    'config_file_consumer': remove_print_lines,
+    'config_file_consumer': config_file_consumer,
     'properties': app.compiler_properties,
     'disable_desugared_lib': False,
     'print_times': options.print_times,
@@ -704,6 +710,7 @@
                              compilation_step_index, mapping):
 
   def rewrite_file(file):
+    compiledump.clean_config(file, options)
     remove_print_lines(file)
     with open(file) as f:
       lines = f.readlines()
@@ -723,7 +730,7 @@
     'nolib': not is_minified_r8(shrinker),
     # The config file will have an -applymapping reference to an old map.
     # Update it to point to mapping file build in the compilation of the app.
-    'config_file_consumer': rewrite_file
+    'config_file_consumer': rewrite_file,
   })
 
   test_jar = os.path.join(
@@ -894,6 +901,11 @@
   result.add_argument('--keystore-password', '--keystore_password',
                       help='Password for app.keystore',
                       default='android')
+  result.add_argument('--minify',
+                      help='Force enable/disable minification' +
+                           ' (defaults to app proguard config)',
+                      choices=['default', 'force-enable', 'force-disable'],
+                      default='default')
   result.add_argument('--monkey',
                       help='Whether to install and run app(s) with monkey',
                       default=False,
@@ -910,6 +922,11 @@
                       help='Disable logging except for errors',
                       default=False,
                       action='store_true')
+  result.add_argument('--optimize',
+                      help='Force enable/disable optimizations' +
+                           ' (defaults to app proguard config)',
+                      choices=['default', 'force-enable', 'force-disable'],
+                      default='default')
   result.add_argument('--print-times',
                       help='Print timing information from r8',
                       default=False,
@@ -938,6 +955,11 @@
                       help='Whether to run instrumentation tests',
                       default=False,
                       action='store_true')
+  result.add_argument('--shrink',
+                      help='Force enable/disable shrinking' +
+                           ' (defaults to app proguard config)',
+                      choices=['default', 'force-enable', 'force-disable'],
+                      default='default')
   result.add_argument('--sign-apks', '--sign_apks',
                       help='Whether the APKs should be signed',
                       default=False,
@@ -1016,6 +1038,8 @@
   print('')
   print('createOpenSourceAppBenchmarks() {')
   print_indented('final cpus = ["Lenovo M90"];', 2)
+  print_indented('final targetsCompat = ["R8"];', 2)
+  print_indented('final targetsFull = ["R8-full-minify-optimize-shrink"];', 2)
   # Avoid calculating this for every app
   jdk_gz = jdk.GetJdkHome() + '.tar.gz'
   download_sha(jdk_gz + '.sha1', False, quiet=True)
@@ -1031,27 +1055,45 @@
       print_indented(
           'new StandardBenchmark(name, [Metric.RunTimeRaw, Metric.CodeSize]);',
           indentation + 4)
-      print_indented(
-          'final options = benchmark.addTargets(noImplementation, ["R8"]);',
-          indentation)
-      print_indented('options.cpus = cpus;', indentation)
-      print_indented('options.isScript = true;', indentation)
-      print_indented('options.fromRevision = 9700;', indentation);
-      print_indented('options.mainFile = "tools/run_on_app_dump.py "',
-                     indentation)
-      print_indented('"--golem --quiet --shrinker r8 --app %s";' % app.name,
-                     indentation + 4)
-
       app_gz = os.path.join(utils.OPENSOURCE_DUMPS_DIR, app.folder + '.tar.gz')
       name = 'appResource'
       add_golem_resource(indentation, app_gz, name)
-      print_indented('options.resources.add(appResource);', indentation)
-      print_indented('options.resources.add(openjdk);', indentation)
+      print_golem_config_target('Compat', 'r8', app, indentation)
+      print_golem_config_target(
+        'Full',
+        'r8-full',
+        app,
+        indentation,
+        minify='force-enable',
+        optimize='force-enable',
+        shrink='force-enable')
       print_indented('dumpsSuite.addBenchmark(name);', indentation)
       indentation = 2
       print_indented('}', indentation)
   print('}')
 
+def print_golem_config_target(
+    target, shrinker, app, indentation,
+    minify='default', optimize='default', shrink='default'):
+  options="options" + target
+  print_indented(
+      'final %s = benchmark.addTargets(noImplementation, targets%s);'
+        % (options, target),
+      indentation)
+  print_indented('%s.cpus = cpus;' % options, indentation)
+  print_indented('%s.isScript = true;' % options, indentation)
+  print_indented('%s.fromRevision = 9700;' % options, indentation);
+  print_indented('%s.mainFile = "tools/run_on_app_dump.py "' % options,
+                 indentation)
+  print_indented('"--golem --quiet --shrinker %s --app %s "'
+                   % (shrinker, app.name),
+                 indentation + 4)
+  print_indented('"--minify %s --optimize %s --shrink %s";'
+                   % (minify, optimize, shrink),
+                 indentation + 4)
+  print_indented('%s.resources.add(appResource);' % options, indentation)
+  print_indented('%s.resources.add(openjdk);' % options, indentation)
+
 def add_golem_resource(indentation, gz, name, sha256=None):
   sha = gz + '.sha1'
   if not sha256: