Merge commit '0f8d71d13180a0b634967f2c48d4f801e3913b36' into dev-release
diff --git a/build.gradle b/build.gradle
index e614057..9f4cf29 100644
--- a/build.gradle
+++ b/build.gradle
@@ -2238,6 +2238,9 @@
         systemProperty 'slow_tests', project.property('slow_tests')
     }
 
+    if (project.hasProperty('force_32_bit_art')) {
+        systemProperty 'force_32_bit_art', project.property('force_32_bit_art')
+    }
 
     if (project.hasProperty('desugar_jdk_json_dir')) {
         systemProperty 'desugar_jdk_json_dir', project.property('desugar_jdk_json_dir')
diff --git a/infra/config/global/generated/cr-buildbucket.cfg b/infra/config/global/generated/cr-buildbucket.cfg
index 49e39c7..f461b56 100644
--- a/infra/config/global/generated/cr-buildbucket.cfg
+++ b/infra/config/global/generated/cr-buildbucket.cfg
@@ -24,7 +24,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -53,7 +53,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -82,7 +82,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -118,7 +118,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -156,7 +156,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -190,7 +190,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -222,7 +222,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -255,7 +255,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -292,7 +292,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -329,7 +329,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -366,7 +366,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -403,7 +403,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -440,7 +440,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -477,7 +477,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -514,7 +514,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -551,7 +551,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -588,7 +588,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -625,7 +625,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -662,7 +662,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -699,7 +699,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -736,7 +736,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -773,7 +773,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -810,7 +810,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -847,7 +847,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -861,6 +861,7 @@
         '  "test_options": ['
         '    "--dex_vm=7.0.0",'
         '    "--all_tests",'
+        '    "--force-32-bit-art",'
         '    "--tool=r8",'
         '    "--no_internal",'
         '    "--one_line_per_test",'
@@ -884,7 +885,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -898,6 +899,7 @@
         '  "test_options": ['
         '    "--dex_vm=7.0.0",'
         '    "--all_tests",'
+        '    "--force-32-bit-art",'
         '    "--tool=r8",'
         '    "--no_internal",'
         '    "--one_line_per_test",'
@@ -921,7 +923,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -958,7 +960,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -995,7 +997,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -1032,7 +1034,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -1069,7 +1071,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -1105,7 +1107,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -1141,7 +1143,7 @@
       dimensions: "cores:2"
       dimensions: "cpu:x86-64"
       dimensions: "internal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -1174,7 +1176,7 @@
       dimensions: "cores:2"
       dimensions: "cpu:x86-64"
       dimensions: "internal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -1207,7 +1209,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -1243,7 +1245,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -1279,7 +1281,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -1315,7 +1317,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -1351,7 +1353,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -1387,7 +1389,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -1423,7 +1425,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -1459,7 +1461,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -1494,7 +1496,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -1531,7 +1533,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -1569,7 +1571,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -1605,7 +1607,7 @@
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "normal:true"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -1640,7 +1642,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
@@ -1672,7 +1674,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-22.04"
+      dimensions: "os:Ubuntu-20.04"
       dimensions: "pool:luci.r8.ci"
       exe {
         cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
diff --git a/infra/config/global/main.star b/infra/config/global/main.star
index 9fb3733..40ea46a 100755
--- a/infra/config/global/main.star
+++ b/infra/config/global/main.star
@@ -178,7 +178,7 @@
   if windows:
     dimensions["os"] = "Windows-10"
   else:
-    dimensions["os"] = "Ubuntu-22.04"
+    dimensions["os"] = "Ubuntu-20.04"
   if internal:
     dimensions["internal"] = "true"
   if normal:
@@ -302,7 +302,7 @@
 r8_tester_with_default("linux-android-6.0.1",
     ["--dex_vm=6.0.1", "--all_tests"])
 r8_tester_with_default("linux-android-7.0.0",
-    ["--dex_vm=7.0.0", "--all_tests"])
+    ["--dex_vm=7.0.0", "--all_tests", "--force-32-bit-art"])
 r8_tester_with_default("linux-android-8.1.0",
     ["--dex_vm=8.1.0", "--all_tests"])
 r8_tester_with_default("linux-android-9.0.0",
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index abf8844..2af2e26 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -10,7 +10,6 @@
 import com.android.tools.r8.dex.ApplicationReader;
 import com.android.tools.r8.dex.ApplicationWriter;
 import com.android.tools.r8.dex.Marker;
-import com.android.tools.r8.experimental.startup.instrumentation.StartupInstrumentation;
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.AppServices;
 import com.android.tools.r8.graph.AppView;
@@ -37,6 +36,7 @@
 import com.android.tools.r8.naming.signature.GenericSignatureRewriter;
 import com.android.tools.r8.origin.CommandLineOrigin;
 import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.profile.startup.instrumentation.StartupInstrumentation;
 import com.android.tools.r8.shaking.AssumeInfoCollection;
 import com.android.tools.r8.shaking.MainDexInfo;
 import com.android.tools.r8.synthesis.SyntheticFinalization;
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index 49f8155..ff649f7 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -291,8 +291,6 @@
      *
      * <p>NOTE: Startup profiles are ignored when compiling to class files or the min-API level does
      * not support native multidex (API<=20).
-     *
-     * <p>NOTE: This API is experimental and may be subject to changes.
      */
     @Override
     public Builder addStartupProfileProviders(StartupProfileProvider... startupProfileProviders) {
@@ -305,8 +303,6 @@
      *
      * <p>NOTE: Startup profiles are ignored when compiling to class files or the min-API level does
      * not support native multidex (API<=20).
-     *
-     * <p>NOTE: This API is experimental and may be subject to changes.
      */
     @Override
     public Builder addStartupProfileProviders(
diff --git a/src/main/java/com/android/tools/r8/D8CommandParser.java b/src/main/java/com/android/tools/r8/D8CommandParser.java
index 444f522..4cf6711 100644
--- a/src/main/java/com/android/tools/r8/D8CommandParser.java
+++ b/src/main/java/com/android/tools/r8/D8CommandParser.java
@@ -5,11 +5,11 @@
 
 import static com.android.tools.r8.ParseFlagInfoImpl.flag1;
 
-import com.android.tools.r8.experimental.startup.StartupProfileProviderUtils;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.origin.PathOrigin;
 import com.android.tools.r8.profile.art.ArtProfileConsumerUtils;
 import com.android.tools.r8.profile.art.ArtProfileProviderUtils;
+import com.android.tools.r8.profile.startup.StartupProfileProviderUtils;
 import com.android.tools.r8.utils.ExceptionDiagnostic;
 import com.android.tools.r8.utils.FlagFile;
 import com.android.tools.r8.utils.StringDiagnostic;
diff --git a/src/main/java/com/android/tools/r8/GenerateMainDexList.java b/src/main/java/com/android/tools/r8/GenerateMainDexList.java
index 14677cc..1e0f9c9 100644
--- a/src/main/java/com/android/tools/r8/GenerateMainDexList.java
+++ b/src/main/java/com/android/tools/r8/GenerateMainDexList.java
@@ -15,7 +15,7 @@
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.SubtypingInfo;
-import com.android.tools.r8.profile.art.rewriting.ProfileCollectionAdditions;
+import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
 import com.android.tools.r8.shaking.Enqueuer;
 import com.android.tools.r8.shaking.EnqueuerFactory;
 import com.android.tools.r8.shaking.MainDexInfo;
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 2ff0966..79d8121 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -17,7 +17,6 @@
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppServices;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.AppliedGraphLens;
 import com.android.tools.r8.graph.Code;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexEncodedMethod;
@@ -28,7 +27,6 @@
 import com.android.tools.r8.graph.DirectMappedDexApplication;
 import com.android.tools.r8.graph.GenericSignatureContextBuilder;
 import com.android.tools.r8.graph.GenericSignatureCorrectnessHelper;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.PrunedItems;
@@ -36,6 +34,8 @@
 import com.android.tools.r8.graph.analysis.ClassInitializerAssertionEnablingAnalysis;
 import com.android.tools.r8.graph.analysis.InitializedClassesInInstanceMethodsAnalysis;
 import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
+import com.android.tools.r8.graph.lens.AppliedGraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.horizontalclassmerging.HorizontalClassMerger;
 import com.android.tools.r8.inspector.internal.InspectorImpl;
 import com.android.tools.r8.ir.conversion.IRConverter;
@@ -73,7 +73,7 @@
 import com.android.tools.r8.optimize.redundantbridgeremoval.RedundantBridgeRemover;
 import com.android.tools.r8.origin.CommandLineOrigin;
 import com.android.tools.r8.profile.art.ArtProfileCompletenessChecker;
-import com.android.tools.r8.profile.art.rewriting.ProfileCollectionAdditions;
+import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
 import com.android.tools.r8.repackaging.Repackaging;
 import com.android.tools.r8.repackaging.RepackagingLens;
 import com.android.tools.r8.shaking.AbstractMethodRemover;
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 6003038..f4a984e 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -484,8 +484,6 @@
      *
      * <p>NOTE: Startup profiles are ignored when compiling to class files or the min-API level does
      * not support native multidex (API<=20).
-     *
-     * <p>NOTE: This API is experimental and may be subject to changes.
      */
     @Override
     public Builder addStartupProfileProviders(StartupProfileProvider... startupProfileProviders) {
@@ -499,8 +497,6 @@
      *
      * <p>NOTE: Startup profiles are ignored when compiling to class files or the min-API level does
      * not support native multidex (API<=20).
-     *
-     * <p>NOTE: This API is experimental and may be subject to changes.
      */
     @Override
     public Builder addStartupProfileProviders(
@@ -1298,20 +1294,20 @@
         return true;
       }
       // Expect one of the following patterns:
-      //   com.android.tools/r8-min-1.5.0/
-      //   com.android.tools/r8-max-1.5.99/
-      //   com.android.tools/r8-min-1.5.0-max-1.5.99/
-      final String minPrefix = "-min-";
-      final String maxPrefix = "-max-";
-      if (!withoutPrefix.startsWith(minPrefix) && !withoutPrefix.startsWith(maxPrefix)) {
+      //   com.android.tools/r8-from-1.5.0/
+      //   com.android.tools/r8-upto-1.6.0/
+      //   com.android.tools/r8-from-1.5.0-upto-1.6.0/
+      final String fromPrefix = "-from-";
+      final String uptoPrefix = "-upto-";
+      if (!withoutPrefix.startsWith(fromPrefix) && !withoutPrefix.startsWith(uptoPrefix)) {
         return false;
       }
 
       SemanticVersion from = SemanticVersion.min();
-      SemanticVersion to = SemanticVersion.max();
+      SemanticVersion upto = null;
 
-      if (withoutPrefix.startsWith(minPrefix)) {
-        withoutPrefix = withoutPrefix.substring(minPrefix.length());
+      if (withoutPrefix.startsWith(fromPrefix)) {
+        withoutPrefix = withoutPrefix.substring(fromPrefix.length());
         int versionEnd = StringUtils.indexOf(withoutPrefix, '-', '/');
         if (versionEnd == -1) {
           return false;
@@ -1323,14 +1319,14 @@
         }
         withoutPrefix = withoutPrefix.substring(versionEnd);
       }
-      if (withoutPrefix.startsWith(maxPrefix)) {
-        withoutPrefix = withoutPrefix.substring(maxPrefix.length());
+      if (withoutPrefix.startsWith(uptoPrefix)) {
+        withoutPrefix = withoutPrefix.substring(uptoPrefix.length());
         int versionEnd = withoutPrefix.indexOf('/');
         if (versionEnd == -1) {
           return false;
         }
         try {
-          to = SemanticVersion.parse(withoutPrefix.substring(0, versionEnd));
+          upto = SemanticVersion.parse(withoutPrefix.substring(0, versionEnd));
         } catch (IllegalArgumentException e) {
           return false;
         }
@@ -1338,7 +1334,8 @@
       if (compilerVersion == null) {
         compilerVersion = compilerVersionSupplier.get();
       }
-      return compilerVersion.isNewerOrEqual(from) && to.isNewerOrEqual(compilerVersion);
+      return compilerVersion.isNewerOrEqual(from)
+          && (upto == null || upto.isNewer(compilerVersion));
     }
 
     private void parse(
diff --git a/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubberEventConsumer.java b/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubberEventConsumer.java
index 47b5efb..b37673b 100644
--- a/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubberEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubberEventConsumer.java
@@ -7,7 +7,7 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexLibraryClass;
 import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.profile.art.rewriting.ProfileRewritingApiReferenceStubberEventConsumer;
+import com.android.tools.r8.profile.rewriting.ProfileRewritingApiReferenceStubberEventConsumer;
 
 public interface ApiReferenceStubberEventConsumer {
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java b/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
index 398da41..460a7d7 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
@@ -9,9 +9,9 @@
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
index a78ca40..0c25941 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
@@ -8,9 +8,9 @@
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
 import com.android.tools.r8.ir.conversion.CfState.Slot;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
index bbffacb..cd21707 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
@@ -9,9 +9,9 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.code.MemberType;
 import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
index 41f6774..aee2e6f 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
@@ -8,9 +8,9 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.code.MemberType;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java b/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
index bec1872..f450da4 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
@@ -10,10 +10,10 @@
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
 import com.android.tools.r8.ir.conversion.CfState.Slot;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfCmp.java b/src/main/java/com/android/tools/r8/cf/code/CfCmp.java
index 6c1eea5..5b35a3e 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfCmp.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfCmp.java
@@ -9,9 +9,9 @@
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.code.Cmp;
 import com.android.tools.r8.ir.code.Cmp.Bias;
 import com.android.tools.r8.ir.code.NumericType;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java b/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
index 6ade9b2..bc226cb 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
@@ -11,10 +11,10 @@
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
 import com.android.tools.r8.ir.conversion.IRBuilder;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstDynamic.java b/src/main/java/com/android/tools/r8/cf/code/CfConstDynamic.java
index 9b9b2b1..9f3f073 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstDynamic.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstDynamic.java
@@ -18,11 +18,11 @@
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.DexValue;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.JarApplicationReader;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
 import com.android.tools.r8.ir.conversion.IRBuilder;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
index ca13ef3..e02b1fe 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
@@ -10,11 +10,11 @@
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethodHandle;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.graph.UseRegistry.MethodHandleUse;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
 import com.android.tools.r8.ir.conversion.IRBuilder;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
index 2c8a35f..7e8d519 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
@@ -10,10 +10,10 @@
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProto;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
 import com.android.tools.r8.ir.conversion.IRBuilder;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java b/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java
index a77dc2c..75eb939 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java
@@ -8,9 +8,9 @@
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java b/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
index cf6d035..21dbd68 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
@@ -9,9 +9,9 @@
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstString.java b/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
index 46f1c0c..9756641 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
@@ -9,9 +9,9 @@
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
 import com.android.tools.r8.ir.conversion.IRBuilder;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java b/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
index abc1113..9bf20e3 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
@@ -11,10 +11,10 @@
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexReference;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
 import com.android.tools.r8.ir.conversion.IRBuilder;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
index 1709270..39e66b1 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
@@ -10,9 +10,9 @@
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFrame.java b/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
index eab78b9..ed3970c 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
@@ -15,10 +15,10 @@
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
 import com.android.tools.r8.ir.conversion.IRBuilder;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFrameVerifier.java b/src/main/java/com/android/tools/r8/cf/code/CfFrameVerifier.java
index 58e9d2a..d56f09a 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfFrameVerifier.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfFrameVerifier.java
@@ -17,8 +17,8 @@
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.optimize.interfaces.analysis.ConcreteCfFrameState;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfGoto.java b/src/main/java/com/android/tools/r8/cf/code/CfGoto.java
index 7df905c..48fe920 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfGoto.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfGoto.java
@@ -8,9 +8,9 @@
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
 import com.android.tools.r8.ir.conversion.IRBuilder;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIf.java b/src/main/java/com/android/tools/r8/cf/code/CfIf.java
index a12fd3ed..25dfd77 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfIf.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfIf.java
@@ -8,9 +8,9 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.code.IfType;
 import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java b/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java
index 510975f..ee9ece8 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java
@@ -8,9 +8,9 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.code.IfType;
 import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIinc.java b/src/main/java/com/android/tools/r8/cf/code/CfIinc.java
index 570a842..063f778 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfIinc.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfIinc.java
@@ -8,9 +8,9 @@
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java b/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
index 7a54a7b..440f799f 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
@@ -11,10 +11,10 @@
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
 import com.android.tools.r8.ir.conversion.IRBuilder;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java b/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
index 4feb794..9a0308e 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
@@ -10,10 +10,10 @@
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
 import com.android.tools.r8.ir.conversion.IRBuilder;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
index 5fbed91..b13fbe8 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
@@ -13,10 +13,10 @@
 import com.android.tools.r8.graph.ClasspathMethod;
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
 import com.android.tools.r8.ir.conversion.IRBuilder;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
index d18bcc7..a0f3d5e 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
@@ -16,11 +16,11 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
+import com.android.tools.r8.graph.lens.MethodLookupResult;
 import com.android.tools.r8.ir.code.InvokeType;
 import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java b/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
index 121305c..c174214 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
@@ -15,10 +15,10 @@
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.DexValue;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java b/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
index db045cd..6abd7ae 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
@@ -9,9 +9,9 @@
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
 import com.android.tools.r8.ir.conversion.IRBuilder;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLabel.java b/src/main/java/com/android/tools/r8/cf/code/CfLabel.java
index 9121e85..0cb0665 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfLabel.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfLabel.java
@@ -8,9 +8,9 @@
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
 import com.android.tools.r8.ir.conversion.IRBuilder;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLoad.java b/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
index f18c47c..0479271 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
@@ -10,9 +10,9 @@
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java b/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java
index a8333d6..32afbc5 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java
@@ -9,9 +9,9 @@
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java b/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java
index c0c62d9..edfb91a 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java
@@ -8,9 +8,9 @@
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.code.MonitorType;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java b/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
index 1fdb693..344e65b 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
@@ -10,10 +10,10 @@
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
 import com.android.tools.r8.ir.conversion.IRBuilder;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNeg.java b/src/main/java/com/android/tools/r8/cf/code/CfNeg.java
index d6f9c18..d861c19 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNeg.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNeg.java
@@ -9,9 +9,9 @@
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNew.java b/src/main/java/com/android/tools/r8/cf/code/CfNew.java
index 4ec3b43..e6a51f8 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNew.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNew.java
@@ -11,10 +11,10 @@
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
 import com.android.tools.r8.ir.conversion.IRBuilder;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java b/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
index aa3d852..5c2a657 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
@@ -11,10 +11,10 @@
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
 import com.android.tools.r8.ir.conversion.CfState.Slot;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNewUnboxedEnum.java b/src/main/java/com/android/tools/r8/cf/code/CfNewUnboxedEnum.java
index e6b8170..5864372 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNewUnboxedEnum.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNewUnboxedEnum.java
@@ -11,10 +11,10 @@
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
 import com.android.tools.r8.ir.conversion.IRBuilder;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNop.java b/src/main/java/com/android/tools/r8/cf/code/CfNop.java
index f4b0527..139c2a7 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNop.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNop.java
@@ -8,9 +8,9 @@
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
 import com.android.tools.r8.ir.conversion.IRBuilder;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java b/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java
index a8a88b6..856cc36 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java
@@ -9,9 +9,9 @@
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfPosition.java b/src/main/java/com/android/tools/r8/cf/code/CfPosition.java
index ec74503..6a442c3 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfPosition.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfPosition.java
@@ -8,9 +8,9 @@
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.code.Position;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfRecordFieldValues.java b/src/main/java/com/android/tools/r8/cf/code/CfRecordFieldValues.java
index dd9c957..98c1e78 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfRecordFieldValues.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfRecordFieldValues.java
@@ -11,9 +11,9 @@
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
 import com.android.tools.r8.ir.conversion.CfState.Slot;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfReturn.java b/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
index ee0f453..bddd05e 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
@@ -9,9 +9,9 @@
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java b/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java
index 497ad00..0a96d17 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java
@@ -8,9 +8,9 @@
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
 import com.android.tools.r8.ir.conversion.IRBuilder;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java
index 2746906..e3b70f6 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java
@@ -10,9 +10,9 @@
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStore.java b/src/main/java/com/android/tools/r8/cf/code/CfStore.java
index 3ff52f9..279014d 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStore.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStore.java
@@ -9,9 +9,9 @@
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java b/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java
index 2492110..f54eaa1 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java
@@ -9,9 +9,9 @@
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
 import com.android.tools.r8.ir.conversion.CfState.Slot;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfThrow.java b/src/main/java/com/android/tools/r8/cf/code/CfThrow.java
index 7333669..4bdf343 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfThrow.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfThrow.java
@@ -8,9 +8,9 @@
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.conversion.CfSourceCode;
 import com.android.tools.r8.ir.conversion.CfState;
 import com.android.tools.r8.ir.conversion.CfState.Slot;
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/BooleanFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/BooleanFrameType.java
index faca255..b0ec955 100644
--- a/src/main/java/com/android/tools/r8/cf/code/frame/BooleanFrameType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/BooleanFrameType.java
@@ -7,7 +7,7 @@
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.naming.NamingLens;
 
 public class BooleanFrameType extends SinglePrimitiveFrameType {
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/ByteFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/ByteFrameType.java
index c55f98f..e6aa4da 100644
--- a/src/main/java/com/android/tools/r8/cf/code/frame/ByteFrameType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/ByteFrameType.java
@@ -7,7 +7,7 @@
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.naming.NamingLens;
 
 public class ByteFrameType extends SinglePrimitiveFrameType {
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/CharFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/CharFrameType.java
index 99fadc1..8dc437d 100644
--- a/src/main/java/com/android/tools/r8/cf/code/frame/CharFrameType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/CharFrameType.java
@@ -7,7 +7,7 @@
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.naming.NamingLens;
 
 public class CharFrameType extends SinglePrimitiveFrameType {
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/DoubleFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/DoubleFrameType.java
index 41ee1b5..7ad8dc2 100644
--- a/src/main/java/com/android/tools/r8/cf/code/frame/DoubleFrameType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/DoubleFrameType.java
@@ -6,7 +6,7 @@
 
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.naming.NamingLens;
 import org.objectweb.asm.Opcodes;
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/DoubleHighFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/DoubleHighFrameType.java
index 7c89492..655fa52 100644
--- a/src/main/java/com/android/tools/r8/cf/code/frame/DoubleHighFrameType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/DoubleHighFrameType.java
@@ -7,7 +7,7 @@
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.naming.NamingLens;
 
 public class DoubleHighFrameType extends DoubleFrameType {
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/FloatFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/FloatFrameType.java
index 6789e2e..9cc991a 100644
--- a/src/main/java/com/android/tools/r8/cf/code/frame/FloatFrameType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/FloatFrameType.java
@@ -6,7 +6,7 @@
 
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.naming.NamingLens;
 import org.objectweb.asm.Opcodes;
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/FrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/FrameType.java
index bf16f11..9db9a68 100644
--- a/src/main/java/com/android/tools/r8/cf/code/frame/FrameType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/FrameType.java
@@ -8,7 +8,7 @@
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.analysis.type.PrimitiveTypeElement;
 import com.android.tools.r8.ir.analysis.type.ReferenceTypeElement;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/InitializedNonNullReferenceFrameTypeWithInterfaces.java b/src/main/java/com/android/tools/r8/cf/code/frame/InitializedNonNullReferenceFrameTypeWithInterfaces.java
index d1187c0..25e8a13 100644
--- a/src/main/java/com/android/tools/r8/cf/code/frame/InitializedNonNullReferenceFrameTypeWithInterfaces.java
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/InitializedNonNullReferenceFrameTypeWithInterfaces.java
@@ -9,7 +9,7 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.analysis.type.ReferenceTypeElement;
 import com.android.tools.r8.naming.NamingLens;
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/InitializedNonNullReferenceFrameTypeWithoutInterfaces.java b/src/main/java/com/android/tools/r8/cf/code/frame/InitializedNonNullReferenceFrameTypeWithoutInterfaces.java
index 88beb14..d25fb70 100644
--- a/src/main/java/com/android/tools/r8/cf/code/frame/InitializedNonNullReferenceFrameTypeWithoutInterfaces.java
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/InitializedNonNullReferenceFrameTypeWithoutInterfaces.java
@@ -9,7 +9,7 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.analysis.type.ReferenceTypeElement;
 import com.android.tools.r8.naming.NamingLens;
 import org.objectweb.asm.Opcodes;
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/IntFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/IntFrameType.java
index 23fd119..0f802b4 100644
--- a/src/main/java/com/android/tools/r8/cf/code/frame/IntFrameType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/IntFrameType.java
@@ -6,7 +6,7 @@
 
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.naming.NamingLens;
 import org.objectweb.asm.Opcodes;
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/LongFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/LongFrameType.java
index 507c164..a73ab16 100644
--- a/src/main/java/com/android/tools/r8/cf/code/frame/LongFrameType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/LongFrameType.java
@@ -6,7 +6,7 @@
 
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.naming.NamingLens;
 import org.objectweb.asm.Opcodes;
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/LongHighFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/LongHighFrameType.java
index fadcd79..f2c5c9a 100644
--- a/src/main/java/com/android/tools/r8/cf/code/frame/LongHighFrameType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/LongHighFrameType.java
@@ -7,7 +7,7 @@
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.naming.NamingLens;
 
 public class LongHighFrameType extends LongFrameType {
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/NullFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/NullFrameType.java
index a5e26c8..be3fa37 100644
--- a/src/main/java/com/android/tools/r8/cf/code/frame/NullFrameType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/NullFrameType.java
@@ -8,7 +8,7 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.naming.NamingLens;
 import org.objectweb.asm.Opcodes;
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/OneWord.java b/src/main/java/com/android/tools/r8/cf/code/frame/OneWord.java
index 06add68..3153ef8 100644
--- a/src/main/java/com/android/tools/r8/cf/code/frame/OneWord.java
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/OneWord.java
@@ -6,7 +6,7 @@
 
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.naming.NamingLens;
 import org.objectweb.asm.Opcodes;
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/ShortFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/ShortFrameType.java
index 0b64a52..82f0279 100644
--- a/src/main/java/com/android/tools/r8/cf/code/frame/ShortFrameType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/ShortFrameType.java
@@ -7,7 +7,7 @@
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.naming.NamingLens;
 
 public class ShortFrameType extends SinglePrimitiveFrameType {
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/TwoWord.java b/src/main/java/com/android/tools/r8/cf/code/frame/TwoWord.java
index 23a4ca1..95cab6f 100644
--- a/src/main/java/com/android/tools/r8/cf/code/frame/TwoWord.java
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/TwoWord.java
@@ -5,7 +5,7 @@
 package com.android.tools.r8.cf.code.frame;
 
 import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.naming.NamingLens;
 
 public class TwoWord extends SingletonFrameType implements WideFrameType {
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/UninitializedNew.java b/src/main/java/com/android/tools/r8/cf/code/frame/UninitializedNew.java
index 0d45c04..5fe76fe 100644
--- a/src/main/java/com/android/tools/r8/cf/code/frame/UninitializedNew.java
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/UninitializedNew.java
@@ -9,7 +9,7 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.naming.NamingLens;
 import java.util.Objects;
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/UninitializedThis.java b/src/main/java/com/android/tools/r8/cf/code/frame/UninitializedThis.java
index 21036e4..a1654ab 100644
--- a/src/main/java/com/android/tools/r8/cf/code/frame/UninitializedThis.java
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/UninitializedThis.java
@@ -8,7 +8,7 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.naming.NamingLens;
 import org.objectweb.asm.Opcodes;
 
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 08b14b8..a664d9d 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -24,8 +24,6 @@
 import com.android.tools.r8.dex.VirtualFile.FilePerInputClassDistributor;
 import com.android.tools.r8.dex.VirtualFile.ItemUseInfo;
 import com.android.tools.r8.errors.CompilationError;
-import com.android.tools.r8.experimental.startup.StartupCompleteness;
-import com.android.tools.r8.experimental.startup.StartupProfile;
 import com.android.tools.r8.features.FeatureSplitConfiguration.DataResourceProvidersAndConsumer;
 import com.android.tools.r8.graph.AppServices;
 import com.android.tools.r8.graph.AppView;
@@ -53,6 +51,8 @@
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.naming.ProguardMapSupplier.ProguardMapId;
 import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.profile.startup.StartupCompleteness;
+import com.android.tools.r8.profile.startup.profile.StartupProfile;
 import com.android.tools.r8.shaking.MainDexInfo;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.ArrayUtils;
@@ -773,7 +773,8 @@
     if (enclosingMethod == null
         && innerClasses.isEmpty()
         && clazz.getClassSignature().hasNoSignature()
-        && !clazz.isInANest()) {
+        && !clazz.isInANest()
+        && !clazz.isRecord()) {
       return;
     }
 
@@ -853,6 +854,10 @@
               clazz.getPermittedSubclassAttributes(), options.itemFactory));
     }
 
+    if (clazz.isRecord() && options.canUseRecords()) {
+      annotations.add(DexAnnotation.createRecordAnnotation(clazz, appView));
+    }
+
     if (!annotations.isEmpty()) {
       // Append the annotations to annotations array of the class.
       DexAnnotation[] copy =
@@ -868,6 +873,7 @@
     clazz.clearInnerClasses();
     clazz.clearClassSignature();
     clazz.clearPermittedSubclasses();
+    clazz.clearRecordComponents();
   }
 
   private void insertAttributeAnnotationsForField(DexEncodedField field) {
diff --git a/src/main/java/com/android/tools/r8/dex/DebugBytecodeWriter.java b/src/main/java/com/android/tools/r8/dex/DebugBytecodeWriter.java
index 5a6a377..e314417 100644
--- a/src/main/java/com/android/tools/r8/dex/DebugBytecodeWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/DebugBytecodeWriter.java
@@ -6,8 +6,8 @@
 import com.android.tools.r8.graph.DexDebugInfoForWriting;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.utils.LebUtils;
 import java.nio.ByteBuffer;
 import java.util.Arrays;
diff --git a/src/main/java/com/android/tools/r8/dex/DexParser.java b/src/main/java/com/android/tools/r8/dex/DexParser.java
index 263acfc..2055d69 100644
--- a/src/main/java/com/android/tools/r8/dex/DexParser.java
+++ b/src/main/java/com/android/tools/r8/dex/DexParser.java
@@ -67,6 +67,7 @@
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.ParameterAnnotationsList;
 import com.android.tools.r8.graph.PermittedSubclassAttribute;
+import com.android.tools.r8.graph.RecordComponentInfo;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.origin.PathOrigin;
 import com.android.tools.r8.utils.InternalOptions;
@@ -898,6 +899,7 @@
               attrs.nestHostAttribute,
               attrs.nestMembersAttribute,
               attrs.permittedSubclassesAttribute,
+              attrs.recordComponents,
               attrs.getEnclosingMethodAttribute(),
               attrs.getInnerClasses(),
               attrs.classSignature,
@@ -1464,6 +1466,7 @@
     private NestHostClassAttribute nestHostAttribute;
     private List<NestMemberClassAttribute> nestMembersAttribute = Collections.emptyList();
     private List<PermittedSubclassAttribute> permittedSubclassesAttribute = Collections.emptyList();
+    private List<RecordComponentInfo> recordComponents = Collections.emptyList();
 
     public DexAnnotationSet getAnnotations() {
       if (lazyAnnotations != null) {
@@ -1545,6 +1548,13 @@
             permittedSubclassesAttribute =
                 ListUtils.map(permittedSubclasses, PermittedSubclassAttribute::new);
           }
+        } else if (DexAnnotation.isRecordAnnotation(annotation, factory)) {
+          ensureAnnotations(i);
+          List<RecordComponentInfo> recordComponents =
+              DexAnnotation.getRecordComponentInfoFromAnnotation(type, annotation, factory, origin);
+          if (recordComponents != null) {
+            this.recordComponents = recordComponents;
+          }
         } else {
           copyAnnotation(annotation);
         }
diff --git a/src/main/java/com/android/tools/r8/dex/FileWriter.java b/src/main/java/com/android/tools/r8/dex/FileWriter.java
index a6d4e84..25d19b0 100644
--- a/src/main/java/com/android/tools/r8/dex/FileWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/FileWriter.java
@@ -40,12 +40,12 @@
 import com.android.tools.r8.graph.DexTypeList;
 import com.android.tools.r8.graph.DexValue;
 import com.android.tools.r8.graph.DexWritableCode;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.IndexedDexItem;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ParameterAnnotationsList;
 import com.android.tools.r8.graph.ProgramClassVisitor;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.position.MethodPosition;
diff --git a/src/main/java/com/android/tools/r8/dex/MixedSectionLayoutStrategy.java b/src/main/java/com/android/tools/r8/dex/MixedSectionLayoutStrategy.java
index 60055c9..158b912 100644
--- a/src/main/java/com/android/tools/r8/dex/MixedSectionLayoutStrategy.java
+++ b/src/main/java/com/android/tools/r8/dex/MixedSectionLayoutStrategy.java
@@ -5,7 +5,6 @@
 package com.android.tools.r8.dex;
 
 import com.android.tools.r8.dex.FileWriter.MixedSectionOffsets;
-import com.android.tools.r8.experimental.startup.StartupProfile;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexAnnotation;
 import com.android.tools.r8.graph.DexAnnotationDirectory;
@@ -16,6 +15,7 @@
 import com.android.tools.r8.graph.DexTypeList;
 import com.android.tools.r8.graph.ParameterAnnotationsList;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.profile.startup.profile.StartupProfile;
 import java.util.Collection;
 
 public abstract class MixedSectionLayoutStrategy {
diff --git a/src/main/java/com/android/tools/r8/dex/ResourceAdapter.java b/src/main/java/com/android/tools/r8/dex/ResourceAdapter.java
index e249186..58f2b54 100644
--- a/src/main/java/com/android/tools/r8/dex/ResourceAdapter.java
+++ b/src/main/java/com/android/tools/r8/dex/ResourceAdapter.java
@@ -13,7 +13,7 @@
 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.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.shaking.ProguardConfiguration;
 import com.android.tools.r8.shaking.ProguardPathFilter;
diff --git a/src/main/java/com/android/tools/r8/dex/StartupMixedSectionLayoutStrategy.java b/src/main/java/com/android/tools/r8/dex/StartupMixedSectionLayoutStrategy.java
index c2ae2a1..b98df1c 100644
--- a/src/main/java/com/android/tools/r8/dex/StartupMixedSectionLayoutStrategy.java
+++ b/src/main/java/com/android/tools/r8/dex/StartupMixedSectionLayoutStrategy.java
@@ -5,9 +5,6 @@
 package com.android.tools.r8.dex;
 
 import com.android.tools.r8.dex.FileWriter.MixedSectionOffsets;
-import com.android.tools.r8.experimental.startup.StartupProfile;
-import com.android.tools.r8.experimental.startup.profile.StartupProfileClassRule;
-import com.android.tools.r8.experimental.startup.profile.StartupProfileMethodRule;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexAnnotation;
 import com.android.tools.r8.graph.DexAnnotationDirectory;
@@ -26,6 +23,9 @@
 import com.android.tools.r8.graph.ParameterAnnotationsList;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import com.android.tools.r8.profile.startup.profile.StartupProfile;
+import com.android.tools.r8.profile.startup.profile.StartupProfileClassRule;
+import com.android.tools.r8.profile.startup.profile.StartupProfileMethodRule;
 import com.android.tools.r8.utils.MapUtils;
 import com.android.tools.r8.utils.collections.LinkedProgramMethodSet;
 import com.android.tools.r8.utils.collections.ProgramMethodSet;
diff --git a/src/main/java/com/android/tools/r8/dex/VirtualFile.java b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
index d163330..63975c0 100644
--- a/src/main/java/com/android/tools/r8/dex/VirtualFile.java
+++ b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
@@ -9,7 +9,6 @@
 import com.android.tools.r8.debuginfo.DebugRepresentation;
 import com.android.tools.r8.errors.DexFileOverflowDiagnostic;
 import com.android.tools.r8.errors.InternalCompilerError;
-import com.android.tools.r8.experimental.startup.StartupProfile;
 import com.android.tools.r8.features.ClassToFeatureSplitMap;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
@@ -23,12 +22,13 @@
 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.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.profile.startup.profile.StartupProfile;
 import com.android.tools.r8.shaking.MainDexInfo;
 import com.android.tools.r8.synthesis.SyntheticNaming;
 import com.android.tools.r8.utils.DescriptorUtils;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexCheckCast.java b/src/main/java/com/android/tools/r8/dex/code/DexCheckCast.java
index 6d95477..224f94a 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexCheckCast.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexCheckCast.java
@@ -6,11 +6,11 @@
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexConstClass.java b/src/main/java/com/android/tools/r8/dex/code/DexConstClass.java
index 791eef5..b4a593e 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexConstClass.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexConstClass.java
@@ -6,11 +6,11 @@
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexConstMethodHandle.java b/src/main/java/com/android/tools/r8/dex/code/DexConstMethodHandle.java
index 7cf55ad..7aa77db 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexConstMethodHandle.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexConstMethodHandle.java
@@ -7,12 +7,12 @@
 import com.android.tools.r8.errors.InternalCompilerError;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethodHandle;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.graph.UseRegistry.MethodHandleUse;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.RetracerForCodePrinting;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexConstMethodType.java b/src/main/java/com/android/tools/r8/dex/code/DexConstMethodType.java
index a4e1941..485b3da 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexConstMethodType.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexConstMethodType.java
@@ -7,11 +7,11 @@
 import com.android.tools.r8.errors.InternalCompilerError;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexProto;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.RetracerForCodePrinting;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexConstString.java b/src/main/java/com/android/tools/r8/dex/code/DexConstString.java
index da79e38..b95b247 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexConstString.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexConstString.java
@@ -7,10 +7,10 @@
 import com.android.tools.r8.errors.InternalCompilerError;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.RetracerForCodePrinting;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFillArrayDataPayload.java b/src/main/java/com/android/tools/r8/dex/code/DexFillArrayDataPayload.java
index 62b99a3..ceaaa09 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFillArrayDataPayload.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFillArrayDataPayload.java
@@ -3,9 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.dex.code;
 
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.RetracerForCodePrinting;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFilledNewArray.java b/src/main/java/com/android/tools/r8/dex/code/DexFilledNewArray.java
index 08d174c..e9ff38e 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFilledNewArray.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFilledNewArray.java
@@ -6,10 +6,10 @@
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import java.nio.ShortBuffer;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFilledNewArrayRange.java b/src/main/java/com/android/tools/r8/dex/code/DexFilledNewArrayRange.java
index 5a7ab7d..436ec57 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFilledNewArrayRange.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFilledNewArrayRange.java
@@ -6,10 +6,10 @@
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import java.nio.ShortBuffer;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat10t.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat10t.java
index 1b1ad0c..eaee763 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat10t.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat10t.java
@@ -5,9 +5,9 @@
 
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.RetracerForCodePrinting;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat10x.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat10x.java
index ce80312..3071bfa 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat10x.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat10x.java
@@ -5,9 +5,9 @@
 
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.RetracerForCodePrinting;
 import java.nio.ShortBuffer;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat11n.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat11n.java
index 805512d..d18c307 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat11n.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat11n.java
@@ -6,9 +6,9 @@
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.RetracerForCodePrinting;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat11x.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat11x.java
index 7a5ada4..ef59bfb 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat11x.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat11x.java
@@ -6,9 +6,9 @@
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.RetracerForCodePrinting;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat12x.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat12x.java
index 711072d..05a6b22 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat12x.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat12x.java
@@ -6,9 +6,9 @@
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.RetracerForCodePrinting;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat20t.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat20t.java
index e226b0b..d398e0d 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat20t.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat20t.java
@@ -5,9 +5,9 @@
 
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.RetracerForCodePrinting;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat21h.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat21h.java
index 40d5684..5dfec30 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat21h.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat21h.java
@@ -6,9 +6,9 @@
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import com.android.tools.r8.utils.structural.HashingVisitor;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat21s.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat21s.java
index 2351a2c..8ccce8c 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat21s.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat21s.java
@@ -6,9 +6,9 @@
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.RetracerForCodePrinting;
 import com.android.tools.r8.utils.StringUtils;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat21t.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat21t.java
index fa27f2c..55eaac6 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat21t.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat21t.java
@@ -6,9 +6,9 @@
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.code.IfType;
 import com.android.tools.r8.ir.code.ValueTypeConstraint;
 import com.android.tools.r8.ir.conversion.IRBuilder;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat22b.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat22b.java
index f9c8419..d3bb2df 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat22b.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat22b.java
@@ -6,9 +6,9 @@
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.RetracerForCodePrinting;
 import com.android.tools.r8.utils.StringUtils;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat22s.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat22s.java
index 715f719..fc22957 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat22s.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat22s.java
@@ -6,9 +6,9 @@
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.RetracerForCodePrinting;
 import com.android.tools.r8.utils.StringUtils;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat22t.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat22t.java
index 37257b1..00b22c1 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat22t.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat22t.java
@@ -6,9 +6,9 @@
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.code.IfType;
 import com.android.tools.r8.ir.code.ValueTypeConstraint;
 import com.android.tools.r8.ir.conversion.IRBuilder;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat22x.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat22x.java
index 9d8f38c..0dedb95 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat22x.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat22x.java
@@ -6,9 +6,9 @@
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.RetracerForCodePrinting;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat23x.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat23x.java
index c6ee23e..bcadc94 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat23x.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat23x.java
@@ -6,9 +6,9 @@
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.RetracerForCodePrinting;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat30t.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat30t.java
index df14fb9..18c9137 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat30t.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat30t.java
@@ -5,9 +5,9 @@
 
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.RetracerForCodePrinting;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat31c.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat31c.java
index d5b1037..695779e 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat31c.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat31c.java
@@ -8,10 +8,10 @@
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.IndexedDexItem;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.RetracerForCodePrinting;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat31i.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat31i.java
index 67ae1b5..d2eed2d 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat31i.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat31i.java
@@ -6,9 +6,9 @@
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.RetracerForCodePrinting;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat31t.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat31t.java
index 07cea77..2e7de21 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat31t.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat31t.java
@@ -6,9 +6,9 @@
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.RetracerForCodePrinting;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat32x.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat32x.java
index 7cd9e2c..dd6f6bf 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat32x.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat32x.java
@@ -7,9 +7,9 @@
 
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.RetracerForCodePrinting;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat45cc.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat45cc.java
index 3a9dff4..0718573 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat45cc.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat45cc.java
@@ -9,10 +9,10 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProto;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.MethodLookupResult;
 import com.android.tools.r8.ir.code.InvokeType;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.RetracerForCodePrinting;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat4rcc.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat4rcc.java
index 7e887dc..e4ec21d 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat4rcc.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat4rcc.java
@@ -8,11 +8,11 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProto;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
 import com.android.tools.r8.graph.IndexedDexItem;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.MethodLookupResult;
 import com.android.tools.r8.ir.code.InvokeType;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.RetracerForCodePrinting;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat51l.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat51l.java
index 15cb63a..a135f5b 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat51l.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat51l.java
@@ -6,9 +6,9 @@
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.RetracerForCodePrinting;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexIgetOrIput.java b/src/main/java/com/android/tools/r8/dex/code/DexIgetOrIput.java
index 1f77b9f..8edfdf6 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexIgetOrIput.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIgetOrIput.java
@@ -6,9 +6,9 @@
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import java.nio.ShortBuffer;
 
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexInitClass.java b/src/main/java/com/android/tools/r8/dex/code/DexInitClass.java
index 77a2f9f..76a3289 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexInitClass.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexInitClass.java
@@ -9,10 +9,10 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.code.FieldMemberType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexInstanceOf.java b/src/main/java/com/android/tools/r8/dex/code/DexInstanceOf.java
index ba204cd..a85b4a3 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexInstanceOf.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexInstanceOf.java
@@ -6,11 +6,11 @@
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import java.nio.ShortBuffer;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexInstruction.java b/src/main/java/com/android/tools/r8/dex/code/DexInstruction.java
index 118556a..184b024 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexInstruction.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexInstruction.java
@@ -12,11 +12,11 @@
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProto;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.IndexedDexItem;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.RetracerForCodePrinting;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexInvokeCustom.java b/src/main/java/com/android/tools/r8/dex/code/DexInvokeCustom.java
index 28464af..21dd606 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexInvokeCustom.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexInvokeCustom.java
@@ -6,11 +6,11 @@
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexCallSite;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import java.nio.ShortBuffer;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexInvokeCustomRange.java b/src/main/java/com/android/tools/r8/dex/code/DexInvokeCustomRange.java
index 51f0908..3bc4796 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexInvokeCustomRange.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexInvokeCustomRange.java
@@ -6,11 +6,11 @@
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexCallSite;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import java.nio.ShortBuffer;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexInvokeMethod.java b/src/main/java/com/android/tools/r8/dex/code/DexInvokeMethod.java
index c59579b..763b823 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexInvokeMethod.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexInvokeMethod.java
@@ -6,10 +6,10 @@
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.MethodLookupResult;
 import com.android.tools.r8.ir.code.InvokeType;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import java.nio.ShortBuffer;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexInvokeMethodRange.java b/src/main/java/com/android/tools/r8/dex/code/DexInvokeMethodRange.java
index 7dc8a6c..8809f06 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexInvokeMethodRange.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexInvokeMethodRange.java
@@ -6,10 +6,10 @@
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.MethodLookupResult;
 import com.android.tools.r8.ir.code.InvokeType;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import java.nio.ShortBuffer;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexItemBasedConstString.java b/src/main/java/com/android/tools/r8/dex/code/DexItemBasedConstString.java
index 451eef1..d2adc25 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexItemBasedConstString.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexItemBasedConstString.java
@@ -7,10 +7,10 @@
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexReference;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.naming.dexitembasedstring.NameComputationInfo;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexNewArray.java b/src/main/java/com/android/tools/r8/dex/code/DexNewArray.java
index 285b82e..cad1490 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexNewArray.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexNewArray.java
@@ -6,11 +6,11 @@
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import java.nio.ShortBuffer;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexNewInstance.java b/src/main/java/com/android/tools/r8/dex/code/DexNewInstance.java
index e3bc04d..20067e5 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexNewInstance.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexNewInstance.java
@@ -6,11 +6,11 @@
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexNewUnboxedEnumInstance.java b/src/main/java/com/android/tools/r8/dex/code/DexNewUnboxedEnumInstance.java
index 3992859..0ef15d8 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexNewUnboxedEnumInstance.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexNewUnboxedEnumInstance.java
@@ -7,10 +7,10 @@
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexPackedSwitchPayload.java b/src/main/java/com/android/tools/r8/dex/code/DexPackedSwitchPayload.java
index 77b35f6..056efc7 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexPackedSwitchPayload.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexPackedSwitchPayload.java
@@ -3,9 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.dex.code;
 
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.RetracerForCodePrinting;
 import com.android.tools.r8.utils.StringUtils;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexRecordFieldValues.java b/src/main/java/com/android/tools/r8/dex/code/DexRecordFieldValues.java
index 8f0b9e8..f7e4684 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexRecordFieldValues.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexRecordFieldValues.java
@@ -7,10 +7,10 @@
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.RetracerForCodePrinting;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexSgetOrSput.java b/src/main/java/com/android/tools/r8/dex/code/DexSgetOrSput.java
index 0e9b3b8..3fe34b47 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexSgetOrSput.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexSgetOrSput.java
@@ -6,9 +6,9 @@
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexSparseSwitchPayload.java b/src/main/java/com/android/tools/r8/dex/code/DexSparseSwitchPayload.java
index f0059d9..0738430 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexSparseSwitchPayload.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexSparseSwitchPayload.java
@@ -3,9 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.dex.code;
 
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.RetracerForCodePrinting;
 import com.android.tools.r8.utils.StringUtils;
diff --git a/src/main/java/com/android/tools/r8/features/ClassToFeatureSplitMap.java b/src/main/java/com/android/tools/r8/features/ClassToFeatureSplitMap.java
index 88bfb4f..3033f19 100644
--- a/src/main/java/com/android/tools/r8/features/ClassToFeatureSplitMap.java
+++ b/src/main/java/com/android/tools/r8/features/ClassToFeatureSplitMap.java
@@ -8,16 +8,16 @@
 import com.android.tools.r8.ProgramResource;
 import com.android.tools.r8.ProgramResourceProvider;
 import com.android.tools.r8.ResourceException;
-import com.android.tools.r8.experimental.startup.StartupProfile;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.profile.startup.profile.StartupProfile;
 import com.android.tools.r8.synthesis.SyntheticItems;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.Reporter;
diff --git a/src/main/java/com/android/tools/r8/features/FeatureSplitBoundaryOptimizationUtils.java b/src/main/java/com/android/tools/r8/features/FeatureSplitBoundaryOptimizationUtils.java
index 4c3c809..f9acf30 100644
--- a/src/main/java/com/android/tools/r8/features/FeatureSplitBoundaryOptimizationUtils.java
+++ b/src/main/java/com/android/tools/r8/features/FeatureSplitBoundaryOptimizationUtils.java
@@ -5,7 +5,6 @@
 package com.android.tools.r8.features;
 
 import com.android.tools.r8.FeatureSplit;
-import com.android.tools.r8.experimental.startup.StartupProfile;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedMember;
@@ -13,6 +12,7 @@
 import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
+import com.android.tools.r8.profile.startup.profile.StartupProfile;
 import com.android.tools.r8.synthesis.SyntheticItems;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.OptionalBool;
diff --git a/src/main/java/com/android/tools/r8/graph/AbstractAccessContexts.java b/src/main/java/com/android/tools/r8/graph/AbstractAccessContexts.java
index 3e180df..4c63987 100644
--- a/src/main/java/com/android/tools/r8/graph/AbstractAccessContexts.java
+++ b/src/main/java/com/android/tools/r8/graph/AbstractAccessContexts.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.graph;
 
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.utils.collections.ProgramMethodSet;
 import java.util.IdentityHashMap;
 import java.util.Map;
diff --git a/src/main/java/com/android/tools/r8/graph/AccessControl.java b/src/main/java/com/android/tools/r8/graph/AccessControl.java
index ecb16404..d692cba 100644
--- a/src/main/java/com/android/tools/r8/graph/AccessControl.java
+++ b/src/main/java/com/android/tools/r8/graph/AccessControl.java
@@ -3,9 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.graph;
 
-import com.android.tools.r8.experimental.startup.StartupProfile;
 import com.android.tools.r8.features.ClassToFeatureSplitMap;
 import com.android.tools.r8.features.FeatureSplitBoundaryOptimizationUtils;
+import com.android.tools.r8.profile.startup.profile.StartupProfile;
 import com.android.tools.r8.synthesis.SyntheticItems;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.OptionalBool;
diff --git a/src/main/java/com/android/tools/r8/graph/AppServices.java b/src/main/java/com/android/tools/r8/graph/AppServices.java
index 6776d2c..dc557e9 100644
--- a/src/main/java/com/android/tools/r8/graph/AppServices.java
+++ b/src/main/java/com/android/tools/r8/graph/AppServices.java
@@ -13,6 +13,7 @@
 import com.android.tools.r8.ResourceException;
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.features.ClassToFeatureSplitMap;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.DescriptorUtils;
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 92848aa..919de23 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -9,13 +9,14 @@
 import com.android.tools.r8.contexts.CompilationContext;
 import com.android.tools.r8.contexts.CompilationContext.ProcessorContext;
 import com.android.tools.r8.errors.dontwarn.DontWarnConfiguration;
-import com.android.tools.r8.experimental.startup.StartupProfile;
 import com.android.tools.r8.features.ClassToFeatureSplitMap;
 import com.android.tools.r8.graph.DexValue.DexValueString;
-import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
 import com.android.tools.r8.graph.analysis.InitializedClassesInInstanceMethodsAnalysis.InitializedClassesInInstanceMethods;
 import com.android.tools.r8.graph.classmerging.MergedClassesCollection;
 import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
+import com.android.tools.r8.graph.lens.NonIdentityGraphLens;
 import com.android.tools.r8.horizontalclassmerging.HorizontalClassMerger;
 import com.android.tools.r8.horizontalclassmerging.HorizontallyMergedClasses;
 import com.android.tools.r8.ir.analysis.inlining.SimpleInliningConstraintFactory;
@@ -35,6 +36,7 @@
 import com.android.tools.r8.optimize.argumentpropagation.ArgumentPropagator;
 import com.android.tools.r8.optimize.interfaces.collection.OpenClosedInterfacesCollection;
 import com.android.tools.r8.profile.art.ArtProfileCollection;
+import com.android.tools.r8.profile.startup.profile.StartupProfile;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.shaking.AssumeInfoCollection;
 import com.android.tools.r8.shaking.KeepClassInfo;
diff --git a/src/main/java/com/android/tools/r8/graph/CfCode.java b/src/main/java/com/android/tools/r8/graph/CfCode.java
index 38bf4ee..b71e8d2 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -27,6 +27,8 @@
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.bytecodemetadata.BytecodeInstructionMetadata;
 import com.android.tools.r8.graph.bytecodemetadata.BytecodeMetadata;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.NumberGenerator;
diff --git a/src/main/java/com/android/tools/r8/graph/ClassKind.java b/src/main/java/com/android/tools/r8/graph/ClassKind.java
index e878e0d..0e3e660 100644
--- a/src/main/java/com/android/tools/r8/graph/ClassKind.java
+++ b/src/main/java/com/android/tools/r8/graph/ClassKind.java
@@ -27,6 +27,7 @@
               nestHost,
               nestMembers,
               permittedSubclasses,
+              recordComponents,
               enclosingMember,
               innerClasses,
               classSignature,
@@ -49,6 +50,7 @@
                   nestHost,
                   nestMembers,
                   permittedSubclasses,
+                  recordComponents,
                   enclosingMember,
                   innerClasses,
                   classSignature,
@@ -72,6 +74,7 @@
               nestHost,
               nestMembers,
               permittedSubclasses,
+              recordComponents,
               enclosingMember,
               innerClasses,
               classSignature,
@@ -94,6 +97,7 @@
                   nestHost,
                   nestMembers,
                   permittedSubclasses,
+                  recordComponents,
                   enclosingMember,
                   innerClasses,
                   classSignature,
@@ -115,6 +119,7 @@
               nestHost,
               nestMembers,
               permittedSubclasses,
+              recordComponents,
               enclosingMember,
               innerClasses,
               classSignature,
@@ -137,6 +142,7 @@
                   nestHost,
                   nestMembers,
                   permittedSubclasses,
+                  recordComponents,
                   enclosingMember,
                   innerClasses,
                   classSignature,
@@ -159,6 +165,7 @@
         NestHostClassAttribute nestHost,
         List<NestMemberClassAttribute> nestMembers,
         List<PermittedSubclassAttribute> permittedSubclasses,
+        List<RecordComponentInfo> recordComponents,
         EnclosingMethodAttribute enclosingMember,
         List<InnerClassAttribute> innerClasses,
         ClassSignature classSignature,
@@ -191,6 +198,7 @@
       NestHostClassAttribute nestHost,
       List<NestMemberClassAttribute> nestMembers,
       List<PermittedSubclassAttribute> permittedSubclasses,
+      List<RecordComponentInfo> recordComponents,
       EnclosingMethodAttribute enclosingMember,
       List<InnerClassAttribute> innerClasses,
       ClassSignature classSignature,
@@ -213,6 +221,7 @@
         nestHost,
         nestMembers,
         permittedSubclasses,
+        recordComponents,
         enclosingMember,
         innerClasses,
         classSignature,
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 c70e226..42dc600 100644
--- a/src/main/java/com/android/tools/r8/graph/Code.java
+++ b/src/main/java/com/android/tools/r8/graph/Code.java
@@ -8,6 +8,7 @@
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.bytecodemetadata.BytecodeInstructionMetadata;
 import com.android.tools.r8.graph.bytecodemetadata.BytecodeMetadata;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.NumberGenerator;
diff --git a/src/main/java/com/android/tools/r8/graph/DefaultInstanceInitializerCode.java b/src/main/java/com/android/tools/r8/graph/DefaultInstanceInitializerCode.java
index 601ce08..06fd92e 100644
--- a/src/main/java/com/android/tools/r8/graph/DefaultInstanceInitializerCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DefaultInstanceInitializerCode.java
@@ -16,7 +16,8 @@
 import com.android.tools.r8.dex.code.DexReturnVoid;
 import com.android.tools.r8.graph.DexCode.Try;
 import com.android.tools.r8.graph.DexCode.TryHandler;
-import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.MethodLookupResult;
 import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.NumberGenerator;
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 f72877a..25a5a97 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
@@ -9,12 +9,15 @@
 import com.android.tools.r8.dex.MixedSectionCollection;
 import com.android.tools.r8.graph.DexValue.DexValueAnnotation;
 import com.android.tools.r8.graph.DexValue.DexValueArray;
+import com.android.tools.r8.graph.DexValue.DexValueByte;
 import com.android.tools.r8.graph.DexValue.DexValueInt;
 import com.android.tools.r8.graph.DexValue.DexValueMethod;
 import com.android.tools.r8.graph.DexValue.DexValueNull;
 import com.android.tools.r8.graph.DexValue.DexValueString;
 import com.android.tools.r8.graph.DexValue.DexValueType;
+import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
 import com.android.tools.r8.ir.desugar.CovariantReturnTypeAnnotationTransformer;
+import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.synthesis.SyntheticItems;
 import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
 import com.android.tools.r8.utils.AndroidApiLevel;
@@ -24,6 +27,7 @@
 import com.android.tools.r8.utils.structural.StructuralMapping;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.function.Function;
 
@@ -209,6 +213,10 @@
     return annotation.annotation.type == factory.annotationPermittedSubclasses;
   }
 
+  public static boolean isRecordAnnotation(DexAnnotation annotation, DexItemFactory factory) {
+    return annotation.getAnnotationType() == factory.annotationRecord;
+  }
+
   public static DexAnnotation createInnerClassAnnotation(
       DexString clazz, int access, DexItemFactory factory) {
     return new DexAnnotation(
@@ -299,6 +307,110 @@
     return getTypesFromAnnotation(factory.annotationPermittedSubclasses, annotation);
   }
 
+  /** See {@link #createRecordAnnotation(DexProgramClass, AppView)} for the representation. */
+  public static List<RecordComponentInfo> getRecordComponentInfoFromAnnotation(
+      DexType type, DexAnnotation annotation, DexItemFactory factory, Origin origin) {
+    DexValue componentNamesValue =
+        getSystemValueAnnotationValueWithName(
+            factory.annotationRecord, annotation, factory.annotationRecordComponentNames);
+    DexValue componentTypesValue =
+        getSystemValueAnnotationValueWithName(
+            factory.annotationRecord, annotation, factory.annotationRecordComponentTypes);
+    DexValue componentSignaturesValue =
+        getSystemValueAnnotationValueWithName(
+            factory.annotationRecord, annotation, factory.annotationRecordComponentSignatures);
+    DexValue componentAnnotationVisibilitiesValue =
+        getSystemValueAnnotationValueWithName(
+            factory.annotationRecord,
+            annotation,
+            factory.annotationRecordComponentAnnotationVisibilities);
+    DexValue componentAnnotationsValue =
+        getSystemValueAnnotationValueWithName(
+            factory.annotationRecord, annotation, factory.annotationRecordComponentAnnotations);
+
+    if (componentNamesValue == null
+        || componentTypesValue == null
+        || componentSignaturesValue == null
+        || componentAnnotationVisibilitiesValue == null
+        || componentAnnotationsValue == null) {
+      return null;
+    }
+    if (!componentNamesValue.isDexValueArray()
+        || !componentTypesValue.isDexValueArray()
+        || !componentSignaturesValue.isDexValueArray()
+        || !componentAnnotationVisibilitiesValue.isDexValueArray()
+        || !componentAnnotationsValue.isDexValueArray()) {
+      return null;
+    }
+    DexValueArray componentNamesValueArray = componentNamesValue.asDexValueArray();
+    DexValueArray componentTypesValueArray = componentTypesValue.asDexValueArray();
+    DexValueArray componentSignaturesValueArray = componentSignaturesValue.asDexValueArray();
+    DexValueArray componentAnnotationVisibilitiesValueArray =
+        componentAnnotationVisibilitiesValue.asDexValueArray();
+    DexValueArray componentAnnotationsValueArray = componentAnnotationsValue.asDexValueArray();
+    if (componentNamesValueArray.size() != componentTypesValueArray.size()
+        || componentNamesValueArray.size() != componentSignaturesValueArray.size()
+        || componentNamesValueArray.size() != componentAnnotationVisibilitiesValueArray.size()
+        || componentNamesValueArray.size() != componentAnnotationsValueArray.size()) {
+      return null;
+    }
+    List<RecordComponentInfo> result = new ArrayList<>(componentNamesValueArray.size());
+    for (int componentIndex = 0;
+        componentIndex < componentNamesValueArray.size();
+        componentIndex++) {
+      DexValue nameValue = componentNamesValueArray.getValue(componentIndex);
+      DexValue typeValue = componentTypesValueArray.getValue(componentIndex);
+      DexValue signatureValue = componentSignaturesValueArray.getValue(componentIndex);
+      DexValue visibilitiesValue =
+          componentAnnotationVisibilitiesValueArray.getValue(componentIndex);
+      DexValue annotationsValue = componentAnnotationsValueArray.getValue(componentIndex);
+      if (!nameValue.isDexValueString()
+          || !typeValue.isDexValueType()
+          || !(signatureValue.isDexValueAnnotation() || signatureValue.isDexValueNull())
+          || !visibilitiesValue.isDexValueArray()
+          || !annotationsValue.isDexValueArray()) {
+        return null;
+      }
+      DexValueArray visibilitiesValueArray = visibilitiesValue.asDexValueArray();
+      DexValueArray annotationsValueArray = annotationsValue.asDexValueArray();
+      if (visibilitiesValueArray.size() != annotationsValueArray.size()) {
+        return null;
+      }
+      List<DexAnnotation> componentAnnotations = Collections.emptyList();
+      if (annotationsValueArray.size() > 0) {
+        componentAnnotations = new ArrayList<>(annotationsValueArray.size());
+        for (int annotationIndex = 0;
+            annotationIndex < annotationsValueArray.size();
+            annotationIndex++) {
+          DexValue visibilityValue = visibilitiesValueArray.getValue(annotationIndex);
+          DexValue annotationValue = annotationsValueArray.getValue(annotationIndex);
+          if (!visibilityValue.isDexValueByte() || !annotationValue.isDexValueAnnotation()) {
+            return null;
+          }
+          componentAnnotations.add(
+              new DexAnnotation(
+                  visibilityValue.asDexValueByte().getValue(),
+                  annotationValue.asDexValueAnnotation().getValue()));
+        }
+      }
+      FieldTypeSignature componentSignature =
+          GenericSignature.parseFieldTypeSignature(
+              nameValue.asDexValueString().getValue().toString(),
+              signatureValue.isDexValueAnnotation()
+                  ? getSignature(signatureValue.asDexValueAnnotation().getValue())
+                  : null,
+              origin,
+              factory,
+              null);
+
+      DexType componentType = typeValue.asDexValueType().getValue();
+      DexString componentName = nameValue.asDexValueString().getValue();
+      DexField componentField = factory.createField(type, componentType, componentName);
+      result.add(new RecordComponentInfo(componentField, componentSignature, componentAnnotations));
+    }
+    return result;
+  }
+
   public static DexAnnotation createSourceDebugExtensionAnnotation(DexValue value,
       DexItemFactory factory) {
     return new DexAnnotation(VISIBILITY_SYSTEM,
@@ -367,8 +479,143 @@
         new DexValue.DexValueArray(list.toArray(DexValue.EMPTY_ARRAY)));
   }
 
+  /**
+   * Record component information is written to DEX as a system annotation named <code>
+   * dalvik.annotation.Record</code> with the following content:
+   *
+   * <pre>
+   *   componentAnnotationVisibilities byte[][]
+   *   componentAnnotations Annotation[][]
+   *   componentNames String[]
+   *   componentSignatures Annotation[]  // Annotation dalvik.annotation.Signature or NULL
+   *   componentTypes String[]
+   * </pre>
+   *
+   * Each of the arrays have one element for each component.
+   *
+   * <p>Example of a two component record with two annotations on the first component and one on the
+   * second and with a signature on the first component.
+   *
+   * <pre>
+   * .annotation system Ldalvik/annotation/Record;
+   *   componentAnnotationVisibilities = {
+   *     {
+   *       0x1,
+   *       0x1
+   *     },
+   *     {
+   *       0x1
+   *     }
+   *   }
+   *   componentAnnotations = {
+   *     {
+   *       .subannotation LAnnotation1;
+   *         value = "a"
+   *       .end subannotation,
+   *       .subannotation LAnnotation2;
+   *         value = "c"
+   *       .end subannotation
+   *     },
+   *     {
+   *       .subannotation LAnnotation3;
+   *         value = "z"
+   *       .end subannotation
+   *     }
+   *   }
+   *   componentNames = {
+   *      "name",
+   *      "age"
+   *   }
+   *   componentSignatures = {
+   *     .subannotation Ldalvik/annotation/Signature;
+   *       value = {
+   *         "TX;"
+   *       }
+   *     .end subannotation,
+   *     NULL
+   *   }
+   *   componentTypes = {
+   *     Ljava/lang/CharSequence;,
+   *     Ljava/lang/Object;
+   *   }
+   * .end annotation
+   * </pre>
+   */
+  public static DexAnnotation createRecordAnnotation(DexProgramClass clazz, AppView<?> appView) {
+    DexItemFactory factory = appView.dexItemFactory();
+    int componentCount = clazz.getRecordComponents().size();
+    DexValueString[] componentNames = new DexValueString[componentCount];
+    DexValueType[] componentTypes = new DexValueType[componentCount];
+    DexValue[] componentSignatures = new DexValue[componentCount];
+    DexValueArray[] componentAnnotationVisibilities = new DexValueArray[componentCount];
+    DexValueArray[] componentAnnotations = new DexValueArray[componentCount];
+    for (int componentIndex = 0; componentIndex < componentCount; componentIndex++) {
+      RecordComponentInfo info = clazz.getRecordComponents().get(componentIndex);
+      componentNames[componentIndex] =
+          new DexValueString(appView.getNamingLens().lookupName(info.getField()));
+      componentTypes[componentIndex] = new DexValueType(info.getType());
+      if (info.getSignature().hasNoSignature()) {
+        componentSignatures[componentIndex] = DexValueNull.NULL;
+      } else {
+        componentSignatures[componentIndex] =
+            new DexValueAnnotation(
+                createSignatureAnnotation(info.getSignature().toString(), factory).annotation);
+      }
+      int annotationsSize = info.getAnnotations().size();
+      DexValueByte[] visibilities = new DexValueByte[annotationsSize];
+      DexValueAnnotation[] annotations = new DexValueAnnotation[annotationsSize];
+      componentAnnotationVisibilities[componentIndex] = new DexValueArray(visibilities);
+      componentAnnotations[componentIndex] = new DexValueArray(annotations);
+      for (int annotationIndex = 0; annotationIndex < annotationsSize; annotationIndex++) {
+        DexAnnotation annotation = info.getAnnotations().get(annotationIndex);
+        visibilities[annotationIndex] = DexValueByte.create((byte) annotation.getVisibility());
+        annotations[annotationIndex] = new DexValueAnnotation(annotation.annotation);
+      }
+    }
+
+    if (appView.options().emitRecordAnnotationsExInDex) {
+      return new DexAnnotation(
+          VISIBILITY_SYSTEM,
+          new DexEncodedAnnotation(
+              factory.annotationRecord,
+              new DexAnnotationElement[] {
+                new DexAnnotationElement(
+                    factory.annotationRecordComponentNames, new DexValueArray(componentNames)),
+                new DexAnnotationElement(
+                    factory.annotationRecordComponentTypes, new DexValueArray(componentTypes)),
+                new DexAnnotationElement(
+                    factory.annotationRecordComponentSignatures,
+                    new DexValueArray(componentSignatures)),
+                new DexAnnotationElement(
+                    factory.annotationRecordComponentAnnotationVisibilities,
+                    new DexValueArray(componentAnnotationVisibilities)),
+                new DexAnnotationElement(
+                    factory.annotationRecordComponentAnnotations,
+                    new DexValueArray(componentAnnotations))
+              }));
+    } else {
+      return new DexAnnotation(
+          VISIBILITY_SYSTEM,
+          new DexEncodedAnnotation(
+              factory.annotationRecord,
+              new DexAnnotationElement[] {
+                new DexAnnotationElement(
+                    factory.annotationRecordComponentNames, new DexValueArray(componentNames)),
+                new DexAnnotationElement(
+                    factory.annotationRecordComponentTypes, new DexValueArray(componentTypes))
+              }));
+    }
+  }
+
   public static String getSignature(DexAnnotation signatureAnnotation) {
-    DexValueArray elements = signatureAnnotation.annotation.elements[0].value.asDexValueArray();
+    return getSignature(signatureAnnotation.annotation);
+  }
+
+  public static String getSignature(DexEncodedAnnotation signatureAnnotation) {
+    return getSignature(signatureAnnotation.elements[0].value.asDexValueArray());
+  }
+
+  public static String getSignature(DexValueArray elements) {
     StringBuilder signature = new StringBuilder();
     for (DexValue element : elements.getValues()) {
       signature.append(element.asDexValueString().value.toString());
@@ -403,6 +650,18 @@
         : annotation.annotation.elements[0].value;
   }
 
+  private static DexValue getSystemValueAnnotationValueWithName(
+      DexType type, DexAnnotation annotation, DexString name) {
+    assert annotation.visibility == VISIBILITY_SYSTEM;
+    assert annotation.getAnnotationType() == type;
+    for (DexAnnotationElement element : annotation.annotation.elements) {
+      if (element.name == name) {
+        return element.value;
+      }
+    }
+    return null;
+  }
+
   public static boolean isThrowingAnnotation(DexAnnotation annotation,
       DexItemFactory factory) {
     return annotation.annotation.type == factory.annotationThrows;
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index 59bff83..342a214 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -78,6 +78,8 @@
 
   private List<PermittedSubclassAttribute> permittedSubclasses;
 
+  private List<RecordComponentInfo> recordComponents;
+
   /** Generic signature information if the attribute is present in the input */
   protected ClassSignature classSignature;
 
@@ -93,6 +95,7 @@
       NestHostClassAttribute nestHost,
       List<NestMemberClassAttribute> nestMembers,
       List<PermittedSubclassAttribute> permittedSubclasses,
+      List<RecordComponentInfo> recordComponents,
       EnclosingMethodAttribute enclosingMethod,
       List<InnerClassAttribute> innerClasses,
       ClassSignature classSignature,
@@ -113,6 +116,7 @@
     this.nestMembers = nestMembers;
     assert nestMembers != null;
     this.permittedSubclasses = permittedSubclasses;
+    this.recordComponents = recordComponents;
     assert permittedSubclasses != null;
     this.enclosingMethod = enclosingMethod;
     this.innerClasses = innerClasses;
@@ -1113,6 +1117,20 @@
     return permittedSubclasses;
   }
 
+  public List<RecordComponentInfo> getRecordComponents() {
+    return recordComponents;
+  }
+
+  public void clearRecordComponents() {
+    recordComponents.clear();
+  }
+
+  public void removeRecordComponents(Predicate<RecordComponentInfo> predicate) {
+    if (!recordComponents.isEmpty()) {
+      recordComponents.removeIf(predicate);
+    }
+  }
+
   /** Returns kotlin class info if the class is synthesized by kotlin compiler. */
   public abstract KotlinClassLevelInfo getKotlinInfo();
 
diff --git a/src/main/java/com/android/tools/r8/graph/DexClasspathClass.java b/src/main/java/com/android/tools/r8/graph/DexClasspathClass.java
index aca2a14..2937cd2 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClasspathClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClasspathClass.java
@@ -36,6 +36,7 @@
       NestHostClassAttribute nestHost,
       List<NestMemberClassAttribute> nestMembers,
       List<PermittedSubclassAttribute> permittedSubclasses,
+      List<RecordComponentInfo> recordComponents,
       EnclosingMethodAttribute enclosingMember,
       List<InnerClassAttribute> innerClasses,
       ClassSignature classSignature,
@@ -56,6 +57,7 @@
         nestHost,
         nestMembers,
         permittedSubclasses,
+        recordComponents,
         enclosingMember,
         innerClasses,
         classSignature,
diff --git a/src/main/java/com/android/tools/r8/graph/DexCode.java b/src/main/java/com/android/tools/r8/graph/DexCode.java
index 401a1eb..486aaa7 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCode.java
@@ -24,6 +24,7 @@
 import com.android.tools.r8.graph.DexDebugInfo.EventBasedDebugInfo;
 import com.android.tools.r8.graph.bytecodemetadata.BytecodeInstructionMetadata;
 import com.android.tools.r8.graph.bytecodemetadata.BytecodeMetadata;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.NumberGenerator;
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java b/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java
index 737df40..ac495b4 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java
@@ -8,6 +8,7 @@
 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.lens.GraphLens;
 import com.android.tools.r8.ir.code.Position;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import com.android.tools.r8.utils.structural.HashingVisitor;
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java b/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java
index 3b40cdb..a7cd5d1 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java
@@ -12,6 +12,7 @@
 import com.android.tools.r8.dex.MixedSectionCollection;
 import com.android.tools.r8.dex.code.DexInstruction;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.utils.ArrayUtils;
 import com.android.tools.r8.utils.LebUtils;
 import com.android.tools.r8.utils.StringUtils;
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugInfoForWriting.java b/src/main/java/com/android/tools/r8/graph/DexDebugInfoForWriting.java
index 75cdd80..67ab2aa 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugInfoForWriting.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugInfoForWriting.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.dex.DebugBytecodeWriter;
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.dex.MixedSectionCollection;
+import com.android.tools.r8.graph.lens.GraphLens;
 
 /** Interface to guarantee that the info only contains writable events. */
 public interface DexDebugInfoForWriting {
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 5c14069..579b21f 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -735,6 +735,14 @@
       createStaticallyKnownType("Ldalvik/annotation/NestMembers;");
   public final DexType annotationPermittedSubclasses =
       createStaticallyKnownType("Ldalvik/annotation/PermittedSubclasses;");
+  public final DexType annotationRecord = createStaticallyKnownType("Ldalvik/annotation/Record;");
+  public final DexString annotationRecordComponentNames = createString("componentNames");
+  public final DexString annotationRecordComponentTypes = createString("componentTypes");
+  public final DexString annotationRecordComponentSignatures = createString("componentSignatures");
+  public final DexString annotationRecordComponentAnnotationVisibilities =
+      createString("componentAnnotationVisibilities");
+  public final DexString annotationRecordComponentAnnotations =
+      createString("componentAnnotations");
   public final DexType annotationSourceDebugExtension =
       createStaticallyKnownType("Ldalvik/annotation/SourceDebugExtension;");
   public final DexType annotationThrows = createStaticallyKnownType("Ldalvik/annotation/Throws;");
diff --git a/src/main/java/com/android/tools/r8/graph/DexLibraryClass.java b/src/main/java/com/android/tools/r8/graph/DexLibraryClass.java
index 24091e4..a145cba 100644
--- a/src/main/java/com/android/tools/r8/graph/DexLibraryClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexLibraryClass.java
@@ -34,6 +34,7 @@
       NestHostClassAttribute nestHost,
       List<NestMemberClassAttribute> nestMembers,
       List<PermittedSubclassAttribute> permittedSubclasses,
+      List<RecordComponentInfo> recordComponents,
       EnclosingMethodAttribute enclosingMember,
       List<InnerClassAttribute> innerClasses,
       ClassSignature classSignature,
@@ -54,6 +55,7 @@
         nestHost,
         nestMembers,
         permittedSubclasses,
+        recordComponents,
         enclosingMember,
         innerClasses,
         classSignature,
@@ -174,6 +176,7 @@
     private NestHostClassAttribute nestHost = null;
     private List<NestMemberClassAttribute> nestMembers = Collections.emptyList();
     private List<PermittedSubclassAttribute> permittedSubclasses = Collections.emptyList();
+    private List<RecordComponentInfo> recordComponents = Collections.emptyList();
     private EnclosingMethodAttribute enclosingMember = null;
     private List<InnerClassAttribute> innerClasses = Collections.emptyList();
     private ClassSignature classSignature = ClassSignature.noSignature();
@@ -217,6 +220,7 @@
           nestHost,
           nestMembers,
           permittedSubclasses,
+          recordComponents,
           enclosingMember,
           innerClasses,
           classSignature,
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
index 01fa0e0..a448af0 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -71,6 +71,7 @@
       NestHostClassAttribute nestHost,
       List<NestMemberClassAttribute> nestMembers,
       List<PermittedSubclassAttribute> permittedSubclasses,
+      List<RecordComponentInfo> recordComponents,
       EnclosingMethodAttribute enclosingMember,
       List<InnerClassAttribute> innerClasses,
       ClassSignature classSignature,
@@ -93,6 +94,7 @@
         nestHost,
         nestMembers,
         permittedSubclasses,
+        recordComponents,
         enclosingMember,
         innerClasses,
         classSignature,
@@ -117,6 +119,7 @@
       NestHostClassAttribute nestHost,
       List<NestMemberClassAttribute> nestMembers,
       List<PermittedSubclassAttribute> permittedSubclasses,
+      List<RecordComponentInfo> recordComponents,
       EnclosingMethodAttribute enclosingMember,
       List<InnerClassAttribute> innerClasses,
       ClassSignature classSignature,
@@ -137,6 +140,7 @@
         nestHost,
         nestMembers,
         permittedSubclasses,
+        recordComponents,
         enclosingMember,
         innerClasses,
         classSignature,
@@ -161,6 +165,7 @@
         null,
         Collections.emptyList(),
         Collections.emptyList(),
+        Collections.emptyList(),
         null,
         Collections.emptyList(),
         ClassSignature.noSignature(),
diff --git a/src/main/java/com/android/tools/r8/graph/DexValue.java b/src/main/java/com/android/tools/r8/graph/DexValue.java
index c455396..5271c0a 100644
--- a/src/main/java/com/android/tools/r8/graph/DexValue.java
+++ b/src/main/java/com/android/tools/r8/graph/DexValue.java
@@ -1600,6 +1600,14 @@
       return values;
     }
 
+    public int size() {
+      return values.length;
+    }
+
+    public DexValue getValue(int i) {
+      return values[i];
+    }
+
     @Override
     public DexValueKind getValueKind() {
       return DexValueKind.ARRAY;
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 af4b8a0..1e8856c 100644
--- a/src/main/java/com/android/tools/r8/graph/DexWritableCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexWritableCode.java
@@ -10,6 +10,7 @@
 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.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import com.android.tools.r8.utils.structural.HashingVisitor;
diff --git a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
index 1f756ee..08dad18 100644
--- a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
@@ -10,6 +10,7 @@
 
 import com.android.tools.r8.DataResourceProvider;
 import com.android.tools.r8.graph.LazyLoadedDexApplication.AllClasses;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.Timing;
diff --git a/src/main/java/com/android/tools/r8/graph/FieldAccessInfoCollectionImpl.java b/src/main/java/com/android/tools/r8/graph/FieldAccessInfoCollectionImpl.java
index 8a8b9da..63e4530 100644
--- a/src/main/java/com/android/tools/r8/graph/FieldAccessInfoCollectionImpl.java
+++ b/src/main/java/com/android/tools/r8/graph/FieldAccessInfoCollectionImpl.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.graph;
 
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.utils.ObjectUtils;
 import com.android.tools.r8.utils.SetUtils;
 import java.util.IdentityHashMap;
diff --git a/src/main/java/com/android/tools/r8/graph/FieldAccessInfoImpl.java b/src/main/java/com/android/tools/r8/graph/FieldAccessInfoImpl.java
index 8779817..e5d9dfe 100644
--- a/src/main/java/com/android/tools/r8/graph/FieldAccessInfoImpl.java
+++ b/src/main/java/com/android/tools/r8/graph/FieldAccessInfoImpl.java
@@ -6,6 +6,7 @@
 
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AbstractAccessContexts.ConcreteAccessContexts;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.utils.collections.ProgramMethodSet;
 import com.google.common.collect.Sets;
 import java.util.IdentityHashMap;
diff --git a/src/main/java/com/android/tools/r8/graph/GraphLens.java b/src/main/java/com/android/tools/r8/graph/GraphLens.java
deleted file mode 100644
index 95921b3..0000000
--- a/src/main/java/com/android/tools/r8/graph/GraphLens.java
+++ /dev/null
@@ -1,1223 +0,0 @@
-// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.graph;
-
-import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
-
-import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
-import com.android.tools.r8.ir.code.InvokeType;
-import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.enums.EnumUnboxingLens;
-import com.android.tools.r8.optimize.MemberRebindingIdentityLens;
-import com.android.tools.r8.optimize.MemberRebindingLens;
-import com.android.tools.r8.shaking.KeepInfoCollection;
-import com.android.tools.r8.utils.Action;
-import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.IterableUtils;
-import com.android.tools.r8.utils.ListUtils;
-import com.android.tools.r8.utils.SetUtils;
-import com.android.tools.r8.utils.collections.BidirectionalManyToOneRepresentativeHashMap;
-import com.android.tools.r8.utils.collections.BidirectionalManyToOneRepresentativeMap;
-import com.android.tools.r8.utils.collections.MutableBidirectionalManyToOneRepresentativeMap;
-import com.android.tools.r8.utils.collections.ProgramMethodSet;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
-import it.unimi.dsi.fastutil.objects.Object2BooleanArrayMap;
-import it.unimi.dsi.fastutil.objects.Object2BooleanMap;
-import java.util.ArrayList;
-import java.util.IdentityHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.function.BiFunction;
-import java.util.function.Function;
-import java.util.function.Predicate;
-
-/**
- * A GraphLens implements a virtual view on top of the graph, used to delay global rewrites until
- * later IR processing stages.
- *
- * <p>Valid remappings are limited to the following operations:
- *
- * <ul>
- *   <li>Mapping a classes type to one of the super/subtypes.
- *   <li>Renaming private methods/fields.
- *   <li>Moving methods/fields to a super/subclass.
- *   <li>Replacing method/field references by the same method/field on a super/subtype
- *   <li>Moved methods might require changed invocation type at the call site
- * </ul>
- *
- * Note that the latter two have to take visibility into account.
- */
-public abstract class GraphLens {
-
-  abstract static class MemberLookupResult<R extends DexMember<?, R>> {
-
-    private final R reference;
-    private final R reboundReference;
-
-    private MemberLookupResult(R reference, R reboundReference) {
-      this.reference = reference;
-      this.reboundReference = reboundReference;
-    }
-
-    public R getReference() {
-      return reference;
-    }
-
-    public R getRewrittenReference(BidirectionalManyToOneRepresentativeMap<R, R> rewritings) {
-      return rewritings.getOrDefault(reference, reference);
-    }
-
-    public R getRewrittenReference(Map<R, R> rewritings) {
-      return rewritings.getOrDefault(reference, reference);
-    }
-
-    public boolean hasReboundReference() {
-      return reboundReference != null;
-    }
-
-    public R getReboundReference() {
-      return reboundReference;
-    }
-
-    public R getRewrittenReboundReference(
-        BidirectionalManyToOneRepresentativeMap<R, R> rewritings) {
-      return rewritings.getOrDefault(reboundReference, reboundReference);
-    }
-
-    public R getRewrittenReboundReference(Function<R, R> rewritings) {
-      R rewrittenReboundReference = rewritings.apply(reboundReference);
-      return rewrittenReboundReference != null ? rewrittenReboundReference : reboundReference;
-    }
-
-    abstract static class Builder<R extends DexMember<?, R>, Self extends Builder<R, Self>> {
-
-      R reference;
-      R reboundReference;
-
-      public Self setReference(R reference) {
-        this.reference = reference;
-        return self();
-      }
-
-      public Self setReboundReference(R reboundReference) {
-        this.reboundReference = reboundReference;
-        return self();
-      }
-
-      public abstract Self self();
-    }
-  }
-
-  /**
-   * Intermediate result of a field lookup that stores the actual non-rebound reference and the
-   * rebound reference that points to the definition of the field.
-   */
-  public static class FieldLookupResult extends MemberLookupResult<DexField> {
-
-    private final DexType readCastType;
-    private final DexType writeCastType;
-
-    private FieldLookupResult(
-        DexField reference,
-        DexField reboundReference,
-        DexType readCastType,
-        DexType writeCastType) {
-      super(reference, reboundReference);
-      this.readCastType = readCastType;
-      this.writeCastType = writeCastType;
-    }
-
-    public static Builder builder(GraphLens lens) {
-      return new Builder(lens);
-    }
-
-    public boolean hasReadCastType() {
-      return readCastType != null;
-    }
-
-    public DexType getReadCastType() {
-      return readCastType;
-    }
-
-    public DexType getRewrittenReadCastType(Function<DexType, DexType> fn) {
-      return hasReadCastType() ? fn.apply(readCastType) : null;
-    }
-
-    public boolean hasWriteCastType() {
-      return writeCastType != null;
-    }
-
-    public DexType getWriteCastType() {
-      return writeCastType;
-    }
-
-    public DexType getRewrittenWriteCastType(Function<DexType, DexType> fn) {
-      return hasWriteCastType() ? fn.apply(writeCastType) : null;
-    }
-
-    public static class Builder extends MemberLookupResult.Builder<DexField, Builder> {
-
-      private DexType readCastType;
-      private DexType writeCastType;
-      private GraphLens lens;
-
-      private Builder(GraphLens lens) {
-        this.lens = lens;
-      }
-
-      public Builder setReadCastType(DexType readCastType) {
-        this.readCastType = readCastType;
-        return this;
-      }
-
-      public Builder setWriteCastType(DexType writeCastType) {
-        this.writeCastType = writeCastType;
-        return this;
-      }
-
-      @Override
-      public Builder self() {
-        return this;
-      }
-
-      public FieldLookupResult build() {
-        // TODO(b/168282032): All non-identity graph lenses should set the rebound reference.
-        return new FieldLookupResult(reference, reboundReference, readCastType, writeCastType);
-      }
-    }
-  }
-
-  /**
-   * Result of a method lookup in a GraphLens.
-   *
-   * <p>This provides the new target and invoke type to use, along with a description of the
-   * prototype changes that have been made to the target method and the corresponding required
-   * changes to the invoke arguments.
-   */
-  public static class MethodLookupResult extends MemberLookupResult<DexMethod> {
-
-    private final InvokeType type;
-    private final RewrittenPrototypeDescription prototypeChanges;
-
-    public MethodLookupResult(
-        DexMethod reference,
-        DexMethod reboundReference,
-        InvokeType type,
-        RewrittenPrototypeDescription prototypeChanges) {
-      super(reference, reboundReference);
-      this.type = type;
-      this.prototypeChanges = prototypeChanges;
-    }
-
-    public static Builder builder(GraphLens lens) {
-      return new Builder(lens);
-    }
-
-    public InvokeType getType() {
-      return type;
-    }
-
-    public RewrittenPrototypeDescription getPrototypeChanges() {
-      return prototypeChanges;
-    }
-
-    public static class Builder extends MemberLookupResult.Builder<DexMethod, Builder> {
-
-      private final GraphLens lens;
-      private RewrittenPrototypeDescription prototypeChanges = RewrittenPrototypeDescription.none();
-      private InvokeType type;
-
-      private Builder(GraphLens lens) {
-        this.lens = lens;
-      }
-
-      public Builder setPrototypeChanges(RewrittenPrototypeDescription prototypeChanges) {
-        this.prototypeChanges = prototypeChanges;
-        return this;
-      }
-
-      public Builder setType(InvokeType type) {
-        this.type = type;
-        return this;
-      }
-
-      public MethodLookupResult build() {
-        assert reference != null;
-        // TODO(b/168282032): All non-identity graph lenses should set the rebound reference.
-        return new MethodLookupResult(reference, reboundReference, type, prototypeChanges);
-      }
-
-      @Override
-      public Builder self() {
-        return this;
-      }
-    }
-  }
-
-  public abstract static class Builder {
-
-    protected final MutableBidirectionalManyToOneRepresentativeMap<DexField, DexField> fieldMap =
-        BidirectionalManyToOneRepresentativeHashMap.newIdentityHashMap();
-    protected final MutableBidirectionalManyToOneRepresentativeMap<DexMethod, DexMethod> methodMap =
-        BidirectionalManyToOneRepresentativeHashMap.newIdentityHashMap();
-    protected final Map<DexType, DexType> typeMap = new IdentityHashMap<>();
-
-    protected Builder() {}
-
-    public void map(DexType from, DexType to) {
-      if (from == to) {
-        return;
-      }
-      typeMap.put(from, to);
-    }
-
-    public void move(DexMethod from, DexMethod to) {
-      if (from == to) {
-        return;
-      }
-      methodMap.put(from, to);
-    }
-
-    public void move(DexField from, DexField to) {
-      if (from == to) {
-        return;
-      }
-      fieldMap.put(from, to);
-    }
-
-    public abstract GraphLens build(AppView<?> appView);
-  }
-
-  /**
-   * Intentionally private. All graph lenses except for {@link IdentityGraphLens} should inherit
-   * from {@link NonIdentityGraphLens}.
-   */
-  private GraphLens() {}
-
-  public boolean isSyntheticFinalizationGraphLens() {
-    return false;
-  }
-
-  public abstract DexType getOriginalType(DexType type);
-
-  public abstract Iterable<DexType> getOriginalTypes(DexType type);
-
-  public abstract DexField getOriginalFieldSignature(DexField field);
-
-  public final DexMember<?, ?> getOriginalMemberSignature(DexMember<?, ?> member) {
-    return member.apply(this::getOriginalFieldSignature, this::getOriginalMethodSignature);
-  }
-
-  public final DexMethod getOriginalMethodSignature(DexMethod method) {
-    return getOriginalMethodSignature(method, null);
-  }
-
-  public final DexMethod getOriginalMethodSignature(DexMethod method, GraphLens atGraphLens) {
-    GraphLens current = this;
-    DexMethod original = method;
-    while (current.isNonIdentityLens() && current != atGraphLens) {
-      NonIdentityGraphLens nonIdentityLens = current.asNonIdentityLens();
-      original = nonIdentityLens.getPreviousMethodSignature(original);
-      current = nonIdentityLens.getPrevious();
-    }
-    assert atGraphLens == null ? current.isIdentityLens() : (current == atGraphLens);
-    return original;
-  }
-
-  public final DexMethod getOriginalMethodSignatureForMapping(DexMethod method) {
-    GraphLens current = this;
-    DexMethod original = method;
-    while (current.isNonIdentityLens()) {
-      NonIdentityGraphLens nonIdentityLens = current.asNonIdentityLens();
-      original = nonIdentityLens.getPreviousMethodSignatureForMapping(original);
-      current = nonIdentityLens.getPrevious();
-    }
-    assert current.isIdentityLens();
-    return original;
-  }
-
-  public final DexField getRenamedFieldSignature(DexField originalField) {
-    return getRenamedFieldSignature(originalField, null);
-  }
-
-  public abstract DexField getRenamedFieldSignature(DexField originalField, GraphLens codeLens);
-
-  public final DexMember<?, ?> getRenamedMemberSignature(DexMember<?, ?> originalMember) {
-    return originalMember.isDexField()
-        ? getRenamedFieldSignature(originalMember.asDexField())
-        : getRenamedMethodSignature(originalMember.asDexMethod());
-  }
-
-  public final DexMethod getRenamedMethodSignature(DexMethod originalMethod) {
-    return getRenamedMethodSignature(originalMethod, null);
-  }
-
-  public abstract DexMethod getRenamedMethodSignature(DexMethod originalMethod, GraphLens applied);
-
-  public DexEncodedMethod mapDexEncodedMethod(
-      DexEncodedMethod originalEncodedMethod, DexDefinitionSupplier definitions) {
-    return mapDexEncodedMethod(originalEncodedMethod, definitions, null);
-  }
-
-  public DexEncodedMethod mapDexEncodedMethod(
-      DexEncodedMethod originalEncodedMethod,
-      DexDefinitionSupplier definitions,
-      GraphLens applied) {
-    assert originalEncodedMethod != DexEncodedMethod.SENTINEL;
-    DexMethod newMethod = getRenamedMethodSignature(originalEncodedMethod.getReference(), applied);
-    // Note that:
-    // * Even if `newMethod` is the same as `originalEncodedMethod.method`, we still need to look it
-    //   up, since `originalEncodedMethod` may be obsolete.
-    // * We can't directly use AppInfo#definitionFor(DexMethod) since definitions may not be
-    //   updated either yet.
-    DexClass newHolder = definitions.definitionFor(newMethod.holder);
-    assert newHolder != null;
-    DexEncodedMethod newEncodedMethod = newHolder.lookupMethod(newMethod);
-    assert newEncodedMethod != null;
-    return newEncodedMethod;
-  }
-
-  public ProgramMethod mapProgramMethod(
-      ProgramMethod oldMethod, DexDefinitionSupplier definitions) {
-    DexMethod newMethod = getRenamedMethodSignature(oldMethod.getReference());
-    DexProgramClass holder = asProgramClassOrNull(definitions.definitionForHolder(newMethod));
-    return newMethod.lookupOnProgramClass(holder);
-  }
-
-  // Predicate indicating if a rewritten reference is a simple renaming, meaning the move from one
-  // reference to another is simply either just a renaming or/also renaming of the references. In
-  // other words, the content of the definition, including the definition of all of its members is
-  // the same modulo the renaming.
-  public <T extends DexReference> boolean isSimpleRenaming(T from, T to) {
-    assert from != to;
-    return false;
-  }
-
-  // Predicate to see if a method definition is only changed by repackaging or synthetic
-  // finalization indicating that it is a simple renaming.
-  public final boolean isSimpleRenaming(DexMethod method) {
-    DexMethod methodToCompareAgainst = method;
-    DexMethod original = method;
-    GraphLens current = this;
-    while (current.isNonIdentityLens()) {
-      NonIdentityGraphLens nonIdentityLens = current.asNonIdentityLens();
-      original = nonIdentityLens.getPreviousMethodSignature(original);
-      if (current.isSimpleRenamingLens()) {
-        methodToCompareAgainst = original;
-      } else if (methodToCompareAgainst != original) {
-        return false;
-      }
-      assert nonIdentityLens.getPrevious() != null;
-      current = nonIdentityLens.getPrevious();
-    }
-    return true;
-  }
-
-  public abstract String lookupPackageName(String pkg);
-
-  public DexType lookupClassType(DexType type) {
-    return lookupClassType(type, getIdentityLens());
-  }
-
-  public abstract DexType lookupClassType(DexType type, GraphLens applied);
-
-  public DexType lookupType(DexType type) {
-    return lookupType(type, getIdentityLens());
-  }
-
-  public abstract DexType lookupType(DexType type, GraphLens applied);
-
-  @Deprecated
-  public final DexMethod lookupMethod(DexMethod method) {
-    assert verifyIsContextFreeForMethod(method);
-    return lookupMethod(method, null, null).getReference();
-  }
-
-  public final MethodLookupResult lookupInvokeDirect(DexMethod method, ProgramMethod context) {
-    return lookupMethod(method, context.getReference(), InvokeType.DIRECT);
-  }
-
-  public final MethodLookupResult lookupInvokeDirect(
-      DexMethod method, ProgramMethod context, GraphLens codeLens) {
-    return lookupMethod(method, context.getReference(), InvokeType.DIRECT, codeLens);
-  }
-
-  public final MethodLookupResult lookupInvokeInterface(DexMethod method, ProgramMethod context) {
-    return lookupMethod(method, context.getReference(), InvokeType.INTERFACE);
-  }
-
-  public final MethodLookupResult lookupInvokeInterface(
-      DexMethod method, ProgramMethod context, GraphLens codeLens) {
-    return lookupMethod(method, context.getReference(), InvokeType.INTERFACE, codeLens);
-  }
-
-  public final MethodLookupResult lookupInvokeStatic(DexMethod method, ProgramMethod context) {
-    return lookupMethod(method, context.getReference(), InvokeType.STATIC);
-  }
-
-  public final MethodLookupResult lookupInvokeStatic(
-      DexMethod method, ProgramMethod context, GraphLens codeLens) {
-    return lookupMethod(method, context.getReference(), InvokeType.STATIC, codeLens);
-  }
-
-  public final MethodLookupResult lookupInvokeSuper(DexMethod method, ProgramMethod context) {
-    return lookupMethod(method, context.getReference(), InvokeType.SUPER);
-  }
-
-  public final MethodLookupResult lookupInvokeSuper(
-      DexMethod method, ProgramMethod context, GraphLens codeLens) {
-    return lookupMethod(method, context.getReference(), InvokeType.SUPER, codeLens);
-  }
-
-  public final MethodLookupResult lookupInvokeVirtual(DexMethod method, ProgramMethod context) {
-    return lookupMethod(method, context.getReference(), InvokeType.VIRTUAL);
-  }
-
-  public final MethodLookupResult lookupInvokeVirtual(
-      DexMethod method, ProgramMethod context, GraphLens codeLens) {
-    return lookupMethod(method, context.getReference(), InvokeType.VIRTUAL, codeLens);
-  }
-
-  public final MethodLookupResult lookupMethod(
-      DexMethod method, DexMethod context, InvokeType type) {
-    return lookupMethod(method, context, type, null);
-  }
-
-  /**
-   * Lookup a rebound or non-rebound method reference using the current graph lens.
-   *
-   * @param codeLens Specifies the graph lens which has already been applied to the code object. The
-   *     lookup procedure will not recurse beyond this graph lens to ensure that each mapping is
-   *     applied at most once.
-   *     <p>Note: since the compiler currently inserts {@link ClearCodeRewritingGraphLens} it is
-   *     generally valid to pass null for the {@param codeLens}. The removal of {@link
-   *     ClearCodeRewritingGraphLens} is tracked by b/202368283. After this is removed, the compiler
-   *     should generally use the result of calling {@link AppView#codeLens()}.
-   */
-  public abstract MethodLookupResult lookupMethod(
-      DexMethod method, DexMethod context, InvokeType type, GraphLens codeLens);
-
-  protected abstract MethodLookupResult internalLookupMethod(
-      DexMethod reference,
-      DexMethod context,
-      InvokeType type,
-      GraphLens codeLens,
-      LookupMethodContinuation continuation);
-
-  interface LookupMethodContinuation {
-
-    MethodLookupResult lookupMethod(MethodLookupResult previous);
-  }
-
-  public final RewrittenPrototypeDescription lookupPrototypeChangesForMethodDefinition(
-      DexMethod method) {
-    return lookupPrototypeChangesForMethodDefinition(method, null);
-  }
-
-  public abstract RewrittenPrototypeDescription lookupPrototypeChangesForMethodDefinition(
-      DexMethod method, GraphLens codeLens);
-
-  public final DexField lookupField(DexField field) {
-    return lookupField(field, null);
-  }
-
-  /** Lookup a rebound or non-rebound field reference using the current graph lens. */
-  public DexField lookupField(DexField field, GraphLens codeLens) {
-    // Lookup the field using the graph lens and return the (non-rebound) reference from the lookup
-    // result.
-    return lookupFieldResult(field, codeLens).getReference();
-  }
-
-  /** Lookup a rebound or non-rebound field reference using the current graph lens. */
-  public final FieldLookupResult lookupFieldResult(DexField field) {
-    // Lookup the field using the graph lens and return the lookup result.
-    return lookupFieldResult(field, null);
-  }
-
-  /** Lookup a rebound or non-rebound field reference using the current graph lens. */
-  public final FieldLookupResult lookupFieldResult(DexField field, GraphLens codeLens) {
-    // Lookup the field using the graph lens and return the lookup result.
-    return internalLookupField(field, codeLens, x -> x);
-  }
-
-  protected abstract FieldLookupResult internalLookupField(
-      DexField reference, GraphLens codeLens, LookupFieldContinuation continuation);
-
-  interface LookupFieldContinuation {
-
-    FieldLookupResult lookupField(FieldLookupResult previous);
-  }
-
-  public DexReference lookupReference(DexReference reference) {
-    return reference.apply(this::lookupType, this::lookupField, this::lookupMethod);
-  }
-
-  // The method lookupMethod() maps a pair INVOKE=(method signature, invoke type) to a new pair
-  // INVOKE'=(method signature', invoke type'). This mapping can be context sensitive, meaning that
-  // the result INVOKE' depends on where the invocation INVOKE is in the program. This is, for
-  // example, used by the vertical class merger to translate invoke-super instructions that hit
-  // a method in the direct super class to invoke-direct instructions after class merging.
-  //
-  // This method can be used to determine if a graph lens is context sensitive. If a graph lens
-  // is context insensitive, it is safe to invoke lookupMethod() without a context (or to pass null
-  // as context). Trying to invoke a context sensitive graph lens without a context will lead to
-  // an assertion error.
-  public abstract boolean isContextFreeForMethods();
-
-  public boolean verifyIsContextFreeForMethod(DexMethod method) {
-    return isContextFreeForMethods();
-  }
-
-  public static GraphLens getIdentityLens() {
-    return IdentityGraphLens.getInstance();
-  }
-
-  public boolean hasCodeRewritings() {
-    return true;
-  }
-
-  public boolean hasCustomCodeRewritings() {
-    return false;
-  }
-
-  public boolean isAppliedLens() {
-    return false;
-  }
-
-  public boolean isArgumentPropagatorGraphLens() {
-    return false;
-  }
-
-  public boolean isClearCodeRewritingLens() {
-    return false;
-  }
-
-  public boolean isEnumUnboxerLens() {
-    return false;
-  }
-
-  public EnumUnboxingLens asEnumUnboxerLens() {
-    return null;
-  }
-
-  public boolean isHorizontalClassMergerGraphLens() {
-    return false;
-  }
-
-  public boolean isSimpleRenamingLens() {
-    return false;
-  }
-
-  public abstract boolean isIdentityLens();
-
-  public boolean isMemberRebindingLens() {
-    return false;
-  }
-
-  public MemberRebindingLens asMemberRebindingLens() {
-    return null;
-  }
-
-  public boolean isMemberRebindingIdentityLens() {
-    return false;
-  }
-
-  public MemberRebindingIdentityLens asMemberRebindingIdentityLens() {
-    return null;
-  }
-
-  public abstract boolean isNonIdentityLens();
-
-  public NonIdentityGraphLens asNonIdentityLens() {
-    return null;
-  }
-
-  public boolean isVerticalClassMergerLens() {
-    return false;
-  }
-
-  public GraphLens withCodeRewritingsApplied(DexItemFactory dexItemFactory) {
-    if (hasCodeRewritings()) {
-      return new ClearCodeRewritingGraphLens(dexItemFactory, this);
-    }
-    return this;
-  }
-
-  public <T extends DexDefinition> boolean assertDefinitionsNotModified(Iterable<T> definitions) {
-    for (DexDefinition definition : definitions) {
-      DexReference reference = definition.getReference();
-      // We allow changes to bridge methods as these get retargeted even if they are kept.
-      boolean isBridge =
-          definition.isDexEncodedMethod() && definition.asDexEncodedMethod().accessFlags.isBridge();
-      assert isBridge || lookupReference(reference) == reference;
-    }
-    return true;
-  }
-
-  public <T extends DexReference> boolean assertPinnedNotModified(
-      KeepInfoCollection keepInfo, InternalOptions options) {
-    List<DexReference> pinnedItems = new ArrayList<>();
-    keepInfo.forEachPinnedType(pinnedItems::add, options);
-    keepInfo.forEachPinnedMethod(pinnedItems::add, options);
-    keepInfo.forEachPinnedField(pinnedItems::add, options);
-    return assertReferencesNotModified(pinnedItems);
-  }
-
-  public <T extends DexReference> boolean assertReferencesNotModified(Iterable<T> references) {
-    for (DexReference reference : references) {
-      if (reference.isDexField()) {
-        DexField field = reference.asDexField();
-        assert getRenamedFieldSignature(field) == field;
-      } else if (reference.isDexMethod()) {
-        DexMethod method = reference.asDexMethod();
-        assert getRenamedMethodSignature(method) == method;
-      } else {
-        assert reference.isDexType();
-        DexType type = reference.asDexType();
-        assert lookupType(type) == type;
-      }
-    }
-    return true;
-  }
-
-  public Map<DexCallSite, ProgramMethodSet> rewriteCallSites(
-      Map<DexCallSite, ProgramMethodSet> callSites, DexDefinitionSupplier definitions) {
-    Map<DexCallSite, ProgramMethodSet> result = new IdentityHashMap<>();
-    LensCodeRewriterUtils rewriter = new LensCodeRewriterUtils(definitions, this, null);
-    callSites.forEach(
-        (callSite, contexts) -> {
-          for (ProgramMethod context : contexts.rewrittenWithLens(definitions, this)) {
-            DexCallSite rewrittenCallSite = rewriter.rewriteCallSite(callSite, context);
-            result
-                .computeIfAbsent(rewrittenCallSite, ignore -> ProgramMethodSet.create())
-                .add(context);
-          }
-        });
-    return result;
-  }
-
-  @SuppressWarnings("unchecked")
-  public <T extends DexReference> T rewriteReference(T reference) {
-    return rewriteReference(reference, null);
-  }
-
-  @SuppressWarnings("unchecked")
-  public <T extends DexReference> T rewriteReference(T reference, GraphLens codeLens) {
-    return (T)
-        reference.apply(
-            type -> lookupType(type, codeLens),
-            field -> getRenamedFieldSignature(field, codeLens),
-            method -> getRenamedMethodSignature(method, codeLens));
-  }
-
-  public <T extends DexReference> Set<T> rewriteReferences(Set<T> references) {
-    Set<T> result = SetUtils.newIdentityHashSet(references.size());
-    for (T reference : references) {
-      result.add(rewriteReference(reference));
-    }
-    return result;
-  }
-
-  public <R extends DexReference, T> Map<R, T> rewriteReferenceKeys(
-      Map<R, T> map, BiFunction<R, List<T>, T> merge) {
-    Map<R, T> result = new IdentityHashMap<>();
-    Map<R, List<T>> needsMerge = new IdentityHashMap<>();
-    map.forEach(
-        (reference, value) -> {
-          R rewrittenReference = rewriteReference(reference);
-          List<T> unmergedValues = needsMerge.get(rewrittenReference);
-          if (unmergedValues != null) {
-            unmergedValues.add(value);
-          } else {
-            T existingValue = result.put(rewrittenReference, value);
-            if (existingValue != null) {
-              // Remove this for now and let the merge function decide when all colliding values are
-              // known.
-              needsMerge.put(rewrittenReference, ListUtils.newArrayList(existingValue, value));
-              result.remove(rewrittenReference);
-            }
-          }
-        });
-    needsMerge.forEach(
-        (rewrittenReference, unmergedValues) -> {
-          T mergedValue = merge.apply(rewrittenReference, unmergedValues);
-          if (mergedValue != null) {
-            result.put(rewrittenReference, mergedValue);
-          }
-        });
-    return result;
-  }
-
-  public <T extends DexReference> Object2BooleanMap<T> rewriteReferenceKeys(
-      Object2BooleanMap<T> map) {
-    Object2BooleanMap<T> result = new Object2BooleanArrayMap<>();
-    for (Object2BooleanMap.Entry<T> entry : map.object2BooleanEntrySet()) {
-      result.put(rewriteReference(entry.getKey()), entry.getBooleanValue());
-    }
-    return result;
-  }
-
-  public <T> ImmutableMap<DexField, T> rewriteFieldKeys(Map<DexField, T> map) {
-    ImmutableMap.Builder<DexField, T> builder = ImmutableMap.builder();
-    map.forEach((field, value) -> builder.put(getRenamedFieldSignature(field), value));
-    return builder.build();
-  }
-
-  public ImmutableSet<DexType> rewriteTypes(Set<DexType> types) {
-    ImmutableSet.Builder<DexType> builder = new ImmutableSet.Builder<>();
-    for (DexType type : types) {
-      builder.add(lookupType(type));
-    }
-    return builder.build();
-  }
-
-  public <T> Map<DexType, T> rewriteTypeKeys(Map<DexType, T> map, BiFunction<T, T, T> merge) {
-    Map<DexType, T> newMap = new IdentityHashMap<>();
-    map.forEach(
-        (type, value) -> {
-          DexType rewrittenType = lookupType(type);
-          T previousValue = newMap.get(rewrittenType);
-          newMap.put(
-              rewrittenType, previousValue != null ? merge.apply(value, previousValue) : value);
-        });
-    return newMap;
-  }
-
-  public boolean verifyMappingToOriginalProgram(
-      AppView<?> appView, DexApplication originalApplication) {
-    Iterable<DexProgramClass> classes = appView.appInfo().classesWithDeterministicOrder();
-    // Collect all original fields and methods for efficient querying.
-    Set<DexField> originalFields = Sets.newIdentityHashSet();
-    Set<DexMethod> originalMethods = Sets.newIdentityHashSet();
-    for (DexProgramClass clazz : originalApplication.classes()) {
-      for (DexEncodedField field : clazz.fields()) {
-        originalFields.add(field.getReference());
-      }
-      for (DexEncodedMethod method : clazz.methods()) {
-        originalMethods.add(method.getReference());
-      }
-    }
-
-    // Check that all fields and methods in the generated program can be mapped back to one of the
-    // original fields or methods.
-    for (DexProgramClass clazz : classes) {
-      if (appView.appInfo().getSyntheticItems().isSyntheticClass(clazz)) {
-        continue;
-      }
-      for (DexEncodedField field : clazz.fields()) {
-        if (field.isD8R8Synthesized()) {
-          // Fields synthesized by D8/R8 may not be mapped.
-          continue;
-        }
-        DexField originalField = getOriginalFieldSignature(field.getReference());
-        assert originalFields.contains(originalField)
-            : "Unable to map field `"
-                + field.getReference().toSourceString()
-                + "` back to original program";
-      }
-      for (DexEncodedMethod method : clazz.methods()) {
-        if (method.isD8R8Synthesized()) {
-          // Methods synthesized by D8/R8 may not be mapped.
-          continue;
-        }
-        DexMethod originalMethod = getOriginalMethodSignature(method.getReference());
-        assert originalMethods.contains(originalMethod)
-            : "Method could not be mapped back: "
-                + method.toSourceString()
-                + ", originalMethod: "
-                + originalMethod.toSourceString();
-      }
-    }
-
-    return true;
-  }
-
-  public abstract static class NonIdentityGraphLens extends GraphLens {
-
-    private final DexItemFactory dexItemFactory;
-    private GraphLens previousLens;
-
-    private final Map<DexType, DexType> arrayTypeCache = new ConcurrentHashMap<>();
-
-    public NonIdentityGraphLens(AppView<?> appView) {
-      this(appView.dexItemFactory(), appView.graphLens());
-    }
-
-    public NonIdentityGraphLens(DexItemFactory dexItemFactory, GraphLens previousLens) {
-      this.dexItemFactory = dexItemFactory;
-      this.previousLens = previousLens;
-    }
-
-    public final DexItemFactory dexItemFactory() {
-      return dexItemFactory;
-    }
-
-    public final GraphLens getPrevious() {
-      return previousLens;
-    }
-
-    @SuppressWarnings("unchecked")
-    public final <T extends NonIdentityGraphLens> T find(
-        Predicate<NonIdentityGraphLens> predicate) {
-      GraphLens current = this;
-      while (current.isNonIdentityLens()) {
-        NonIdentityGraphLens nonIdentityGraphLens = current.asNonIdentityLens();
-        if (predicate.test(nonIdentityGraphLens)) {
-          return (T) nonIdentityGraphLens;
-        }
-        current = nonIdentityGraphLens.getPrevious();
-      }
-      return null;
-    }
-
-    @SuppressWarnings("unchecked")
-    public final <T extends NonIdentityGraphLens> T findPrevious(
-        Predicate<NonIdentityGraphLens> predicate) {
-      GraphLens previous = getPrevious();
-      return previous.isNonIdentityLens() ? previous.asNonIdentityLens().find(predicate) : null;
-    }
-
-    public final <T extends NonIdentityGraphLens> T findPreviousUntil(
-        Predicate<NonIdentityGraphLens> predicate,
-        Predicate<NonIdentityGraphLens> stoppingCriterion) {
-      T found = findPrevious(predicate.or(stoppingCriterion));
-      return (found == null || stoppingCriterion.test(found)) ? null : found;
-    }
-
-    public final void withAlternativeParentLens(GraphLens lens, Action action) {
-      GraphLens oldParent = getPrevious();
-      previousLens = lens;
-      action.execute();
-      previousLens = oldParent;
-    }
-
-    @Override
-    public MethodLookupResult lookupMethod(
-        DexMethod method, DexMethod context, InvokeType type, GraphLens codeLens) {
-      if (method.getHolderType().isArrayType()) {
-        assert lookupType(method.getReturnType()) == method.getReturnType();
-        assert method.getParameters().stream()
-            .allMatch(parameterType -> lookupType(parameterType) == parameterType);
-        return MethodLookupResult.builder(this)
-            .setReference(method.withHolder(lookupType(method.getHolderType()), dexItemFactory))
-            .setType(type)
-            .build();
-      }
-      assert method.getHolderType().isClassType();
-      return internalLookupMethod(method, context, type, codeLens, result -> result);
-    }
-
-    @Override
-    public String lookupPackageName(String pkg) {
-      return getPrevious().lookupPackageName(pkg);
-    }
-
-    @Override
-    public final DexType lookupType(DexType type, GraphLens applied) {
-      if (this == applied) {
-        return type;
-      }
-      if (type.isPrimitiveType() || type.isVoidType() || type.isNullValueType()) {
-        return type;
-      }
-      if (type.isArrayType()) {
-        DexType result = arrayTypeCache.get(type);
-        if (result == null) {
-          DexType baseType = type.toBaseType(dexItemFactory);
-          DexType newType = lookupType(baseType);
-          result = baseType == newType ? type : type.replaceBaseType(newType, dexItemFactory);
-          arrayTypeCache.put(type, result);
-        }
-        return result;
-      }
-      return lookupClassType(type);
-    }
-
-    @Override
-    public final DexType lookupClassType(DexType type, GraphLens applied) {
-      assert type.isClassType() : "Expected class type, but was `" + type.toSourceString() + "`";
-      if (this == applied) {
-        return type;
-      }
-      return internalDescribeLookupClassType(getPrevious().lookupClassType(type));
-    }
-
-    @Override
-    protected FieldLookupResult internalLookupField(
-        DexField reference, GraphLens codeLens, LookupFieldContinuation continuation) {
-      if (this == codeLens) {
-        return getIdentityLens().internalLookupField(reference, codeLens, continuation);
-      }
-      return previousLens.internalLookupField(
-          reference,
-          codeLens,
-          previous -> continuation.lookupField(internalDescribeLookupField(previous)));
-    }
-
-    @Override
-    protected MethodLookupResult internalLookupMethod(
-        DexMethod reference,
-        DexMethod context,
-        InvokeType type,
-        GraphLens codeLens,
-        LookupMethodContinuation continuation) {
-      if (this == codeLens) {
-        GraphLens identityLens = getIdentityLens();
-        return identityLens.internalLookupMethod(
-            reference, context, type, identityLens, continuation);
-      }
-      return previousLens.internalLookupMethod(
-          reference,
-          getPreviousMethodSignature(context),
-          type,
-          codeLens,
-          previous -> continuation.lookupMethod(internalDescribeLookupMethod(previous, context)));
-    }
-
-    protected abstract FieldLookupResult internalDescribeLookupField(FieldLookupResult previous);
-
-    protected abstract MethodLookupResult internalDescribeLookupMethod(
-        MethodLookupResult previous, DexMethod context);
-
-    protected abstract DexType internalDescribeLookupClassType(DexType previous);
-
-    public abstract DexMethod getPreviousMethodSignature(DexMethod method);
-
-    /***
-     * The previous mapping for a method often coincides with the previous method signature, but it
-     * may not, for example for bridges inserted in vertically merged classes where the original
-     * signature is used for computing invoke-super but should not be used for mapping output.
-     */
-    public DexMethod getPreviousMethodSignatureForMapping(DexMethod method) {
-      return getPreviousMethodSignature(method);
-    }
-
-    public abstract DexMethod getNextMethodSignature(DexMethod method);
-
-    @Override
-    public final boolean isIdentityLens() {
-      return false;
-    }
-
-    @Override
-    public final boolean isNonIdentityLens() {
-      return true;
-    }
-
-    @Override
-    public final NonIdentityGraphLens asNonIdentityLens() {
-      return this;
-    }
-  }
-
-  private static final class IdentityGraphLens extends GraphLens {
-
-    private static IdentityGraphLens INSTANCE = new IdentityGraphLens();
-
-    private IdentityGraphLens() {}
-
-    private static IdentityGraphLens getInstance() {
-      return INSTANCE;
-    }
-
-    @Override
-    public boolean isIdentityLens() {
-      return true;
-    }
-
-    @Override
-    public boolean isNonIdentityLens() {
-      return false;
-    }
-
-    @Override
-    public DexType getOriginalType(DexType type) {
-      return type;
-    }
-
-    @Override
-    public Iterable<DexType> getOriginalTypes(DexType type) {
-      return IterableUtils.singleton(type);
-    }
-
-    @Override
-    public DexField getOriginalFieldSignature(DexField field) {
-      return field;
-    }
-
-    @Override
-    public DexField getRenamedFieldSignature(DexField originalField, GraphLens codeLens) {
-      return originalField;
-    }
-
-    @Override
-    public DexMethod getRenamedMethodSignature(DexMethod originalMethod, GraphLens applied) {
-      return originalMethod;
-    }
-
-    @Override
-    public String lookupPackageName(String pkg) {
-      return pkg;
-    }
-
-    @Override
-    public DexType lookupType(DexType type, GraphLens applied) {
-      return type;
-    }
-
-    @Override
-    public DexType lookupClassType(DexType type, GraphLens applied) {
-      assert type.isClassType();
-      return type;
-    }
-
-    @Override
-    public MethodLookupResult lookupMethod(
-        DexMethod method, DexMethod context, InvokeType type, GraphLens codeLens) {
-      assert codeLens == null || codeLens.isIdentityLens();
-      return MethodLookupResult.builder(this).setReference(method).setType(type).build();
-    }
-
-    @Override
-    public RewrittenPrototypeDescription lookupPrototypeChangesForMethodDefinition(
-        DexMethod method, GraphLens codeLens) {
-      return RewrittenPrototypeDescription.none();
-    }
-
-    @Override
-    protected FieldLookupResult internalLookupField(
-        DexField reference, GraphLens codeLens, LookupFieldContinuation continuation) {
-      // Passes the field reference back to the next graph lens. The identity lens intentionally
-      // does not set the rebound field reference, since it does not know what that is.
-      return continuation.lookupField(
-          FieldLookupResult.builder(this).setReference(reference).build());
-    }
-
-    @Override
-    protected MethodLookupResult internalLookupMethod(
-        DexMethod reference,
-        DexMethod context,
-        InvokeType type,
-        GraphLens codeLens,
-        LookupMethodContinuation continuation) {
-      // Passes the method reference back to the next graph lens. The identity lens intentionally
-      // does not set the rebound method reference, since it does not know what that is.
-      return continuation.lookupMethod(lookupMethod(reference, context, type, codeLens));
-    }
-
-    @Override
-    public boolean isContextFreeForMethods() {
-      return true;
-    }
-
-    @Override
-    public boolean hasCodeRewritings() {
-      return false;
-    }
-  }
-
-  // This lens clears all code rewriting (lookup methods mimics identity lens behavior) but still
-  // relies on the previous lens for names (getRenamed/Original methods).
-  public static class ClearCodeRewritingGraphLens extends NonIdentityGraphLens {
-
-    public ClearCodeRewritingGraphLens(DexItemFactory dexItemFactory, GraphLens previousLens) {
-      super(dexItemFactory, previousLens);
-    }
-
-    @Override
-    public DexType getOriginalType(DexType type) {
-      return getPrevious().getOriginalType(type);
-    }
-
-    @Override
-    public Iterable<DexType> getOriginalTypes(DexType type) {
-      return getPrevious().getOriginalTypes(type);
-    }
-
-    @Override
-    public DexField getOriginalFieldSignature(DexField field) {
-      return getPrevious().getOriginalFieldSignature(field);
-    }
-
-    @Override
-    public DexField getRenamedFieldSignature(DexField originalField, GraphLens codeLens) {
-      return this != codeLens
-          ? getPrevious().getRenamedFieldSignature(originalField)
-          : originalField;
-    }
-
-    @Override
-    public DexMethod getRenamedMethodSignature(DexMethod originalMethod, GraphLens applied) {
-      return this != applied
-          ? getPrevious().getRenamedMethodSignature(originalMethod, applied)
-          : originalMethod;
-    }
-
-    @Override
-    public boolean isClearCodeRewritingLens() {
-      return true;
-    }
-
-    @Override
-    public RewrittenPrototypeDescription lookupPrototypeChangesForMethodDefinition(
-        DexMethod method, GraphLens codeLens) {
-      return getIdentityLens().lookupPrototypeChangesForMethodDefinition(method, codeLens);
-    }
-
-    @Override
-    public final DexType internalDescribeLookupClassType(DexType previous) {
-      return previous;
-    }
-
-    @Override
-    protected FieldLookupResult internalLookupField(
-        DexField reference, GraphLens codeLens, LookupFieldContinuation continuation) {
-      return getIdentityLens().internalLookupField(reference, codeLens, continuation);
-    }
-
-    @Override
-    protected FieldLookupResult internalDescribeLookupField(FieldLookupResult previous) {
-      throw new Unreachable();
-    }
-
-    @Override
-    protected MethodLookupResult internalLookupMethod(
-        DexMethod reference,
-        DexMethod context,
-        InvokeType type,
-        GraphLens codeLens,
-        LookupMethodContinuation continuation) {
-      assert codeLens == null || codeLens == this;
-      GraphLens identityLens = getIdentityLens();
-      return identityLens.internalLookupMethod(
-          reference, context, type, identityLens, continuation);
-    }
-
-    @Override
-    public MethodLookupResult internalDescribeLookupMethod(
-        MethodLookupResult previous, DexMethod context) {
-      throw new Unreachable();
-    }
-
-    @Override
-    public DexMethod getPreviousMethodSignature(DexMethod method) {
-      return method;
-    }
-
-    @Override
-    public DexMethod getNextMethodSignature(DexMethod method) {
-      return method;
-    }
-
-    @Override
-    public boolean isContextFreeForMethods() {
-      return getIdentityLens().isContextFreeForMethods();
-    }
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
index 368ffea..d9158fc 100644
--- a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
@@ -48,9 +48,9 @@
 import com.android.tools.r8.utils.StringUtils;
 import com.google.common.base.Equivalence.Wrapper;
 import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
@@ -203,7 +203,7 @@
       int typeRef,
       TypePath typePath) {
     assert annotations != null;
-    // Java 8 type annotations are not supported by Dex. Ignore them.
+    // Java 8 type annotations are not supported by DEX. Ignore them.
     if (!application.options.isGeneratingClassFiles()) {
       return null;
     }
@@ -252,7 +252,7 @@
     private NestHostClassAttribute nestHost = null;
     private final List<NestMemberClassAttribute> nestMembers = new ArrayList<>();
     private final List<PermittedSubclassAttribute> permittedSubclasses = new ArrayList<>();
-    private final Set<DexField> recordComponents = Sets.newIdentityHashSet();
+    private final List<RecordComponentInfo> recordComponents = new ArrayList<>();
     private EnclosingMethodAttribute enclosingMember = null;
     private final List<InnerClassAttribute> innerClasses = new ArrayList<>();
     private ClassSignature classSignature = ClassSignature.noSignature();
@@ -361,15 +361,7 @@
         String name, String descriptor, String signature) {
       assert name != null;
       assert descriptor != null;
-      // Javac generated record components are only the instance fields, so we just reuse the field
-      // to avoid duplicating the field and field signature rewriting logic.
-      DexField field =
-          application
-              .getFactory()
-              .createField(
-                  type, application.getTypeFromDescriptor(descriptor), application.getString(name));
-      recordComponents.add(field);
-      return super.visitRecordComponent(name, descriptor, signature);
+      return new CreateRecordComponentVisitor(this, name, descriptor, signature);
     }
 
     @Override
@@ -502,6 +494,7 @@
               nestHost,
               nestMembers,
               permittedSubclasses,
+              recordComponents,
               enclosingMember,
               innerClasses,
               classSignature,
@@ -568,18 +561,12 @@
         // so it's safe to compile even if there is a missmatch.
         return;
       }
-      // TODO(b/169645628): Change this logic if we start stripping the record components.
+      // TODO(b/274888318): Change this logic if we start stripping the record components.
       // Another approach would be to mark a bit in fields that are record components instead.
       String message = "Records are expected to have one record component per instance field.";
       if (recordComponents.size() != instanceFields.size()) {
         throw new CompilationError(message, origin);
       }
-      for (DexEncodedField instanceField : instanceFields) {
-        if (!recordComponents.contains(instanceField.getReference())) {
-          throw new CompilationError(
-              message + " Unmatched field " + instanceField.getReference() + ".", origin);
-        }
-      }
     }
 
     private ChecksumSupplier getChecksumSupplier(ClassKind<T> classKind) {
@@ -1172,6 +1159,66 @@
     }
   }
 
+  private static class CreateRecordComponentVisitor extends RecordComponentVisitor {
+    private final CreateDexClassVisitor<?> parent;
+    private final String name;
+    private final String descriptor;
+    private final DexField field;
+    private final FieldTypeSignature componentSignature;
+
+    public CreateRecordComponentVisitor(
+        CreateDexClassVisitor<?> parent, String name, String descriptor, String signature) {
+      super(ASM_VERSION);
+      this.field = parent.application.getField(parent.type, name, descriptor);
+      this.parent = parent;
+      this.name = name;
+      this.descriptor = descriptor;
+      this.componentSignature =
+          parent.application.options.parseSignatureAttribute()
+              ? GenericSignature.parseFieldTypeSignature(
+                  name,
+                  signature,
+                  parent.origin,
+                  parent.application.getFactory(),
+                  parent.application.options.reporter)
+              : FieldTypeSignature.noSignature();
+    }
+
+    private List<DexAnnotation> annotations = null;
+
+    private List<DexAnnotation> getAnnotations() {
+      if (annotations == null) {
+        annotations = new ArrayList<>();
+      }
+      return annotations;
+    }
+
+    @Override
+    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+      return createAnnotationVisitor(
+          desc, visible, getAnnotations(), parent.application, DexAnnotation::new);
+    }
+
+    @Override
+    public AnnotationVisitor visitTypeAnnotation(
+        int typeRef, TypePath typePath, String desc, boolean visible) {
+      // Java 8 type annotations are not supported by DEX, thus ignore them.
+      return null;
+    }
+
+    @Override
+    public void visitEnd() {
+      assert annotations == null || !annotations.isEmpty();
+      parent.recordComponents.add(
+          new RecordComponentInfo(
+              field,
+              componentSignature,
+              annotations != null && !annotations.isEmpty()
+                  ? annotations
+                  : Collections.emptyList()));
+    }
+  }
+
   public static class ReparseContext {
 
     // This will hold the content of the whole class. Once all the methods of the class are swapped
diff --git a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
index d393d72..e54e691 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
@@ -53,6 +53,7 @@
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.CfCode.LocalVariableInfo;
 import com.android.tools.r8.graph.JarClassFileReader.ReparseContext;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.IfType;
diff --git a/src/main/java/com/android/tools/r8/graph/MethodAccessInfoCollection.java b/src/main/java/com/android/tools/r8/graph/MethodAccessInfoCollection.java
index d6efacb..b4dbc3d 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodAccessInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodAccessInfoCollection.java
@@ -4,7 +4,8 @@
 
 package com.android.tools.r8.graph;
 
-import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.MethodLookupResult;
 import com.android.tools.r8.ir.code.InvokeType;
 import com.android.tools.r8.utils.ConsumerUtils;
 import com.android.tools.r8.utils.collections.ProgramMethodSet;
diff --git a/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollection.java b/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollection.java
index 300bca7..0edf837 100644
--- a/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollection.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.graph;
 
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.desugar.LambdaDescriptor;
 import com.android.tools.r8.utils.TraversalContinuation;
 import java.util.Set;
diff --git a/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollectionImpl.java b/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollectionImpl.java
index 98eab7f..45936b7 100644
--- a/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollectionImpl.java
+++ b/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollectionImpl.java
@@ -7,6 +7,7 @@
 import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
 import static com.android.tools.r8.utils.MapUtils.ignoreKey;
 
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.desugar.LambdaDescriptor;
 import com.android.tools.r8.shaking.GraphReporter;
 import com.android.tools.r8.shaking.InstantiationReason;
diff --git a/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java b/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java
index 028617e..9b37860 100644
--- a/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java
+++ b/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java
@@ -5,6 +5,8 @@
 
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.utils.Box;
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
index 32d7fd3..c1f869c 100644
--- a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
@@ -6,6 +6,7 @@
 import static com.android.tools.r8.ir.optimize.info.OptimizationFeedback.getSimpleFeedback;
 
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.NumberGenerator;
diff --git a/src/main/java/com/android/tools/r8/graph/RecordComponentInfo.java b/src/main/java/com/android/tools/r8/graph/RecordComponentInfo.java
new file mode 100644
index 0000000..c6ac18f
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/RecordComponentInfo.java
@@ -0,0 +1,101 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph;
+
+import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
+import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.utils.structural.StructuralItem;
+import com.android.tools.r8.utils.structural.StructuralMapping;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.BiConsumer;
+import java.util.function.Predicate;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.RecordComponentVisitor;
+
+public class RecordComponentInfo implements StructuralItem<RecordComponentInfo> {
+
+  private final DexField field;
+  private final FieldTypeSignature signature;
+  private final List<DexAnnotation> annotations;
+
+  private static void specify(StructuralSpecification<RecordComponentInfo, ?> spec) {
+    spec.withItem(RecordComponentInfo::getName).withItem(RecordComponentInfo::getType);
+  }
+
+  public RecordComponentInfo(
+      DexField field, FieldTypeSignature signature, List<DexAnnotation> annotations) {
+    assert field != null;
+    assert signature != null;
+    assert annotations != null;
+    this.field = field;
+    this.signature = signature;
+    this.annotations = annotations;
+  }
+
+  public static List<RecordComponentInfo> emptyList() {
+    return Collections.emptyList();
+  }
+
+  public DexField getField() {
+    return field;
+  }
+
+  public DexString getName() {
+    return field.getName();
+  }
+
+  public DexType getType() {
+    return field.getType();
+  }
+
+  public FieldTypeSignature getSignature() {
+    return signature;
+  }
+
+  public List<DexAnnotation> getAnnotations() {
+    return annotations;
+  }
+
+  public void write(
+      ClassWriter writer,
+      NamingLens lens,
+      Predicate<DexType> isTypeMissing,
+      BiConsumer<AnnotationVisitor, DexEncodedAnnotation> annotationWriter) {
+    RecordComponentVisitor v =
+        writer.visitRecordComponent(
+            lens.lookupName(field).toString(),
+            lens.lookupDescriptor(getType()).toString(),
+            signature.toRenamedString(lens, isTypeMissing));
+    for (DexAnnotation annotation : annotations) {
+      if (annotation.visibility == DexAnnotation.VISIBILITY_SYSTEM) {
+        // Annotations with VISIBILITY_SYSTEM are not annotations in CF, but are special
+        // annotations in DEX, i.e. default, enclosing class, enclosing method, member classes,
+        // signature, throws.
+        continue;
+      }
+      String desc = lens.lookupDescriptor(annotation.getAnnotationType()).toString();
+      boolean visible = annotation.visibility == DexAnnotation.VISIBILITY_RUNTIME;
+      AnnotationVisitor av = v.visitAnnotation(desc, visible);
+      if (av != null) {
+        annotationWriter.accept(av, annotation.annotation);
+        av.visitEnd();
+      }
+    }
+    v.visitEnd();
+  }
+
+  @Override
+  public RecordComponentInfo self() {
+    return this;
+  }
+
+  @Override
+  public StructuralMapping<RecordComponentInfo> getStructuralMapping() {
+    return RecordComponentInfo::specify;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/ThrowExceptionCode.java b/src/main/java/com/android/tools/r8/graph/ThrowExceptionCode.java
index 57baddf..383504d 100644
--- a/src/main/java/com/android/tools/r8/graph/ThrowExceptionCode.java
+++ b/src/main/java/com/android/tools/r8/graph/ThrowExceptionCode.java
@@ -13,6 +13,7 @@
 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.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.NumberGenerator;
diff --git a/src/main/java/com/android/tools/r8/graph/ThrowNullCode.java b/src/main/java/com/android/tools/r8/graph/ThrowNullCode.java
index a15e551..82f320c 100644
--- a/src/main/java/com/android/tools/r8/graph/ThrowNullCode.java
+++ b/src/main/java/com/android/tools/r8/graph/ThrowNullCode.java
@@ -12,6 +12,7 @@
 import com.android.tools.r8.dex.code.DexThrow;
 import com.android.tools.r8.graph.DexCode.Try;
 import com.android.tools.r8.graph.DexCode.TryHandler;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.NumberGenerator;
diff --git a/src/main/java/com/android/tools/r8/graph/TreeFixerBase.java b/src/main/java/com/android/tools/r8/graph/TreeFixerBase.java
index 7a6a5fc..f3cc3e9 100644
--- a/src/main/java/com/android/tools/r8/graph/TreeFixerBase.java
+++ b/src/main/java/com/android/tools/r8/graph/TreeFixerBase.java
@@ -108,6 +108,7 @@
             fixupNestHost(clazz.getNestHostClassAttribute()),
             fixupNestMemberAttributes(clazz.getNestMembersClassAttributes()),
             fixupPermittedSubclassAttribute(clazz.getPermittedSubclassAttributes()),
+            fixupRecordComponents(clazz.getRecordComponents()),
             fixupEnclosingMethodAttribute(clazz.getEnclosingMethodAttribute()),
             fixupInnerClassAttributes(clazz.getInnerClasses()),
             clazz.getClassSignature(),
@@ -289,6 +290,24 @@
     return changed ? newPermittedSubclassAttributes : permittedSubclassAttributes;
   }
 
+  protected List<RecordComponentInfo> fixupRecordComponents(
+      List<RecordComponentInfo> recordComponents) {
+    if (recordComponents.isEmpty()) {
+      return recordComponents;
+    }
+    // TODO(b/274888318): Check this.
+    boolean changed = false;
+    List<RecordComponentInfo> newRecordComponents = new ArrayList<>(recordComponents.size());
+    for (RecordComponentInfo info : recordComponents) {
+      DexField field = info.getField();
+      DexField newField = fixupFieldReference(field);
+      newRecordComponents.add(
+          new RecordComponentInfo(newField, info.getSignature(), info.getAnnotations()));
+      changed |= newField != field;
+    }
+    return changed ? newRecordComponents : recordComponents;
+  }
+
   /** Fixup a proto descriptor. */
   public DexProto fixupProto(DexProto proto) {
     DexProto result = protoFixupCache.get(proto);
diff --git a/src/main/java/com/android/tools/r8/graph/UseRegistry.java b/src/main/java/com/android/tools/r8/graph/UseRegistry.java
index be1b904c06..3797119 100644
--- a/src/main/java/com/android/tools/r8/graph/UseRegistry.java
+++ b/src/main/java/com/android/tools/r8/graph/UseRegistry.java
@@ -6,6 +6,7 @@
 import com.android.tools.r8.dex.code.CfOrDexInstanceFieldRead;
 import com.android.tools.r8.dex.code.CfOrDexInstruction;
 import com.android.tools.r8.dex.code.CfOrDexStaticFieldRead;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.code.InvokeType;
 import com.android.tools.r8.utils.TraversalContinuation;
 import java.util.ListIterator;
diff --git a/src/main/java/com/android/tools/r8/graph/AppliedGraphLens.java b/src/main/java/com/android/tools/r8/graph/lens/AppliedGraphLens.java
similarity index 91%
rename from src/main/java/com/android/tools/r8/graph/AppliedGraphLens.java
rename to src/main/java/com/android/tools/r8/graph/lens/AppliedGraphLens.java
index f360949..0e85802 100644
--- a/src/main/java/com/android/tools/r8/graph/AppliedGraphLens.java
+++ b/src/main/java/com/android/tools/r8/graph/lens/AppliedGraphLens.java
@@ -1,10 +1,17 @@
-// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-package com.android.tools.r8.graph;
+package com.android.tools.r8.graph.lens;
 
-import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexEncodedField;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
 import com.android.tools.r8.utils.MapUtils;
 import com.android.tools.r8.utils.collections.BidirectionalManyToOneRepresentativeHashMap;
@@ -25,7 +32,7 @@
  *
  * <p>The mappings from the original program to the generated program are kept, though.
  */
-public final class AppliedGraphLens extends NonIdentityGraphLens {
+public final class AppliedGraphLens extends DefaultNonIdentityGraphLens {
 
   private final MutableBidirectionalManyToOneRepresentativeMap<DexType, DexType> renamedTypeNames =
       BidirectionalManyToOneRepresentativeHashMap.newIdentityHashMap();
@@ -147,17 +154,6 @@
   }
 
   @Override
-  protected FieldLookupResult internalDescribeLookupField(FieldLookupResult previous) {
-    return previous;
-  }
-
-  @Override
-  public MethodLookupResult internalDescribeLookupMethod(
-      MethodLookupResult previous, DexMethod context) {
-    return previous;
-  }
-
-  @Override
   public DexMethod getPreviousMethodSignature(DexMethod method) {
     if (extraOriginalMethodSignatures.containsKey(method)) {
       return extraOriginalMethodSignatures.get(method);
diff --git a/src/main/java/com/android/tools/r8/graph/lens/ClearCodeRewritingGraphLens.java b/src/main/java/com/android/tools/r8/graph/lens/ClearCodeRewritingGraphLens.java
new file mode 100644
index 0000000..f63985a
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/lens/ClearCodeRewritingGraphLens.java
@@ -0,0 +1,78 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph.lens;
+
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
+import com.android.tools.r8.ir.code.InvokeType;
+
+// This lens clears all code rewriting (lookup methods mimics identity lens behavior) but still
+// relies on the previous lens for names (getRenamed/Original methods).
+public class ClearCodeRewritingGraphLens extends DefaultNonIdentityGraphLens {
+
+  public ClearCodeRewritingGraphLens(DexItemFactory dexItemFactory, GraphLens previousLens) {
+    super(dexItemFactory, previousLens);
+  }
+
+  @Override
+  public DexField getRenamedFieldSignature(DexField originalField, GraphLens codeLens) {
+    return this != codeLens ? getPrevious().getRenamedFieldSignature(originalField) : originalField;
+  }
+
+  @Override
+  public DexMethod getRenamedMethodSignature(DexMethod originalMethod, GraphLens applied) {
+    return this != applied
+        ? getPrevious().getRenamedMethodSignature(originalMethod, applied)
+        : originalMethod;
+  }
+
+  @Override
+  public boolean isClearCodeRewritingLens() {
+    return true;
+  }
+
+  @Override
+  public RewrittenPrototypeDescription lookupPrototypeChangesForMethodDefinition(
+      DexMethod method, GraphLens codeLens) {
+    return getIdentityLens().lookupPrototypeChangesForMethodDefinition(method, codeLens);
+  }
+
+  @Override
+  protected FieldLookupResult internalLookupField(
+      DexField reference, GraphLens codeLens, LookupFieldContinuation continuation) {
+    return getIdentityLens().internalLookupField(reference, codeLens, continuation);
+  }
+
+  @Override
+  protected FieldLookupResult internalDescribeLookupField(FieldLookupResult previous) {
+    throw new Unreachable();
+  }
+
+  @Override
+  protected MethodLookupResult internalLookupMethod(
+      DexMethod reference,
+      DexMethod context,
+      InvokeType type,
+      GraphLens codeLens,
+      LookupMethodContinuation continuation) {
+    assert codeLens == null || codeLens == this;
+    GraphLens identityLens = getIdentityLens();
+    return identityLens.internalLookupMethod(reference, context, type, identityLens, continuation);
+  }
+
+  @Override
+  public MethodLookupResult internalDescribeLookupMethod(
+      MethodLookupResult previous, DexMethod context) {
+    throw new Unreachable();
+  }
+
+  @Override
+  public boolean isContextFreeForMethods() {
+    return getIdentityLens().isContextFreeForMethods();
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/lens/DefaultNonIdentityGraphLens.java b/src/main/java/com/android/tools/r8/graph/lens/DefaultNonIdentityGraphLens.java
new file mode 100644
index 0000000..1f8f516
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/lens/DefaultNonIdentityGraphLens.java
@@ -0,0 +1,103 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph.lens;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
+
+public class DefaultNonIdentityGraphLens extends NonIdentityGraphLens {
+
+  public DefaultNonIdentityGraphLens(AppView<?> appView) {
+    this(appView.dexItemFactory(), appView.graphLens());
+  }
+
+  public DefaultNonIdentityGraphLens(DexItemFactory dexItemFactory, GraphLens previousLens) {
+    super(dexItemFactory, previousLens);
+  }
+
+  @Override
+  public boolean isContextFreeForMethods() {
+    return getPrevious().isContextFreeForMethods();
+  }
+
+  // Class lookup APIs.
+
+  @Override
+  protected DexType internalDescribeLookupClassType(DexType previous) {
+    return previous;
+  }
+
+  @Override
+  public DexType getOriginalType(DexType type) {
+    return getPrevious().getOriginalType(type);
+  }
+
+  @Override
+  public Iterable<DexType> getOriginalTypes(DexType type) {
+    return getPrevious().getOriginalTypes(type);
+  }
+
+  // Field lookup APIs.
+
+  @Override
+  protected FieldLookupResult internalDescribeLookupField(FieldLookupResult previous) {
+    return previous;
+  }
+
+  @Override
+  public DexField getOriginalFieldSignature(DexField field) {
+    return getPrevious().getOriginalFieldSignature(field);
+  }
+
+  @Override
+  public DexField getRenamedFieldSignature(DexField originalField, GraphLens codeLens) {
+    if (this == codeLens) {
+      return originalField;
+    }
+    return getPrevious().getRenamedFieldSignature(originalField);
+  }
+
+  // Method lookup APIs.
+
+  @Override
+  protected MethodLookupResult internalDescribeLookupMethod(
+      MethodLookupResult previous, DexMethod context) {
+    return previous;
+  }
+
+  @Override
+  public DexMethod getPreviousMethodSignature(DexMethod method) {
+    return method;
+  }
+
+  @Override
+  public DexMethod getNextMethodSignature(DexMethod method) {
+    return method;
+  }
+
+  @Override
+  public DexMethod getRenamedMethodSignature(DexMethod originalMethod, GraphLens codeLens) {
+    if (this == codeLens) {
+      return originalMethod;
+    }
+    return getNextMethodSignature(getPrevious().getRenamedMethodSignature(originalMethod));
+  }
+
+  // Prototype lookup APIs.
+
+  @Override
+  public RewrittenPrototypeDescription lookupPrototypeChangesForMethodDefinition(
+      DexMethod method, GraphLens codeLens) {
+    if (this == codeLens) {
+      return RewrittenPrototypeDescription.none();
+    }
+    DexMethod previousMethodSignature = getPreviousMethodSignature(method);
+    return getPrevious().lookupPrototypeChangesForMethodDefinition(previousMethodSignature);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/lens/FieldLookupResult.java b/src/main/java/com/android/tools/r8/graph/lens/FieldLookupResult.java
new file mode 100644
index 0000000..b031af1
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/lens/FieldLookupResult.java
@@ -0,0 +1,85 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph.lens;
+
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexType;
+import java.util.function.Function;
+
+/**
+ * Intermediate result of a field lookup that stores the actual non-rebound reference and the
+ * rebound reference that points to the definition of the field.
+ */
+public class FieldLookupResult extends MemberLookupResult<DexField> {
+
+  private final DexType readCastType;
+  private final DexType writeCastType;
+
+  private FieldLookupResult(
+      DexField reference, DexField reboundReference, DexType readCastType, DexType writeCastType) {
+    super(reference, reboundReference);
+    this.readCastType = readCastType;
+    this.writeCastType = writeCastType;
+  }
+
+  public static Builder builder(GraphLens lens) {
+    return new Builder(lens);
+  }
+
+  public boolean hasReadCastType() {
+    return readCastType != null;
+  }
+
+  public DexType getReadCastType() {
+    return readCastType;
+  }
+
+  public DexType getRewrittenReadCastType(Function<DexType, DexType> fn) {
+    return hasReadCastType() ? fn.apply(readCastType) : null;
+  }
+
+  public boolean hasWriteCastType() {
+    return writeCastType != null;
+  }
+
+  public DexType getWriteCastType() {
+    return writeCastType;
+  }
+
+  public DexType getRewrittenWriteCastType(Function<DexType, DexType> fn) {
+    return hasWriteCastType() ? fn.apply(writeCastType) : null;
+  }
+
+  public static class Builder extends MemberLookupResult.Builder<DexField, Builder> {
+
+    private DexType readCastType;
+    private DexType writeCastType;
+    private GraphLens lens;
+
+    private Builder(GraphLens lens) {
+      this.lens = lens;
+    }
+
+    public Builder setReadCastType(DexType readCastType) {
+      this.readCastType = readCastType;
+      return this;
+    }
+
+    public Builder setWriteCastType(DexType writeCastType) {
+      this.writeCastType = writeCastType;
+      return this;
+    }
+
+    @Override
+    public Builder self() {
+      return this;
+    }
+
+    public FieldLookupResult build() {
+      // TODO(b/168282032): All non-identity graph lenses should set the rebound reference.
+      return new FieldLookupResult(reference, reboundReference, readCastType, writeCastType);
+    }
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/FinalInitClassLens.java b/src/main/java/com/android/tools/r8/graph/lens/FinalInitClassLens.java
similarity index 85%
rename from src/main/java/com/android/tools/r8/graph/FinalInitClassLens.java
rename to src/main/java/com/android/tools/r8/graph/lens/FinalInitClassLens.java
index 07e4dc2..54949fa 100644
--- a/src/main/java/com/android/tools/r8/graph/FinalInitClassLens.java
+++ b/src/main/java/com/android/tools/r8/graph/lens/FinalInitClassLens.java
@@ -1,10 +1,12 @@
-// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-package com.android.tools.r8.graph;
+package com.android.tools.r8.graph.lens;
 
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexType;
 import java.util.Map;
 
 public class FinalInitClassLens extends InitClassLens {
diff --git a/src/main/java/com/android/tools/r8/graph/lens/GraphLens.java b/src/main/java/com/android/tools/r8/graph/lens/GraphLens.java
new file mode 100644
index 0000000..bd71700
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/lens/GraphLens.java
@@ -0,0 +1,645 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.graph.lens;
+
+import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.graph.DexCallSite;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexDefinition;
+import com.android.tools.r8.graph.DexDefinitionSupplier;
+import com.android.tools.r8.graph.DexEncodedField;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMember;
+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.ProgramMethod;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
+import com.android.tools.r8.ir.code.InvokeType;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import com.android.tools.r8.ir.optimize.enums.EnumUnboxingLens;
+import com.android.tools.r8.optimize.MemberRebindingIdentityLens;
+import com.android.tools.r8.optimize.MemberRebindingLens;
+import com.android.tools.r8.shaking.KeepInfoCollection;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.ListUtils;
+import com.android.tools.r8.utils.SetUtils;
+import com.android.tools.r8.utils.collections.BidirectionalManyToOneRepresentativeHashMap;
+import com.android.tools.r8.utils.collections.MutableBidirectionalManyToOneRepresentativeMap;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import it.unimi.dsi.fastutil.objects.Object2BooleanArrayMap;
+import it.unimi.dsi.fastutil.objects.Object2BooleanMap;
+import java.util.ArrayList;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.BiFunction;
+
+/**
+ * A GraphLens implements a virtual view on top of the graph, used to delay global rewrites until
+ * later IR processing stages.
+ *
+ * <p>Valid remappings are limited to the following operations:
+ *
+ * <ul>
+ *   <li>Mapping a classes type to one of the super/subtypes.
+ *   <li>Renaming private methods/fields.
+ *   <li>Moving methods/fields to a super/subclass.
+ *   <li>Replacing method/field references by the same method/field on a super/subtype
+ *   <li>Moved methods might require changed invocation type at the call site
+ * </ul>
+ *
+ * Note that the latter two have to take visibility into account.
+ */
+public abstract class GraphLens {
+
+  public abstract static class Builder {
+
+    protected final MutableBidirectionalManyToOneRepresentativeMap<DexField, DexField> fieldMap =
+        BidirectionalManyToOneRepresentativeHashMap.newIdentityHashMap();
+    protected final MutableBidirectionalManyToOneRepresentativeMap<DexMethod, DexMethod> methodMap =
+        BidirectionalManyToOneRepresentativeHashMap.newIdentityHashMap();
+    protected final Map<DexType, DexType> typeMap = new IdentityHashMap<>();
+
+    protected Builder() {}
+
+    public void map(DexType from, DexType to) {
+      if (from == to) {
+        return;
+      }
+      typeMap.put(from, to);
+    }
+
+    public void move(DexMethod from, DexMethod to) {
+      if (from == to) {
+        return;
+      }
+      methodMap.put(from, to);
+    }
+
+    public void move(DexField from, DexField to) {
+      if (from == to) {
+        return;
+      }
+      fieldMap.put(from, to);
+    }
+
+    public abstract GraphLens build(AppView<?> appView);
+  }
+
+  /**
+   * Intentionally package private. All graph lenses except for {@link IdentityGraphLens} should
+   * inherit from {@link NonIdentityGraphLens}.
+   */
+  GraphLens() {}
+
+  public boolean isSyntheticFinalizationGraphLens() {
+    return false;
+  }
+
+  public abstract DexType getOriginalType(DexType type);
+
+  public abstract Iterable<DexType> getOriginalTypes(DexType type);
+
+  public abstract DexField getOriginalFieldSignature(DexField field);
+
+  public final DexMember<?, ?> getOriginalMemberSignature(DexMember<?, ?> member) {
+    return member.apply(this::getOriginalFieldSignature, this::getOriginalMethodSignature);
+  }
+
+  public final DexMethod getOriginalMethodSignature(DexMethod method) {
+    return getOriginalMethodSignature(method, null);
+  }
+
+  public final DexMethod getOriginalMethodSignature(DexMethod method, GraphLens atGraphLens) {
+    GraphLens current = this;
+    DexMethod original = method;
+    while (current.isNonIdentityLens() && current != atGraphLens) {
+      NonIdentityGraphLens nonIdentityLens = current.asNonIdentityLens();
+      original = nonIdentityLens.getPreviousMethodSignature(original);
+      current = nonIdentityLens.getPrevious();
+    }
+    assert atGraphLens == null ? current.isIdentityLens() : (current == atGraphLens);
+    return original;
+  }
+
+  public final DexMethod getOriginalMethodSignatureForMapping(DexMethod method) {
+    GraphLens current = this;
+    DexMethod original = method;
+    while (current.isNonIdentityLens()) {
+      NonIdentityGraphLens nonIdentityLens = current.asNonIdentityLens();
+      original = nonIdentityLens.getPreviousMethodSignatureForMapping(original);
+      current = nonIdentityLens.getPrevious();
+    }
+    assert current.isIdentityLens();
+    return original;
+  }
+
+  public final DexField getRenamedFieldSignature(DexField originalField) {
+    return getRenamedFieldSignature(originalField, null);
+  }
+
+  public abstract DexField getRenamedFieldSignature(DexField originalField, GraphLens codeLens);
+
+  public final DexMember<?, ?> getRenamedMemberSignature(DexMember<?, ?> originalMember) {
+    return originalMember.isDexField()
+        ? getRenamedFieldSignature(originalMember.asDexField())
+        : getRenamedMethodSignature(originalMember.asDexMethod());
+  }
+
+  public final DexMethod getRenamedMethodSignature(DexMethod originalMethod) {
+    return getRenamedMethodSignature(originalMethod, null);
+  }
+
+  public abstract DexMethod getRenamedMethodSignature(DexMethod originalMethod, GraphLens applied);
+
+  public DexEncodedMethod mapDexEncodedMethod(
+      DexEncodedMethod originalEncodedMethod, DexDefinitionSupplier definitions) {
+    return mapDexEncodedMethod(originalEncodedMethod, definitions, null);
+  }
+
+  public DexEncodedMethod mapDexEncodedMethod(
+      DexEncodedMethod originalEncodedMethod,
+      DexDefinitionSupplier definitions,
+      GraphLens applied) {
+    assert originalEncodedMethod != DexEncodedMethod.SENTINEL;
+    DexMethod newMethod = getRenamedMethodSignature(originalEncodedMethod.getReference(), applied);
+    // Note that:
+    // * Even if `newMethod` is the same as `originalEncodedMethod.method`, we still need to look it
+    //   up, since `originalEncodedMethod` may be obsolete.
+    // * We can't directly use AppInfo#definitionFor(DexMethod) since definitions may not be
+    //   updated either yet.
+    DexClass newHolder = definitions.definitionFor(newMethod.holder);
+    assert newHolder != null;
+    DexEncodedMethod newEncodedMethod = newHolder.lookupMethod(newMethod);
+    assert newEncodedMethod != null;
+    return newEncodedMethod;
+  }
+
+  public ProgramMethod mapProgramMethod(
+      ProgramMethod oldMethod, DexDefinitionSupplier definitions) {
+    DexMethod newMethod = getRenamedMethodSignature(oldMethod.getReference());
+    DexProgramClass holder = asProgramClassOrNull(definitions.definitionForHolder(newMethod));
+    return newMethod.lookupOnProgramClass(holder);
+  }
+
+  // Predicate indicating if a rewritten reference is a simple renaming, meaning the move from one
+  // reference to another is simply either just a renaming or/also renaming of the references. In
+  // other words, the content of the definition, including the definition of all of its members is
+  // the same modulo the renaming.
+  public <T extends DexReference> boolean isSimpleRenaming(T from, T to) {
+    assert from != to;
+    return false;
+  }
+
+  // Predicate to see if a method definition is only changed by repackaging or synthetic
+  // finalization indicating that it is a simple renaming.
+  public final boolean isSimpleRenaming(DexMethod method) {
+    DexMethod methodToCompareAgainst = method;
+    DexMethod original = method;
+    GraphLens current = this;
+    while (current.isNonIdentityLens()) {
+      NonIdentityGraphLens nonIdentityLens = current.asNonIdentityLens();
+      original = nonIdentityLens.getPreviousMethodSignature(original);
+      if (current.isSimpleRenamingLens()) {
+        methodToCompareAgainst = original;
+      } else if (methodToCompareAgainst != original) {
+        return false;
+      }
+      assert nonIdentityLens.getPrevious() != null;
+      current = nonIdentityLens.getPrevious();
+    }
+    return true;
+  }
+
+  public abstract String lookupPackageName(String pkg);
+
+  public DexType lookupClassType(DexType type) {
+    return lookupClassType(type, getIdentityLens());
+  }
+
+  public abstract DexType lookupClassType(DexType type, GraphLens applied);
+
+  public DexType lookupType(DexType type) {
+    return lookupType(type, getIdentityLens());
+  }
+
+  public abstract DexType lookupType(DexType type, GraphLens applied);
+
+  @Deprecated
+  public final DexMethod lookupMethod(DexMethod method) {
+    assert verifyIsContextFreeForMethod(method);
+    return lookupMethod(method, null, null).getReference();
+  }
+
+  public final MethodLookupResult lookupInvokeDirect(DexMethod method, ProgramMethod context) {
+    return lookupMethod(method, context.getReference(), InvokeType.DIRECT);
+  }
+
+  public final MethodLookupResult lookupInvokeDirect(
+      DexMethod method, ProgramMethod context, GraphLens codeLens) {
+    return lookupMethod(method, context.getReference(), InvokeType.DIRECT, codeLens);
+  }
+
+  public final MethodLookupResult lookupInvokeInterface(DexMethod method, ProgramMethod context) {
+    return lookupMethod(method, context.getReference(), InvokeType.INTERFACE);
+  }
+
+  public final MethodLookupResult lookupInvokeInterface(
+      DexMethod method, ProgramMethod context, GraphLens codeLens) {
+    return lookupMethod(method, context.getReference(), InvokeType.INTERFACE, codeLens);
+  }
+
+  public final MethodLookupResult lookupInvokeStatic(DexMethod method, ProgramMethod context) {
+    return lookupMethod(method, context.getReference(), InvokeType.STATIC);
+  }
+
+  public final MethodLookupResult lookupInvokeStatic(
+      DexMethod method, ProgramMethod context, GraphLens codeLens) {
+    return lookupMethod(method, context.getReference(), InvokeType.STATIC, codeLens);
+  }
+
+  public final MethodLookupResult lookupInvokeSuper(DexMethod method, ProgramMethod context) {
+    return lookupMethod(method, context.getReference(), InvokeType.SUPER);
+  }
+
+  public final MethodLookupResult lookupInvokeSuper(
+      DexMethod method, ProgramMethod context, GraphLens codeLens) {
+    return lookupMethod(method, context.getReference(), InvokeType.SUPER, codeLens);
+  }
+
+  public final MethodLookupResult lookupInvokeVirtual(DexMethod method, ProgramMethod context) {
+    return lookupMethod(method, context.getReference(), InvokeType.VIRTUAL);
+  }
+
+  public final MethodLookupResult lookupInvokeVirtual(
+      DexMethod method, ProgramMethod context, GraphLens codeLens) {
+    return lookupMethod(method, context.getReference(), InvokeType.VIRTUAL, codeLens);
+  }
+
+  public final MethodLookupResult lookupMethod(
+      DexMethod method, DexMethod context, InvokeType type) {
+    return lookupMethod(method, context, type, null);
+  }
+
+  /**
+   * Lookup a rebound or non-rebound method reference using the current graph lens.
+   *
+   * @param codeLens Specifies the graph lens which has already been applied to the code object. The
+   *     lookup procedure will not recurse beyond this graph lens to ensure that each mapping is
+   *     applied at most once.
+   *     <p>Note: since the compiler currently inserts {@link ClearCodeRewritingGraphLens} it is
+   *     generally valid to pass null for the {@param codeLens}. The removal of {@link
+   *     ClearCodeRewritingGraphLens} is tracked by b/202368283. After this is removed, the compiler
+   *     should generally use the result of calling {@link AppView#codeLens()}.
+   */
+  public abstract MethodLookupResult lookupMethod(
+      DexMethod method, DexMethod context, InvokeType type, GraphLens codeLens);
+
+  protected abstract MethodLookupResult internalLookupMethod(
+      DexMethod reference,
+      DexMethod context,
+      InvokeType type,
+      GraphLens codeLens,
+      LookupMethodContinuation continuation);
+
+  interface LookupMethodContinuation {
+
+    MethodLookupResult lookupMethod(MethodLookupResult previous);
+  }
+
+  public final RewrittenPrototypeDescription lookupPrototypeChangesForMethodDefinition(
+      DexMethod method) {
+    return lookupPrototypeChangesForMethodDefinition(method, null);
+  }
+
+  public abstract RewrittenPrototypeDescription lookupPrototypeChangesForMethodDefinition(
+      DexMethod method, GraphLens codeLens);
+
+  public final DexField lookupField(DexField field) {
+    return lookupField(field, null);
+  }
+
+  /** Lookup a rebound or non-rebound field reference using the current graph lens. */
+  public DexField lookupField(DexField field, GraphLens codeLens) {
+    // Lookup the field using the graph lens and return the (non-rebound) reference from the lookup
+    // result.
+    return lookupFieldResult(field, codeLens).getReference();
+  }
+
+  /** Lookup a rebound or non-rebound field reference using the current graph lens. */
+  public final FieldLookupResult lookupFieldResult(DexField field) {
+    // Lookup the field using the graph lens and return the lookup result.
+    return lookupFieldResult(field, null);
+  }
+
+  /** Lookup a rebound or non-rebound field reference using the current graph lens. */
+  public final FieldLookupResult lookupFieldResult(DexField field, GraphLens codeLens) {
+    // Lookup the field using the graph lens and return the lookup result.
+    return internalLookupField(field, codeLens, x -> x);
+  }
+
+  protected abstract FieldLookupResult internalLookupField(
+      DexField reference, GraphLens codeLens, LookupFieldContinuation continuation);
+
+  interface LookupFieldContinuation {
+
+    FieldLookupResult lookupField(FieldLookupResult previous);
+  }
+
+  public DexReference lookupReference(DexReference reference) {
+    return reference.apply(this::lookupType, this::lookupField, this::lookupMethod);
+  }
+
+  // The method lookupMethod() maps a pair INVOKE=(method signature, invoke type) to a new pair
+  // INVOKE'=(method signature', invoke type'). This mapping can be context sensitive, meaning that
+  // the result INVOKE' depends on where the invocation INVOKE is in the program. This is, for
+  // example, used by the vertical class merger to translate invoke-super instructions that hit
+  // a method in the direct super class to invoke-direct instructions after class merging.
+  //
+  // This method can be used to determine if a graph lens is context sensitive. If a graph lens
+  // is context insensitive, it is safe to invoke lookupMethod() without a context (or to pass null
+  // as context). Trying to invoke a context sensitive graph lens without a context will lead to
+  // an assertion error.
+  public abstract boolean isContextFreeForMethods();
+
+  public boolean verifyIsContextFreeForMethod(DexMethod method) {
+    return isContextFreeForMethods();
+  }
+
+  public static GraphLens getIdentityLens() {
+    return IdentityGraphLens.getInstance();
+  }
+
+  public boolean hasCodeRewritings() {
+    return true;
+  }
+
+  public boolean hasCustomCodeRewritings() {
+    return false;
+  }
+
+  public boolean isAppliedLens() {
+    return false;
+  }
+
+  public boolean isArgumentPropagatorGraphLens() {
+    return false;
+  }
+
+  public boolean isClearCodeRewritingLens() {
+    return false;
+  }
+
+  public boolean isEnumUnboxerLens() {
+    return false;
+  }
+
+  public EnumUnboxingLens asEnumUnboxerLens() {
+    return null;
+  }
+
+  public boolean isHorizontalClassMergerGraphLens() {
+    return false;
+  }
+
+  public boolean isSimpleRenamingLens() {
+    return false;
+  }
+
+  public abstract boolean isIdentityLens();
+
+  public boolean isMemberRebindingLens() {
+    return false;
+  }
+
+  public MemberRebindingLens asMemberRebindingLens() {
+    return null;
+  }
+
+  public boolean isMemberRebindingIdentityLens() {
+    return false;
+  }
+
+  public MemberRebindingIdentityLens asMemberRebindingIdentityLens() {
+    return null;
+  }
+
+  public abstract boolean isNonIdentityLens();
+
+  public NonIdentityGraphLens asNonIdentityLens() {
+    return null;
+  }
+
+  public boolean isVerticalClassMergerLens() {
+    return false;
+  }
+
+  public GraphLens withCodeRewritingsApplied(DexItemFactory dexItemFactory) {
+    if (hasCodeRewritings()) {
+      return new ClearCodeRewritingGraphLens(dexItemFactory, this);
+    }
+    return this;
+  }
+
+  public <T extends DexDefinition> boolean assertDefinitionsNotModified(Iterable<T> definitions) {
+    for (DexDefinition definition : definitions) {
+      DexReference reference = definition.getReference();
+      // We allow changes to bridge methods as these get retargeted even if they are kept.
+      boolean isBridge =
+          definition.isDexEncodedMethod() && definition.asDexEncodedMethod().accessFlags.isBridge();
+      assert isBridge || lookupReference(reference) == reference;
+    }
+    return true;
+  }
+
+  public <T extends DexReference> boolean assertPinnedNotModified(
+      KeepInfoCollection keepInfo, InternalOptions options) {
+    List<DexReference> pinnedItems = new ArrayList<>();
+    keepInfo.forEachPinnedType(pinnedItems::add, options);
+    keepInfo.forEachPinnedMethod(pinnedItems::add, options);
+    keepInfo.forEachPinnedField(pinnedItems::add, options);
+    return assertReferencesNotModified(pinnedItems);
+  }
+
+  public <T extends DexReference> boolean assertReferencesNotModified(Iterable<T> references) {
+    for (DexReference reference : references) {
+      if (reference.isDexField()) {
+        DexField field = reference.asDexField();
+        assert getRenamedFieldSignature(field) == field;
+      } else if (reference.isDexMethod()) {
+        DexMethod method = reference.asDexMethod();
+        assert getRenamedMethodSignature(method) == method;
+      } else {
+        assert reference.isDexType();
+        DexType type = reference.asDexType();
+        assert lookupType(type) == type;
+      }
+    }
+    return true;
+  }
+
+  public Map<DexCallSite, ProgramMethodSet> rewriteCallSites(
+      Map<DexCallSite, ProgramMethodSet> callSites, DexDefinitionSupplier definitions) {
+    Map<DexCallSite, ProgramMethodSet> result = new IdentityHashMap<>();
+    LensCodeRewriterUtils rewriter = new LensCodeRewriterUtils(definitions, this, null);
+    callSites.forEach(
+        (callSite, contexts) -> {
+          for (ProgramMethod context : contexts.rewrittenWithLens(definitions, this)) {
+            DexCallSite rewrittenCallSite = rewriter.rewriteCallSite(callSite, context);
+            result
+                .computeIfAbsent(rewrittenCallSite, ignore -> ProgramMethodSet.create())
+                .add(context);
+          }
+        });
+    return result;
+  }
+
+  @SuppressWarnings("unchecked")
+  public <T extends DexReference> T rewriteReference(T reference) {
+    return rewriteReference(reference, null);
+  }
+
+  @SuppressWarnings("unchecked")
+  public <T extends DexReference> T rewriteReference(T reference, GraphLens codeLens) {
+    return (T)
+        reference.apply(
+            type -> lookupType(type, codeLens),
+            field -> getRenamedFieldSignature(field, codeLens),
+            method -> getRenamedMethodSignature(method, codeLens));
+  }
+
+  public <T extends DexReference> Set<T> rewriteReferences(Set<T> references) {
+    Set<T> result = SetUtils.newIdentityHashSet(references.size());
+    for (T reference : references) {
+      result.add(rewriteReference(reference));
+    }
+    return result;
+  }
+
+  public <R extends DexReference, T> Map<R, T> rewriteReferenceKeys(
+      Map<R, T> map, BiFunction<R, List<T>, T> merge) {
+    Map<R, T> result = new IdentityHashMap<>();
+    Map<R, List<T>> needsMerge = new IdentityHashMap<>();
+    map.forEach(
+        (reference, value) -> {
+          R rewrittenReference = rewriteReference(reference);
+          List<T> unmergedValues = needsMerge.get(rewrittenReference);
+          if (unmergedValues != null) {
+            unmergedValues.add(value);
+          } else {
+            T existingValue = result.put(rewrittenReference, value);
+            if (existingValue != null) {
+              // Remove this for now and let the merge function decide when all colliding values are
+              // known.
+              needsMerge.put(rewrittenReference, ListUtils.newArrayList(existingValue, value));
+              result.remove(rewrittenReference);
+            }
+          }
+        });
+    needsMerge.forEach(
+        (rewrittenReference, unmergedValues) -> {
+          T mergedValue = merge.apply(rewrittenReference, unmergedValues);
+          if (mergedValue != null) {
+            result.put(rewrittenReference, mergedValue);
+          }
+        });
+    return result;
+  }
+
+  public <T extends DexReference> Object2BooleanMap<T> rewriteReferenceKeys(
+      Object2BooleanMap<T> map) {
+    Object2BooleanMap<T> result = new Object2BooleanArrayMap<>();
+    for (Object2BooleanMap.Entry<T> entry : map.object2BooleanEntrySet()) {
+      result.put(rewriteReference(entry.getKey()), entry.getBooleanValue());
+    }
+    return result;
+  }
+
+  public <T> ImmutableMap<DexField, T> rewriteFieldKeys(Map<DexField, T> map) {
+    ImmutableMap.Builder<DexField, T> builder = ImmutableMap.builder();
+    map.forEach((field, value) -> builder.put(getRenamedFieldSignature(field), value));
+    return builder.build();
+  }
+
+  public ImmutableSet<DexType> rewriteTypes(Set<DexType> types) {
+    ImmutableSet.Builder<DexType> builder = new ImmutableSet.Builder<>();
+    for (DexType type : types) {
+      builder.add(lookupType(type));
+    }
+    return builder.build();
+  }
+
+  public <T> Map<DexType, T> rewriteTypeKeys(Map<DexType, T> map, BiFunction<T, T, T> merge) {
+    Map<DexType, T> newMap = new IdentityHashMap<>();
+    map.forEach(
+        (type, value) -> {
+          DexType rewrittenType = lookupType(type);
+          T previousValue = newMap.get(rewrittenType);
+          newMap.put(
+              rewrittenType, previousValue != null ? merge.apply(value, previousValue) : value);
+        });
+    return newMap;
+  }
+
+  public boolean verifyMappingToOriginalProgram(
+      AppView<?> appView, DexApplication originalApplication) {
+    Iterable<DexProgramClass> classes = appView.appInfo().classesWithDeterministicOrder();
+    // Collect all original fields and methods for efficient querying.
+    Set<DexField> originalFields = Sets.newIdentityHashSet();
+    Set<DexMethod> originalMethods = Sets.newIdentityHashSet();
+    for (DexProgramClass clazz : originalApplication.classes()) {
+      for (DexEncodedField field : clazz.fields()) {
+        originalFields.add(field.getReference());
+      }
+      for (DexEncodedMethod method : clazz.methods()) {
+        originalMethods.add(method.getReference());
+      }
+    }
+
+    // Check that all fields and methods in the generated program can be mapped back to one of the
+    // original fields or methods.
+    for (DexProgramClass clazz : classes) {
+      if (appView.appInfo().getSyntheticItems().isSyntheticClass(clazz)) {
+        continue;
+      }
+      for (DexEncodedField field : clazz.fields()) {
+        if (field.isD8R8Synthesized()) {
+          // Fields synthesized by D8/R8 may not be mapped.
+          continue;
+        }
+        DexField originalField = getOriginalFieldSignature(field.getReference());
+        assert originalFields.contains(originalField)
+            : "Unable to map field `"
+                + field.getReference().toSourceString()
+                + "` back to original program";
+      }
+      for (DexEncodedMethod method : clazz.methods()) {
+        if (method.isD8R8Synthesized()) {
+          // Methods synthesized by D8/R8 may not be mapped.
+          continue;
+        }
+        DexMethod originalMethod = getOriginalMethodSignature(method.getReference());
+        assert originalMethods.contains(originalMethod)
+            : "Method could not be mapped back: "
+                + method.toSourceString()
+                + ", originalMethod: "
+                + originalMethod.toSourceString();
+      }
+    }
+
+    return true;
+  }
+
+}
diff --git a/src/main/java/com/android/tools/r8/graph/lens/IdentityGraphLens.java b/src/main/java/com/android/tools/r8/graph/lens/IdentityGraphLens.java
new file mode 100644
index 0000000..ce9aca7
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/lens/IdentityGraphLens.java
@@ -0,0 +1,118 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph.lens;
+
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
+import com.android.tools.r8.ir.code.InvokeType;
+import com.android.tools.r8.utils.IterableUtils;
+
+final class IdentityGraphLens extends GraphLens {
+
+  private static IdentityGraphLens INSTANCE = new IdentityGraphLens();
+
+  private IdentityGraphLens() {}
+
+  static IdentityGraphLens getInstance() {
+    return INSTANCE;
+  }
+
+  @Override
+  public boolean isIdentityLens() {
+    return true;
+  }
+
+  @Override
+  public boolean isNonIdentityLens() {
+    return false;
+  }
+
+  @Override
+  public DexType getOriginalType(DexType type) {
+    return type;
+  }
+
+  @Override
+  public Iterable<DexType> getOriginalTypes(DexType type) {
+    return IterableUtils.singleton(type);
+  }
+
+  @Override
+  public DexField getOriginalFieldSignature(DexField field) {
+    return field;
+  }
+
+  @Override
+  public DexField getRenamedFieldSignature(DexField originalField, GraphLens codeLens) {
+    return originalField;
+  }
+
+  @Override
+  public DexMethod getRenamedMethodSignature(DexMethod originalMethod, GraphLens applied) {
+    return originalMethod;
+  }
+
+  @Override
+  public String lookupPackageName(String pkg) {
+    return pkg;
+  }
+
+  @Override
+  public DexType lookupType(DexType type, GraphLens applied) {
+    return type;
+  }
+
+  @Override
+  public DexType lookupClassType(DexType type, GraphLens applied) {
+    assert type.isClassType();
+    return type;
+  }
+
+  @Override
+  public MethodLookupResult lookupMethod(
+      DexMethod method, DexMethod context, InvokeType type, GraphLens codeLens) {
+    assert codeLens == null || codeLens.isIdentityLens();
+    return MethodLookupResult.builder(this).setReference(method).setType(type).build();
+  }
+
+  @Override
+  public RewrittenPrototypeDescription lookupPrototypeChangesForMethodDefinition(
+      DexMethod method, GraphLens codeLens) {
+    return RewrittenPrototypeDescription.none();
+  }
+
+  @Override
+  protected FieldLookupResult internalLookupField(
+      DexField reference, GraphLens codeLens, LookupFieldContinuation continuation) {
+    // Passes the field reference back to the next graph lens. The identity lens intentionally
+    // does not set the rebound field reference, since it does not know what that is.
+    return continuation.lookupField(
+        FieldLookupResult.builder(this).setReference(reference).build());
+  }
+
+  @Override
+  protected MethodLookupResult internalLookupMethod(
+      DexMethod reference,
+      DexMethod context,
+      InvokeType type,
+      GraphLens codeLens,
+      LookupMethodContinuation continuation) {
+    // Passes the method reference back to the next graph lens. The identity lens intentionally
+    // does not set the rebound method reference, since it does not know what that is.
+    return continuation.lookupMethod(lookupMethod(reference, context, type, codeLens));
+  }
+
+  @Override
+  public boolean isContextFreeForMethods() {
+    return true;
+  }
+
+  @Override
+  public boolean hasCodeRewritings() {
+    return false;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/InitClassLens.java b/src/main/java/com/android/tools/r8/graph/lens/InitClassLens.java
similarity index 83%
rename from src/main/java/com/android/tools/r8/graph/InitClassLens.java
rename to src/main/java/com/android/tools/r8/graph/lens/InitClassLens.java
index 2b74f9f..8ec8404 100644
--- a/src/main/java/com/android/tools/r8/graph/InitClassLens.java
+++ b/src/main/java/com/android/tools/r8/graph/lens/InitClassLens.java
@@ -1,9 +1,11 @@
-// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-package com.android.tools.r8.graph;
+package com.android.tools.r8.graph.lens;
 
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexType;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
diff --git a/src/main/java/com/android/tools/r8/graph/lens/MemberLookupResult.java b/src/main/java/com/android/tools/r8/graph/lens/MemberLookupResult.java
new file mode 100644
index 0000000..7ec7c85
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/lens/MemberLookupResult.java
@@ -0,0 +1,68 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph.lens;
+
+import com.android.tools.r8.graph.DexMember;
+import com.android.tools.r8.utils.collections.BidirectionalManyToOneRepresentativeMap;
+import java.util.Map;
+import java.util.function.Function;
+
+abstract class MemberLookupResult<R extends DexMember<?, R>> {
+
+  private final R reference;
+  private final R reboundReference;
+
+  MemberLookupResult(R reference, R reboundReference) {
+    this.reference = reference;
+    this.reboundReference = reboundReference;
+  }
+
+  public R getReference() {
+    return reference;
+  }
+
+  public R getRewrittenReference(BidirectionalManyToOneRepresentativeMap<R, R> rewritings) {
+    return rewritings.getOrDefault(reference, reference);
+  }
+
+  public R getRewrittenReference(Map<R, R> rewritings) {
+    return rewritings.getOrDefault(reference, reference);
+  }
+
+  public boolean hasReboundReference() {
+    return reboundReference != null;
+  }
+
+  public R getReboundReference() {
+    return reboundReference;
+  }
+
+  public R getRewrittenReboundReference(BidirectionalManyToOneRepresentativeMap<R, R> rewritings) {
+    return rewritings.getOrDefault(reboundReference, reboundReference);
+  }
+
+  public R getRewrittenReboundReference(Function<R, R> rewritings) {
+    R rewrittenReboundReference = rewritings.apply(reboundReference);
+    return rewrittenReboundReference != null ? rewrittenReboundReference : reboundReference;
+  }
+
+  abstract static class Builder<R extends DexMember<?, R>, Self extends Builder<R, Self>> {
+
+    R reference;
+    R reboundReference;
+
+    public Self setReference(R reference) {
+      this.reference = reference;
+      return self();
+    }
+
+    public Self setReboundReference(R reboundReference) {
+      this.reboundReference = reboundReference;
+      return self();
+    }
+
+    public abstract Self self();
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/lens/MethodLookupResult.java b/src/main/java/com/android/tools/r8/graph/lens/MethodLookupResult.java
new file mode 100644
index 0000000..a69267e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/lens/MethodLookupResult.java
@@ -0,0 +1,76 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph.lens;
+
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
+import com.android.tools.r8.ir.code.InvokeType;
+
+/**
+ * Result of a method lookup in a GraphLens.
+ *
+ * <p>This provides the new target and invoke type to use, along with a description of the prototype
+ * changes that have been made to the target method and the corresponding required changes to the
+ * invoke arguments.
+ */
+public class MethodLookupResult extends MemberLookupResult<DexMethod> {
+
+  private final InvokeType type;
+  private final RewrittenPrototypeDescription prototypeChanges;
+
+  public MethodLookupResult(
+      DexMethod reference,
+      DexMethod reboundReference,
+      InvokeType type,
+      RewrittenPrototypeDescription prototypeChanges) {
+    super(reference, reboundReference);
+    this.type = type;
+    this.prototypeChanges = prototypeChanges;
+  }
+
+  public static Builder builder(GraphLens lens) {
+    return new Builder(lens);
+  }
+
+  public InvokeType getType() {
+    return type;
+  }
+
+  public RewrittenPrototypeDescription getPrototypeChanges() {
+    return prototypeChanges;
+  }
+
+  public static class Builder extends MemberLookupResult.Builder<DexMethod, Builder> {
+
+    private final GraphLens lens;
+    private RewrittenPrototypeDescription prototypeChanges = RewrittenPrototypeDescription.none();
+    private InvokeType type;
+
+    private Builder(GraphLens lens) {
+      this.lens = lens;
+    }
+
+    public Builder setPrototypeChanges(RewrittenPrototypeDescription prototypeChanges) {
+      this.prototypeChanges = prototypeChanges;
+      return this;
+    }
+
+    public Builder setType(InvokeType type) {
+      this.type = type;
+      return this;
+    }
+
+    public MethodLookupResult build() {
+      assert reference != null;
+      // TODO(b/168282032): All non-identity graph lenses should set the rebound reference.
+      return new MethodLookupResult(reference, reboundReference, type, prototypeChanges);
+    }
+
+    @Override
+    public Builder self() {
+      return this;
+    }
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/NestedGraphLens.java b/src/main/java/com/android/tools/r8/graph/lens/NestedGraphLens.java
similarity index 97%
rename from src/main/java/com/android/tools/r8/graph/NestedGraphLens.java
rename to src/main/java/com/android/tools/r8/graph/lens/NestedGraphLens.java
index 85bd133..7c921ca 100644
--- a/src/main/java/com/android/tools/r8/graph/NestedGraphLens.java
+++ b/src/main/java/com/android/tools/r8/graph/lens/NestedGraphLens.java
@@ -1,10 +1,15 @@
-// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-package com.android.tools.r8.graph;
+package com.android.tools.r8.graph.lens;
 
-import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexDefinitionSupplier;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
 import com.android.tools.r8.ir.code.InvokeType;
 import com.android.tools.r8.utils.IterableUtils;
diff --git a/src/main/java/com/android/tools/r8/graph/lens/NonIdentityGraphLens.java b/src/main/java/com/android/tools/r8/graph/lens/NonIdentityGraphLens.java
new file mode 100644
index 0000000..fb0c944
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/lens/NonIdentityGraphLens.java
@@ -0,0 +1,195 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph.lens;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.code.InvokeType;
+import com.android.tools.r8.utils.Action;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Predicate;
+
+public abstract class NonIdentityGraphLens extends GraphLens {
+
+  private final DexItemFactory dexItemFactory;
+  private GraphLens previousLens;
+
+  private final Map<DexType, DexType> arrayTypeCache = new ConcurrentHashMap<>();
+
+  public NonIdentityGraphLens(AppView<?> appView) {
+    this(appView.dexItemFactory(), appView.graphLens());
+  }
+
+  public NonIdentityGraphLens(DexItemFactory dexItemFactory, GraphLens previousLens) {
+    this.dexItemFactory = dexItemFactory;
+    this.previousLens = previousLens;
+  }
+
+  public final DexItemFactory dexItemFactory() {
+    return dexItemFactory;
+  }
+
+  public final GraphLens getPrevious() {
+    return previousLens;
+  }
+
+  @SuppressWarnings("unchecked")
+  public final <T extends com.android.tools.r8.graph.lens.NonIdentityGraphLens> T find(
+      Predicate<com.android.tools.r8.graph.lens.NonIdentityGraphLens> predicate) {
+    GraphLens current = this;
+    while (current.isNonIdentityLens()) {
+      com.android.tools.r8.graph.lens.NonIdentityGraphLens nonIdentityGraphLens =
+          current.asNonIdentityLens();
+      if (predicate.test(nonIdentityGraphLens)) {
+        return (T) nonIdentityGraphLens;
+      }
+      current = nonIdentityGraphLens.getPrevious();
+    }
+    return null;
+  }
+
+  @SuppressWarnings("unchecked")
+  public final <T extends com.android.tools.r8.graph.lens.NonIdentityGraphLens> T findPrevious(
+      Predicate<com.android.tools.r8.graph.lens.NonIdentityGraphLens> predicate) {
+    GraphLens previous = getPrevious();
+    return previous.isNonIdentityLens() ? previous.asNonIdentityLens().find(predicate) : null;
+  }
+
+  public final <T extends com.android.tools.r8.graph.lens.NonIdentityGraphLens> T findPreviousUntil(
+      Predicate<com.android.tools.r8.graph.lens.NonIdentityGraphLens> predicate,
+      Predicate<com.android.tools.r8.graph.lens.NonIdentityGraphLens> stoppingCriterion) {
+    T found = findPrevious(predicate.or(stoppingCriterion));
+    return (found == null || stoppingCriterion.test(found)) ? null : found;
+  }
+
+  public final void withAlternativeParentLens(GraphLens lens, Action action) {
+    GraphLens oldParent = getPrevious();
+    previousLens = lens;
+    action.execute();
+    previousLens = oldParent;
+  }
+
+  @Override
+  public MethodLookupResult lookupMethod(
+      DexMethod method, DexMethod context, InvokeType type, GraphLens codeLens) {
+    if (method.getHolderType().isArrayType()) {
+      assert lookupType(method.getReturnType()) == method.getReturnType();
+      assert method.getParameters().stream()
+          .allMatch(parameterType -> lookupType(parameterType) == parameterType);
+      return MethodLookupResult.builder(this)
+          .setReference(method.withHolder(lookupType(method.getHolderType()), dexItemFactory))
+          .setType(type)
+          .build();
+    }
+    assert method.getHolderType().isClassType();
+    return internalLookupMethod(method, context, type, codeLens, result -> result);
+  }
+
+  @Override
+  public String lookupPackageName(String pkg) {
+    return getPrevious().lookupPackageName(pkg);
+  }
+
+  @Override
+  public final DexType lookupType(DexType type, GraphLens applied) {
+    if (this == applied) {
+      return type;
+    }
+    if (type.isPrimitiveType() || type.isVoidType() || type.isNullValueType()) {
+      return type;
+    }
+    if (type.isArrayType()) {
+      DexType result = arrayTypeCache.get(type);
+      if (result == null) {
+        DexType baseType = type.toBaseType(dexItemFactory);
+        DexType newType = lookupType(baseType);
+        result = baseType == newType ? type : type.replaceBaseType(newType, dexItemFactory);
+        arrayTypeCache.put(type, result);
+      }
+      return result;
+    }
+    return lookupClassType(type);
+  }
+
+  @Override
+  public final DexType lookupClassType(DexType type, GraphLens applied) {
+    assert type.isClassType() : "Expected class type, but was `" + type.toSourceString() + "`";
+    if (this == applied) {
+      return type;
+    }
+    return internalDescribeLookupClassType(getPrevious().lookupClassType(type));
+  }
+
+  @Override
+  protected FieldLookupResult internalLookupField(
+      DexField reference, GraphLens codeLens, LookupFieldContinuation continuation) {
+    if (this == codeLens) {
+      return getIdentityLens().internalLookupField(reference, codeLens, continuation);
+    }
+    return previousLens.internalLookupField(
+        reference,
+        codeLens,
+        previous -> continuation.lookupField(internalDescribeLookupField(previous)));
+  }
+
+  @Override
+  protected MethodLookupResult internalLookupMethod(
+      DexMethod reference,
+      DexMethod context,
+      InvokeType type,
+      GraphLens codeLens,
+      LookupMethodContinuation continuation) {
+    if (this == codeLens) {
+      GraphLens identityLens = getIdentityLens();
+      return identityLens.internalLookupMethod(
+          reference, context, type, identityLens, continuation);
+    }
+    return previousLens.internalLookupMethod(
+        reference,
+        getPreviousMethodSignature(context),
+        type,
+        codeLens,
+        previous -> continuation.lookupMethod(internalDescribeLookupMethod(previous, context)));
+  }
+
+  protected abstract FieldLookupResult internalDescribeLookupField(FieldLookupResult previous);
+
+  protected abstract MethodLookupResult internalDescribeLookupMethod(
+      MethodLookupResult previous, DexMethod context);
+
+  protected abstract DexType internalDescribeLookupClassType(DexType previous);
+
+  public abstract DexMethod getPreviousMethodSignature(DexMethod method);
+
+  /***
+   * The previous mapping for a method often coincides with the previous method signature, but it
+   * may not, for example for bridges inserted in vertically merged classes where the original
+   * signature is used for computing invoke-super but should not be used for mapping output.
+   */
+  public DexMethod getPreviousMethodSignatureForMapping(DexMethod method) {
+    return getPreviousMethodSignature(method);
+  }
+
+  public abstract DexMethod getNextMethodSignature(DexMethod method);
+
+  @Override
+  public final boolean isIdentityLens() {
+    return false;
+  }
+
+  @Override
+  public final boolean isNonIdentityLens() {
+    return true;
+  }
+
+  @Override
+  public final com.android.tools.r8.graph.lens.NonIdentityGraphLens asNonIdentityLens() {
+    return this;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/ThrowingInitClassLens.java b/src/main/java/com/android/tools/r8/graph/lens/ThrowingInitClassLens.java
similarity index 79%
rename from src/main/java/com/android/tools/r8/graph/ThrowingInitClassLens.java
rename to src/main/java/com/android/tools/r8/graph/lens/ThrowingInitClassLens.java
index 730a873..66a60d5 100644
--- a/src/main/java/com/android/tools/r8/graph/ThrowingInitClassLens.java
+++ b/src/main/java/com/android/tools/r8/graph/lens/ThrowingInitClassLens.java
@@ -1,10 +1,12 @@
-// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-package com.android.tools.r8.graph;
+package com.android.tools.r8.graph.lens;
 
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexType;
 
 public class ThrowingInitClassLens extends InitClassLens {
 
diff --git a/src/main/java/com/android/tools/r8/graph/proto/ArgumentInfo.java b/src/main/java/com/android/tools/r8/graph/proto/ArgumentInfo.java
index d221385..de74d62 100644
--- a/src/main/java/com/android/tools/r8/graph/proto/ArgumentInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/proto/ArgumentInfo.java
@@ -5,7 +5,7 @@
 package com.android.tools.r8.graph.proto;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
 public abstract class ArgumentInfo {
diff --git a/src/main/java/com/android/tools/r8/graph/proto/ArgumentInfoCollection.java b/src/main/java/com/android/tools/r8/graph/proto/ArgumentInfoCollection.java
index 889f21a..f08d256 100644
--- a/src/main/java/com/android/tools/r8/graph/proto/ArgumentInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/graph/proto/ArgumentInfoCollection.java
@@ -6,8 +6,8 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfoFixer;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.BooleanUtils;
diff --git a/src/main/java/com/android/tools/r8/graph/proto/RemovedArgumentInfo.java b/src/main/java/com/android/tools/r8/graph/proto/RemovedArgumentInfo.java
index 79b3b6c..8d560c5 100644
--- a/src/main/java/com/android/tools/r8/graph/proto/RemovedArgumentInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/proto/RemovedArgumentInfo.java
@@ -6,7 +6,7 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.analysis.value.SingleValue;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import java.util.Objects;
diff --git a/src/main/java/com/android/tools/r8/graph/proto/RemovedReceiverInfo.java b/src/main/java/com/android/tools/r8/graph/proto/RemovedReceiverInfo.java
index 7bd6530..9bcda3a 100644
--- a/src/main/java/com/android/tools/r8/graph/proto/RemovedReceiverInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/proto/RemovedReceiverInfo.java
@@ -6,7 +6,7 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.analysis.value.SingleValue;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import java.util.Objects;
diff --git a/src/main/java/com/android/tools/r8/graph/proto/RewrittenPrototypeDescription.java b/src/main/java/com/android/tools/r8/graph/proto/RewrittenPrototypeDescription.java
index 06c5418..e149d62 100644
--- a/src/main/java/com/android/tools/r8/graph/proto/RewrittenPrototypeDescription.java
+++ b/src/main/java/com/android/tools/r8/graph/proto/RewrittenPrototypeDescription.java
@@ -10,9 +10,9 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.RewrittenPrototypeDescriptionMethodOptimizationInfoFixer;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.analysis.value.SingleValue;
 import com.android.tools.r8.ir.code.ConstInstruction;
 import com.android.tools.r8.ir.code.IRCode;
diff --git a/src/main/java/com/android/tools/r8/graph/proto/RewrittenTypeInfo.java b/src/main/java/com/android/tools/r8/graph/proto/RewrittenTypeInfo.java
index 0f0c49f..d3388bc 100644
--- a/src/main/java/com/android/tools/r8/graph/proto/RewrittenTypeInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/proto/RewrittenTypeInfo.java
@@ -6,7 +6,7 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.analysis.value.SingleValue;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import java.util.Objects;
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
index 1cf6415..459cf9a 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
@@ -29,7 +29,7 @@
 import com.android.tools.r8.ir.analysis.value.NumberFromIntervalValue;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
-import com.android.tools.r8.profile.art.rewriting.ProfileCollectionAdditions;
+import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
 import com.android.tools.r8.utils.SetUtils;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
index 32dd38f..1fbc713 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
@@ -12,13 +12,13 @@
 import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.MethodLookupResult;
 import com.android.tools.r8.horizontalclassmerging.code.SyntheticInitializerConverter;
 import com.android.tools.r8.ir.code.InvokeType;
 import com.android.tools.r8.profile.art.ArtProfileCompletenessChecker;
-import com.android.tools.r8.profile.art.rewriting.ProfileCollectionAdditions;
+import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.shaking.FieldAccessInfoCollectionModifier;
 import com.android.tools.r8.shaking.KeepInfoCollection;
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java
index 53f08a6..72e96a7 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java
@@ -10,8 +10,10 @@
 import com.android.tools.r8.graph.DexMember;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.NestedGraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.FieldLookupResult;
+import com.android.tools.r8.graph.lens.MethodLookupResult;
+import com.android.tools.r8.graph.lens.NestedGraphLens;
 import com.android.tools.r8.ir.conversion.ExtraParameter;
 import com.android.tools.r8.utils.IterableUtils;
 import com.android.tools.r8.utils.collections.BidirectionalManyToOneHashMap;
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/IRCodeProvider.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/IRCodeProvider.java
index 8718185..ab14412 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/IRCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/IRCodeProvider.java
@@ -7,8 +7,8 @@
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.synthesis.SyntheticItems.GlobalSyntheticsStrategy;
 
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteMergedInstanceInitializerCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteMergedInstanceInitializerCode.java
index 329d43a..15f0d57 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteMergedInstanceInitializerCode.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteMergedInstanceInitializerCode.java
@@ -23,9 +23,9 @@
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.MethodLookupResult;
 import com.android.tools.r8.ir.analysis.value.SingleConstValue;
 import com.android.tools.r8.ir.analysis.value.SingleDexItemBasedStringValue;
 import com.android.tools.r8.ir.code.Position;
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteVirtuallyMergedMethodCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteVirtuallyMergedMethodCode.java
index 2bd4d6e..6f6a957 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteVirtuallyMergedMethodCode.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteVirtuallyMergedMethodCode.java
@@ -21,8 +21,8 @@
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.horizontalclassmerging.VirtualMethodMerger.SuperMethodReference;
 import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.utils.BooleanUtils;
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java
index e1a6710..0cf3a94 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java
@@ -24,7 +24,7 @@
 import com.android.tools.r8.ir.conversion.ExtraConstantIntParameter;
 import com.android.tools.r8.ir.conversion.ExtraParameter;
 import com.android.tools.r8.ir.conversion.ExtraUnusedNullParameter;
-import com.android.tools.r8.profile.art.rewriting.ProfileCollectionAdditions;
+import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
 import com.android.tools.r8.utils.ArrayUtils;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.Box;
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java
index 948c889..55aad86d 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java
@@ -21,7 +21,7 @@
 import com.android.tools.r8.graph.TreeFixerBase;
 import com.android.tools.r8.horizontalclassmerging.HorizontalClassMerger.Mode;
 import com.android.tools.r8.ir.conversion.ExtraUnusedNullParameter;
-import com.android.tools.r8.profile.art.rewriting.ProfileCollectionAdditions;
+import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
 import com.android.tools.r8.shaking.AnnotationFixer;
 import com.android.tools.r8.utils.ArrayUtils;
 import com.android.tools.r8.utils.Box;
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
index a9dd719..d937a8e 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
@@ -14,7 +14,7 @@
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
 import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.profile.art.rewriting.ProfileCollectionAdditions;
+import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
 import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.OptionalBool;
 import com.android.tools.r8.utils.structural.Ordered;
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/SyntheticInitializerConverter.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/SyntheticInitializerConverter.java
index 93572c6..8685b4a 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/SyntheticInitializerConverter.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/SyntheticInitializerConverter.java
@@ -8,8 +8,8 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.Code;
 import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.horizontalclassmerging.HorizontalClassMerger.Mode;
 import com.android.tools.r8.horizontalclassmerging.IRCodeProvider;
 import com.android.tools.r8.ir.code.IRCode;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/AbstractFieldSet.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/AbstractFieldSet.java
index ab29351..99707bf 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/AbstractFieldSet.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/AbstractFieldSet.java
@@ -6,8 +6,8 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/ConcreteMutableFieldSet.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/ConcreteMutableFieldSet.java
index d62a1d6..b18d02a 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/ConcreteMutableFieldSet.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/ConcreteMutableFieldSet.java
@@ -8,8 +8,8 @@
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.InternalOptions;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/EmptyFieldSet.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/EmptyFieldSet.java
index 9d2e36a..e4efd96 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/EmptyFieldSet.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/EmptyFieldSet.java
@@ -6,8 +6,8 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
 import com.android.tools.r8.graph.proto.RemovedArgumentInfo;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/UnknownFieldSet.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/UnknownFieldSet.java
index 43823c3..6131581 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/UnknownFieldSet.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/UnknownFieldSet.java
@@ -6,8 +6,8 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/DestructivePhiTypeUpdater.java b/src/main/java/com/android/tools/r8/ir/analysis/type/DestructivePhiTypeUpdater.java
index 89e78e5..b0fc54d 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/DestructivePhiTypeUpdater.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/DestructivePhiTypeUpdater.java
@@ -7,7 +7,7 @@
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Phi;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicType.java b/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicType.java
index 1b9bb1e..e31d2db 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicType.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicType.java
@@ -7,7 +7,7 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import java.util.Set;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicTypeWithUpperBound.java b/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicTypeWithUpperBound.java
index 5784e9e..4ed918e 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicTypeWithUpperBound.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicTypeWithUpperBound.java
@@ -7,7 +7,7 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import java.util.Objects;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/ExactDynamicType.java b/src/main/java/com/android/tools/r8/ir/analysis/type/ExactDynamicType.java
index 0cd29f2..0b92334 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/ExactDynamicType.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/ExactDynamicType.java
@@ -6,7 +6,7 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import java.util.Set;
 
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/NotNullDynamicType.java b/src/main/java/com/android/tools/r8/ir/analysis/type/NotNullDynamicType.java
index a9830ff..7645341 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/NotNullDynamicType.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/NotNullDynamicType.java
@@ -6,7 +6,7 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import java.util.Set;
 
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/TypeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/TypeElement.java
index 0efe7d0..6800d1c 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/TypeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/TypeElement.java
@@ -10,7 +10,7 @@
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.code.Value;
 import java.util.Collections;
 import java.util.Set;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java
index d62f8e7..c4e0a83 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java
@@ -6,7 +6,7 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.analysis.value.objectstate.ObjectState;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/BottomValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/BottomValue.java
index 4253a3d..0653a7c 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/BottomValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/BottomValue.java
@@ -5,7 +5,7 @@
 package com.android.tools.r8.ir.analysis.value;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
 public class BottomValue extends AbstractValue {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/NullOrAbstractValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/NullOrAbstractValue.java
index db25101..983708f 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/NullOrAbstractValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/NullOrAbstractValue.java
@@ -5,7 +5,7 @@
 package com.android.tools.r8.ir.analysis.value;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
 public class NullOrAbstractValue extends AbstractValue {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/NumberFromIntervalValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/NumberFromIntervalValue.java
index 94d2d59..11f395b 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/NumberFromIntervalValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/NumberFromIntervalValue.java
@@ -5,7 +5,7 @@
 package com.android.tools.r8.ir.analysis.value;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.OptionalBool;
 import java.util.Objects;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/NumberFromSetValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/NumberFromSetValue.java
index 1c539c9..629ebf1 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/NumberFromSetValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/NumberFromSetValue.java
@@ -5,7 +5,7 @@
 package com.android.tools.r8.ir.analysis.value;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.ArrayUtils;
 import com.android.tools.r8.utils.OptionalBool;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java
index 80718a7..fc86d70 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java
@@ -14,8 +14,8 @@
 import com.android.tools.r8.graph.DebugLocalInfo;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.code.ConstClass;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleDexItemBasedStringValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleDexItemBasedStringValue.java
index c1e6c43..bc0aef8 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleDexItemBasedStringValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleDexItemBasedStringValue.java
@@ -11,8 +11,8 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DebugLocalInfo;
 import com.android.tools.r8.graph.DexReference;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.code.DexItemBasedConstString;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
index da02bae..9acf109 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
@@ -15,8 +15,8 @@
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
 import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java
index 934f0e6..5327427 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java
@@ -7,8 +7,8 @@
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DebugLocalInfo;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.code.ConstNumber;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStringValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStringValue.java
index f4ce6ae..d51ff72 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStringValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStringValue.java
@@ -11,8 +11,8 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DebugLocalInfo;
 import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.code.ConstString;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleValue.java
index 0f0ff90..51bc690 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleValue.java
@@ -6,8 +6,8 @@
 
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.NumberGenerator;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/StatefulObjectValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/StatefulObjectValue.java
index 2d090e9..1d46931 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/StatefulObjectValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/StatefulObjectValue.java
@@ -4,7 +4,7 @@
 package com.android.tools.r8.ir.analysis.value;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.analysis.value.objectstate.ObjectState;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/UnknownValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/UnknownValue.java
index 8faaea4..e2ef4e0 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/UnknownValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/UnknownValue.java
@@ -5,7 +5,7 @@
 package com.android.tools.r8.ir.analysis.value;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
 public class UnknownValue extends AbstractValue {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/EmptyObjectState.java b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/EmptyObjectState.java
index 0d1255e..1f2b960 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/EmptyObjectState.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/EmptyObjectState.java
@@ -7,7 +7,7 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
 import com.android.tools.r8.ir.analysis.value.UnknownValue;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/EnumValuesObjectState.java b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/EnumValuesObjectState.java
index 8311d1e..3a50ca7 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/EnumValuesObjectState.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/EnumValuesObjectState.java
@@ -7,7 +7,7 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
 import com.android.tools.r8.ir.analysis.value.UnknownValue;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/KnownLengthArrayState.java b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/KnownLengthArrayState.java
index 8c9e449..f05e962 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/KnownLengthArrayState.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/KnownLengthArrayState.java
@@ -7,7 +7,7 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
 import com.android.tools.r8.ir.analysis.value.UnknownValue;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/NonEmptyObjectState.java b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/NonEmptyObjectState.java
index 7133b9c..b9a9933 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/NonEmptyObjectState.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/NonEmptyObjectState.java
@@ -7,7 +7,7 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
 import com.android.tools.r8.ir.analysis.value.UnknownValue;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/ObjectState.java b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/ObjectState.java
index bc0762a..00165e5 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/ObjectState.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/ObjectState.java
@@ -8,8 +8,8 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
 import com.android.tools.r8.ir.analysis.value.SingleValue;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
diff --git a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
index 276150a..bef0a26 100644
--- a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
+++ b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
@@ -12,10 +12,10 @@
 import com.android.tools.r8.graph.DebugLocalInfo.PrintLevel;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.NonIdentityGraphLens;
 import com.android.tools.r8.ir.analysis.VerifyTypesHelper;
 import com.android.tools.r8.ir.analysis.type.Nullability;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeType.java b/src/main/java/com/android/tools/r8/ir/code/InvokeType.java
index 214b6db..bed9095 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeType.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeType.java
@@ -26,8 +26,8 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexMethodHandle.MethodHandleType;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.MethodLookupResult;
 import org.objectweb.asm.Opcodes;
 
 public enum InvokeType {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/ClassConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/ClassConverter.java
index 9782300..ac5cc44 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/ClassConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/ClassConverter.java
@@ -13,7 +13,7 @@
 import com.android.tools.r8.ir.desugar.CfClassSynthesizerDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.itf.InterfaceProcessor;
-import com.android.tools.r8.profile.art.rewriting.ProfileCollectionAdditions;
+import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
 import com.android.tools.r8.utils.MapUtils;
 import com.android.tools.r8.utils.ThreadUtils;
 import com.android.tools.r8.utils.collections.ImmutableDeque;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/D8MethodProcessor.java b/src/main/java/com/android/tools/r8/ir/conversion/D8MethodProcessor.java
index fec53b0..6c7a613 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/D8MethodProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/D8MethodProcessor.java
@@ -12,7 +12,7 @@
 import com.android.tools.r8.ir.conversion.callgraph.CallSiteInformation;
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackIgnore;
-import com.android.tools.r8.profile.art.rewriting.ProfileCollectionAdditions;
+import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
 import com.android.tools.r8.utils.ThreadUtils;
 import com.google.common.collect.Sets;
 import java.util.ArrayList;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index c9bc10c..779beba 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -33,8 +33,8 @@
 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.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.ArgumentInfo;
 import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
 import com.android.tools.r8.graph.proto.RemovedArgumentInfo;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
index 362d883..1efe772 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
@@ -49,12 +49,12 @@
 import com.android.tools.r8.graph.DexMethodHandle;
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.GraphLens.FieldLookupResult;
-import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
-import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
+import com.android.tools.r8.graph.lens.FieldLookupResult;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.MethodLookupResult;
+import com.android.tools.r8.graph.lens.NonIdentityGraphLens;
 import com.android.tools.r8.graph.proto.ArgumentInfo;
 import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
 import com.android.tools.r8.graph.proto.RemovedArgumentInfo;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriterUtils.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriterUtils.java
index aefb54d..b82af15 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriterUtils.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriterUtils.java
@@ -23,10 +23,10 @@
 import com.android.tools.r8.graph.DexValue.DexValueMethodHandle;
 import com.android.tools.r8.graph.DexValue.DexValueMethodType;
 import com.android.tools.r8.graph.DexValue.DexValueType;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry.MethodHandleUse;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.MethodLookupResult;
 import com.android.tools.r8.ir.code.InvokeType;
 import com.android.tools.r8.ir.desugar.LambdaDescriptor;
 import java.util.ArrayList;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/MethodProcessorEventConsumer.java b/src/main/java/com/android/tools/r8/ir/conversion/MethodProcessorEventConsumer.java
index a14171a..ac0ca71 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/MethodProcessorEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/MethodProcessorEventConsumer.java
@@ -12,8 +12,8 @@
 import com.android.tools.r8.ir.optimize.UtilityMethodsForCodeOptimizationsEventConsumer;
 import com.android.tools.r8.ir.optimize.api.InstanceInitializerOutlinerEventConsumer;
 import com.android.tools.r8.ir.optimize.enums.EnumUnboxerMethodProcessorEventConsumer;
-import com.android.tools.r8.profile.art.rewriting.ProfileCollectionAdditions;
-import com.android.tools.r8.profile.art.rewriting.ProfileRewritingMethodProcessorEventConsumer;
+import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
+import com.android.tools.r8.profile.rewriting.ProfileRewritingMethodProcessorEventConsumer;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
 public abstract class MethodProcessorEventConsumer
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java b/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java
index e7d3441..fe3085a 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java
@@ -12,8 +12,8 @@
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.PrimaryMethodProcessor.MethodAction;
 import com.android.tools.r8.ir.conversion.callgraph.CallGraph;
 import com.android.tools.r8.ir.conversion.callgraph.PartialCallGraphBuilder;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/PrimaryD8L8IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/PrimaryD8L8IRConverter.java
index cf8e52d..532c129 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/PrimaryD8L8IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/PrimaryD8L8IRConverter.java
@@ -33,7 +33,7 @@
 import com.android.tools.r8.ir.desugar.nest.D8NestBasedAccessDesugaring;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
 import com.android.tools.r8.position.MethodPosition;
-import com.android.tools.r8.profile.art.rewriting.ProfileCollectionAdditions;
+import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
 import com.android.tools.r8.utils.ExceptionUtils;
 import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.ThreadUtils;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/PrimaryR8IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/PrimaryR8IRConverter.java
index 0ad28d4..68073e7 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/PrimaryR8IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/PrimaryR8IRConverter.java
@@ -10,8 +10,8 @@
 import com.android.tools.r8.graph.DexApplication.Builder;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.analysis.fieldaccess.TrivialFieldAccessReprocessor;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackDelayed;
 import com.android.tools.r8.optimize.argumentpropagation.ArgumentPropagator;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/callgraph/InvokeExtractor.java b/src/main/java/com/android/tools/r8/ir/conversion/callgraph/InvokeExtractor.java
index 34e00ef..38bc387 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/callgraph/InvokeExtractor.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/callgraph/InvokeExtractor.java
@@ -11,11 +11,11 @@
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
 import com.android.tools.r8.graph.LookupResult;
 import com.android.tools.r8.graph.MethodResolutionResult;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.MethodLookupResult;
 import com.android.tools.r8.ir.code.InvokeType;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.collections.ProgramMethodSet;
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 0db5e13..ca51bd8 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
@@ -14,8 +14,8 @@
 import com.android.tools.r8.ir.desugar.itf.EmulatedInterfaceSynthesizerEventConsumer.L8ProgramEmulatedInterfaceSynthesizerEventConsumer;
 import com.android.tools.r8.ir.desugar.records.RecordDesugaringEventConsumer.RecordClassSynthesizerDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.varhandle.VarHandleDesugaringEventConsumer;
-import com.android.tools.r8.profile.art.rewriting.ProfileCollectionAdditions;
-import com.android.tools.r8.profile.art.rewriting.ProfileRewritingCfClassSynthesizerDesugaringEventConsumer;
+import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
+import com.android.tools.r8.profile.rewriting.ProfileRewritingCfClassSynthesizerDesugaringEventConsumer;
 import com.google.common.collect.Sets;
 import java.util.Set;
 
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 509a1ff..3e410e8 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
@@ -32,8 +32,8 @@
 import com.android.tools.r8.ir.desugar.records.RecordDesugaringEventConsumer.RecordInstructionDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.twr.TwrCloseResourceDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.varhandle.VarHandleDesugaringEventConsumer;
-import com.android.tools.r8.profile.art.rewriting.ProfileCollectionAdditions;
-import com.android.tools.r8.profile.art.rewriting.ProfileRewritingCfInstructionDesugaringEventConsumer;
+import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
+import com.android.tools.r8.profile.rewriting.ProfileRewritingCfInstructionDesugaringEventConsumer;
 import com.android.tools.r8.shaking.Enqueuer.SyntheticAdditions;
 import com.android.tools.r8.shaking.KeepMethodInfo.Joiner;
 import com.google.common.collect.Sets;
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 adeecfe..1a232e1 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
@@ -18,8 +18,8 @@
 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.profile.art.rewriting.ProfileCollectionAdditions;
-import com.android.tools.r8.profile.art.rewriting.ProfileRewritingCfPostProcessingDesugaringEventConsumer;
+import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
+import com.android.tools.r8.profile.rewriting.ProfileRewritingCfPostProcessingDesugaringEventConsumer;
 import com.android.tools.r8.shaking.Enqueuer.SyntheticAdditions;
 import com.android.tools.r8.utils.collections.ProgramMethodSet;
 import java.util.Collections;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CovariantReturnTypeAnnotationTransformerEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/CovariantReturnTypeAnnotationTransformerEventConsumer.java
index 86c74d8..f5c97fe 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CovariantReturnTypeAnnotationTransformerEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CovariantReturnTypeAnnotationTransformerEventConsumer.java
@@ -5,8 +5,8 @@
 package com.android.tools.r8.ir.desugar;
 
 import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.profile.art.rewriting.ProfileCollectionAdditions;
-import com.android.tools.r8.profile.art.rewriting.ProfileRewritingCovariantReturnTypeAnnotationTransformerEventConsumer;
+import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
+import com.android.tools.r8.profile.rewriting.ProfileRewritingCovariantReturnTypeAnnotationTransformerEventConsumer;
 
 public interface CovariantReturnTypeAnnotationTransformerEventConsumer {
 
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/GenerateLintFiles.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/GenerateLintFiles.java
index e1e72d8..de9f350 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/GenerateLintFiles.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/GenerateLintFiles.java
@@ -131,6 +131,7 @@
             null,
             Collections.emptyList(),
             Collections.emptyList(),
+            Collections.emptyList(),
             null,
             Collections.emptyList(),
             ClassSignature.noSignature(),
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 fd607ee..47a6d30 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
@@ -79,6 +79,7 @@
             null,
             Collections.emptyList(),
             Collections.emptyList(),
+            Collections.emptyList(),
             null, // Note that we clear the enclosing and inner class attributes.
             Collections.emptyList(),
             emulatedInterface.getClassSignature(),
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
index a7562ee..31037b9 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
@@ -24,11 +24,11 @@
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GenericSignature.ClassTypeSignature;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.InvalidCode;
 import com.android.tools.r8.graph.MethodCollection;
-import com.android.tools.r8.graph.NestedGraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.NestedGraphLens;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.EmulatedDispatchMethodDescriptor;
 import com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringSyntheticHelper.InterfaceMethodDesugaringMode;
 import com.android.tools.r8.synthesis.SyntheticMethodBuilder;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/nest/D8NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/nest/D8NestBasedAccessDesugaring.java
index 4e037ad..34d6b95 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/nest/D8NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/nest/D8NestBasedAccessDesugaring.java
@@ -18,7 +18,7 @@
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.conversion.D8MethodProcessor;
-import com.android.tools.r8.profile.art.rewriting.ProfileRewritingNestBasedAccessDesugaringEventConsumer;
+import com.android.tools.r8.profile.rewriting.ProfileRewritingNestBasedAccessDesugaringEventConsumer;
 import com.android.tools.r8.utils.ThreadUtils;
 import com.google.common.collect.Iterables;
 import java.util.ArrayList;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordCfToCfRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordCfToCfRewriter.java
index b5e08d5..d1803d3 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordCfToCfRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordCfToCfRewriter.java
@@ -19,8 +19,8 @@
 import com.android.tools.r8.graph.DexValue.DexValueMethodHandle;
 import com.android.tools.r8.graph.DexValue.DexValueString;
 import com.android.tools.r8.graph.DexValue.DexValueType;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.desugar.records.RecordRewriterHelper.RecordInvokeDynamic;
 import com.android.tools.r8.naming.NamingLens;
 import java.util.ArrayList;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
index 5bdde13..0d20bc3 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -18,10 +18,10 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
 import com.android.tools.r8.graph.NestMemberClassAttribute;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
 import com.android.tools.r8.ir.analysis.proto.ProtoInliningReasonStrategy;
 import com.android.tools.r8.ir.analysis.type.Nullability;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java b/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
index 3452d98..449bb2e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
@@ -17,9 +17,9 @@
 import com.android.tools.r8.graph.DexReference;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.FieldResolutionResult;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.MethodResolutionResult;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.code.InvokeType;
 import com.android.tools.r8.ir.optimize.Inliner.Constraint;
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MultiCallerInliner.java b/src/main/java/com/android/tools/r8/ir/optimize/MultiCallerInliner.java
index e111ec0..54c8f61 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MultiCallerInliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MultiCallerInliner.java
@@ -8,9 +8,9 @@
 import static com.android.tools.r8.utils.MapUtils.ignoreKey;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EmptyEnumUnboxer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EmptyEnumUnboxer.java
index bde3a44..6f94842 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EmptyEnumUnboxer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EmptyEnumUnboxer.java
@@ -6,8 +6,8 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
 import com.android.tools.r8.ir.analysis.fieldvalueanalysis.StaticFieldValues;
 import com.android.tools.r8.ir.code.IRCode;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
index 659d802..cfb23b0 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
@@ -6,8 +6,8 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
 import com.android.tools.r8.ir.analysis.fieldvalueanalysis.StaticFieldValues;
 import com.android.tools.r8.ir.code.IRCode;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
index 1767d8b..4666036 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
@@ -41,10 +41,10 @@
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.FieldResolutionResult;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.NonIdentityGraphLens;
 import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
 import com.android.tools.r8.ir.analysis.fieldvalueanalysis.StaticFieldValues;
 import com.android.tools.r8.ir.analysis.fieldvalueanalysis.StaticFieldValues.EnumStaticFieldValues;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateAnalysis.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateAnalysis.java
index 51e4191..abc0fde 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateAnalysis.java
@@ -4,18 +4,27 @@
 
 package com.android.tools.r8.ir.optimize.enums;
 
+import static com.android.tools.r8.utils.MapUtils.ignoreKey;
+
 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.DexItemFactory;
 import com.android.tools.r8.graph.DexMember;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.optimize.enums.eligibility.Reason;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.shaking.KeepInfoCollection;
 import com.android.tools.r8.utils.InternalOptions;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+import java.util.IdentityHashMap;
+import java.util.Map;
+import java.util.Set;
 
 class EnumUnboxingCandidateAnalysis {
 
@@ -30,6 +39,9 @@
   private EnumUnboxingCandidateInfoCollection enumToUnboxCandidates =
       new EnumUnboxingCandidateInfoCollection();
 
+  private final Map<DexType, Set<DexProgramClass>> enumSubclasses = new IdentityHashMap<>();
+  private final Set<DexType> ineligibleCandidates = Sets.newIdentityHashSet();
+
   EnumUnboxingCandidateAnalysis(AppView<AppInfoWithLiveness> appView, EnumUnboxerImpl enumUnboxer) {
     this.appView = appView;
     this.enumUnboxer = enumUnboxer;
@@ -44,32 +56,125 @@
       return enumToUnboxCandidates;
     }
     for (DexProgramClass clazz : appView.appInfo().classes()) {
-      if (isEnumUnboxingCandidate(clazz)) {
-        enumToUnboxCandidates.addCandidate(appView, clazz, graphLensForPrimaryOptimizationPass);
+      if (clazz.isEnum()) {
+        analyzeEnum(graphLensForPrimaryOptimizationPass, clazz);
       }
     }
+    removeIneligibleCandidates();
     removeEnumsInAnnotations();
     removePinnedCandidates();
     if (appView.options().protoShrinking().isProtoShrinkingEnabled()) {
       enumToUnboxCandidates.removeCandidate(appView.protoShrinker().references.methodToInvokeType);
     }
+    setEnumSubclassesOnCandidates();
+    assert enumToUnboxCandidates.verifyAllSubtypesAreSet();
     return enumToUnboxCandidates;
   }
 
-  private boolean isEnumUnboxingCandidate(DexProgramClass clazz) {
-    if (!clazz.isEnum()) {
-      return false;
-    }
+  private void setEnumSubclassesOnCandidates() {
+    enumToUnboxCandidates.forEachCandidate(
+        candidate ->
+            enumToUnboxCandidates.setEnumSubclasses(
+                candidate.getType(),
+                enumSubclasses.getOrDefault(candidate.getType(), ImmutableSet.of())));
+  }
 
+  private void removeIneligibleCandidates() {
+    for (DexType ineligibleCandidate : ineligibleCandidates) {
+      enumToUnboxCandidates.removeCandidate(ineligibleCandidate);
+    }
+  }
+
+  private void analyzeEnum(GraphLens graphLensForPrimaryOptimizationPass, DexProgramClass clazz) {
+    if (!appView.options().testing.enableEnumWithSubtypesUnboxing) {
+      if (legacyIsEnumUnboxingCandidate(clazz)) {
+        enumToUnboxCandidates.addCandidate(appView, clazz, graphLensForPrimaryOptimizationPass);
+      }
+      return;
+    }
+    if (clazz.superType == factory.enumType) {
+      if (isSuperEnumUnboxingCandidate(clazz)) {
+        enumToUnboxCandidates.addCandidate(appView, clazz, graphLensForPrimaryOptimizationPass);
+      }
+    } else {
+      if (isSubEnumUnboxingCandidate(clazz)) {
+        enumSubclasses
+            .computeIfAbsent(clazz.superType, ignoreKey(Sets::newIdentityHashSet))
+            .add(clazz);
+      } else {
+        ineligibleCandidates.add(clazz.superType);
+      }
+    }
+  }
+
+  private boolean isSubEnumUnboxingCandidate(DexProgramClass clazz) {
+    assert clazz.isEnum();
     boolean result = true;
-    if (clazz.superType != factory.enumType || !clazz.isEffectivelyFinal(appView)) {
+    // Javac does not seem to generate enums with more than a single subtype level.
+    // TODO(b/273910479): Stop using isEffectivelyFinal.
+    if (!clazz.isEffectivelyFinal(appView)) {
+      if (!enumUnboxer.reportFailure(clazz.superType, Reason.SUBENUM_SUBTYPES)) {
+        return false;
+      }
+      result = false;
+    }
+    DexClass superEnum = appView.definitionFor(clazz.superType);
+    if (superEnum == null || !superEnum.isEnum() || superEnum.superType != factory.enumType) {
+      if (!enumUnboxer.reportFailure(clazz.superType, Reason.SUBENUM_INVALID_HIERARCHY)) {
+        return false;
+      }
+      result = false;
+    }
+    // TODO(b/271385332): Support subEnums with instance fields.
+    if (!clazz.instanceFields().isEmpty()) {
+      if (!enumUnboxer.reportFailure(clazz.superType, Reason.SUBENUM_INSTANCE_FIELDS)) {
+        return false;
+      }
+      result = false;
+    }
+    // TODO(b/271385332): Support subEnums with static members (JDK16+).
+    if (!clazz.staticFields().isEmpty()
+        || !Iterables.isEmpty(clazz.directMethods(DexEncodedMethod::isStatic))) {
+      if (!enumUnboxer.reportFailure(clazz.superType, Reason.SUBENUM_STATIC_MEMBER)) {
+        return false;
+      }
+      result = false;
+    }
+    return result;
+  }
+
+  private boolean legacyIsEnumUnboxingCandidate(DexProgramClass clazz) {
+    assert clazz.isEnum();
+
+    // This is used in debug mode, where we don't do quick returns to log all the reasons an enum
+    // is not unboxed.
+    boolean result = true;
+
+    if (!clazz.isEffectivelyFinal(appView)) {
       if (!enumUnboxer.reportFailure(clazz, Reason.SUBTYPES)) {
         return false;
       }
-      // Record that `clazz` is ineligible, and continue analysis to ensure all reasons are reported
-      // for debugging.
       result = false;
     }
+
+    return isSuperEnumUnboxingCandidate(clazz) && result;
+  }
+
+  private boolean isSuperEnumUnboxingCandidate(DexProgramClass clazz) {
+    assert clazz.isEnum();
+
+    // This is used in debug mode, where we don't do quick returns to log all the reasons an enum
+    // is not unboxed.
+    boolean result = true;
+
+    // TODO(b/271385332): Change this into an assert when legacy is removed.
+    if (clazz.superType != factory.enumType) {
+      if (!enumUnboxer.reportFailure(clazz, Reason.INVALID_LIBRARY_SUPERTYPE)) {
+        return false;
+      }
+      result = false;
+    }
+
     if (clazz.instanceFields().size() > MAX_INSTANCE_FIELDS_FOR_UNBOXING) {
       if (!enumUnboxer.reportFailure(clazz, Reason.MANY_INSTANCE_FIELDS)) {
         return false;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateInfoCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateInfoCollection.java
index b79dea1..9feeed2 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateInfoCollection.java
@@ -9,8 +9,8 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.collections.LongLivedProgramMethodSetBuilder;
 import com.android.tools.r8.utils.collections.ProgramMethodSet;
@@ -38,6 +38,10 @@
         new EnumUnboxingCandidateInfo(appView, enumClass, graphLensForPrimaryOptimizationPass));
   }
 
+  public void setEnumSubclasses(DexType superEnum, Set<DexProgramClass> subclasses) {
+    enumTypeToInfo.get(superEnum).setSubclasses(subclasses);
+  }
+
   public void addPrunedMethod(ProgramMethod method) {
     prunedMethods.add(method.getReference());
   }
@@ -128,12 +132,21 @@
     enumTypeToInfo.clear();
   }
 
+  public boolean verifyAllSubtypesAreSet() {
+    for (EnumUnboxingCandidateInfo value : enumTypeToInfo.values()) {
+      assert value.subclasses != null;
+    }
+    return true;
+  }
+
   private static class EnumUnboxingCandidateInfo {
 
     private final DexProgramClass enumClass;
     private final LongLivedProgramMethodSetBuilder<ProgramMethodSet> methodDependencies;
     private final Set<DexField> requiredInstanceFieldData = Sets.newConcurrentHashSet();
 
+    private Set<DexProgramClass> subclasses = null;
+
     public EnumUnboxingCandidateInfo(
         AppView<AppInfoWithLiveness> appView,
         DexProgramClass enumClass,
@@ -146,6 +159,10 @@
               graphLensForPrimaryOptimizationPass);
     }
 
+    public void setSubclasses(Set<DexProgramClass> subclasses) {
+      this.subclasses = subclasses;
+    }
+
     public DexProgramClass getEnumClass() {
       return enumClass;
     }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java
index fa272ca..91e6e67 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java
@@ -9,8 +9,8 @@
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.NestedGraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.NestedGraphLens;
 import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
 import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
 import com.android.tools.r8.graph.proto.RewrittenTypeInfo;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
index a186580..67efedd 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
@@ -18,11 +18,11 @@
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.DexValue;
-import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.ProgramField;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.MethodLookupResult;
 import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
 import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/eligibility/Reason.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/eligibility/Reason.java
index 7cb0290..5f31298 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/eligibility/Reason.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/eligibility/Reason.java
@@ -14,7 +14,14 @@
   public static final Reason ANNOTATION = new StringReason("ANNOTATION");
   public static final Reason PINNED = new StringReason("PINNED");
   public static final Reason DOWN_CAST = new StringReason("DOWN_CAST");
+  public static final Reason INVALID_LIBRARY_SUPERTYPE =
+      new StringReason("INVALID_LIBRARY_SUPERTYPE");
   public static final Reason SUBTYPES = new StringReason("SUBTYPES");
+  public static final Reason SUBENUM_SUBTYPES = new StringReason("SUBENUM_SUBTYPES");
+  public static final Reason SUBENUM_INVALID_HIERARCHY =
+      new StringReason("SUBENUM_INVALID_HIERARCHY");
+  public static final Reason SUBENUM_INSTANCE_FIELDS = new StringReason("SUBENUM_INSTANCE_FIELDS");
+  public static final Reason SUBENUM_STATIC_MEMBER = new StringReason("SUBENUM_STATIC_MEMBER");
   public static final Reason MANY_INSTANCE_FIELDS = new StringReason("MANY_INSTANCE_FIELDS");
   public static final Reason DEFAULT_METHOD_INVOKE = new StringReason("DEFAULT_METHOD_INVOKE");
   public static final Reason UNRESOLVABLE_FIELD = new StringReason("UNRESOLVABLE_FIELD");
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java
index 3bf8709..89b97ad 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java
@@ -8,7 +8,7 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.analysis.type.DynamicType;
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
 import com.android.tools.r8.ir.analysis.value.UnknownValue;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
index 8ee971e..d5127e3 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
@@ -9,8 +9,8 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.analysis.inlining.NeverSimpleInliningConstraint;
 import com.android.tools.r8.ir.analysis.inlining.SimpleInliningConstraint;
 import com.android.tools.r8.ir.analysis.type.DynamicType;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/EmptyInstanceFieldInitializationInfoCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/EmptyInstanceFieldInitializationInfoCollection.java
index 7694837..1de19ad 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/field/EmptyInstanceFieldInitializationInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/EmptyInstanceFieldInitializationInfoCollection.java
@@ -7,7 +7,7 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import java.util.function.BiConsumer;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldArgumentInitializationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldArgumentInitializationInfo.java
index 0d28a5c..d737cda 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldArgumentInitializationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldArgumentInitializationInfo.java
@@ -5,7 +5,7 @@
 package com.android.tools.r8.ir.optimize.info.field;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.ArgumentInfo;
 import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
 import com.android.tools.r8.graph.proto.RemovedArgumentInfo;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfo.java
index 6bf9604..856dfc0 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfo.java
@@ -5,7 +5,7 @@
 package com.android.tools.r8.ir.optimize.info.field;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
 import com.android.tools.r8.ir.analysis.value.SingleValue;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfoCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfoCollection.java
index 772e2d8..d6ab75a 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfoCollection.java
@@ -9,7 +9,7 @@
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import java.util.TreeMap;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldTypeInitializationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldTypeInitializationInfo.java
index b494732..3f70c66 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldTypeInitializationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldTypeInitializationInfo.java
@@ -5,7 +5,7 @@
 package com.android.tools.r8.ir.optimize.info.field;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
 import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/NonTrivialInstanceFieldInitializationInfoCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/NonTrivialInstanceFieldInitializationInfoCollection.java
index 19c4ab9..1ecc4df 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/field/NonTrivialInstanceFieldInitializationInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/NonTrivialInstanceFieldInitializationInfoCollection.java
@@ -10,7 +10,7 @@
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.StringUtils;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/UnknownInstanceFieldInitializationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/UnknownInstanceFieldInitializationInfo.java
index 0f41427..356926c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/field/UnknownInstanceFieldInitializationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/UnknownInstanceFieldInitializationInfo.java
@@ -5,7 +5,7 @@
 package com.android.tools.r8.ir.optimize.info.field;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/ContextInsensitiveInstanceInitializerInfoCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/ContextInsensitiveInstanceInitializerInfoCollection.java
index 0e5ce2c..0cd8dba 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/ContextInsensitiveInstanceInitializerInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/ContextInsensitiveInstanceInitializerInfoCollection.java
@@ -5,8 +5,8 @@
 package com.android.tools.r8.ir.optimize.info.initializer;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
 import com.android.tools.r8.ir.code.InvokeDirect;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/ContextSensitiveInstanceInitializerInfoCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/ContextSensitiveInstanceInitializerInfoCollection.java
index 6a5efbb..de71f01 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/ContextSensitiveInstanceInitializerInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/ContextSensitiveInstanceInitializerInfoCollection.java
@@ -5,8 +5,8 @@
 package com.android.tools.r8.ir.optimize.info.initializer;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
 import com.android.tools.r8.ir.code.InvokeDirect;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/DefaultInstanceInitializerInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/DefaultInstanceInitializerInfo.java
index 59a6141..f16d460 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/DefaultInstanceInitializerInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/DefaultInstanceInitializerInfo.java
@@ -6,8 +6,8 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
 import com.android.tools.r8.ir.analysis.fieldvalueanalysis.AbstractFieldSet;
 import com.android.tools.r8.ir.analysis.fieldvalueanalysis.UnknownFieldSet;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/EmptyInstanceInitializerInfoCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/EmptyInstanceInitializerInfoCollection.java
index 19fea9a..aaf6701 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/EmptyInstanceInitializerInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/EmptyInstanceInitializerInfoCollection.java
@@ -5,8 +5,8 @@
 package com.android.tools.r8.ir.optimize.info.initializer;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
 import com.android.tools.r8.ir.code.InvokeDirect;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/InstanceInitializerInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/InstanceInitializerInfo.java
index cbf442c..abc4a80 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/InstanceInitializerInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/InstanceInitializerInfo.java
@@ -6,8 +6,8 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
 import com.android.tools.r8.ir.analysis.fieldvalueanalysis.AbstractFieldSet;
 import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoCollection;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/InstanceInitializerInfoCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/InstanceInitializerInfoCollection.java
index fd793a6..ba53dc8 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/InstanceInitializerInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/InstanceInitializerInfoCollection.java
@@ -5,8 +5,8 @@
 package com.android.tools.r8.ir.optimize.info.initializer;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
 import com.android.tools.r8.ir.code.InvokeDirect;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/NonTrivialInstanceInitializerInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/NonTrivialInstanceInitializerInfo.java
index 327e46a..2005de2 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/NonTrivialInstanceInitializerInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/NonTrivialInstanceInitializerInfo.java
@@ -7,8 +7,8 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
 import com.android.tools.r8.ir.analysis.fieldvalueanalysis.AbstractFieldSet;
 import com.android.tools.r8.ir.analysis.fieldvalueanalysis.ConcreteMutableFieldSet;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/inliner/multicallerinliner/MultiCallerInlinerInvokeRegistry.java b/src/main/java/com/android/tools/r8/ir/optimize/inliner/multicallerinliner/MultiCallerInlinerInvokeRegistry.java
index 06dab92..10d15ca 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/inliner/multicallerinliner/MultiCallerInlinerInvokeRegistry.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/inliner/multicallerinliner/MultiCallerInlinerInvokeRegistry.java
@@ -9,8 +9,8 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.code.InvokeType;
 import com.android.tools.r8.ir.conversion.callgraph.InvokeExtractor;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/membervaluepropagation/assume/AssumeInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/membervaluepropagation/assume/AssumeInfo.java
index 21d8d33..53dd0bf 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/membervaluepropagation/assume/AssumeInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/membervaluepropagation/assume/AssumeInfo.java
@@ -6,8 +6,8 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.analysis.type.DynamicType;
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
 import com.android.tools.r8.ir.analysis.value.SingleFieldValue;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlineCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlineCollection.java
index a3782b6..2982c98 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlineCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlineCollection.java
@@ -9,8 +9,8 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.optimize.outliner.OutlinerImpl.Outline;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.ListUtils;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlineOptimizationEventConsumer.java b/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlineOptimizationEventConsumer.java
index d9e8a39..620ce77 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlineOptimizationEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlineOptimizationEventConsumer.java
@@ -6,7 +6,7 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.profile.art.rewriting.ProfileRewritingOutlineOptimizationEventConsumer;
+import com.android.tools.r8.profile.rewriting.ProfileRewritingOutlineOptimizationEventConsumer;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import java.util.Collection;
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/outliner/Outliner.java b/src/main/java/com/android/tools/r8/ir/optimize/outliner/Outliner.java
index 472f1b1..9c77201 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/outliner/Outliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/outliner/Outliner.java
@@ -5,8 +5,8 @@
 package com.android.tools.r8.ir.optimize.outliner;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.conversion.IRConverter;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackDelayed;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlinerImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlinerImpl.java
index 7a888d8..ef163ad 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlinerImpl.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlinerImpl.java
@@ -22,10 +22,10 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.analysis.type.ArrayTypeElement;
 import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
 import com.android.tools.r8.ir.analysis.type.PrimitiveTypeElement;
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java
index ad0b54c..2200050 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java
@@ -10,9 +10,9 @@
 import com.android.tools.r8.graph.Code;
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.NumberGenerator;
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 f10a6cf..5c92ac9 100644
--- a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
@@ -41,6 +41,7 @@
 import com.android.tools.r8.graph.ParameterAnnotationsList;
 import com.android.tools.r8.graph.PermittedSubclassAttribute;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.RecordComponentInfo;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.naming.ProguardMapSupplier.ProguardMapId;
@@ -293,14 +294,9 @@
     }
 
     if (clazz.isRecord()) {
-      // TODO(b/169645628): Strip record components if not kept.
-      for (DexEncodedField instanceField : clazz.instanceFields()) {
-        String componentName = getNamingLens().lookupName(instanceField.getReference()).toString();
-        String componentDescriptor =
-            getNamingLens().lookupDescriptor(instanceField.getReference().type).toString();
-        String componentSignature =
-            instanceField.getGenericSignature().toRenamedString(getNamingLens(), isTypeMissing);
-        writer.visitRecordComponent(componentName, componentDescriptor, componentSignature);
+      // TODO(b/274888318): Strip record components if not kept.
+      for (RecordComponentInfo info : clazz.getRecordComponents()) {
+        info.write(writer, getNamingLens(), isTypeMissing, this::writeAnnotation);
       }
     }
 
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java
index b6ee8e3..890d89e 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java
@@ -10,7 +10,7 @@
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.kotlin.Kotlin.ClassClassifiers;
 import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.DescriptorUtils;
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeInfo.java
index 93735f4..ab3b27f 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeInfo.java
@@ -13,7 +13,7 @@
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.Reporter;
 import com.google.common.collect.ImmutableList;
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java
index adbb277..553c174 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java
@@ -10,7 +10,7 @@
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.kotlin.Kotlin.ClassClassifiers;
 import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.DescriptorUtils;
diff --git a/src/main/java/com/android/tools/r8/naming/KotlinModuleSynthesizer.java b/src/main/java/com/android/tools/r8/naming/KotlinModuleSynthesizer.java
index 7686a1e..de480da 100644
--- a/src/main/java/com/android/tools/r8/naming/KotlinModuleSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/naming/KotlinModuleSynthesizer.java
@@ -11,7 +11,7 @@
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.kotlin.KotlinClassLevelInfo;
 import com.android.tools.r8.kotlin.KotlinMultiFileClassPartInfo;
 import com.android.tools.r8.origin.Origin;
diff --git a/src/main/java/com/android/tools/r8/naming/dexitembasedstring/NameComputationInfo.java b/src/main/java/com/android/tools/r8/naming/dexitembasedstring/NameComputationInfo.java
index 8a16fb0..029547e 100644
--- a/src/main/java/com/android/tools/r8/naming/dexitembasedstring/NameComputationInfo.java
+++ b/src/main/java/com/android/tools/r8/naming/dexitembasedstring/NameComputationInfo.java
@@ -7,7 +7,7 @@
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexReference;
 import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.naming.NamingLens;
 
 public abstract class NameComputationInfo<T extends DexReference> {
diff --git a/src/main/java/com/android/tools/r8/naming/dexitembasedstring/RecordFieldNamesComputationInfo.java b/src/main/java/com/android/tools/r8/naming/dexitembasedstring/RecordFieldNamesComputationInfo.java
index 5ad5e27..8c2f8b7 100644
--- a/src/main/java/com/android/tools/r8/naming/dexitembasedstring/RecordFieldNamesComputationInfo.java
+++ b/src/main/java/com/android/tools/r8/naming/dexitembasedstring/RecordFieldNamesComputationInfo.java
@@ -12,7 +12,7 @@
 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.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.utils.StringUtils;
 import java.util.ArrayList;
diff --git a/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java b/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java
index 7b5a3ef..ad239c5 100644
--- a/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java
+++ b/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java
@@ -12,6 +12,7 @@
 import com.android.tools.r8.graph.GenericSignatureContextBuilder;
 import com.android.tools.r8.graph.GenericSignaturePartialTypeArgumentApplier;
 import com.android.tools.r8.graph.GenericSignatureTypeRewriter;
+import com.android.tools.r8.graph.RecordComponentInfo;
 import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.ThreadUtils;
 import java.util.Collection;
@@ -108,6 +109,10 @@
                                 .visitMethodSignature(method.getGenericSignature())
                             : method.getGenericSignature()));
               });
+          // TODO(b/274888318): Check this.
+          for (RecordComponentInfo recordComponent : clazz.getRecordComponents()) {
+            genericSignatureTypeRewriter.rewrite(recordComponent.getSignature());
+          }
         },
         executorService);
   }
diff --git a/src/main/java/com/android/tools/r8/optimize/AccessModifier.java b/src/main/java/com/android/tools/r8/optimize/AccessModifier.java
index b2d577c..85533d5 100644
--- a/src/main/java/com/android/tools/r8/optimize/AccessModifier.java
+++ b/src/main/java/com/android/tools/r8/optimize/AccessModifier.java
@@ -16,13 +16,13 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.FieldAccessFlags;
 import com.android.tools.r8.graph.FieldAccessInfo;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.InnerClassAttribute;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.graph.ProgramField;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.SubtypingInfo;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.optimize.MemberPoolCollection.MemberPool;
 import com.android.tools.r8.ir.optimize.MethodPoolCollection;
 import com.android.tools.r8.optimize.PublicizerLens.PublicizedLensBuilder;
diff --git a/src/main/java/com/android/tools/r8/optimize/FieldRebindingIdentityLens.java b/src/main/java/com/android/tools/r8/optimize/FieldRebindingIdentityLens.java
index a980c52..2e641f6 100644
--- a/src/main/java/com/android/tools/r8/optimize/FieldRebindingIdentityLens.java
+++ b/src/main/java/com/android/tools/r8/optimize/FieldRebindingIdentityLens.java
@@ -6,11 +6,9 @@
 
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
-import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
+import com.android.tools.r8.graph.lens.DefaultNonIdentityGraphLens;
+import com.android.tools.r8.graph.lens.FieldLookupResult;
+import com.android.tools.r8.graph.lens.GraphLens;
 import java.util.IdentityHashMap;
 import java.util.Map;
 
@@ -20,7 +18,7 @@
  *
  * <p>TODO(b/157616970): All uses of this should be replaced by {@link MemberRebindingIdentityLens}.
  */
-public class FieldRebindingIdentityLens extends NonIdentityGraphLens {
+public class FieldRebindingIdentityLens extends DefaultNonIdentityGraphLens {
 
   private final Map<DexField, DexField> nonReboundFieldReferenceToDefinitionMap;
 
@@ -55,69 +53,6 @@
     return nonReboundFieldReferenceToDefinitionMap.getOrDefault(field, field);
   }
 
-  @Override
-  public DexType getOriginalType(DexType type) {
-    return getPrevious().getOriginalType(type);
-  }
-
-  @Override
-  public Iterable<DexType> getOriginalTypes(DexType type) {
-    return getPrevious().getOriginalTypes(type);
-  }
-
-  @Override
-  public DexField getOriginalFieldSignature(DexField field) {
-    return getPrevious().getOriginalFieldSignature(field);
-  }
-
-  @Override
-  public DexField getRenamedFieldSignature(DexField originalField, GraphLens codeLens) {
-    if (this == codeLens) {
-      return originalField;
-    }
-    return getPrevious().getRenamedFieldSignature(originalField);
-  }
-
-  @Override
-  public DexMethod getRenamedMethodSignature(DexMethod originalMethod, GraphLens applied) {
-    return getPrevious().getRenamedMethodSignature(originalMethod, applied);
-  }
-
-  @Override
-  public final DexType internalDescribeLookupClassType(DexType previous) {
-    return previous;
-  }
-
-  @Override
-  public MethodLookupResult internalDescribeLookupMethod(
-      MethodLookupResult previous, DexMethod context) {
-    return previous;
-  }
-
-  @Override
-  public DexMethod getPreviousMethodSignature(DexMethod method) {
-    return method;
-  }
-
-  @Override
-  public DexMethod getNextMethodSignature(DexMethod method) {
-    return method;
-  }
-
-  @Override
-  public RewrittenPrototypeDescription lookupPrototypeChangesForMethodDefinition(
-      DexMethod method, GraphLens codeLens) {
-    if (this == codeLens) {
-      return getIdentityLens().lookupPrototypeChangesForMethodDefinition(method, codeLens);
-    }
-    return getPrevious().lookupPrototypeChangesForMethodDefinition(method, codeLens);
-  }
-
-  @Override
-  public boolean isContextFreeForMethods() {
-    return getPrevious().isContextFreeForMethods();
-  }
-
   public static class Builder {
 
     private final Map<DexField, DexField> nonReboundFieldReferenceToDefinitionMap =
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingEventConsumer.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingEventConsumer.java
index c6d1656..019f204 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingEventConsumer.java
@@ -7,7 +7,7 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.profile.art.rewriting.ProfileRewritingMemberRebindingEventConsumer;
+import com.android.tools.r8.profile.rewriting.ProfileRewritingMemberRebindingEventConsumer;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
 public interface MemberRebindingEventConsumer {
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingIdentityLens.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingIdentityLens.java
index 2e6fb53..0c6a75a 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingIdentityLens.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingIdentityLens.java
@@ -10,12 +10,13 @@
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.FieldAccessInfo;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
 import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
-import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
+import com.android.tools.r8.graph.lens.DefaultNonIdentityGraphLens;
+import com.android.tools.r8.graph.lens.FieldLookupResult;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.MethodLookupResult;
+import com.android.tools.r8.graph.lens.NonIdentityGraphLens;
 import java.util.IdentityHashMap;
 import java.util.Map;
 
@@ -24,7 +25,7 @@
  * both the non-rebound and rebound field and method references are available to all descendants of
  * this lens.
  */
-public class MemberRebindingIdentityLens extends NonIdentityGraphLens {
+public class MemberRebindingIdentityLens extends DefaultNonIdentityGraphLens {
 
   private final Map<DexField, DexField> nonReboundFieldReferenceToDefinitionMap;
   private final Map<DexMethod, DexMethod> nonReboundMethodReferenceToDefinitionMap;
@@ -96,66 +97,6 @@
   }
 
   @Override
-  public DexType getOriginalType(DexType type) {
-    return getPrevious().getOriginalType(type);
-  }
-
-  @Override
-  public Iterable<DexType> getOriginalTypes(DexType type) {
-    return getPrevious().getOriginalTypes(type);
-  }
-
-  @Override
-  public DexField getOriginalFieldSignature(DexField field) {
-    return getPrevious().getOriginalFieldSignature(field);
-  }
-
-  @Override
-  public DexField getRenamedFieldSignature(DexField originalField, GraphLens codeLens) {
-    if (this == codeLens) {
-      return originalField;
-    }
-    return getPrevious().getRenamedFieldSignature(originalField);
-  }
-
-  @Override
-  public DexMethod getRenamedMethodSignature(DexMethod originalMethod, GraphLens applied) {
-    if (this == applied) {
-      return originalMethod;
-    }
-    return getPrevious().getRenamedMethodSignature(originalMethod, applied);
-  }
-
-  @Override
-  public final DexType internalDescribeLookupClassType(DexType previous) {
-    return previous;
-  }
-
-  @Override
-  public DexMethod getPreviousMethodSignature(DexMethod method) {
-    return method;
-  }
-
-  @Override
-  public DexMethod getNextMethodSignature(DexMethod method) {
-    return method;
-  }
-
-  @Override
-  public RewrittenPrototypeDescription lookupPrototypeChangesForMethodDefinition(
-      DexMethod method, GraphLens codeLens) {
-    if (this == codeLens) {
-      return getIdentityLens().lookupPrototypeChangesForMethodDefinition(method, codeLens);
-    }
-    return getPrevious().lookupPrototypeChangesForMethodDefinition(method, codeLens);
-  }
-
-  @Override
-  public boolean isContextFreeForMethods() {
-    return getPrevious().isContextFreeForMethods();
-  }
-
-  @Override
   public boolean isMemberRebindingIdentityLens() {
     return true;
   }
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingLens.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingLens.java
index 367cd15..21796c5 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingLens.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingLens.java
@@ -4,25 +4,26 @@
 
 package com.android.tools.r8.optimize;
 
-import static com.android.tools.r8.graph.NestedGraphLens.mapVirtualInterfaceInvocationTypes;
+import static com.android.tools.r8.graph.lens.NestedGraphLens.mapVirtualInterfaceInvocationTypes;
 
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.FieldAccessInfo;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
-import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
+import com.android.tools.r8.graph.lens.DefaultNonIdentityGraphLens;
+import com.android.tools.r8.graph.lens.FieldLookupResult;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.MethodLookupResult;
+import com.android.tools.r8.graph.lens.NonIdentityGraphLens;
 import com.android.tools.r8.ir.code.InvokeType;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import java.util.Collections;
 import java.util.IdentityHashMap;
 import java.util.Map;
 
-public class MemberRebindingLens extends NonIdentityGraphLens {
+public class MemberRebindingLens extends DefaultNonIdentityGraphLens {
 
   private final AppView<AppInfoWithLiveness> appView;
   private final Map<InvokeType, Map<DexMethod, DexMethod>> methodMaps;
@@ -53,55 +54,6 @@
   }
 
   @Override
-  public DexType getOriginalType(DexType type) {
-    return getPrevious().getOriginalType(type);
-  }
-
-  @Override
-  public Iterable<DexType> getOriginalTypes(DexType type) {
-    return getPrevious().getOriginalTypes(type);
-  }
-
-  @Override
-  public DexField getOriginalFieldSignature(DexField field) {
-    return getPrevious().getOriginalFieldSignature(field);
-  }
-
-  @Override
-  public DexField getRenamedFieldSignature(DexField originalField, GraphLens codeLens) {
-    if (this == codeLens) {
-      return originalField;
-    }
-    return getPrevious().getRenamedFieldSignature(originalField);
-  }
-
-  @Override
-  public DexMethod getRenamedMethodSignature(DexMethod originalMethod, GraphLens applied) {
-    return this != applied
-        ? getPrevious().getRenamedMethodSignature(originalMethod, applied)
-        : originalMethod;
-  }
-
-  @Override
-  public RewrittenPrototypeDescription lookupPrototypeChangesForMethodDefinition(
-      DexMethod method, GraphLens codeLens) {
-    if (this == codeLens) {
-      return getIdentityLens().lookupPrototypeChangesForMethodDefinition(method, codeLens);
-    }
-    return getPrevious().lookupPrototypeChangesForMethodDefinition(method, codeLens);
-  }
-
-  @Override
-  public boolean isContextFreeForMethods() {
-    return getPrevious().isContextFreeForMethods();
-  }
-
-  @Override
-  protected DexType internalDescribeLookupClassType(DexType previous) {
-    return previous;
-  }
-
-  @Override
   protected FieldLookupResult internalDescribeLookupField(FieldLookupResult previous) {
     assert !previous.hasReadCastType();
     assert !previous.hasReboundReference();
@@ -133,16 +85,6 @@
         .build();
   }
 
-  @Override
-  public DexMethod getPreviousMethodSignature(DexMethod method) {
-    return method;
-  }
-
-  @Override
-  public DexMethod getNextMethodSignature(DexMethod method) {
-    return method;
-  }
-
   public FieldRebindingIdentityLens toRewrittenFieldRebindingLens(
       AppView<? extends AppInfoWithClassHierarchy> appView,
       GraphLens lens,
diff --git a/src/main/java/com/android/tools/r8/optimize/PublicizerLens.java b/src/main/java/com/android/tools/r8/optimize/PublicizerLens.java
index a3365ce..54d66e4 100644
--- a/src/main/java/com/android/tools/r8/optimize/PublicizerLens.java
+++ b/src/main/java/com/android/tools/r8/optimize/PublicizerLens.java
@@ -7,8 +7,10 @@
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.NestedGraphLens;
+import com.android.tools.r8.graph.lens.FieldLookupResult;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.MethodLookupResult;
+import com.android.tools.r8.graph.lens.NestedGraphLens;
 import com.android.tools.r8.ir.code.InvokeType;
 import com.google.common.collect.Sets;
 import java.util.Set;
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorApplicationFixer.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorApplicationFixer.java
index 8dd8cb0..eff4f92 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorApplicationFixer.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorApplicationFixer.java
@@ -16,10 +16,10 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
 import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.MethodCollection;
 import com.android.tools.r8.graph.PrunedItems;
 import com.android.tools.r8.graph.TreeFixerBase;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
 import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfoFixer;
 import com.android.tools.r8.ir.optimize.info.MutableFieldOptimizationInfo;
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorGraphLens.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorGraphLens.java
index 35b3a9c..42213aa 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorGraphLens.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorGraphLens.java
@@ -7,7 +7,8 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.NestedGraphLens;
+import com.android.tools.r8.graph.lens.FieldLookupResult;
+import com.android.tools.r8.graph.lens.NestedGraphLens;
 import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
 import com.android.tools.r8.ir.code.InvokeType;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java
index cd962c3..acdb13b 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java
@@ -11,11 +11,11 @@
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.FieldResolutionResult;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
 import com.android.tools.r8.graph.ProgramField;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistryWithResult;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.IRConverter;
 import com.android.tools.r8.ir.conversion.PostMethodProcessor;
 import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorSyntheticEventConsumer.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorSyntheticEventConsumer.java
index 397a23f..f20e6a8 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorSyntheticEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorSyntheticEventConsumer.java
@@ -7,7 +7,7 @@
 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.profile.art.rewriting.ProfileRewritingArgumentPropagatorSyntheticEventConsumer;
+import com.android.tools.r8.profile.rewriting.ProfileRewritingArgumentPropagatorSyntheticEventConsumer;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
 public interface ArgumentPropagatorSyntheticEventConsumer {
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/lenscoderewriter/NullCheckInserter.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/lenscoderewriter/NullCheckInserter.java
index 07ffe61..468b735 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/lenscoderewriter/NullCheckInserter.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/lenscoderewriter/NullCheckInserter.java
@@ -8,9 +8,9 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.FieldResolutionResult;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
-import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.MethodLookupResult;
+import com.android.tools.r8.graph.lens.NonIdentityGraphLens;
 import com.android.tools.r8.graph.proto.ArgumentInfo;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.code.BasicBlock;
diff --git a/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoistingLens.java b/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoistingLens.java
index d47ecd6..69f9248 100644
--- a/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoistingLens.java
+++ b/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoistingLens.java
@@ -5,16 +5,13 @@
 package com.android.tools.r8.optimize.bridgehoisting;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
-import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
+import com.android.tools.r8.graph.lens.DefaultNonIdentityGraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.utils.collections.BidirectionalManyToOneMap;
 import java.util.Set;
 
-class BridgeHoistingLens extends NonIdentityGraphLens {
+class BridgeHoistingLens extends DefaultNonIdentityGraphLens {
 
   // Mapping from non-hoisted bridge methods to hoisted bridge methods.
   private final BidirectionalManyToOneMap<DexMethod, DexMethod> bridgeToHoistedBridgeMap;
@@ -44,60 +41,7 @@
   }
 
   @Override
-  public DexType getOriginalType(DexType type) {
-    return getPrevious().getOriginalType(type);
-  }
-
-  @Override
-  public Iterable<DexType> getOriginalTypes(DexType type) {
-    return getPrevious().getOriginalTypes(type);
-  }
-
-  @Override
-  public DexField getOriginalFieldSignature(DexField field) {
-    return getPrevious().getOriginalFieldSignature(field);
-  }
-
-  @Override
-  public DexField getRenamedFieldSignature(DexField originalField, GraphLens codeLens) {
-    if (this == codeLens) {
-      return originalField;
-    }
-    return getPrevious().getRenamedFieldSignature(originalField);
-  }
-
-  @Override
-  public RewrittenPrototypeDescription lookupPrototypeChangesForMethodDefinition(
-      DexMethod method, GraphLens codeLens) {
-    if (this == codeLens) {
-      return getIdentityLens().lookupPrototypeChangesForMethodDefinition(method, codeLens);
-    }
-    return getPrevious().lookupPrototypeChangesForMethodDefinition(method, codeLens);
-  }
-
-  @Override
-  public boolean isContextFreeForMethods() {
-    return getPrevious().isContextFreeForMethods();
-  }
-
-  @Override
   public boolean hasCodeRewritings() {
     return getPrevious().hasCodeRewritings();
   }
-
-  @Override
-  protected FieldLookupResult internalDescribeLookupField(FieldLookupResult previous) {
-    return previous;
-  }
-
-  @Override
-  protected MethodLookupResult internalDescribeLookupMethod(
-      MethodLookupResult previous, DexMethod context) {
-    return previous;
-  }
-
-  @Override
-  protected DexType internalDescribeLookupClassType(DexType previous) {
-    return previous;
-  }
 }
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/collection/DefaultOpenClosedInterfacesCollection.java b/src/main/java/com/android/tools/r8/optimize/interfaces/collection/DefaultOpenClosedInterfacesCollection.java
index df264e4..6759bca 100644
--- a/src/main/java/com/android/tools/r8/optimize/interfaces/collection/DefaultOpenClosedInterfacesCollection.java
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/collection/DefaultOpenClosedInterfacesCollection.java
@@ -5,8 +5,8 @@
 package com.android.tools.r8.optimize.interfaces.collection;
 
 import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.GraphLens;
 
 /** Default oracle for that answers "maybe open" for each interface. */
 public class DefaultOpenClosedInterfacesCollection extends OpenClosedInterfacesCollection {
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/collection/NonEmptyOpenClosedInterfacesCollection.java b/src/main/java/com/android/tools/r8/optimize/interfaces/collection/NonEmptyOpenClosedInterfacesCollection.java
index b3382e0..8553b40 100644
--- a/src/main/java/com/android/tools/r8/optimize/interfaces/collection/NonEmptyOpenClosedInterfacesCollection.java
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/collection/NonEmptyOpenClosedInterfacesCollection.java
@@ -6,8 +6,8 @@
 
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.utils.SetUtils;
 import java.util.Set;
 
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/collection/OpenClosedInterfacesCollection.java b/src/main/java/com/android/tools/r8/optimize/interfaces/collection/OpenClosedInterfacesCollection.java
index 755c319..648c8a3 100644
--- a/src/main/java/com/android/tools/r8/optimize/interfaces/collection/OpenClosedInterfacesCollection.java
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/collection/OpenClosedInterfacesCollection.java
@@ -6,8 +6,8 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
 import com.android.tools.r8.ir.analysis.type.DynamicType;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
diff --git a/src/main/java/com/android/tools/r8/optimize/proto/ProtoNormalizerGraphLens.java b/src/main/java/com/android/tools/r8/optimize/proto/ProtoNormalizerGraphLens.java
index 6f7f61f..5aedebc 100644
--- a/src/main/java/com/android/tools/r8/optimize/proto/ProtoNormalizerGraphLens.java
+++ b/src/main/java/com/android/tools/r8/optimize/proto/ProtoNormalizerGraphLens.java
@@ -6,11 +6,11 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
+import com.android.tools.r8.graph.lens.DefaultNonIdentityGraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.MethodLookupResult;
 import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
 import com.android.tools.r8.graph.proto.ArgumentPermutation;
 import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
@@ -22,7 +22,7 @@
 import java.util.IdentityHashMap;
 import java.util.Map;
 
-public class ProtoNormalizerGraphLens extends NonIdentityGraphLens {
+public class ProtoNormalizerGraphLens extends DefaultNonIdentityGraphLens {
 
   private final BidirectionalOneToOneMap<DexMethod, DexMethod> newMethodSignatures;
   private final Map<DexMethod, RewrittenPrototypeDescription> prototypeChanges;
@@ -41,37 +41,6 @@
   }
 
   @Override
-  public DexType getOriginalType(DexType type) {
-    return getPrevious().getOriginalType(type);
-  }
-
-  @Override
-  public Iterable<DexType> getOriginalTypes(DexType type) {
-    return getPrevious().getOriginalTypes(type);
-  }
-
-  @Override
-  public DexField getOriginalFieldSignature(DexField field) {
-    return getPrevious().getOriginalFieldSignature(field);
-  }
-
-  @Override
-  public DexField getRenamedFieldSignature(DexField originalField, GraphLens applied) {
-    if (this == applied) {
-      return originalField;
-    }
-    return getPrevious().getRenamedFieldSignature(originalField);
-  }
-
-  @Override
-  public DexMethod getRenamedMethodSignature(DexMethod originalMethod, GraphLens applied) {
-    if (this == applied) {
-      return originalMethod;
-    }
-    return getNextMethodSignature(getPrevious().getRenamedMethodSignature(originalMethod));
-  }
-
-  @Override
   public RewrittenPrototypeDescription lookupPrototypeChangesForMethodDefinition(
       DexMethod method, GraphLens codeLens) {
     if (this == codeLens) {
@@ -88,16 +57,6 @@
   }
 
   @Override
-  public boolean isContextFreeForMethods() {
-    return getPrevious().isContextFreeForMethods();
-  }
-
-  @Override
-  protected FieldLookupResult internalDescribeLookupField(FieldLookupResult previous) {
-    return previous;
-  }
-
-  @Override
   protected MethodLookupResult internalDescribeLookupMethod(
       MethodLookupResult previous, DexMethod context) {
     DexMethod methodSignature = previous.getReference();
@@ -120,11 +79,6 @@
   }
 
   @Override
-  protected DexType internalDescribeLookupClassType(DexType previous) {
-    return previous;
-  }
-
-  @Override
   public DexMethod getPreviousMethodSignature(DexMethod method) {
     return newMethodSignatures.getRepresentativeKeyOrDefault(method, method);
   }
diff --git a/src/main/java/com/android/tools/r8/optimize/redundantbridgeremoval/RedundantBridgeRemovalLens.java b/src/main/java/com/android/tools/r8/optimize/redundantbridgeremoval/RedundantBridgeRemovalLens.java
index 343cece..427b37e 100644
--- a/src/main/java/com/android/tools/r8/optimize/redundantbridgeremoval/RedundantBridgeRemovalLens.java
+++ b/src/main/java/com/android/tools/r8/optimize/redundantbridgeremoval/RedundantBridgeRemovalLens.java
@@ -6,20 +6,19 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClassAndMethod;
-import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
+import com.android.tools.r8.graph.lens.DefaultNonIdentityGraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.MethodLookupResult;
 import com.android.tools.r8.ir.code.InvokeType;
 import com.google.common.collect.Sets;
 import java.util.IdentityHashMap;
 import java.util.Map;
 import java.util.Set;
 
-public class RedundantBridgeRemovalLens extends NonIdentityGraphLens {
+public class RedundantBridgeRemovalLens extends DefaultNonIdentityGraphLens {
 
   private final Set<DexType> interfaces;
   private final Map<DexMethod, DexMethod> methodMap;
@@ -31,26 +30,6 @@
     this.methodMap = methodMap;
   }
 
-  // Fields.
-
-  @Override
-  public DexField getOriginalFieldSignature(DexField field) {
-    return getPrevious().getOriginalFieldSignature(field);
-  }
-
-  @Override
-  public DexField getRenamedFieldSignature(DexField originalField, GraphLens codeLens) {
-    if (this == codeLens) {
-      return originalField;
-    }
-    return getPrevious().getRenamedFieldSignature(originalField, codeLens);
-  }
-
-  @Override
-  protected FieldLookupResult internalDescribeLookupField(FieldLookupResult previous) {
-    return previous;
-  }
-
   // Methods.
 
   @Override
@@ -64,16 +43,6 @@
   }
 
   @Override
-  public DexMethod getNextMethodSignature(DexMethod method) {
-    return method;
-  }
-
-  @Override
-  public DexMethod getPreviousMethodSignature(DexMethod method) {
-    return method;
-  }
-
-  @Override
   protected MethodLookupResult internalDescribeLookupMethod(
       MethodLookupResult previous, DexMethod context) {
     if (methodMap.containsKey(previous.getReference())) {
@@ -98,39 +67,6 @@
     return previous;
   }
 
-  @Override
-  public RewrittenPrototypeDescription lookupPrototypeChangesForMethodDefinition(
-      DexMethod method, GraphLens codeLens) {
-    if (this == codeLens) {
-      return RewrittenPrototypeDescription.none();
-    }
-    return getPrevious().lookupPrototypeChangesForMethodDefinition(method, codeLens);
-  }
-
-  // Types.
-
-  @Override
-  public DexType getOriginalType(DexType type) {
-    return getPrevious().getOriginalType(type);
-  }
-
-  @Override
-  public Iterable<DexType> getOriginalTypes(DexType type) {
-    return getPrevious().getOriginalTypes(type);
-  }
-
-  @Override
-  protected DexType internalDescribeLookupClassType(DexType previous) {
-    return previous;
-  }
-
-  // Misc.
-
-  @Override
-  public boolean isContextFreeForMethods() {
-    return getPrevious().isContextFreeForMethods();
-  }
-
   public static class Builder {
 
     private final Set<DexType> interfaces = Sets.newIdentityHashSet();
diff --git a/src/main/java/com/android/tools/r8/profile/AbstractProfileRule.java b/src/main/java/com/android/tools/r8/profile/AbstractProfileRule.java
index ad28bfd..6d72137 100644
--- a/src/main/java/com/android/tools/r8/profile/AbstractProfileRule.java
+++ b/src/main/java/com/android/tools/r8/profile/AbstractProfileRule.java
@@ -4,8 +4,8 @@
 
 package com.android.tools.r8.profile;
 
-import com.android.tools.r8.experimental.startup.profile.StartupProfileRule;
 import com.android.tools.r8.profile.art.ArtProfileRule;
+import com.android.tools.r8.profile.startup.profile.StartupProfileRule;
 
 public interface AbstractProfileRule {
 
diff --git a/src/main/java/com/android/tools/r8/profile/art/ArtProfile.java b/src/main/java/com/android/tools/r8/profile/art/ArtProfile.java
index e42e8ba..1455800 100644
--- a/src/main/java/com/android/tools/r8/profile/art/ArtProfile.java
+++ b/src/main/java/com/android/tools/r8/profile/art/ArtProfile.java
@@ -15,8 +15,8 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexReference;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.optimize.enums.EnumUnboxingLens;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.profile.AbstractProfile;
diff --git a/src/main/java/com/android/tools/r8/profile/art/ArtProfileCollection.java b/src/main/java/com/android/tools/r8/profile/art/ArtProfileCollection.java
index a571922..e6dc68a 100644
--- a/src/main/java/com/android/tools/r8/profile/art/ArtProfileCollection.java
+++ b/src/main/java/com/android/tools/r8/profile/art/ArtProfileCollection.java
@@ -8,8 +8,8 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.InternalOptions;
diff --git a/src/main/java/com/android/tools/r8/profile/art/EmptyArtProfileCollection.java b/src/main/java/com/android/tools/r8/profile/art/EmptyArtProfileCollection.java
index 744ea4d..2c63d2e 100644
--- a/src/main/java/com/android/tools/r8/profile/art/EmptyArtProfileCollection.java
+++ b/src/main/java/com/android/tools/r8/profile/art/EmptyArtProfileCollection.java
@@ -6,8 +6,8 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.naming.NamingLens;
 
 public class EmptyArtProfileCollection extends ArtProfileCollection {
diff --git a/src/main/java/com/android/tools/r8/profile/art/NonEmptyArtProfileCollection.java b/src/main/java/com/android/tools/r8/profile/art/NonEmptyArtProfileCollection.java
index 0cb809e..d91ebae 100644
--- a/src/main/java/com/android/tools/r8/profile/art/NonEmptyArtProfileCollection.java
+++ b/src/main/java/com/android/tools/r8/profile/art/NonEmptyArtProfileCollection.java
@@ -6,8 +6,8 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.ListUtils;
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileAdditions.java b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileAdditions.java
index 6207388..2425ef4 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileAdditions.java
+++ b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileAdditions.java
@@ -9,22 +9,24 @@
 import com.android.tools.r8.profile.AbstractProfileRule;
 import com.android.tools.r8.profile.art.ArtProfile;
 import com.android.tools.r8.profile.art.ArtProfileClassRule;
+import com.android.tools.r8.profile.art.ArtProfileClassRule.Builder;
 import com.android.tools.r8.profile.art.ArtProfileMethodRule;
 import com.android.tools.r8.profile.art.ArtProfileRule;
+import com.android.tools.r8.profile.rewriting.ProfileAdditions;
 import java.util.Comparator;
 
 public class ArtProfileAdditions
     extends ProfileAdditions<
         ArtProfileAdditions,
         ArtProfileClassRule,
-        ArtProfileClassRule.Builder,
+        Builder,
         ArtProfileMethodRule,
         ArtProfileMethodRule.Builder,
         ArtProfileRule,
         ArtProfile,
         ArtProfile.Builder> {
 
-  ArtProfileAdditions(ArtProfile profile) {
+  public ArtProfileAdditions(ArtProfile profile) {
     super(profile);
   }
 
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ConcreteProfileCollectionAdditions.java b/src/main/java/com/android/tools/r8/profile/rewriting/ConcreteProfileCollectionAdditions.java
similarity index 95%
rename from src/main/java/com/android/tools/r8/profile/art/rewriting/ConcreteProfileCollectionAdditions.java
rename to src/main/java/com/android/tools/r8/profile/rewriting/ConcreteProfileCollectionAdditions.java
index 90cbd6b..cb799fd 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/ConcreteProfileCollectionAdditions.java
+++ b/src/main/java/com/android/tools/r8/profile/rewriting/ConcreteProfileCollectionAdditions.java
@@ -2,10 +2,8 @@
 // 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.profile.art.rewriting;
+package com.android.tools.r8.profile.rewriting;
 
-import com.android.tools.r8.experimental.startup.StartupProfile;
-import com.android.tools.r8.experimental.startup.rewriting.StartupProfileAdditions;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexMethod;
@@ -16,7 +14,10 @@
 import com.android.tools.r8.profile.art.ArtProfile;
 import com.android.tools.r8.profile.art.ArtProfileCollection;
 import com.android.tools.r8.profile.art.NonEmptyArtProfileCollection;
-import com.android.tools.r8.profile.art.rewriting.ProfileAdditions.ProfileAdditionsBuilder;
+import com.android.tools.r8.profile.art.rewriting.ArtProfileAdditions;
+import com.android.tools.r8.profile.rewriting.ProfileAdditions.ProfileAdditionsBuilder;
+import com.android.tools.r8.profile.startup.profile.StartupProfile;
+import com.android.tools.r8.profile.startup.rewriting.StartupProfileAdditions;
 import com.android.tools.r8.utils.Box;
 import com.google.common.collect.Iterables;
 import java.util.ArrayList;
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/NopProfileCollectionAdditions.java b/src/main/java/com/android/tools/r8/profile/rewriting/NopProfileCollectionAdditions.java
similarity index 89%
rename from src/main/java/com/android/tools/r8/profile/art/rewriting/NopProfileCollectionAdditions.java
rename to src/main/java/com/android/tools/r8/profile/rewriting/NopProfileCollectionAdditions.java
index d27a083..fbbccd7 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/NopProfileCollectionAdditions.java
+++ b/src/main/java/com/android/tools/r8/profile/rewriting/NopProfileCollectionAdditions.java
@@ -2,14 +2,14 @@
 // 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.profile.art.rewriting;
+package com.android.tools.r8.profile.rewriting;
 
-import com.android.tools.r8.experimental.startup.StartupProfile;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.profile.art.ArtProfileCollection;
-import com.android.tools.r8.profile.art.rewriting.ProfileAdditions.ProfileAdditionsBuilder;
+import com.android.tools.r8.profile.rewriting.ProfileAdditions.ProfileAdditionsBuilder;
+import com.android.tools.r8.profile.startup.profile.StartupProfile;
 import java.util.function.Consumer;
 import java.util.function.Function;
 
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileAdditions.java b/src/main/java/com/android/tools/r8/profile/rewriting/ProfileAdditions.java
similarity index 99%
rename from src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileAdditions.java
rename to src/main/java/com/android/tools/r8/profile/rewriting/ProfileAdditions.java
index 3df9866..869f88b 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileAdditions.java
+++ b/src/main/java/com/android/tools/r8/profile/rewriting/ProfileAdditions.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.profile.art.rewriting;
+package com.android.tools.r8.profile.rewriting;
 
 import static com.android.tools.r8.utils.MapUtils.ignoreKey;
 
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileCollectionAdditions.java b/src/main/java/com/android/tools/r8/profile/rewriting/ProfileCollectionAdditions.java
similarity index 91%
rename from src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileCollectionAdditions.java
rename to src/main/java/com/android/tools/r8/profile/rewriting/ProfileCollectionAdditions.java
index 93be945..cd9de9b 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileCollectionAdditions.java
+++ b/src/main/java/com/android/tools/r8/profile/rewriting/ProfileCollectionAdditions.java
@@ -2,14 +2,14 @@
 // 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.profile.art.rewriting;
+package com.android.tools.r8.profile.rewriting;
 
-import com.android.tools.r8.experimental.startup.StartupProfile;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.profile.art.ArtProfileCollection;
-import com.android.tools.r8.profile.art.rewriting.ProfileAdditions.ProfileAdditionsBuilder;
+import com.android.tools.r8.profile.rewriting.ProfileAdditions.ProfileAdditionsBuilder;
+import com.android.tools.r8.profile.startup.profile.StartupProfile;
 import java.util.function.Consumer;
 import java.util.function.Function;
 
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingApiReferenceStubberEventConsumer.java b/src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingApiReferenceStubberEventConsumer.java
similarity index 97%
rename from src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingApiReferenceStubberEventConsumer.java
rename to src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingApiReferenceStubberEventConsumer.java
index 4f7f76c..c5bbcf7 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingApiReferenceStubberEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingApiReferenceStubberEventConsumer.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.profile.art.rewriting;
+package com.android.tools.r8.profile.rewriting;
 
 import static com.android.tools.r8.utils.ConsumerUtils.emptyConsumer;
 
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingArgumentPropagatorSyntheticEventConsumer.java b/src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingArgumentPropagatorSyntheticEventConsumer.java
similarity index 97%
rename from src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingArgumentPropagatorSyntheticEventConsumer.java
rename to src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingArgumentPropagatorSyntheticEventConsumer.java
index dece00f..156f392 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingArgumentPropagatorSyntheticEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingArgumentPropagatorSyntheticEventConsumer.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.profile.art.rewriting;
+package com.android.tools.r8.profile.rewriting;
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexProgramClass;
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingCfClassSynthesizerDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingCfClassSynthesizerDesugaringEventConsumer.java
similarity index 95%
rename from src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingCfClassSynthesizerDesugaringEventConsumer.java
rename to src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingCfClassSynthesizerDesugaringEventConsumer.java
index 2d0f51c..c16dd21 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingCfClassSynthesizerDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingCfClassSynthesizerDesugaringEventConsumer.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.profile.art.rewriting;
+package com.android.tools.r8.profile.rewriting;
 
-import static com.android.tools.r8.profile.art.rewriting.ProfileRewritingVarHandleDesugaringEventConsumerUtils.handleVarHandleDesugaringClassContext;
+import static com.android.tools.r8.profile.rewriting.ProfileRewritingVarHandleDesugaringEventConsumerUtils.handleVarHandleDesugaringClassContext;
 
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingCfInstructionDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingCfInstructionDesugaringEventConsumer.java
similarity index 98%
rename from src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingCfInstructionDesugaringEventConsumer.java
rename to src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingCfInstructionDesugaringEventConsumer.java
index 60a9e96..a9d901a 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingCfInstructionDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingCfInstructionDesugaringEventConsumer.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.profile.art.rewriting;
+package com.android.tools.r8.profile.rewriting;
 
-import static com.android.tools.r8.profile.art.rewriting.ProfileRewritingVarHandleDesugaringEventConsumerUtils.handleVarHandleDesugaringClassContext;
+import static com.android.tools.r8.profile.rewriting.ProfileRewritingVarHandleDesugaringEventConsumerUtils.handleVarHandleDesugaringClassContext;
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClassAndMethod;
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingCfPostProcessingDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingCfPostProcessingDesugaringEventConsumer.java
similarity index 98%
rename from src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingCfPostProcessingDesugaringEventConsumer.java
rename to src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingCfPostProcessingDesugaringEventConsumer.java
index 5402a78..0d5c835 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingCfPostProcessingDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingCfPostProcessingDesugaringEventConsumer.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.profile.art.rewriting;
+package com.android.tools.r8.profile.rewriting;
 
 import static com.android.tools.r8.utils.ConsumerUtils.emptyConsumer;
 
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingCovariantReturnTypeAnnotationTransformerEventConsumer.java b/src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingCovariantReturnTypeAnnotationTransformerEventConsumer.java
similarity index 96%
rename from src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingCovariantReturnTypeAnnotationTransformerEventConsumer.java
rename to src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingCovariantReturnTypeAnnotationTransformerEventConsumer.java
index 32c6d73..ef07715 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingCovariantReturnTypeAnnotationTransformerEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingCovariantReturnTypeAnnotationTransformerEventConsumer.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.profile.art.rewriting;
+package com.android.tools.r8.profile.rewriting;
 
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.desugar.CovariantReturnTypeAnnotationTransformerEventConsumer;
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingMemberRebindingEventConsumer.java b/src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingMemberRebindingEventConsumer.java
similarity index 97%
rename from src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingMemberRebindingEventConsumer.java
rename to src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingMemberRebindingEventConsumer.java
index 1c9b0a5..c7aa6b9 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingMemberRebindingEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingMemberRebindingEventConsumer.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.profile.art.rewriting;
+package com.android.tools.r8.profile.rewriting;
 
 import static com.android.tools.r8.utils.ConsumerUtils.emptyConsumer;
 
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingMethodProcessorEventConsumer.java b/src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingMethodProcessorEventConsumer.java
similarity index 98%
rename from src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingMethodProcessorEventConsumer.java
rename to src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingMethodProcessorEventConsumer.java
index c5193da..5df02c0 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingMethodProcessorEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingMethodProcessorEventConsumer.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.profile.art.rewriting;
+package com.android.tools.r8.profile.rewriting;
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.ProgramMethod;
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingNestBasedAccessDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingNestBasedAccessDesugaringEventConsumer.java
similarity index 98%
rename from src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingNestBasedAccessDesugaringEventConsumer.java
rename to src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingNestBasedAccessDesugaringEventConsumer.java
index 28552b5..65cce7f 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingNestBasedAccessDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingNestBasedAccessDesugaringEventConsumer.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.profile.art.rewriting;
+package com.android.tools.r8.profile.rewriting;
 
 import static com.android.tools.r8.utils.ConsumerUtils.emptyConsumer;
 
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingOutlineOptimizationEventConsumer.java b/src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingOutlineOptimizationEventConsumer.java
similarity index 97%
rename from src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingOutlineOptimizationEventConsumer.java
rename to src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingOutlineOptimizationEventConsumer.java
index 4343c25..c64cea3 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingOutlineOptimizationEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingOutlineOptimizationEventConsumer.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.profile.art.rewriting;
+package com.android.tools.r8.profile.rewriting;
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.ProgramMethod;
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingRootSetBuilderEventConsumer.java b/src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingRootSetBuilderEventConsumer.java
similarity index 97%
rename from src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingRootSetBuilderEventConsumer.java
rename to src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingRootSetBuilderEventConsumer.java
index 9b9d6a5..2a10ce0 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingRootSetBuilderEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingRootSetBuilderEventConsumer.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.profile.art.rewriting;
+package com.android.tools.r8.profile.rewriting;
 
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.shaking.RootSetBuilderEventConsumer;
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingVarHandleDesugaringEventConsumerUtils.java b/src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingVarHandleDesugaringEventConsumerUtils.java
similarity index 95%
rename from src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingVarHandleDesugaringEventConsumerUtils.java
rename to src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingVarHandleDesugaringEventConsumerUtils.java
index 8792769..c9ff809 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileRewritingVarHandleDesugaringEventConsumerUtils.java
+++ b/src/main/java/com/android/tools/r8/profile/rewriting/ProfileRewritingVarHandleDesugaringEventConsumerUtils.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.profile.art.rewriting;
+package com.android.tools.r8.profile.rewriting;
 
 import static com.android.tools.r8.utils.ConsumerUtils.emptyConsumer;
 
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupCompleteness.java b/src/main/java/com/android/tools/r8/profile/startup/StartupCompleteness.java
similarity index 96%
rename from src/main/java/com/android/tools/r8/experimental/startup/StartupCompleteness.java
rename to src/main/java/com/android/tools/r8/profile/startup/StartupCompleteness.java
index f45e4c0..decafac 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/StartupCompleteness.java
+++ b/src/main/java/com/android/tools/r8/profile/startup/StartupCompleteness.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.experimental.startup;
+package com.android.tools.r8.profile.startup;
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedMethod;
@@ -11,6 +11,7 @@
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.ThrowNullCode;
+import com.android.tools.r8.profile.startup.profile.StartupProfile;
 import com.android.tools.r8.startup.diagnostic.MissingStartupProfileItemsDiagnostic;
 import com.android.tools.r8.utils.InternalOptions;
 import com.google.common.collect.Sets;
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupOptions.java b/src/main/java/com/android/tools/r8/profile/startup/StartupOptions.java
similarity index 98%
rename from src/main/java/com/android/tools/r8/experimental/startup/StartupOptions.java
rename to src/main/java/com/android/tools/r8/profile/startup/StartupOptions.java
index 531c50e..4180266 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/StartupOptions.java
+++ b/src/main/java/com/android/tools/r8/profile/startup/StartupOptions.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.experimental.startup;
+package com.android.tools.r8.profile.startup;
 
 import static com.android.tools.r8.utils.SystemPropertyUtils.parseSystemPropertyForDevelopmentOrDefault;
 
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupProfileProviderUtils.java b/src/main/java/com/android/tools/r8/profile/startup/StartupProfileProviderUtils.java
similarity index 93%
rename from src/main/java/com/android/tools/r8/experimental/startup/StartupProfileProviderUtils.java
rename to src/main/java/com/android/tools/r8/profile/startup/StartupProfileProviderUtils.java
index ff5b0e9..3b12dfd 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/StartupProfileProviderUtils.java
+++ b/src/main/java/com/android/tools/r8/profile/startup/StartupProfileProviderUtils.java
@@ -2,14 +2,15 @@
 // 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.experimental.startup;
+package com.android.tools.r8.profile.startup;
 
 import static com.android.tools.r8.utils.ConsumerUtils.emptyConsumer;
 
-import com.android.tools.r8.experimental.startup.profile.StartupProfileRule;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.origin.PathOrigin;
 import com.android.tools.r8.profile.art.HumanReadableArtProfileParserBuilder;
+import com.android.tools.r8.profile.startup.profile.StartupProfile;
+import com.android.tools.r8.profile.startup.profile.StartupProfileRule;
 import com.android.tools.r8.startup.StartupProfileBuilder;
 import com.android.tools.r8.startup.StartupProfileProvider;
 import com.android.tools.r8.startup.diagnostic.MissingStartupProfileItemsDiagnostic;
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/instrumentation/StartupInstrumentation.java b/src/main/java/com/android/tools/r8/profile/startup/instrumentation/StartupInstrumentation.java
similarity index 99%
rename from src/main/java/com/android/tools/r8/experimental/startup/instrumentation/StartupInstrumentation.java
rename to src/main/java/com/android/tools/r8/profile/startup/instrumentation/StartupInstrumentation.java
index 6e9c218..a64d1c7 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/instrumentation/StartupInstrumentation.java
+++ b/src/main/java/com/android/tools/r8/profile/startup/instrumentation/StartupInstrumentation.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.experimental.startup.instrumentation;
+package com.android.tools.r8.profile.startup.instrumentation;
 
 import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
 import static com.android.tools.r8.utils.PredicateUtils.not;
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/instrumentation/StartupInstrumentationOptions.java b/src/main/java/com/android/tools/r8/profile/startup/instrumentation/StartupInstrumentationOptions.java
similarity index 97%
rename from src/main/java/com/android/tools/r8/experimental/startup/instrumentation/StartupInstrumentationOptions.java
rename to src/main/java/com/android/tools/r8/profile/startup/instrumentation/StartupInstrumentationOptions.java
index 0d47783..ad94406 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/instrumentation/StartupInstrumentationOptions.java
+++ b/src/main/java/com/android/tools/r8/profile/startup/instrumentation/StartupInstrumentationOptions.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.experimental.startup.instrumentation;
+package com.android.tools.r8.profile.startup.instrumentation;
 
 import static com.android.tools.r8.utils.SystemPropertyUtils.getSystemPropertyForDevelopment;
 import static com.android.tools.r8.utils.SystemPropertyUtils.parseSystemPropertyForDevelopmentOrDefault;
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/instrumentation/StartupInstrumentationReferences.java b/src/main/java/com/android/tools/r8/profile/startup/instrumentation/StartupInstrumentationReferences.java
similarity index 93%
rename from src/main/java/com/android/tools/r8/experimental/startup/instrumentation/StartupInstrumentationReferences.java
rename to src/main/java/com/android/tools/r8/profile/startup/instrumentation/StartupInstrumentationReferences.java
index 92d3e9c..78d55f0 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/instrumentation/StartupInstrumentationReferences.java
+++ b/src/main/java/com/android/tools/r8/profile/startup/instrumentation/StartupInstrumentationReferences.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.experimental.startup.instrumentation;
+package com.android.tools.r8.profile.startup.instrumentation;
 
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/EmptyStartupProfile.java b/src/main/java/com/android/tools/r8/profile/startup/profile/EmptyStartupProfile.java
similarity index 85%
rename from src/main/java/com/android/tools/r8/experimental/startup/EmptyStartupProfile.java
rename to src/main/java/com/android/tools/r8/profile/startup/profile/EmptyStartupProfile.java
index f629224..e585fe6 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/EmptyStartupProfile.java
+++ b/src/main/java/com/android/tools/r8/profile/startup/profile/EmptyStartupProfile.java
@@ -2,16 +2,13 @@
 // 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.experimental.startup;
+package com.android.tools.r8.profile.startup.profile;
 
-import com.android.tools.r8.experimental.startup.profile.StartupProfileClassRule;
-import com.android.tools.r8.experimental.startup.profile.StartupProfileMethodRule;
-import com.android.tools.r8.experimental.startup.profile.StartupProfileRule;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.synthesis.SyntheticItems;
 import com.android.tools.r8.utils.ThrowingConsumer;
 
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/profile/NonEmptyStartupProfile.java b/src/main/java/com/android/tools/r8/profile/startup/profile/NonEmptyStartupProfile.java
similarity index 93%
rename from src/main/java/com/android/tools/r8/experimental/startup/profile/NonEmptyStartupProfile.java
rename to src/main/java/com/android/tools/r8/profile/startup/profile/NonEmptyStartupProfile.java
index 4cec4e9..8f047a4 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/profile/NonEmptyStartupProfile.java
+++ b/src/main/java/com/android/tools/r8/profile/startup/profile/NonEmptyStartupProfile.java
@@ -2,9 +2,8 @@
 // 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.experimental.startup.profile;
+package com.android.tools.r8.profile.startup.profile;
 
-import com.android.tools.r8.experimental.startup.StartupProfile;
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
@@ -12,25 +11,28 @@
 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.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.synthesis.SyntheticItems;
+import com.android.tools.r8.utils.MapUtils;
 import com.android.tools.r8.utils.SetUtils;
 import com.android.tools.r8.utils.ThrowingConsumer;
 import java.util.LinkedHashMap;
+import java.util.Map;
 import java.util.Set;
 import java.util.function.BiConsumer;
 
 public class NonEmptyStartupProfile extends StartupProfile {
 
   private final Set<DexType> startupClasses;
-  private final LinkedHashMap<DexReference, StartupProfileRule> startupRules;
+  private final Map<DexReference, StartupProfileRule> startupRules;
 
   public NonEmptyStartupProfile(LinkedHashMap<DexReference, StartupProfileRule> startupRules) {
     assert !startupRules.isEmpty();
     this.startupClasses =
-        SetUtils.mapIdentityHashSet(startupRules.keySet(), DexReference::getContextType);
-    this.startupRules = startupRules;
+        SetUtils.unmodifiableForTesting(
+            SetUtils.mapIdentityHashSet(startupRules.keySet(), DexReference::getContextType));
+    this.startupRules = MapUtils.unmodifiableForTesting(startupRules);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupProfile.java b/src/main/java/com/android/tools/r8/profile/startup/profile/StartupProfile.java
similarity index 95%
rename from src/main/java/com/android/tools/r8/experimental/startup/StartupProfile.java
rename to src/main/java/com/android/tools/r8/profile/startup/profile/StartupProfile.java
index 747097f..7a517de 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/StartupProfile.java
+++ b/src/main/java/com/android/tools/r8/profile/startup/profile/StartupProfile.java
@@ -2,20 +2,16 @@
 // 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.experimental.startup;
+package com.android.tools.r8.profile.startup.profile;
 
 import com.android.tools.r8.TextInputStream;
-import com.android.tools.r8.experimental.startup.profile.NonEmptyStartupProfile;
-import com.android.tools.r8.experimental.startup.profile.StartupProfileClassRule;
-import com.android.tools.r8.experimental.startup.profile.StartupProfileMethodRule;
-import com.android.tools.r8.experimental.startup.profile.StartupProfileRule;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexApplication;
 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.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.profile.AbstractProfile;
 import com.android.tools.r8.profile.AbstractProfileRule;
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/profile/StartupProfileClassRule.java b/src/main/java/com/android/tools/r8/profile/startup/profile/StartupProfileClassRule.java
similarity index 97%
rename from src/main/java/com/android/tools/r8/experimental/startup/profile/StartupProfileClassRule.java
rename to src/main/java/com/android/tools/r8/profile/startup/profile/StartupProfileClassRule.java
index 8da68cf..83aa6c8 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/profile/StartupProfileClassRule.java
+++ b/src/main/java/com/android/tools/r8/profile/startup/profile/StartupProfileClassRule.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.experimental.startup.profile;
+package com.android.tools.r8.profile.startup.profile;
 
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/profile/StartupProfileMethodRule.java b/src/main/java/com/android/tools/r8/profile/startup/profile/StartupProfileMethodRule.java
similarity index 97%
rename from src/main/java/com/android/tools/r8/experimental/startup/profile/StartupProfileMethodRule.java
rename to src/main/java/com/android/tools/r8/profile/startup/profile/StartupProfileMethodRule.java
index 54a7b17..e16699f 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/profile/StartupProfileMethodRule.java
+++ b/src/main/java/com/android/tools/r8/profile/startup/profile/StartupProfileMethodRule.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.experimental.startup.profile;
+package com.android.tools.r8.profile.startup.profile;
 
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/profile/StartupProfileRule.java b/src/main/java/com/android/tools/r8/profile/startup/profile/StartupProfileRule.java
similarity index 95%
rename from src/main/java/com/android/tools/r8/experimental/startup/profile/StartupProfileRule.java
rename to src/main/java/com/android/tools/r8/profile/startup/profile/StartupProfileRule.java
index 64dbb2c..369fea5 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/profile/StartupProfileRule.java
+++ b/src/main/java/com/android/tools/r8/profile/startup/profile/StartupProfileRule.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.experimental.startup.profile;
+package com.android.tools.r8.profile.startup.profile;
 
 import com.android.tools.r8.graph.DexReference;
 import com.android.tools.r8.profile.AbstractProfileRule;
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/rewriting/StartupProfileAdditions.java b/src/main/java/com/android/tools/r8/profile/startup/rewriting/StartupProfileAdditions.java
similarity index 78%
rename from src/main/java/com/android/tools/r8/experimental/startup/rewriting/StartupProfileAdditions.java
rename to src/main/java/com/android/tools/r8/profile/startup/rewriting/StartupProfileAdditions.java
index 2522234..559be04 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/rewriting/StartupProfileAdditions.java
+++ b/src/main/java/com/android/tools/r8/profile/startup/rewriting/StartupProfileAdditions.java
@@ -2,16 +2,16 @@
 // 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.experimental.startup.rewriting;
+package com.android.tools.r8.profile.startup.rewriting;
 
-import com.android.tools.r8.experimental.startup.StartupProfile;
-import com.android.tools.r8.experimental.startup.profile.StartupProfileClassRule;
-import com.android.tools.r8.experimental.startup.profile.StartupProfileMethodRule;
-import com.android.tools.r8.experimental.startup.profile.StartupProfileRule;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.profile.AbstractProfileRule;
-import com.android.tools.r8.profile.art.rewriting.ProfileAdditions;
+import com.android.tools.r8.profile.rewriting.ProfileAdditions;
+import com.android.tools.r8.profile.startup.profile.StartupProfile;
+import com.android.tools.r8.profile.startup.profile.StartupProfileClassRule;
+import com.android.tools.r8.profile.startup.profile.StartupProfileMethodRule;
+import com.android.tools.r8.profile.startup.profile.StartupProfileRule;
 import java.util.Comparator;
 
 public class StartupProfileAdditions
diff --git a/src/main/java/com/android/tools/r8/repackaging/Repackaging.java b/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
index 3bebc24..00e55a7 100644
--- a/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
+++ b/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
@@ -17,11 +17,11 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.DirectMappedDexApplication;
 import com.android.tools.r8.graph.InnerClassAttribute;
-import com.android.tools.r8.graph.NestedGraphLens;
 import com.android.tools.r8.graph.ProgramPackage;
 import com.android.tools.r8.graph.ProgramPackageCollection;
 import com.android.tools.r8.graph.SortedProgramPackageCollection;
 import com.android.tools.r8.graph.TreeFixerBase;
+import com.android.tools.r8.graph.lens.NestedGraphLens;
 import com.android.tools.r8.naming.Minifier.MinificationPackageNamingStrategy;
 import com.android.tools.r8.repackaging.RepackagingLens.Builder;
 import com.android.tools.r8.shaking.AnnotationFixer;
diff --git a/src/main/java/com/android/tools/r8/repackaging/RepackagingAnnotationTracer.java b/src/main/java/com/android/tools/r8/repackaging/RepackagingAnnotationTracer.java
index d119f1c..3bf5519 100644
--- a/src/main/java/com/android/tools/r8/repackaging/RepackagingAnnotationTracer.java
+++ b/src/main/java/com/android/tools/r8/repackaging/RepackagingAnnotationTracer.java
@@ -13,8 +13,8 @@
 import com.android.tools.r8.graph.DexEncodedAnnotation;
 import com.android.tools.r8.graph.DexMethodHandle;
 import com.android.tools.r8.graph.DexValue;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ParameterAnnotationsList;
+import com.android.tools.r8.graph.lens.GraphLens;
 
 public class RepackagingAnnotationTracer {
 
diff --git a/src/main/java/com/android/tools/r8/repackaging/RepackagingLens.java b/src/main/java/com/android/tools/r8/repackaging/RepackagingLens.java
index 8b4ad76..7a462ed 100644
--- a/src/main/java/com/android/tools/r8/repackaging/RepackagingLens.java
+++ b/src/main/java/com/android/tools/r8/repackaging/RepackagingLens.java
@@ -10,7 +10,7 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexReference;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.NestedGraphLens;
+import com.android.tools.r8.graph.lens.NestedGraphLens;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.IterableUtils;
 import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
diff --git a/src/main/java/com/android/tools/r8/repackaging/RepackagingUseRegistry.java b/src/main/java/com/android/tools/r8/repackaging/RepackagingUseRegistry.java
index 16bef88..49eb0a2 100644
--- a/src/main/java/com/android/tools/r8/repackaging/RepackagingUseRegistry.java
+++ b/src/main/java/com/android/tools/r8/repackaging/RepackagingUseRegistry.java
@@ -18,8 +18,6 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.EnclosingMethodAttribute;
 import com.android.tools.r8.graph.FieldResolutionResult;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.InnerClassAttribute;
 import com.android.tools.r8.graph.MemberResolutionResult;
 import com.android.tools.r8.graph.MethodResolutionResult;
@@ -29,6 +27,8 @@
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.SuccessfulMemberResolutionResult;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.InternalOptions;
 import java.util.List;
diff --git a/src/main/java/com/android/tools/r8/shaking/AnnotationFixer.java b/src/main/java/com/android/tools/r8/shaking/AnnotationFixer.java
index fedb75d..c1a8677 100644
--- a/src/main/java/com/android/tools/r8/shaking/AnnotationFixer.java
+++ b/src/main/java/com/android/tools/r8/shaking/AnnotationFixer.java
@@ -20,7 +20,7 @@
 import com.android.tools.r8.graph.DexValue.DexValueArray;
 import com.android.tools.r8.graph.DexValue.DexValueEnum;
 import com.android.tools.r8.graph.DexValue.DexValueType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.utils.ArrayUtils;
 
 public class AnnotationFixer {
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 9321484..ab4015d 100644
--- a/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
+++ b/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
@@ -16,10 +16,10 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.DexValue;
 import com.android.tools.r8.graph.EnclosingMethodAttribute;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.InnerClassAttribute;
 import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.graph.ProgramMember;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.kotlin.KotlinMemberLevelInfo;
 import com.android.tools.r8.kotlin.KotlinPropertyInfo;
 import com.android.tools.r8.shaking.Enqueuer.Mode;
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 bd42c6a..39d8035 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -32,8 +32,6 @@
 import com.android.tools.r8.graph.FieldAccessInfoCollection;
 import com.android.tools.r8.graph.FieldAccessInfoCollectionImpl;
 import com.android.tools.r8.graph.FieldResolutionResult;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
 import com.android.tools.r8.graph.InstantiatedSubTypeInfo;
 import com.android.tools.r8.graph.LookupMethodTarget;
 import com.android.tools.r8.graph.LookupResult.LookupResultSuccess;
@@ -47,6 +45,8 @@
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.PrunedItems;
 import com.android.tools.r8.graph.SubtypingInfo;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.NonIdentityGraphLens;
 import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
 import com.android.tools.r8.ir.analysis.type.DynamicType;
 import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
diff --git a/src/main/java/com/android/tools/r8/shaking/AssumeInfoCollection.java b/src/main/java/com/android/tools/r8/shaking/AssumeInfoCollection.java
index f9cda2f..bc3f728 100644
--- a/src/main/java/com/android/tools/r8/shaking/AssumeInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/shaking/AssumeInfoCollection.java
@@ -9,8 +9,8 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClassAndMember;
 import com.android.tools.r8.graph.DexMember;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.analysis.type.DynamicType;
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
 import com.android.tools.r8.ir.optimize.membervaluepropagation.assume.AssumeInfo;
diff --git a/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java b/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java
index 813328d..848ea2a 100644
--- a/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java
@@ -14,7 +14,7 @@
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.FieldAccessFlags;
-import com.android.tools.r8.graph.InitClassLens;
+import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.utils.ThreadUtils;
 import com.android.tools.r8.utils.Visibility;
 import java.util.concurrent.ExecutionException;
diff --git a/src/main/java/com/android/tools/r8/shaking/DependentMinimumKeepInfoCollection.java b/src/main/java/com/android/tools/r8/shaking/DependentMinimumKeepInfoCollection.java
index 4c36623..a1129346d 100644
--- a/src/main/java/com/android/tools/r8/shaking/DependentMinimumKeepInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/shaking/DependentMinimumKeepInfoCollection.java
@@ -13,9 +13,9 @@
 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.GraphLens;
 import com.android.tools.r8.graph.ProgramField;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.shaking.EnqueuerEvent.ClassEnqueuerEvent;
 import com.android.tools.r8.shaking.EnqueuerEvent.UnconditionalKeepInfoEvent;
 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 f45bf9b..ca51281 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -122,7 +122,7 @@
 import com.android.tools.r8.naming.identifiernamestring.IdentifierNameStringLookupResult;
 import com.android.tools.r8.naming.identifiernamestring.IdentifierNameStringTypeLookupResult;
 import com.android.tools.r8.position.Position;
-import com.android.tools.r8.profile.art.rewriting.ProfileCollectionAdditions;
+import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
 import com.android.tools.r8.shaking.AnnotationMatchResult.MatchedAnnotation;
 import com.android.tools.r8.shaking.DelayedRootSetActionItem.InterfaceMethodSyntheticBridgeAction;
 import com.android.tools.r8.shaking.EnqueuerEvent.ClassEnqueuerEvent;
diff --git a/src/main/java/com/android/tools/r8/shaking/EnqueuerEvent.java b/src/main/java/com/android/tools/r8/shaking/EnqueuerEvent.java
index 93d5f60..8aea7e4 100644
--- a/src/main/java/com/android/tools/r8/shaking/EnqueuerEvent.java
+++ b/src/main/java/com/android/tools/r8/shaking/EnqueuerEvent.java
@@ -8,7 +8,7 @@
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 
 public abstract class EnqueuerEvent {
 
diff --git a/src/main/java/com/android/tools/r8/shaking/EnqueuerFactory.java b/src/main/java/com/android/tools/r8/shaking/EnqueuerFactory.java
index e09b9be..e5f90c2 100644
--- a/src/main/java/com/android/tools/r8/shaking/EnqueuerFactory.java
+++ b/src/main/java/com/android/tools/r8/shaking/EnqueuerFactory.java
@@ -9,7 +9,7 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.SubtypingInfo;
-import com.android.tools.r8.profile.art.rewriting.ProfileCollectionAdditions;
+import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
 import com.android.tools.r8.shaking.Enqueuer.Mode;
 import java.util.Set;
 import java.util.concurrent.ExecutorService;
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java b/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java
index f13a407..9491483 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java
@@ -20,12 +20,12 @@
 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.GraphLens.NonIdentityGraphLens;
 import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.graph.ProgramField;
 import com.android.tools.r8.graph.ProgramMember;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.NonIdentityGraphLens;
 import com.android.tools.r8.shaking.KeepFieldInfo.Joiner;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.MapUtils;
diff --git a/src/main/java/com/android/tools/r8/shaking/MainDexInfo.java b/src/main/java/com/android/tools/r8/shaking/MainDexInfo.java
index 14d0dba..69bc36a 100644
--- a/src/main/java/com/android/tools/r8/shaking/MainDexInfo.java
+++ b/src/main/java/com/android/tools/r8/shaking/MainDexInfo.java
@@ -13,10 +13,10 @@
 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.GraphLens;
 import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.synthesis.SyntheticItems;
 import com.android.tools.r8.utils.ConsumerUtils;
 import com.google.common.collect.Sets;
diff --git a/src/main/java/com/android/tools/r8/shaking/MinimumKeepInfoCollection.java b/src/main/java/com/android/tools/r8/shaking/MinimumKeepInfoCollection.java
index 5a07f2a..f0ca7f9 100644
--- a/src/main/java/com/android/tools/r8/shaking/MinimumKeepInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/shaking/MinimumKeepInfoCollection.java
@@ -13,11 +13,11 @@
 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.GraphLens;
 import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.graph.ProgramField;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.shaking.KeepInfo.Joiner;
 import com.android.tools.r8.utils.MapUtils;
 import java.util.Collections;
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardCompatibilityActions.java b/src/main/java/com/android/tools/r8/shaking/ProguardCompatibilityActions.java
index eed4fec..b1ec100 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardCompatibilityActions.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardCompatibilityActions.java
@@ -6,8 +6,8 @@
 
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.google.common.collect.Sets;
 import java.util.Set;
 
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetBuilderEventConsumer.java b/src/main/java/com/android/tools/r8/shaking/RootSetBuilderEventConsumer.java
index 4102d80..b59961e 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetBuilderEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetBuilderEventConsumer.java
@@ -6,8 +6,8 @@
 
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.desugar.itf.InterfaceMethodDesugaringBaseEventConsumer;
-import com.android.tools.r8.profile.art.rewriting.ProfileCollectionAdditions;
-import com.android.tools.r8.profile.art.rewriting.ProfileRewritingRootSetBuilderEventConsumer;
+import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
+import com.android.tools.r8.profile.rewriting.ProfileRewritingRootSetBuilderEventConsumer;
 
 public interface RootSetBuilderEventConsumer extends InterfaceMethodDesugaringBaseEventConsumer {
 
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
index bbb8726..d60e464 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
@@ -38,7 +38,6 @@
 import com.android.tools.r8.graph.DexReference;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.DirectMappedDexApplication;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
 import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.graph.ProgramField;
@@ -46,13 +45,14 @@
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.PrunedItems;
 import com.android.tools.r8.graph.SubtypingInfo;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.analysis.proto.GeneratedMessageLiteBuilderShrinker;
 import com.android.tools.r8.ir.analysis.type.DynamicType;
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
 import com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringSyntheticHelper;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
 import com.android.tools.r8.ir.optimize.membervaluepropagation.assume.AssumeInfo;
-import com.android.tools.r8.profile.art.rewriting.ProfileCollectionAdditions;
+import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
 import com.android.tools.r8.repackaging.RepackagingUtils;
 import com.android.tools.r8.shaking.AnnotationMatchResult.AnnotationsIgnoredMatchResult;
 import com.android.tools.r8.shaking.AnnotationMatchResult.ConcreteAnnotationMatchResult;
diff --git a/src/main/java/com/android/tools/r8/shaking/RuntimeTypeCheckInfo.java b/src/main/java/com/android/tools/r8/shaking/RuntimeTypeCheckInfo.java
index 67f1c75..cb0f347 100644
--- a/src/main/java/com/android/tools/r8/shaking/RuntimeTypeCheckInfo.java
+++ b/src/main/java/com/android/tools/r8/shaking/RuntimeTypeCheckInfo.java
@@ -8,11 +8,12 @@
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.analysis.EnqueuerCheckCastAnalysis;
 import com.android.tools.r8.graph.analysis.EnqueuerExceptionGuardAnalysis;
 import com.android.tools.r8.graph.analysis.EnqueuerInstanceOfAnalysis;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.NonIdentityGraphLens;
 import com.android.tools.r8.utils.SetUtils;
 import com.google.common.collect.Sets;
 import java.util.Set;
@@ -106,7 +107,7 @@
     return isInstanceOfType(clazz) || isCheckCastType(clazz) || isExceptionGuardType(clazz);
   }
 
-  public RuntimeTypeCheckInfo rewriteWithLens(GraphLens.NonIdentityGraphLens graphLens) {
+  public RuntimeTypeCheckInfo rewriteWithLens(NonIdentityGraphLens graphLens) {
     return new RuntimeTypeCheckInfo(
         SetUtils.mapIdentityHashSet(instanceOfTypes, graphLens::lookupType),
         SetUtils.mapIdentityHashSet(checkCastTypes, graphLens::lookupType),
diff --git a/src/main/java/com/android/tools/r8/shaking/TreePruner.java b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
index 401d9af..6124e82 100644
--- a/src/main/java/com/android/tools/r8/shaking/TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.shaking;
 
+import static com.google.common.base.Predicates.alwaysFalse;
+
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DefaultInstanceInitializerCode;
 import com.android.tools.r8.graph.DexClass;
@@ -21,15 +23,18 @@
 import com.android.tools.r8.graph.NestMemberClassAttribute;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.RecordComponentInfo;
 import com.android.tools.r8.ir.optimize.info.MutableFieldOptimizationInfo;
 import com.android.tools.r8.ir.optimize.info.MutableMethodOptimizationInfo;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedback.OptimizationInfoFixer;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
+import com.android.tools.r8.utils.ArrayUtils;
 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.IterableUtils;
+import com.android.tools.r8.utils.PredicateUtils;
 import com.android.tools.r8.utils.Timing;
 import com.google.common.collect.Sets;
 import java.util.ArrayList;
@@ -219,6 +224,13 @@
     clazz.removeInnerClasses(this::isAttributeReferencingMissingOrPrunedType);
     clazz.removeEnclosingMethodAttribute(this::isAttributeReferencingPrunedItem);
     rewriteNestAttributes(clazz, this::isTypeLive, appView::definitionFor);
+    // TODO(b/274888318): Check this.
+    if (reachableInstanceFields != null) {
+      if (!clazz.getRecordComponents().isEmpty()) {
+        clazz.removeRecordComponents(
+            PredicateUtils.not(isReachableInstanceField(reachableInstanceFields)));
+      }
+    }
     unusedItemsPrinter.visited();
     assert verifyNoDeadFields(clazz);
   }
@@ -238,6 +250,24 @@
     }
   }
 
+  public static Predicate<RecordComponentInfo> isReachableInstanceField(
+      DexEncodedField[] reachableInstanceFields) {
+    final int ARRAY_LOOKUP_THRESHOLD = 10;
+    if (reachableInstanceFields.length == 0) {
+      return alwaysFalse();
+    } else if (reachableInstanceFields.length < ARRAY_LOOKUP_THRESHOLD) {
+      return info ->
+          ArrayUtils.contains(
+              reachableInstanceFields, DexEncodedField::getReference, info.getField());
+    } else {
+      Set<DexField> reachableInstanceFieldSet = Sets.newIdentityHashSet();
+      for (DexEncodedField reachableInstanceField : reachableInstanceFields) {
+        reachableInstanceFieldSet.add(reachableInstanceField.getReference());
+      }
+      return info -> reachableInstanceFieldSet.contains(info.getField());
+    }
+  }
+
   private boolean isTypeMissing(DexType type) {
     return appView.appInfo().getMissingClasses().contains(type);
   }
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 c0e541b..91c86e3 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -48,9 +48,6 @@
 import com.android.tools.r8.graph.GenericSignatureContextBuilder.TypeParameterContext;
 import com.android.tools.r8.graph.GenericSignatureCorrectnessHelper;
 import com.android.tools.r8.graph.GenericSignaturePartialTypeArgumentApplier;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
-import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
 import com.android.tools.r8.graph.LookupResult.LookupResultSuccess;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.MethodResolutionResult;
@@ -63,6 +60,10 @@
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.graph.UseRegistryWithResult;
 import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
+import com.android.tools.r8.graph.lens.FieldLookupResult;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.MethodLookupResult;
+import com.android.tools.r8.graph.lens.NonIdentityGraphLens;
 import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
 import com.android.tools.r8.ir.code.InvokeType;
 import com.android.tools.r8.ir.code.Position.SyntheticPosition;
@@ -73,7 +74,7 @@
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
 import com.android.tools.r8.ir.synthetic.AbstractSynthesizedCode;
 import com.android.tools.r8.ir.synthetic.ForwardMethodSourceCode;
-import com.android.tools.r8.profile.art.rewriting.ProfileCollectionAdditions;
+import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
 import com.android.tools.r8.utils.Box;
 import com.android.tools.r8.utils.CollectionUtils;
 import com.android.tools.r8.utils.FieldSignatureEquivalence;
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLens.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLens.java
index 259c35a..0b4a990 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLens.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLens.java
@@ -11,8 +11,9 @@
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.NestedGraphLens;
 import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
+import com.android.tools.r8.graph.lens.MethodLookupResult;
+import com.android.tools.r8.graph.lens.NestedGraphLens;
 import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
 import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
 import com.android.tools.r8.ir.code.InvokeType;
diff --git a/src/main/java/com/android/tools/r8/startup/diagnostic/MissingStartupProfileItemsDiagnostic.java b/src/main/java/com/android/tools/r8/startup/diagnostic/MissingStartupProfileItemsDiagnostic.java
index 0c33a74..144e210 100644
--- a/src/main/java/com/android/tools/r8/startup/diagnostic/MissingStartupProfileItemsDiagnostic.java
+++ b/src/main/java/com/android/tools/r8/startup/diagnostic/MissingStartupProfileItemsDiagnostic.java
@@ -6,13 +6,13 @@
 
 import com.android.tools.r8.Diagnostic;
 import com.android.tools.r8.Keep;
-import com.android.tools.r8.experimental.startup.profile.StartupProfileClassRule;
-import com.android.tools.r8.experimental.startup.profile.StartupProfileMethodRule;
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexReference;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.position.Position;
+import com.android.tools.r8.profile.startup.profile.StartupProfileClassRule;
+import com.android.tools.r8.profile.startup.profile.StartupProfileMethodRule;
 import com.google.common.collect.Sets;
 import java.util.ArrayList;
 import java.util.Iterator;
diff --git a/src/main/java/com/android/tools/r8/startup/generated/InstrumentationServerFactory.java b/src/main/java/com/android/tools/r8/startup/generated/InstrumentationServerFactory.java
index 1c5dd2b..d63bcf5 100644
--- a/src/main/java/com/android/tools/r8/startup/generated/InstrumentationServerFactory.java
+++ b/src/main/java/com/android/tools/r8/startup/generated/InstrumentationServerFactory.java
@@ -48,6 +48,7 @@
         NestHostClassAttribute.none(),
         Collections.emptyList(),
         Collections.emptyList(),
+        Collections.emptyList(),
         EnclosingMethodAttribute.none(),
         Collections.emptyList(),
         ClassSignature.noSignature(),
diff --git a/src/main/java/com/android/tools/r8/startup/generated/InstrumentationServerImplFactory.java b/src/main/java/com/android/tools/r8/startup/generated/InstrumentationServerImplFactory.java
index e971964..e9d64ab 100644
--- a/src/main/java/com/android/tools/r8/startup/generated/InstrumentationServerImplFactory.java
+++ b/src/main/java/com/android/tools/r8/startup/generated/InstrumentationServerImplFactory.java
@@ -70,6 +70,7 @@
         NestHostClassAttribute.none(),
         Collections.emptyList(),
         Collections.emptyList(),
+        Collections.emptyList(),
         EnclosingMethodAttribute.none(),
         Collections.emptyList(),
         ClassSignature.noSignature(),
diff --git a/src/main/java/com/android/tools/r8/synthesis/CommittedSyntheticsCollection.java b/src/main/java/com/android/tools/r8/synthesis/CommittedSyntheticsCollection.java
index 02979c5..c4152fa 100644
--- a/src/main/java/com/android/tools/r8/synthesis/CommittedSyntheticsCollection.java
+++ b/src/main/java/com/android/tools/r8/synthesis/CommittedSyntheticsCollection.java
@@ -7,8 +7,8 @@
 
 import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.NonIdentityGraphLens;
 import com.android.tools.r8.synthesis.SyntheticItems.ContextsForGlobalSynthetics;
 import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
 import com.android.tools.r8.utils.IterableUtils;
diff --git a/src/main/java/com/android/tools/r8/synthesis/Rewritable.java b/src/main/java/com/android/tools/r8/synthesis/Rewritable.java
index 408b3a3..f48e058 100644
--- a/src/main/java/com/android/tools/r8/synthesis/Rewritable.java
+++ b/src/main/java/com/android/tools/r8/synthesis/Rewritable.java
@@ -4,7 +4,7 @@
 package com.android.tools.r8.synthesis;
 
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
+import com.android.tools.r8.graph.lens.NonIdentityGraphLens;
 
 public interface Rewritable<R extends Rewritable<R>> {
 
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 e92442b..21fd289 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java
@@ -12,8 +12,8 @@
 import com.android.tools.r8.graph.ClasspathOrLibraryClass;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
 import com.android.tools.r8.graph.ProgramDefinition;
+import com.android.tools.r8.graph.lens.NonIdentityGraphLens;
 import com.android.tools.r8.origin.GlobalSyntheticOrigin;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.shaking.MainDexInfo;
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 e9951c3..da83f1e 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java
@@ -22,6 +22,7 @@
 import com.android.tools.r8.graph.NestHostClassAttribute;
 import com.android.tools.r8.graph.NestMemberClassAttribute;
 import com.android.tools.r8.graph.PermittedSubclassAttribute;
+import com.android.tools.r8.graph.RecordComponentInfo;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
 import java.util.ArrayList;
@@ -173,6 +174,7 @@
     NestHostClassAttribute nestHost = null;
     List<NestMemberClassAttribute> nestMembers = Collections.emptyList();
     List<PermittedSubclassAttribute> permittedSubclasses = Collections.emptyList();
+    List<RecordComponentInfo> recordComponents = Collections.emptyList();
     EnclosingMethodAttribute enclosingMembers = null;
     List<InnerClassAttribute> innerClasses = Collections.emptyList();
     for (SyntheticMethodBuilder builder : methods) {
@@ -201,6 +203,7 @@
                 nestHost,
                 nestMembers,
                 permittedSubclasses,
+                recordComponents,
                 enclosingMembers,
                 innerClasses,
                 signature,
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticClasspathClassReference.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticClasspathClassReference.java
index 72beb13..cd6fcbf 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticClasspathClassReference.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticClasspathClassReference.java
@@ -6,7 +6,7 @@
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexClasspathClass;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
+import com.android.tools.r8.graph.lens.NonIdentityGraphLens;
 import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
 import java.util.function.Function;
 
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticDefinition.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticDefinition.java
index 1a75811..1ad0796 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticDefinition.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticDefinition.java
@@ -7,7 +7,7 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
 import com.android.tools.r8.utils.structural.HasherWrapper;
 import com.android.tools.r8.utils.structural.RepresentativeMap;
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
index efe5d62..68c2918 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
@@ -19,11 +19,11 @@
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
-import com.android.tools.r8.graph.NestedGraphLens;
 import com.android.tools.r8.graph.PrunedItems;
 import com.android.tools.r8.graph.TreeFixerBase;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.NestedGraphLens;
+import com.android.tools.r8.graph.lens.NonIdentityGraphLens;
 import com.android.tools.r8.ir.code.NumberGenerator;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.shaking.KeepInfoCollection;
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 066c144..24dab29 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
@@ -11,7 +11,6 @@
 import com.android.tools.r8.contexts.CompilationContext.UniqueContext;
 import com.android.tools.r8.errors.MissingGlobalSyntheticsConsumerDiagnostic;
 import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.experimental.startup.StartupProfile;
 import com.android.tools.r8.features.ClassToFeatureSplitMap;
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
@@ -31,15 +30,16 @@
 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.graph.GraphLens.NonIdentityGraphLens;
 import com.android.tools.r8.graph.MethodCollection;
 import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.ProgramOrClasspathDefinition;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.lens.NonIdentityGraphLens;
 import com.android.tools.r8.horizontalclassmerging.HorizontalClassMerger;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.profile.startup.profile.StartupProfile;
 import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.synthesis.SyntheticFinalization.Result;
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodReference.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodReference.java
index d1347f3..8853f7c8 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodReference.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodReference.java
@@ -7,8 +7,8 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.NonIdentityGraphLens;
 import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
 import java.util.function.Consumer;
 import java.util.function.Function;
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticProgramClassReference.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticProgramClassReference.java
index d5973f6..4845892 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticProgramClassReference.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticProgramClassReference.java
@@ -6,7 +6,7 @@
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
+import com.android.tools.r8.graph.lens.NonIdentityGraphLens;
 import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
 import java.util.function.Consumer;
 import java.util.function.Function;
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticReference.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticReference.java
index 9824ebc..801204a 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticReference.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticReference.java
@@ -6,7 +6,7 @@
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexReference;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
+import com.android.tools.r8.graph.lens.NonIdentityGraphLens;
 import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
 import java.util.function.Function;
 
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 8715d7d..b1d434a 100644
--- a/src/main/java/com/android/tools/r8/tracereferences/Tracer.java
+++ b/src/main/java/com/android/tools/r8/tracereferences/Tracer.java
@@ -25,14 +25,14 @@
 import com.android.tools.r8.graph.DexValue;
 import com.android.tools.r8.graph.DexValue.DexValueArray;
 import com.android.tools.r8.graph.FieldResolutionResult;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.GraphLens.FieldLookupResult;
-import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
 import com.android.tools.r8.graph.MethodResolutionResult;
 import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
 import com.android.tools.r8.graph.ProgramField;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.FieldLookupResult;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.MethodLookupResult;
 import com.android.tools.r8.ir.desugar.LambdaDescriptor;
 import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.references.FieldReference;
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApp.java b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
index ee770f8..7135faa 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApp.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
@@ -34,8 +34,6 @@
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.errors.InternalCompilerError;
 import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.experimental.startup.StartupProfile;
-import com.android.tools.r8.experimental.startup.StartupProfileProviderUtils;
 import com.android.tools.r8.features.ClassToFeatureSplitMap;
 import com.android.tools.r8.features.FeatureSplitConfiguration;
 import com.android.tools.r8.graph.DexType;
@@ -44,6 +42,8 @@
 import com.android.tools.r8.origin.PathOrigin;
 import com.android.tools.r8.profile.art.ArtProfileProvider;
 import com.android.tools.r8.profile.art.ArtProfileProviderUtils;
+import com.android.tools.r8.profile.startup.StartupProfileProviderUtils;
+import com.android.tools.r8.profile.startup.profile.StartupProfile;
 import com.android.tools.r8.shaking.FilteredClassPath;
 import com.android.tools.r8.startup.StartupProfileProvider;
 import com.android.tools.r8.synthesis.SyntheticItems;
diff --git a/src/main/java/com/android/tools/r8/utils/ArrayUtils.java b/src/main/java/com/android/tools/r8/utils/ArrayUtils.java
index e1741af..b8d37cb 100644
--- a/src/main/java/com/android/tools/r8/utils/ArrayUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/ArrayUtils.java
@@ -144,6 +144,16 @@
     return false;
   }
 
+  public static <T, U> boolean contains(
+      T[] elements, Function<T, U> elementMap, U mappedElementToLookFor) {
+    for (T element : elements) {
+      if (elementMap.apply(element).equals(mappedElementToLookFor)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
   public static int[] fromPredicate(IntPredicate predicate, int size) {
     int[] result = new int[size];
     for (int i = 0; i < size; i++) {
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 8ce6323..1a27736 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -40,8 +40,6 @@
 import com.android.tools.r8.errors.MissingNestHostNestDesugarDiagnostic;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.experimental.graphinfo.GraphConsumer;
-import com.android.tools.r8.experimental.startup.StartupOptions;
-import com.android.tools.r8.experimental.startup.instrumentation.StartupInstrumentationOptions;
 import com.android.tools.r8.features.FeatureSplitConfiguration;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
@@ -80,6 +78,8 @@
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.position.Position;
 import com.android.tools.r8.profile.art.ArtProfileOptions;
+import com.android.tools.r8.profile.startup.StartupOptions;
+import com.android.tools.r8.profile.startup.instrumentation.StartupInstrumentationOptions;
 import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.references.FieldReference;
 import com.android.tools.r8.references.MethodReference;
@@ -449,6 +449,8 @@
   // Flag to allow record annotations in DEX. See b/231930852 for context.
   public boolean emitRecordAnnotationsInDex =
       System.getProperty("com.android.tools.r8.emitRecordAnnotationsInDex") != null;
+  public boolean emitRecordAnnotationsExInDex =
+      System.getProperty("com.android.tools.r8.emitRecordAnnotationsExInDex") != null;
 
   // Flag to allow nest annotations in DEX. See b/231930852 for context.
   public boolean emitNestAnnotationsInDex =
@@ -2144,6 +2146,7 @@
     public boolean enableSwitchToIfRewriting = true;
     public boolean enableEnumUnboxingDebugLogs =
         System.getProperty("com.android.tools.r8.enableEnumUnboxingDebugLogs") != null;
+    public boolean enableEnumWithSubtypesUnboxing = false;
     public boolean forceRedundantConstNumberRemoval = false;
     public boolean enableExperimentalDesugaredLibraryKeepRuleGenerator = false;
     public boolean invertConditionals = false;
diff --git a/src/main/java/com/android/tools/r8/utils/LensUtils.java b/src/main/java/com/android/tools/r8/utils/LensUtils.java
index 2c67ac3..1b88985 100644
--- a/src/main/java/com/android/tools/r8/utils/LensUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/LensUtils.java
@@ -7,7 +7,7 @@
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexReference;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.google.common.collect.Sets;
 import java.util.Set;
 import java.util.function.Consumer;
diff --git a/src/main/java/com/android/tools/r8/utils/MapUtils.java b/src/main/java/com/android/tools/r8/utils/MapUtils.java
index e0a915f..7c603b2 100644
--- a/src/main/java/com/android/tools/r8/utils/MapUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/MapUtils.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.utils.StringUtils.BraceType;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceMaps;
+import java.util.Collections;
 import java.util.IdentityHashMap;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -121,4 +122,8 @@
     }
     return true;
   }
+
+  public static <K, V> Map<K, V> unmodifiableForTesting(Map<K, V> map) {
+    return InternalOptions.assertionsEnabled() ? Collections.unmodifiableMap(map) : map;
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/utils/SemanticVersion.java b/src/main/java/com/android/tools/r8/utils/SemanticVersion.java
index 0bd7b67..e71312c 100644
--- a/src/main/java/com/android/tools/r8/utils/SemanticVersion.java
+++ b/src/main/java/com/android/tools/r8/utils/SemanticVersion.java
@@ -85,14 +85,18 @@
     return patch;
   }
 
-  public boolean isNewerOrEqual(SemanticVersion other) {
+  public boolean isNewer(SemanticVersion other) {
     if (major != other.major) {
       return major > other.major;
     }
     if (minor != other.minor) {
       return minor > other.minor;
     }
-    return patch >= other.patch;
+    return patch > other.patch;
+  }
+
+  public boolean isNewerOrEqual(SemanticVersion other) {
+    return isNewer(other) || equals(other);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/utils/SetUtils.java b/src/main/java/com/android/tools/r8/utils/SetUtils.java
index 834a3df..a0ecdfc 100644
--- a/src/main/java/com/android/tools/r8/utils/SetUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/SetUtils.java
@@ -131,4 +131,8 @@
     union.addAll(other);
     return union;
   }
+
+  public static <K> Set<K> unmodifiableForTesting(Set<K> map) {
+    return InternalOptions.assertionsEnabled() ? Collections.unmodifiableSet(map) : map;
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/utils/collections/LongLivedClassSetBuilder.java b/src/main/java/com/android/tools/r8/utils/collections/LongLivedClassSetBuilder.java
index fe3361e..44fe24d 100644
--- a/src/main/java/com/android/tools/r8/utils/collections/LongLivedClassSetBuilder.java
+++ b/src/main/java/com/android/tools/r8/utils/collections/LongLivedClassSetBuilder.java
@@ -7,7 +7,7 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.SetUtils;
 import java.util.Set;
diff --git a/src/main/java/com/android/tools/r8/utils/collections/LongLivedCollectionBuilder.java b/src/main/java/com/android/tools/r8/utils/collections/LongLivedCollectionBuilder.java
index 6c7fdc2..b40d74b 100644
--- a/src/main/java/com/android/tools/r8/utils/collections/LongLivedCollectionBuilder.java
+++ b/src/main/java/com/android/tools/r8/utils/collections/LongLivedCollectionBuilder.java
@@ -4,7 +4,7 @@
 
 package com.android.tools.r8.utils.collections;
 
-import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
 import java.util.function.IntFunction;
 
 public abstract class LongLivedCollectionBuilder<BuilderCollection, ResultCollection> {
diff --git a/src/main/java/com/android/tools/r8/utils/collections/LongLivedProgramMethodMapBuilder.java b/src/main/java/com/android/tools/r8/utils/collections/LongLivedProgramMethodMapBuilder.java
index 1591350..a871a59 100644
--- a/src/main/java/com/android/tools/r8/utils/collections/LongLivedProgramMethodMapBuilder.java
+++ b/src/main/java/com/android/tools/r8/utils/collections/LongLivedProgramMethodMapBuilder.java
@@ -10,8 +10,8 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import java.util.IdentityHashMap;
 import java.util.Map;
diff --git a/src/main/java/com/android/tools/r8/utils/collections/LongLivedProgramMethodSetBuilder.java b/src/main/java/com/android/tools/r8/utils/collections/LongLivedProgramMethodSetBuilder.java
index 735146a..5bc7e56 100644
--- a/src/main/java/com/android/tools/r8/utils/collections/LongLivedProgramMethodSetBuilder.java
+++ b/src/main/java/com/android/tools/r8/utils/collections/LongLivedProgramMethodSetBuilder.java
@@ -10,8 +10,8 @@
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.DeterminismChecker.LineCallback;
 import com.android.tools.r8.utils.SetUtils;
diff --git a/src/main/java/com/android/tools/r8/utils/collections/ProgramMethodSet.java b/src/main/java/com/android/tools/r8/utils/collections/ProgramMethodSet.java
index 81bb460..57ad688 100644
--- a/src/main/java/com/android/tools/r8/utils/collections/ProgramMethodSet.java
+++ b/src/main/java/com/android/tools/r8/utils/collections/ProgramMethodSet.java
@@ -8,8 +8,8 @@
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.utils.ForEachable;
 import com.google.common.collect.ImmutableMap;
 import java.util.IdentityHashMap;
diff --git a/src/main/java/com/android/tools/r8/utils/collections/SortedProgramMethodSet.java b/src/main/java/com/android/tools/r8/utils/collections/SortedProgramMethodSet.java
index d625aae..3a17dc5 100644
--- a/src/main/java/com/android/tools/r8/utils/collections/SortedProgramMethodSet.java
+++ b/src/main/java/com/android/tools/r8/utils/collections/SortedProgramMethodSet.java
@@ -7,8 +7,8 @@
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.utils.ComparatorUtils;
 import com.android.tools.r8.utils.ForEachable;
 import com.android.tools.r8.utils.ForEachableUtils;
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/EmptyInterfaceTypeToClassTypeLensCodeRewriterHelper.java b/src/main/java/com/android/tools/r8/verticalclassmerging/EmptyInterfaceTypeToClassTypeLensCodeRewriterHelper.java
index dce166b..b4c0163 100644
--- a/src/main/java/com/android/tools/r8/verticalclassmerging/EmptyInterfaceTypeToClassTypeLensCodeRewriterHelper.java
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/EmptyInterfaceTypeToClassTypeLensCodeRewriterHelper.java
@@ -4,7 +4,7 @@
 
 package com.android.tools.r8.verticalclassmerging;
 
-import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
+import com.android.tools.r8.graph.lens.MethodLookupResult;
 import com.android.tools.r8.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.BasicBlockIterator;
 import com.android.tools.r8.ir.code.FieldPut;
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/InterfaceTypeToClassTypeLensCodeRewriterHelper.java b/src/main/java/com/android/tools/r8/verticalclassmerging/InterfaceTypeToClassTypeLensCodeRewriterHelper.java
index 15efa1a..d365ddd 100644
--- a/src/main/java/com/android/tools/r8/verticalclassmerging/InterfaceTypeToClassTypeLensCodeRewriterHelper.java
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/InterfaceTypeToClassTypeLensCodeRewriterHelper.java
@@ -6,9 +6,9 @@
 
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
-import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.MethodLookupResult;
+import com.android.tools.r8.graph.lens.NonIdentityGraphLens;
 import com.android.tools.r8.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.BasicBlockIterator;
 import com.android.tools.r8.ir.code.FieldPut;
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/InterfaceTypeToClassTypeLensCodeRewriterHelperImpl.java b/src/main/java/com/android/tools/r8/verticalclassmerging/InterfaceTypeToClassTypeLensCodeRewriterHelperImpl.java
index 387788a..3087061 100644
--- a/src/main/java/com/android/tools/r8/verticalclassmerging/InterfaceTypeToClassTypeLensCodeRewriterHelperImpl.java
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/InterfaceTypeToClassTypeLensCodeRewriterHelperImpl.java
@@ -12,7 +12,7 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
+import com.android.tools.r8.graph.lens.MethodLookupResult;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.BasicBlockIterator;
diff --git a/src/test/examplesJava17/records/RecordWithAnnotations.java b/src/test/examplesJava17/records/RecordWithAnnotations.java
new file mode 100644
index 0000000..d1648b6
--- /dev/null
+++ b/src/test/examplesJava17/records/RecordWithAnnotations.java
@@ -0,0 +1,73 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package records;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.Field;
+import java.lang.reflect.RecordComponent;
+
+public class RecordWithAnnotations {
+
+  @Target({ElementType.FIELD, ElementType.RECORD_COMPONENT})
+  @Retention(RetentionPolicy.RUNTIME)
+  @interface Annotation {
+    String value();
+  }
+
+  @Target(ElementType.FIELD)
+  @Retention(RetentionPolicy.RUNTIME)
+  @interface AnnotationFieldOnly {
+    String value();
+  }
+
+  @Target(ElementType.RECORD_COMPONENT)
+  @Retention(RetentionPolicy.RUNTIME)
+  @interface AnnotationRecordComponentOnly {
+    String value();
+  }
+
+  record Person(
+      @Annotation("a") @AnnotationFieldOnly("b") @AnnotationRecordComponentOnly("c") String name,
+      @Annotation("x") @AnnotationFieldOnly("y") @AnnotationRecordComponentOnly("z") int age) {}
+
+  public static void main(String[] args) {
+    Person janeDoe = new Person("Jane Doe", 42);
+    System.out.println(janeDoe.name);
+    System.out.println(janeDoe.age);
+    System.out.println(janeDoe.name());
+    System.out.println(janeDoe.age());
+    try {
+      Class.class.getDeclaredMethod("isRecord");
+    } catch (NoSuchMethodException e) {
+      System.out.println("Class.isRecord not present");
+      return;
+    }
+    System.out.println(Person.class.isRecord());
+    if (Person.class.isRecord()) {
+      System.out.println(Person.class.getRecordComponents().length);
+      for (int i = 0; i < Person.class.getRecordComponents().length; i++) {
+        RecordComponent c = Person.class.getRecordComponents()[i];
+        System.out.println(c.getName());
+        System.out.println(c.getType().getName());
+        System.out.println(c.getGenericSignature() == null);
+        System.out.println(c.getAnnotations().length);
+        for (int j = 0; j < c.getAnnotations().length; j++) {
+          System.out.println(c.getAnnotations()[j]);
+        }
+      }
+      System.out.println(Person.class.getDeclaredFields().length);
+      for (int i = 0; i < Person.class.getDeclaredFields().length; i++) {
+        Field f = Person.class.getDeclaredFields()[i];
+        System.out.println(f.getDeclaredAnnotations().length);
+        for (int j = 0; j < f.getDeclaredAnnotations().length; j++) {
+          System.out.println(f.getAnnotations()[j]);
+        }
+      }
+    }
+  }
+}
diff --git a/src/test/examplesJava17/records/RecordWithSignature.java b/src/test/examplesJava17/records/RecordWithSignature.java
new file mode 100644
index 0000000..be31024
--- /dev/null
+++ b/src/test/examplesJava17/records/RecordWithSignature.java
@@ -0,0 +1,37 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package records;
+
+import java.lang.reflect.RecordComponent;
+
+public class RecordWithSignature {
+
+  record Person<N extends CharSequence, A>(N name, A age) {}
+
+  public static void main(String[] args) {
+    Person<String, Integer> janeDoe = new Person<>("Jane Doe", 42);
+    System.out.println(janeDoe.name);
+    System.out.println(janeDoe.age);
+    System.out.println(janeDoe.name());
+    System.out.println(janeDoe.age());
+    try {
+      Class.class.getDeclaredMethod("isRecord");
+    } catch (NoSuchMethodException e) {
+      System.out.println("Class.isRecord not present");
+      return;
+    }
+    System.out.println(Person.class.isRecord());
+    if (Person.class.isRecord()) {
+      System.out.println(Person.class.getRecordComponents().length);
+      for (int i = 0; i < Person.class.getRecordComponents().length; i++) {
+        RecordComponent c = Person.class.getRecordComponents()[i];
+        System.out.println(c.getName());
+        System.out.println(c.getType().getName());
+        System.out.println(c.getGenericSignature());
+        System.out.println(c.getAnnotations().length);
+      }
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/D8CommandTest.java b/src/test/java/com/android/tools/r8/D8CommandTest.java
index 87b5338..f4cbb5d 100644
--- a/src/test/java/com/android/tools/r8/D8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/D8CommandTest.java
@@ -21,10 +21,10 @@
 import com.android.tools.r8.ToolHelper.ProcessResult;
 import com.android.tools.r8.dex.Marker;
 import com.android.tools.r8.dex.Marker.Tool;
-import com.android.tools.r8.experimental.startup.StartupProfile;
-import com.android.tools.r8.experimental.startup.profile.StartupProfileRule;
 import com.android.tools.r8.origin.EmbeddedOrigin;
 import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.profile.startup.profile.StartupProfile;
+import com.android.tools.r8.profile.startup.profile.StartupProfileRule;
 import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.startup.StartupProfileProvider;
 import com.android.tools.r8.startup.diagnostic.MissingStartupProfileItemsDiagnostic;
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index 74d850c..4adcef9 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -45,7 +45,7 @@
 import com.android.tools.r8.jasmin.JasminBuilder;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.origin.PathOrigin;
-import com.android.tools.r8.profile.art.rewriting.ProfileCollectionAdditions;
+import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
 import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.references.FieldReference;
 import com.android.tools.r8.references.MethodReference;
diff --git a/src/test/java/com/android/tools/r8/TestCompileResult.java b/src/test/java/com/android/tools/r8/TestCompileResult.java
index dfdfa9d..ce189e6 100644
--- a/src/test/java/com/android/tools/r8/TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/TestCompileResult.java
@@ -660,9 +660,11 @@
             .add(out.toString())
             .build();
     Consumer<ArtCommandBuilder> commandConsumer =
-        withArt6Plus64BitsLib && vm.getVersion().isNewerThanOrEqual(DexVm.Version.V6_0_1)
-            ? builder -> builder.appendArtOption("--64")
-            : builder -> {};
+        ToolHelper.force32BitArt()
+            ? builder -> builder.appendArtOption("--32")
+            : withArt6Plus64BitsLib && vm.getVersion().isNewerThanOrEqual(DexVm.Version.V6_0_1)
+                ? builder -> builder.appendArtOption("--64")
+                : builder -> {};
     commandConsumer =
         commandConsumer.andThen(
             builder -> {
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 592892a..c9cd81f 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -1907,6 +1907,10 @@
     return new ProcessResult(passed ? 0 : -1, "", stdErr);
   }
 
+  public static boolean force32BitArt() {
+    return System.getProperty("force_32_bit_art") != null;
+  }
+
   public static boolean dealsWithGoldenFiles() {
     return compareAgaintsGoldenFiles() || generateGoldenFiles();
   }
diff --git a/src/test/java/com/android/tools/r8/cfmethodgeneration/CfClassGenerator.java b/src/test/java/com/android/tools/r8/cfmethodgeneration/CfClassGenerator.java
index 0630571..309c226 100644
--- a/src/test/java/com/android/tools/r8/cfmethodgeneration/CfClassGenerator.java
+++ b/src/test/java/com/android/tools/r8/cfmethodgeneration/CfClassGenerator.java
@@ -119,7 +119,7 @@
 
     builder.startLine().append(imports.getNestHostClassAttribute()).appendLine(".none(),");
 
-    for (int i = 0; i < 2; i++) {
+    for (int i = 0; i < 3; i++) {
       builder.startLine().append(imports.getJavaUtilCollections()).appendLine(".emptyList(),");
     }
 
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordComponentAnnotationsTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordComponentAnnotationsTest.java
new file mode 100644
index 0000000..dc3ef4e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordComponentAnnotationsTest.java
@@ -0,0 +1,332 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.desugar.records;
+
+import static com.android.tools.r8.utils.codeinspector.AnnotationMatchers.hasAnnotationTypes;
+import static com.android.tools.r8.utils.codeinspector.AnnotationMatchers.hasElements;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.TestShrinkerBuilder;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.Pair;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.FieldSubject;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class RecordComponentAnnotationsTest extends TestBase {
+
+  private static final String RECORD_NAME = "RecordWithAnnotations";
+  private static final byte[][] PROGRAM_DATA = RecordTestUtils.getProgramData(RECORD_NAME);
+  private static final String MAIN_TYPE = RecordTestUtils.getMainType(RECORD_NAME);
+  private static final String EXPECTED_RESULT =
+      StringUtils.lines(
+          "Jane Doe",
+          "42",
+          "Jane Doe",
+          "42",
+          "true",
+          "2",
+          "name",
+          "java.lang.String",
+          "true",
+          "2",
+          "@records.RecordWithAnnotations$Annotation(\"a\")",
+          "@records.RecordWithAnnotations$AnnotationRecordComponentOnly(\"c\")",
+          "age",
+          "int",
+          "true",
+          "2",
+          "@records.RecordWithAnnotations$Annotation(\"x\")",
+          "@records.RecordWithAnnotations$AnnotationRecordComponentOnly(\"z\")",
+          "2",
+          "2",
+          "@records.RecordWithAnnotations$Annotation(\"a\")",
+          "@records.RecordWithAnnotations$AnnotationFieldOnly(\"b\")",
+          "2",
+          "@records.RecordWithAnnotations$Annotation(\"x\")",
+          "@records.RecordWithAnnotations$AnnotationFieldOnly(\"y\")");
+  private static final String EXPECTED_RESULT_R8 =
+      StringUtils.lines(
+          "Jane Doe",
+          "42",
+          "Jane Doe",
+          "42",
+          "true",
+          "2",
+          "a",
+          "java.lang.String",
+          "true",
+          "2",
+          "@records.RecordWithAnnotations$Annotation(\"a\")",
+          "@records.RecordWithAnnotations$AnnotationRecordComponentOnly(\"c\")",
+          "b",
+          "int",
+          "true",
+          "2",
+          "@records.RecordWithAnnotations$Annotation(\"x\")",
+          "@records.RecordWithAnnotations$AnnotationRecordComponentOnly(\"z\")",
+          "2",
+          "2",
+          "@records.RecordWithAnnotations$Annotation(\"a\")",
+          "@records.RecordWithAnnotations$AnnotationFieldOnly(\"b\")",
+          "2",
+          "@records.RecordWithAnnotations$Annotation(\"x\")",
+          "@records.RecordWithAnnotations$AnnotationFieldOnly(\"y\")");
+  private static final String EXPECTED_RESULT_R8_NO_KEEP_ANNOTATIONS =
+      StringUtils.lines(
+          "Jane Doe",
+          "42",
+          "Jane Doe",
+          "42",
+          "true",
+          "2",
+          "a",
+          "java.lang.String",
+          "true",
+          "2",
+          "@records.RecordWithAnnotations$Annotation(\"a\")",
+          "@records.RecordWithAnnotations$AnnotationRecordComponentOnly(\"c\")",
+          "b",
+          "int",
+          "true",
+          "2",
+          "@records.RecordWithAnnotations$Annotation(\"x\")",
+          "@records.RecordWithAnnotations$AnnotationRecordComponentOnly(\"z\")",
+          "2",
+          "0",
+          "0");
+  private static final String EXPECTED_RESULT_DESUGARED =
+      StringUtils.lines("Jane Doe", "42", "Jane Doe", "42", "Class.isRecord not present");
+  private static final String EXPECTED_RESULT_DESUGARED_JVM17 =
+      StringUtils.lines("Jane Doe", "42", "Jane Doe", "42", "false");
+
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameter(1)
+  public Boolean keepAnnotations;
+
+  @Parameters(name = "{0}, keepAnnotations: {1}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters()
+            .withDexRuntimesAndAllApiLevels()
+            .withCfRuntimesStartingFromIncluding(CfVm.JDK17)
+            .withAllApiLevelsAlsoForCf()
+            .build(),
+        BooleanUtils.values());
+  }
+
+  @Test
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    assumeTrue(keepAnnotations);
+    testForJvm(parameters)
+        .addProgramClassFileData(PROGRAM_DATA)
+        .run(parameters.getRuntime(), MAIN_TYPE)
+        .assertSuccessWithOutput(EXPECTED_RESULT);
+  }
+
+  @Test
+  public void testDesugaring() throws Exception {
+    parameters.assumeDexRuntime();
+    assumeTrue(keepAnnotations);
+    // Android U will support records.
+    boolean compilingForNativeRecordSupport =
+        parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.U);
+    testForDesugaring(
+            parameters,
+            options -> {
+              if (compilingForNativeRecordSupport) {
+                // TODO(b/231930852): When Art 14 support records this will be controlled by API
+                // level.
+                options.emitRecordAnnotationsInDex = true;
+                options.emitRecordAnnotationsExInDex = true;
+              }
+            })
+        .addProgramClassFileData(PROGRAM_DATA)
+        .run(parameters.getRuntime(), MAIN_TYPE)
+        .applyIf(
+            parameters.isDexRuntime() && compilingForNativeRecordSupport,
+            // Current Art 14 build does not support the java.lang.Record class.
+            r -> r.assertFailureWithErrorThatThrows(NoClassDefFoundError.class),
+            compilingForNativeRecordSupport,
+            r -> r.assertSuccessWithOutput(EXPECTED_RESULT),
+            r ->
+                r.assertSuccessWithOutput(
+                        !parameters.isCfRuntime()
+                            ? EXPECTED_RESULT_DESUGARED
+                            : EXPECTED_RESULT_DESUGARED_JVM17)
+                    .inspect(
+                        inspector -> {
+                          ClassSubject person =
+                              inspector.clazz("records.RecordWithAnnotations$Person");
+                          FieldSubject name = person.uniqueFieldWithOriginalName("name");
+                          assertThat(name, isPresentAndNotRenamed());
+                          FieldSubject age = person.uniqueFieldWithOriginalName("age");
+                          assertThat(age, isPresentAndNotRenamed());
+                          if (compilingForNativeRecordSupport) {
+                            assertEquals(2, person.getFinalRecordComponents().size());
+
+                            assertEquals(
+                                name.getFinalName(),
+                                person.getFinalRecordComponents().get(0).getName());
+                            assertTrue(
+                                person
+                                    .getFinalRecordComponents()
+                                    .get(0)
+                                    .getType()
+                                    .is("java.lang.String"));
+                            assertNull(person.getFinalRecordComponents().get(0).getSignature());
+                            assertEquals(
+                                2,
+                                person.getFinalRecordComponents().get(0).getAnnotations().size());
+                            assertThat(
+                                person.getFinalRecordComponents().get(0).getAnnotations(),
+                                hasAnnotationTypes(
+                                    inspector.getTypeSubject(
+                                        "records.RecordWithAnnotations$Annotation"),
+                                    inspector.getTypeSubject(
+                                        "records.RecordWithAnnotations$AnnotationRecordComponentOnly")));
+                            assertThat(
+                                person.getFinalRecordComponents().get(0).getAnnotations().get(0),
+                                hasElements(new Pair<>("value", "a")));
+                            assertThat(
+                                person.getFinalRecordComponents().get(0).getAnnotations().get(1),
+                                hasElements(new Pair<>("value", "c")));
+
+                            assertEquals(
+                                age.getFinalName(),
+                                person.getFinalRecordComponents().get(1).getName());
+                            assertTrue(
+                                person.getFinalRecordComponents().get(1).getType().is("int"));
+                            assertNull(person.getFinalRecordComponents().get(1).getSignature());
+                            assertEquals(
+                                2,
+                                person.getFinalRecordComponents().get(1).getAnnotations().size());
+                            assertThat(
+                                person.getFinalRecordComponents().get(1).getAnnotations(),
+                                hasAnnotationTypes(
+                                    inspector.getTypeSubject(
+                                        "records.RecordWithAnnotations$Annotation"),
+                                    inspector.getTypeSubject(
+                                        "records.RecordWithAnnotations$AnnotationRecordComponentOnly")));
+                            assertThat(
+                                person.getFinalRecordComponents().get(1).getAnnotations().get(0),
+                                hasElements(new Pair<>("value", "x")));
+                            assertThat(
+                                person.getFinalRecordComponents().get(1).getAnnotations().get(1),
+                                hasElements(new Pair<>("value", "z")));
+                          } else {
+                            assertEquals(0, person.getFinalRecordComponents().size());
+                          }
+                        }));
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    parameters.assumeR8TestParameters();
+    // Android U will support records.
+    boolean compilingForNativeRecordSupport =
+        parameters.isCfRuntime()
+            || parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.U);
+    testForR8(parameters.getBackend())
+        .addProgramClassFileData(PROGRAM_DATA)
+        // TODO(b/231930852): Change to android.jar for Androud U when that contains
+        // java.lang.Record.
+        .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
+        .addKeepMainRule(MAIN_TYPE)
+        .addKeepClassAndMembersRulesWithAllowObfuscation("records.RecordWithAnnotations$Person")
+        .addKeepClassAndMembersRules(
+            "records.RecordWithAnnotations$Annotation",
+            "records.RecordWithAnnotations$AnnotationFieldOnly",
+            "records.RecordWithAnnotations$AnnotationRecordComponentOnly")
+        .applyIf(keepAnnotations, TestShrinkerBuilder::addKeepRuntimeVisibleAnnotations)
+        .setMinApi(parameters)
+        .applyIf(
+            compilingForNativeRecordSupport,
+            // TODO(b/231930852): When Art 14 support records this will be controlled by API level.
+            b ->
+                b.addOptionsModification(options -> options.emitRecordAnnotationsInDex = true)
+                    .addOptionsModification(options -> options.emitRecordAnnotationsExInDex = true))
+        .compile()
+        .inspect(
+            inspector -> {
+              ClassSubject person = inspector.clazz("records.RecordWithAnnotations$Person");
+              FieldSubject name = person.uniqueFieldWithOriginalName("name");
+              FieldSubject age = person.uniqueFieldWithOriginalName("age");
+              if (compilingForNativeRecordSupport) {
+                assertEquals(2, person.getFinalRecordComponents().size());
+
+                assertEquals(
+                    name.getFinalName(), person.getFinalRecordComponents().get(0).getName());
+                assertTrue(
+                    person.getFinalRecordComponents().get(0).getType().is("java.lang.String"));
+                assertNull(person.getFinalRecordComponents().get(0).getSignature());
+                assertEquals(2, person.getFinalRecordComponents().get(0).getAnnotations().size());
+                assertThat(
+                    person.getFinalRecordComponents().get(0).getAnnotations(),
+                    hasAnnotationTypes(
+                        inspector.getTypeSubject("records.RecordWithAnnotations$Annotation"),
+                        inspector.getTypeSubject(
+                            "records.RecordWithAnnotations$AnnotationRecordComponentOnly")));
+                assertThat(
+                    person.getFinalRecordComponents().get(0).getAnnotations().get(0),
+                    hasElements(new Pair<>("value", "a")));
+                assertThat(
+                    person.getFinalRecordComponents().get(0).getAnnotations().get(1),
+                    hasElements(new Pair<>("value", "c")));
+
+                assertEquals(
+                    age.getFinalName(), person.getFinalRecordComponents().get(1).getName());
+                assertTrue(person.getFinalRecordComponents().get(1).getType().is("int"));
+                assertNull(person.getFinalRecordComponents().get(1).getSignature());
+                assertEquals(2, person.getFinalRecordComponents().get(1).getAnnotations().size());
+                assertThat(
+                    person.getFinalRecordComponents().get(1).getAnnotations(),
+                    hasAnnotationTypes(
+                        inspector.getTypeSubject("records.RecordWithAnnotations$Annotation"),
+                        inspector.getTypeSubject(
+                            "records.RecordWithAnnotations$AnnotationRecordComponentOnly")));
+                assertThat(
+                    person.getFinalRecordComponents().get(1).getAnnotations().get(0),
+                    hasElements(new Pair<>("value", "x")));
+                assertThat(
+                    person.getFinalRecordComponents().get(1).getAnnotations().get(1),
+                    hasElements(new Pair<>("value", "z")));
+              } else {
+                assertEquals(0, person.getFinalRecordComponents().size());
+              }
+            })
+        .run(parameters.getRuntime(), MAIN_TYPE)
+        .applyIf(
+            parameters.isCfRuntime(),
+            // TODO(b/274888318): EXPECTED_RESULT_R8_NO_KEEP_ANNOTATIONS still has component
+            //  annotations.
+            r ->
+                r.assertSuccessWithOutput(
+                    keepAnnotations ? EXPECTED_RESULT_R8 : EXPECTED_RESULT_R8_NO_KEEP_ANNOTATIONS),
+            // r -> r.assertSuccessWithOutput(EXPECTED_RESULT_R8),
+            compilingForNativeRecordSupport,
+            // Current Art 14 build does not support the java.lang.Record class.
+            r -> r.assertFailureWithErrorThatThrows(NoClassDefFoundError.class),
+            r -> r.assertSuccessWithOutput(EXPECTED_RESULT_DESUGARED));
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordComponentSignatureTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordComponentSignatureTest.java
new file mode 100644
index 0000000..5ce845f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordComponentSignatureTest.java
@@ -0,0 +1,205 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.desugar.records;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.TestShrinkerBuilder;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.FieldSubject;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class RecordComponentSignatureTest extends TestBase {
+
+  private static final String RECORD_NAME = "RecordWithSignature";
+  private static final byte[][] PROGRAM_DATA = RecordTestUtils.getProgramData(RECORD_NAME);
+  private static final String MAIN_TYPE = RecordTestUtils.getMainType(RECORD_NAME);
+  private static final String EXPECTED_RESULT =
+      StringUtils.lines(
+          "Jane Doe",
+          "42",
+          "Jane Doe",
+          "42",
+          "true",
+          "2",
+          "name",
+          "java.lang.CharSequence",
+          "TN;",
+          "0",
+          "age",
+          "java.lang.Object",
+          "TA;",
+          "0");
+  private static final String EXPECTED_RESULT_R8 =
+      StringUtils.lines(
+          "Jane Doe", "42", "Jane Doe", "42", "true", "1", "a", "java.lang.Object", "TA;", "0");
+  private static final String EXPECTED_RESULT_R8_NO_KEEP_SIGNATURE =
+      StringUtils.lines(
+          "Jane Doe", "42", "Jane Doe", "42", "true", "1", "a", "java.lang.Object", "null", "0");
+  private static final String EXPECTED_RESULT_DESUGARED =
+      StringUtils.lines("Jane Doe", "42", "Jane Doe", "42", "Class.isRecord not present");
+
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameter(1)
+  public Boolean keepSignatures;
+
+  @Parameters(name = "{0}, keepSignatures: {1}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters()
+            .withDexRuntimesAndAllApiLevels()
+            .withCfRuntimesStartingFromIncluding(CfVm.JDK17)
+            .withAllApiLevelsAlsoForCf()
+            .build(),
+        BooleanUtils.values());
+  }
+
+  @Test
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    assumeTrue(keepSignatures);
+    testForJvm(parameters)
+        .addProgramClassFileData(PROGRAM_DATA)
+        .run(parameters.getRuntime(), MAIN_TYPE)
+        .assertSuccessWithOutput(EXPECTED_RESULT);
+  }
+
+  @Test
+  public void testDesugaring() throws Exception {
+    parameters.assumeDexRuntime();
+    assumeTrue(keepSignatures);
+    // Android U will support records.
+    boolean compilingForNativeRecordSupport =
+        parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.U);
+    testForDesugaring(
+            parameters,
+            options -> {
+              if (compilingForNativeRecordSupport) {
+                // TODO(b/231930852): When Art 14 support records this will be controlled by API
+                // level.
+                options.emitRecordAnnotationsInDex = true;
+                options.emitRecordAnnotationsExInDex = true;
+              }
+            })
+        .addProgramClassFileData(PROGRAM_DATA)
+        .run(parameters.getRuntime(), MAIN_TYPE)
+        .applyIf(
+            compilingForNativeRecordSupport,
+            // Current Art 14 build does not support the java.lang.Record class.
+            r -> r.assertFailureWithErrorThatThrows(NoClassDefFoundError.class),
+            r ->
+                r.assertSuccessWithOutput(EXPECTED_RESULT_DESUGARED)
+                    .inspect(
+                        inspector -> {
+                          ClassSubject person =
+                              inspector.clazz("records.RecordWithSignature$Person");
+                          if (compilingForNativeRecordSupport) {
+                            assertEquals(2, person.getFinalRecordComponents().size());
+
+                            assertEquals(
+                                "name", person.getFinalRecordComponents().get(0).getName());
+                            assertTrue(
+                                person
+                                    .getFinalRecordComponents()
+                                    .get(0)
+                                    .getType()
+                                    .is("java.lang.CharSequence"));
+                            assertEquals(
+                                "TN;", person.getFinalRecordComponents().get(0).getSignature());
+                            assertEquals(
+                                0,
+                                person.getFinalRecordComponents().get(0).getAnnotations().size());
+
+                            assertEquals("age", person.getFinalRecordComponents().get(1).getName());
+                            assertTrue(
+                                person
+                                    .getFinalRecordComponents()
+                                    .get(1)
+                                    .getType()
+                                    .is("java.lang.Object"));
+                            assertEquals(
+                                "TA;", person.getFinalRecordComponents().get(1).getSignature());
+                            assertEquals(
+                                0,
+                                person.getFinalRecordComponents().get(1).getAnnotations().size());
+                          } else {
+                            assertEquals(0, person.getFinalRecordComponents().size());
+                          }
+                        }));
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    parameters.assumeR8TestParameters();
+    boolean compilingForNativeRecordSupport =
+        parameters.isCfRuntime()
+            || parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.U);
+    testForR8(parameters.getBackend())
+        .addProgramClassFileData(PROGRAM_DATA)
+        // TODO(b/231930852): Change to android.jar for Androud U when that contains
+        // java.lang.Record.
+        .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
+        .addKeepMainRule(MAIN_TYPE)
+        .applyIf(keepSignatures, TestShrinkerBuilder::addKeepAttributeSignature)
+        .setMinApi(parameters)
+        .applyIf(
+            compilingForNativeRecordSupport,
+            // TODO(b/231930852): When Art 14 support records this will be controlled by API level.
+            b ->
+                b.addOptionsModification(options -> options.emitRecordAnnotationsInDex = true)
+                    .addOptionsModification(options -> options.emitRecordAnnotationsExInDex = true))
+        .compile()
+        .inspect(
+            inspector -> {
+              ClassSubject person = inspector.clazz("records.RecordWithSignature$Person");
+              FieldSubject age = person.uniqueFieldWithOriginalName("age");
+              assertThat(age, isPresentAndRenamed());
+              if (compilingForNativeRecordSupport) {
+                assertEquals(1, person.getFinalRecordComponents().size());
+                assertEquals(
+                    age.getFinalName(), person.getFinalRecordComponents().get(0).getName());
+                assertTrue(
+                    person.getFinalRecordComponents().get(0).getType().is("java.lang.Object"));
+                if (keepSignatures) {
+                  assertEquals("TA;", person.getFinalRecordComponents().get(0).getSignature());
+                } else {
+                  assertNull(person.getFinalRecordComponents().get(0).getSignature());
+                }
+                assertEquals(0, person.getFinalRecordComponents().get(0).getAnnotations().size());
+              } else {
+                assertEquals(0, person.getFinalRecordComponents().size());
+              }
+            })
+        .run(parameters.getRuntime(), MAIN_TYPE)
+        // No Art VM actually supports the java.lang.Record class.
+        .applyIf(
+            parameters.isCfRuntime(),
+            r ->
+                r.assertSuccessWithOutput(
+                    keepSignatures ? EXPECTED_RESULT_R8 : EXPECTED_RESULT_R8_NO_KEEP_SIGNATURE),
+            compilingForNativeRecordSupport,
+            // Current Art 14 build does not support the java.lang.Record class.
+            r -> r.assertFailureWithErrorThatThrows(NoClassDefFoundError.class),
+            r -> r.assertSuccessWithOutput(EXPECTED_RESULT_DESUGARED));
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/dex/DebugByteCodeWriterTest.java b/src/test/java/com/android/tools/r8/dex/DebugByteCodeWriterTest.java
index e09c293..37deb3c 100644
--- a/src/test/java/com/android/tools/r8/dex/DebugByteCodeWriterTest.java
+++ b/src/test/java/com/android/tools/r8/dex/DebugByteCodeWriterTest.java
@@ -15,8 +15,8 @@
 import com.android.tools.r8.graph.DexDebugInfo.EventBasedDebugInfo;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.synthesis.SyntheticItems.GlobalSyntheticsStrategy;
 import com.android.tools.r8.utils.InternalOptions;
diff --git a/src/test/java/com/android/tools/r8/internal/startup/ChromeStartupTest.java b/src/test/java/com/android/tools/r8/internal/startup/ChromeStartupTest.java
index 2527b81..a8cf85a 100644
--- a/src/test/java/com/android/tools/r8/internal/startup/ChromeStartupTest.java
+++ b/src/test/java/com/android/tools/r8/internal/startup/ChromeStartupTest.java
@@ -18,7 +18,7 @@
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.ThrowableConsumer;
 import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.experimental.startup.StartupProfileProviderUtils;
+import com.android.tools.r8.profile.startup.StartupProfileProviderUtils;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.ZipUtils;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
diff --git a/src/test/java/com/android/tools/r8/ir/InlineTest.java b/src/test/java/com/android/tools/r8/ir/InlineTest.java
index bd6303e..d89807c 100644
--- a/src/test/java/com/android/tools/r8/ir/InlineTest.java
+++ b/src/test/java/com/android/tools/r8/ir/InlineTest.java
@@ -23,7 +23,7 @@
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionListIterator;
 import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.profile.art.rewriting.ProfileCollectionAdditions;
+import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
 import com.android.tools.r8.shaking.Enqueuer;
 import com.android.tools.r8.shaking.EnqueuerFactory;
 import com.android.tools.r8.shaking.EnqueuerResult;
diff --git a/src/test/java/com/android/tools/r8/ir/conversion/CallGraphTestBase.java b/src/test/java/com/android/tools/r8/ir/conversion/CallGraphTestBase.java
index d5f5e91..c7c00b8 100644
--- a/src/test/java/com/android/tools/r8/ir/conversion/CallGraphTestBase.java
+++ b/src/test/java/com/android/tools/r8/ir/conversion/CallGraphTestBase.java
@@ -35,6 +35,7 @@
           null,
           Collections.emptyList(),
           Collections.emptyList(),
+          Collections.emptyList(),
           null,
           Collections.emptyList(),
           ClassSignature.noSignature(),
diff --git a/src/test/java/com/android/tools/r8/rewrite/JavaScriptScriptEngineTest.java b/src/test/java/com/android/tools/r8/rewrite/JavaScriptScriptEngineTest.java
index 2450204..276e660 100644
--- a/src/test/java/com/android/tools/r8/rewrite/JavaScriptScriptEngineTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/JavaScriptScriptEngineTest.java
@@ -86,8 +86,8 @@
                         equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))))
         .run(parameters.getRuntime(), TestClass.class)
         .applyIf(
-            // TODO(b/227162584): Fails to find any engine on JDK17.
-            parameters.isCfRuntime(CfVm.JDK17),
+            // No default JS engine starting from JDK-14 where Nashorn was removed, see b/227162584.
+            parameters.isCfRuntime() && parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK14),
             r -> r.assertFailureWithErrorThatThrows(NullPointerException.class),
             r ->
                 r.assertSuccessWithOutput(
diff --git a/src/test/java/com/android/tools/r8/rewrite/ScriptEngineTest.java b/src/test/java/com/android/tools/r8/rewrite/ScriptEngineTest.java
index 839e03e..81a977b 100644
--- a/src/test/java/com/android/tools/r8/rewrite/ScriptEngineTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/ScriptEngineTest.java
@@ -107,8 +107,10 @@
         //  comes with "Oracle Nashorn" included.
         .assertSuccessWithOutput(
             parameters.isCfRuntime()
-                // TODO(b/227162584): It looks like the JS engine is not in the jdk anymore.
-                ? (parameters.isCfRuntime(CfVm.JDK17)
+                // No default JS engine starting from JDK-14 where Nashorn was removed,
+                // see b/227162584.
+                ? (parameters.isCfRuntime()
+                        && parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK14)
                     ? StringUtils.lines("MyEngine1", "MyEngine2")
                     : StringUtils.lines("MyEngine1", "MyEngine2", "Oracle Nashorn"))
                 : StringUtils.lines("Mozilla Rhino", "MyEngine1", "MyEngine2"));
diff --git a/src/test/java/com/android/tools/r8/shaking/LibraryProvidedProguardRulesR8SpecificTest.java b/src/test/java/com/android/tools/r8/shaking/LibraryProvidedProguardRulesR8SpecificTest.java
index 419ebfc..884de68 100644
--- a/src/test/java/com/android/tools/r8/shaking/LibraryProvidedProguardRulesR8SpecificTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/LibraryProvidedProguardRulesR8SpecificTest.java
@@ -76,16 +76,16 @@
     if (libraryType.hasRulesInJar()) {
       jarBuilder.addText("META-INF/com.android.tools/r8/test1.pro", "-keep class A1");
       jarBuilder.addText("META-INF/com.android.tools/r8/test2.pro", "-keep class A2");
-      jarBuilder.addText("META-INF/com.android.tools/r8-min-4.0.0/test1.pro", "-keep class B1");
-      jarBuilder.addText("META-INF/com.android.tools/r8-min-4.0.0/test2.pro", "-keep class B2");
-      jarBuilder.addText("META-INF/com.android.tools/r8-max-8.1.0/test1.pro", "-keep class C1");
-      jarBuilder.addText("META-INF/com.android.tools/r8-max-8.1.0/test2.pro", "-keep class C2");
+      jarBuilder.addText("META-INF/com.android.tools/r8-from-4.0.0/test1.pro", "-keep class B1");
+      jarBuilder.addText("META-INF/com.android.tools/r8-from-4.0.0/test2.pro", "-keep class B2");
+      jarBuilder.addText("META-INF/com.android.tools/r8-upto-8.1.0/test1.pro", "-keep class C1");
+      jarBuilder.addText("META-INF/com.android.tools/r8-upto-8.1.0/test2.pro", "-keep class C2");
       jarBuilder.addText(
-          "META-INF/com.android.tools/r8-min-5.0.0-max-8.0.0/test1.pro", "-keep class D1");
+          "META-INF/com.android.tools/r8-from-5.0.0-upto-8.0.0/test1.pro", "-keep class D1");
       jarBuilder.addText(
-          "META-INF/com.android.tools/r8-min-5.0.0-max-8.0.0/test2.pro", "-keep class D2");
-      jarBuilder.addText("META-INF/com.android.tools/r8-min-10.5.0/test1.pro", "-keep class E1");
-      jarBuilder.addText("META-INF/com.android.tools/r8-min-10.5.0/test2.pro", "-keep class E2");
+          "META-INF/com.android.tools/r8-from-5.0.0-upto-8.0.0/test2.pro", "-keep class D2");
+      jarBuilder.addText("META-INF/com.android.tools/r8-from-10.5.0/test1.pro", "-keep class E1");
+      jarBuilder.addText("META-INF/com.android.tools/r8-from-10.5.0/test2.pro", "-keep class E2");
       jarBuilder.addText("META-INF/proguard/test1.pro", "-keep class X1");
       jarBuilder.addText("META-INF/proguard/test2.pro", "-keep class X2");
     }
@@ -171,18 +171,31 @@
   }
 
   @Test
-  public void runTestVersion8() throws Exception {
+  public void runTestVersion7_99_99() throws Exception {
     runTest(
-        SemanticVersion.create(8, 0, 0),
+        SemanticVersion.create(7, 99, 99),
         StringUtils.lines(
             EXPECTED_A.trim(), EXPECTED_B.trim(), EXPECTED_C.trim(), EXPECTED_D.trim()));
   }
 
   @Test
+  public void runTestVersion8() throws Exception {
+    runTest(
+        SemanticVersion.create(8, 0, 0),
+        StringUtils.lines(EXPECTED_A.trim(), EXPECTED_B.trim(), EXPECTED_C.trim()));
+  }
+
+  @Test
+  public void runTestVersion8_0_99() throws Exception {
+    runTest(
+        SemanticVersion.create(8, 0, 99),
+        StringUtils.lines(EXPECTED_A.trim(), EXPECTED_B.trim(), EXPECTED_C.trim()));
+  }
+
+  @Test
   public void runTestVersion8_1() throws Exception {
     runTest(
-        SemanticVersion.create(8, 1, 0),
-        StringUtils.lines(EXPECTED_A.trim(), EXPECTED_B.trim(), EXPECTED_C.trim()));
+        SemanticVersion.create(8, 1, 0), StringUtils.lines(EXPECTED_A.trim(), EXPECTED_B.trim()));
   }
 
   @Test
@@ -286,14 +299,14 @@
   public void testUnusedProguardOnlyRules() throws Exception {
     for (String directory :
         ImmutableList.of(
-            "proguard-min-6.1.0",
-            "proguard-max-7.0.0",
-            "proguard-min-6.1.0-max-7.0.0",
+            "proguard-from-6.1.0",
+            "proguard-upto-7.0.0",
+            "proguard-from-6.1.0-upto-7.0.0",
             "proguard610",
             "com.android.tools/proguard",
-            "com.android.tools/proguard-min-6.1.0",
-            "com.android.tools/proguard-max-7.0.0",
-            "com.android.tools/proguard-min-6.1.0-max-7.0.0",
+            "com.android.tools/proguard-from-6.1.0",
+            "com.android.tools/proguard-upto-7.0.0",
+            "com.android.tools/proguard-from-6.1.0-upto-7.0.0",
             "com.android.tools/proguard610")) {
       Path library = buildLibraryProguardOnlyRules(directory);
       testForR8(Backend.DEX)
@@ -311,14 +324,14 @@
   public void testUnusedProguardOnlyRulesVersionMain() throws Exception {
     for (String directory :
         ImmutableList.of(
-            "proguard-min-6.1.0",
-            "proguard-max-7.0.0",
-            "proguard-min-6.1.0-max-7.0.0",
+            "proguard-from-6.1.0",
+            "proguard-upto-7.0.0",
+            "proguard-from-6.1.0-upto-7.0.0",
             "proguard610",
             "com.android.tools/proguard",
-            "com.android.tools/proguard-min-6.1.0",
-            "com.android.tools/proguard-max-7.0.0",
-            "com.android.tools/proguard-min-6.1.0-max-7.0.0",
+            "com.android.tools/proguard-from-6.1.0",
+            "com.android.tools/proguard-upto-7.0.0",
+            "com.android.tools/proguard-from-6.1.0-upto-7.0.0",
             "com.android.tools/proguard610")) {
       Path library = buildLibraryProguardOnlyRules(directory);
       testForR8(Backend.DEX)
diff --git a/src/test/java/com/android/tools/r8/startup/utils/StartupTestingUtils.java b/src/test/java/com/android/tools/r8/startup/utils/StartupTestingUtils.java
index 93dc0a0..3ee4a45 100644
--- a/src/test/java/com/android/tools/r8/startup/utils/StartupTestingUtils.java
+++ b/src/test/java/com/android/tools/r8/startup/utils/StartupTestingUtils.java
@@ -17,12 +17,12 @@
 import com.android.tools.r8.TextInputStream;
 import com.android.tools.r8.ThrowableConsumer;
 import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.experimental.startup.instrumentation.StartupInstrumentationOptions;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.profile.art.ArtProfileBuilder;
 import com.android.tools.r8.profile.art.ArtProfileBuilderUtils;
 import com.android.tools.r8.profile.art.HumanReadableArtProfileParser;
 import com.android.tools.r8.profile.art.HumanReadableArtProfileParserBuilder;
+import com.android.tools.r8.profile.startup.instrumentation.StartupInstrumentationOptions;
 import com.android.tools.r8.startup.StartupClassBuilder;
 import com.android.tools.r8.startup.StartupMethodBuilder;
 import com.android.tools.r8.startup.StartupProfileBuilder;
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java
index 0d8f6d0..39e3174 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java
@@ -235,6 +235,11 @@
   }
 
   @Override
+  public List<RecordComponentSubject> getFinalRecordComponents() {
+    throw new Unreachable("Cannot determine RecordComponents attribute of an absent class");
+  }
+
+  @Override
   public KmClassSubject getKmClass() {
     return null;
   }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AnnotationMatchers.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AnnotationMatchers.java
index bb1c57a..4a0f1ac 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/AnnotationMatchers.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AnnotationMatchers.java
@@ -4,6 +4,8 @@
 
 package com.android.tools.r8.utils.codeinspector;
 
+import com.android.tools.r8.graph.DexAnnotationElement;
+import com.android.tools.r8.utils.Pair;
 import com.android.tools.r8.utils.StringUtils;
 import java.util.Arrays;
 import java.util.List;
@@ -101,4 +103,50 @@
       }
     };
   }
+
+  @SafeVarargs
+  public static Matcher<FoundAnnotationSubject> hasElements(
+      Pair<String, String>... expectedElements) {
+    return new TypeSafeMatcher<FoundAnnotationSubject>() {
+
+      @Override
+      protected boolean matchesSafely(FoundAnnotationSubject subject) {
+        if (expectedElements.length != subject.getAnnotation().elements.length) {
+          return false;
+        }
+        for (int i = 0; i < expectedElements.length; i++) {
+          DexAnnotationElement element = subject.getAnnotation().elements[i];
+          if (!element.name.toString().equals(expectedElements[i].getFirst())
+              || !element.value.isDexValueString()
+              || !element
+                  .value
+                  .asDexValueString()
+                  .getValue()
+                  .toString()
+                  .equals(expectedElements[i].getSecond())) {
+            return false;
+          }
+        }
+        return true;
+      }
+
+      @Override
+      public void describeTo(Description description) {
+        StringBuilder builder = new StringBuilder("has elements ");
+        for (Pair<String, String> expectedElement : expectedElements) {
+          builder
+              .append(expectedElement.getFirst())
+              .append(" = ")
+              .append(expectedElement.getSecond())
+              .append(", ");
+        }
+        description.appendText(builder.toString());
+      }
+
+      @Override
+      public void describeMismatchSafely(FoundAnnotationSubject subject, Description description) {
+        description.appendText("annotation did not");
+      }
+    };
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
index 1aebbdd..99dd879 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
@@ -250,6 +250,8 @@
 
   public abstract List<TypeSubject> getFinalPermittedSubclassAttributes();
 
+  public abstract List<RecordComponentSubject> getFinalRecordComponents();
+
   public abstract KmClassSubject getKmClass();
 
   public abstract KmPackageSubject getKmPackage();
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 fcfe160..457e4a2 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
@@ -525,6 +525,15 @@
   }
 
   @Override
+  public List<RecordComponentSubject> getFinalRecordComponents() {
+    List<RecordComponentSubject> result = new ArrayList<>(dexClass.getRecordComponents().size());
+    for (int i = 0; i < dexClass.getRecordComponents().size(); i++) {
+      result.add(new RecordComponentSubject(codeInspector, dexClass, i));
+    }
+    return result;
+  }
+
+  @Override
   public int hashCode() {
     int result = codeInspector.hashCode();
     result = 31 * result + dexClass.hashCode();
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/RecordComponentSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/RecordComponentSubject.java
new file mode 100644
index 0000000..87b36df
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/RecordComponentSubject.java
@@ -0,0 +1,67 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.utils.codeinspector;
+
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexAnnotation;
+import com.android.tools.r8.graph.DexClass;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class RecordComponentSubject extends Subject {
+
+  private final CodeInspector codeInspector;
+  private final DexClass clazz;
+  private final int index;
+
+  public RecordComponentSubject(CodeInspector codeInspector, DexClass clazz, int index) {
+    this.codeInspector = codeInspector;
+    this.clazz = clazz;
+    this.index = index;
+  }
+
+  public int size() {
+    return clazz.getRecordComponents().size();
+  }
+
+  public String getName() {
+    return clazz.getRecordComponents().get(index).getName().toString();
+  }
+
+  public TypeSubject getType() {
+    return new TypeSubject(codeInspector, clazz.getRecordComponents().get(index).getType());
+  }
+
+  public String getSignature() {
+    return clazz.getRecordComponents().get(index).getSignature().toString();
+  }
+
+  public List<FoundAnnotationSubject> getAnnotations() {
+    int size = clazz.getRecordComponents().get(index).getAnnotations().size();
+    if (size == 0) {
+      return Collections.emptyList();
+    }
+    List<FoundAnnotationSubject> result = new ArrayList<>(size);
+    for (DexAnnotation annotation : clazz.getRecordComponents().get(index).getAnnotations()) {
+      result.add(new FoundAnnotationSubject(annotation, codeInspector));
+    }
+    return result;
+  }
+
+  @Override
+  public boolean isPresent() {
+    return true;
+  }
+
+  @Override
+  public boolean isRenamed() {
+    throw new Unreachable("Cannot determine if a record component is renamed");
+  }
+
+  @Override
+  public boolean isSynthetic() {
+    throw new Unreachable("Cannot determine if a record component is synthetic");
+  }
+}
diff --git a/tools/test.py b/tools/test.py
index 2f0254c..3c52be4 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -82,6 +82,9 @@
   result.add_option('--slow-tests', '--slow_tests',
       help='Also run slow tests.',
       default=False, action='store_true')
+  result.add_option('--force-32-bit-art', '--force_32_bit_art',
+      help='Force art to run 32 bits.',
+      default=False, action='store_true')
   result.add_option('-v', '--verbose',
       help='Print test stdout to, well, stdout.',
       default=False, action='store_true')
@@ -290,6 +293,8 @@
     gradle_args.append('-Pall_tests')
   if options.slow_tests:
     gradle_args.append('-Pslow_tests=1')
+  if options.force_32_bit_art:
+    gradle_args.append('-Pforce_32_bit_art=1')
   if options.tool:
     gradle_args.append('-Ptool=%s' % options.tool)
   if options.one_line_per_test: