Merge commit '5182c2d1499a93910b0735ba5360ead042013aea' into dev-release
diff --git a/AUTHORS b/AUTHORS
index 02ac16e..df9cd8d 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -5,6 +5,7 @@
 
 Google Inc.
 Uber Technologies Inc.
+Square Inc.
 
 Albert Jin <albert.jin@gmail.com>
 Kevin Sun <snxngxng@gmail.com>
diff --git a/build.gradle b/build.gradle
index 2e908a5..30c839c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -307,6 +307,7 @@
                 "android_jar/lib-v28",
                 "android_jar/lib-v29",
                 "android_jar/lib-v30",
+                "android_jar/lib-v31",
                 "core-lambda-stubs",
                 "dart-sdk",
                 "ddmlib",
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index cdbcdd8..9b3f92c 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -27,8 +27,10 @@
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
 import com.android.tools.r8.jar.CfApplicationWriter;
 import com.android.tools.r8.kotlin.KotlinMetadataRewriter;
+import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.naming.PrefixRewritingNamingLens;
+import com.android.tools.r8.naming.ProguardMapSupplier;
 import com.android.tools.r8.naming.RecordRewritingNamingLens;
 import com.android.tools.r8.naming.signature.GenericSignatureRewriter;
 import com.android.tools.r8.origin.CommandLineOrigin;
@@ -41,6 +43,8 @@
 import com.android.tools.r8.utils.ExceptionUtils;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.InternalOptions.DesugarState;
+import com.android.tools.r8.utils.InternalOptions.LineNumberOptimization;
+import com.android.tools.r8.utils.LineNumberOptimizer;
 import com.android.tools.r8.utils.StringDiagnostic;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.ThreadUtils;
@@ -268,9 +272,10 @@
         namingLens = RecordRewritingNamingLens.createRecordRewritingNamingLens(appView, namingLens);
       }
       if (options.isGeneratingClassFiles()) {
-        // TODO(b/158159959): Move this out so it is shared for both CF and DEX pipelines.
-        SyntheticFinalization.finalize(appView);
-        new CfApplicationWriter(appView, marker, GraphLens.getIdentityLens(), namingLens, null)
+        ProguardMapSupplier proguardMapSupplier =
+            finalizeApplication(inputApp, appView, namingLens);
+        new CfApplicationWriter(
+                appView, marker, GraphLens.getIdentityLens(), namingLens, proguardMapSupplier)
             .write(options.getClassFileConsumer());
       } else {
         if (!hasDexResources || !hasClassResources || !appView.rewritePrefix.isRewriting()) {
@@ -311,9 +316,8 @@
                       executor, appView.appInfo().app(), appView.appInfo().getMainDexInfo());
           appView.setAppInfo(appView.appInfo().rebuildWithMainDexInfo(mainDexInfo));
         }
-
-        // TODO(b/158159959): Move this out so it is shared for both CF and DEX pipelines.
-        SyntheticFinalization.finalize(appView);
+        ProguardMapSupplier proguardMapSupplier =
+            finalizeApplication(inputApp, appView, namingLens);
 
         new ApplicationWriter(
                 appView,
@@ -321,7 +325,7 @@
                 appView.graphLens(),
                 InitClassLens.getDefault(),
                 namingLens,
-                null)
+                proguardMapSupplier)
             .write(executor);
       }
       options.printWarnings();
@@ -336,6 +340,19 @@
     }
   }
 
+  private static ProguardMapSupplier finalizeApplication(
+      AndroidApp inputApp, AppView<AppInfo> appView, NamingLens namingLens) {
+    SyntheticFinalization.finalize(appView);
+    // TODO(b/37830524): Once D8 supports PC mapping this will need to be run for that too.
+    assert appView.options().lineNumberOptimization == LineNumberOptimization.OFF;
+    if (appView.options().proguardMapConsumer == null) {
+      return null;
+    }
+    ClassNameMapper classNameMapper =
+        LineNumberOptimizer.run(appView, appView.appInfo().app(), inputApp, namingLens);
+    return ProguardMapSupplier.create(classNameMapper, appView.options());
+  }
+
   private static DexApplication rewriteNonDexInputs(
       AppView<AppInfo> appView,
       AndroidApp inputApp,
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index 05c2e8e..7e20368 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -23,6 +23,7 @@
 import com.android.tools.r8.utils.AssertionConfigurationWithDefault;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.InternalOptions.DesugarState;
+import com.android.tools.r8.utils.InternalOptions.LineNumberOptimization;
 import com.android.tools.r8.utils.Reporter;
 import com.android.tools.r8.utils.StringDiagnostic;
 import com.android.tools.r8.utils.ThreadUtils;
@@ -459,6 +460,7 @@
     internal.readCompileTimeAnnotations = intermediate;
     internal.desugarGraphConsumer = desugarGraphConsumer;
     internal.mainDexKeepRules = mainDexKeepRules;
+    internal.lineNumberOptimization = LineNumberOptimization.OFF;
 
     // Assert and fixup defaults.
     assert !internal.isShrinking();
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 e6bc084..3fb79c6 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
@@ -2211,6 +2211,14 @@
                     TypeElement.fromDexType(phiTypeForBlock, Nullability.maybeNull(), appView),
                     local,
                     readType);
+          } else if (readType == RegisterReadType.DEBUG) {
+            throw new InvalidDebugInfoException(
+                "Information in locals-table is invalid with respect to the stack map table. "
+                    + "Local refers to non-present stack map type for register: "
+                    + register
+                    + " with constraint "
+                    + constraint
+                    + ".");
           } else {
             assert method.getDefinition().getClassFileVersion().isLessThan(CfVersion.V1_8);
             hasIncorrectStackMapTypes = true;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
index 2fc5c3a..8c7528c 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
@@ -983,6 +983,17 @@
           new MethodGenerator(
               method, BackportedMethods::CollectionsMethods_copyOfSet, "copyOfSet"));
 
+      // Map
+      type = factory.mapType;
+
+      // Map Map.copyOf(Map)
+      name = factory.createString("copyOf");
+      proto = factory.createProto(factory.mapType, factory.mapType);
+      method = factory.createMethod(type, proto, name);
+      addProvider(
+          new MethodGenerator(
+              method, BackportedMethods::CollectionsMethods_copyOfMap, "copyOfMap"));
+
       // Byte
       type = factory.boxedByteType;
 
@@ -1048,7 +1059,7 @@
     private void initializeJava9MethodProviders(DexItemFactory factory) {
       // Integer
       DexType type = factory.boxedIntType;
-      // long Long.parseLong(CharSequence s, int beginIndex, int endIndex, int radix)
+      // int Integer.parseInt(CharSequence s, int beginIndex, int endIndex, int radix)
       DexString name = factory.createString("parseInt");
       DexProto proto =
           factory.createProto(
@@ -1120,17 +1131,6 @@
       addProvider(
           new MethodGenerator(
               method, BackportedMethods::CollectionsMethods_copyOfList, "copyOfList"));
-
-      // Map
-      type = factory.mapType;
-
-      // Map Map.copyOf(Map)
-      name = factory.createString("copyOf");
-      proto = factory.createProto(factory.mapType, factory.mapType);
-      method = factory.createMethod(type, proto, name);
-      addProvider(
-          new MethodGenerator(
-              method, BackportedMethods::CollectionsMethods_copyOfMap, "copyOfMap"));
     }
 
     private void initializeJava11MethodProviders(DexItemFactory factory) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
index 854f6e9..aacfec7 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
@@ -735,7 +735,7 @@
     Set<Instruction> users = eligibleInstance.uniqueUsers();
     for (Instruction user : users) {
       BasicBlock block = user.getBlock();
-      if (!seen.add(block)) {
+      if (block == null || !seen.add(block)) {
         continue;
       }
 
@@ -746,8 +746,8 @@
           continue;
         }
 
-        if (user.isInstanceGet()) {
-          if (user.hasUsedOutValue()) {
+        if (instruction.isInstanceGet()) {
+          if (instruction.hasUsedOutValue()) {
             replaceFieldReadFromStaticGet(
                 code, instructionIterator, user.asInstanceGet(), affectedValues);
           } else {
@@ -756,7 +756,7 @@
           continue;
         }
 
-        if (user.isInstancePut()) {
+        if (instruction.isInstancePut()) {
           instructionIterator.removeOrReplaceByDebugLocalRead();
           continue;
         }
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java b/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java
index 1fdb08f..bd44c7b 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java
@@ -5,6 +5,7 @@
 
 import static com.android.tools.r8.naming.ClassNameMapper.MissingFileAction.MISSING_FILE_IS_ERROR;
 import static com.android.tools.r8.utils.DescriptorUtils.descriptorToJavaType;
+import static com.android.tools.r8.utils.FunctionUtils.ignoreArgument;
 
 import com.android.tools.r8.DiagnosticsHandler;
 import com.android.tools.r8.graph.DexField;
@@ -14,9 +15,11 @@
 import com.android.tools.r8.naming.MemberNaming.FieldSignature;
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
 import com.android.tools.r8.naming.MemberNaming.Signature;
+import com.android.tools.r8.naming.mappinginformation.ScopedMappingInformation;
 import com.android.tools.r8.position.Position;
 import com.android.tools.r8.utils.BiMapContainer;
 import com.android.tools.r8.utils.ChainableStringConsumer;
+import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.Reporter;
 import com.google.common.collect.BiMap;
 import com.google.common.collect.ImmutableBiMap;
@@ -29,9 +32,12 @@
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 
@@ -43,10 +49,11 @@
   }
 
   public static class Builder extends ProguardMap.Builder {
-    private final ImmutableMap.Builder<String, ClassNamingForNameMapper.Builder> mapBuilder;
+    private final Map<String, ClassNamingForNameMapper.Builder> mapping = new HashMap<>();
+    private final Map<String, List<ScopedMappingInformation>> scopedMappingInfo = new HashMap<>();
 
     private Builder() {
-      this.mapBuilder = ImmutableMap.builder();
+
     }
 
     @Override
@@ -54,13 +61,40 @@
         String renamedName, String originalName, Position position) {
       ClassNamingForNameMapper.Builder classNamingBuilder =
           ClassNamingForNameMapper.builder(renamedName, originalName);
-      mapBuilder.put(renamedName, classNamingBuilder);
+      mapping.put(renamedName, classNamingBuilder);
       return classNamingBuilder;
     }
 
     @Override
+    void addScopedMappingInformation(ScopedMappingInformation scopedMappingInformation) {
+      scopedMappingInformation.forEach(
+          (ref, info) ->
+              scopedMappingInfo.computeIfAbsent(ref, ignoreArgument(ArrayList::new)).add(info));
+    }
+
+    @Override
     public ClassNameMapper build() {
-      return new ClassNameMapper(mapBuilder.build());
+      return new ClassNameMapper(buildClassNameMappings());
+    }
+
+    private ImmutableMap<String, ClassNamingForNameMapper> buildClassNameMappings() {
+      // Ensure that all scoped references have at least the identity in the final mapping.
+      for (String descriptor : scopedMappingInfo.keySet()) {
+        String typename = DescriptorUtils.descriptorToJavaType(descriptor);
+        mapping.computeIfAbsent(typename, t -> ClassNamingForNameMapper.builder(t, t));
+      }
+      // Build the final mapping while amending any entries with the scoped info.
+      ImmutableMap.Builder<String, ClassNamingForNameMapper> builder = ImmutableMap.builder();
+      builder.orderEntriesByValue(Comparator.comparing(x -> x.originalName));
+      mapping.forEach(
+          (renamedName, valueBuilder) -> {
+            String descriptor = DescriptorUtils.javaTypeToDescriptor(renamedName);
+            scopedMappingInfo
+                .getOrDefault(descriptor, Collections.emptyList())
+                .forEach(valueBuilder::addMappingInformation);
+            builder.put(renamedName, valueBuilder.build());
+          });
+      return builder.build();
     }
   }
 
@@ -126,17 +160,8 @@
 
   private final ImmutableMap<String, ClassNamingForNameMapper> classNameMappings;
   private BiMapContainer<String, String> nameMapping;
-
   private final Map<Signature, Signature> signatureMap = new HashMap<>();
 
-  private ClassNameMapper(Map<String, ClassNamingForNameMapper.Builder> classNameMappings) {
-    ImmutableMap.Builder<String, ClassNamingForNameMapper> builder = ImmutableMap.builder();
-    for(Map.Entry<String, ClassNamingForNameMapper.Builder> entry : classNameMappings.entrySet()) {
-      builder.put(entry.getKey(), entry.getValue().build());
-    }
-    this.classNameMappings = builder.build();
-  }
-
   private ClassNameMapper(ImmutableMap<String, ClassNamingForNameMapper> classNameMappings) {
     this.classNameMappings = classNameMappings;
   }
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java b/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java
index 12ea2a6..fb084f1 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java
@@ -3,8 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.naming;
 
-import static com.android.tools.r8.naming.MemberNaming.NoSignature.NO_SIGNATURE;
-
 import com.android.tools.r8.DiagnosticsHandler;
 import com.android.tools.r8.naming.MemberNaming.FieldSignature;
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
@@ -14,6 +12,7 @@
 import com.android.tools.r8.naming.mappinginformation.MappingInformationDiagnostics;
 import com.android.tools.r8.utils.ChainableStringConsumer;
 import com.android.tools.r8.utils.ThrowingConsumer;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Maps;
 import java.util.ArrayList;
@@ -41,7 +40,7 @@
     private final Map<FieldSignature, MemberNaming> fieldMembers = Maps.newHashMap();
     private final Map<String, List<MappedRange>> mappedRangesByName = Maps.newHashMap();
     private final Map<String, List<MemberNaming>> mappedFieldNamingsByName = Maps.newHashMap();
-    private final Map<Signature, List<MappingInformation>> additionalMappings = Maps.newHashMap();
+    private final List<MappingInformation> additionalMappings = new ArrayList<>();
 
     private Builder(String renamedName, String originalName) {
       this.originalName = originalName;
@@ -85,18 +84,12 @@
 
     private ClassNaming.Builder addMappingInformation(
         MappingInformation mappingInformation, Consumer<MappingInformation> notAllowedCombination) {
-      Signature signature =
-          mappingInformation.isSignatureMappingInformation()
-              ? mappingInformation.asSignatureMappingInformation().getSignature()
-              : NO_SIGNATURE;
-      List<MappingInformation> additionalMappingForSignature =
-          additionalMappings.computeIfAbsent(signature, ignored -> new ArrayList<>());
-      for (MappingInformation information : additionalMappingForSignature) {
+      for (MappingInformation information : additionalMappings) {
         if (!information.allowOther(mappingInformation)) {
           notAllowedCombination.accept(information);
         }
       }
-      additionalMappingForSignature.add(mappingInformation);
+      additionalMappings.add(mappingInformation);
       return this;
     }
 
@@ -120,7 +113,7 @@
           fieldMembers,
           map,
           mappedFieldNamingsByName,
-          additionalMappings);
+          ImmutableList.copyOf(additionalMappings));
     }
 
     /** The parameters are forwarded to MappedRange constructor, see explanation there. */
@@ -251,7 +244,7 @@
 
   public final Map<String, List<MemberNaming>> mappedFieldNamingsByName;
 
-  private final Map<Signature, List<MappingInformation>> additionalMappings;
+  private final ImmutableList<MappingInformation> additionalMappings;
 
   private ClassNamingForNameMapper(
       String renamedName,
@@ -260,13 +253,14 @@
       Map<FieldSignature, MemberNaming> fieldMembers,
       Map<String, MappedRangesOfName> mappedRangesByRenamedName,
       Map<String, List<MemberNaming>> mappedFieldNamingsByName,
-      Map<Signature, List<MappingInformation>> additionalMappings) {
+      ImmutableList<MappingInformation> additionalMappings) {
     this.renamedName = renamedName;
     this.originalName = originalName;
     this.methodMembers = ImmutableMap.copyOf(methodMembers);
     this.fieldMembers = ImmutableMap.copyOf(fieldMembers);
     this.mappedRangesByRenamedName = mappedRangesByRenamedName;
     this.mappedFieldNamingsByName = mappedFieldNamingsByName;
+    assert additionalMappings != null;
     this.additionalMappings = additionalMappings;
   }
 
@@ -356,13 +350,7 @@
     consumer.accept(originalName).accept(" -> ").accept(renamedName).accept(":\n");
 
     // Print all additional mapping information.
-    additionalMappings.forEach(
-        (signature, mappingInformations) -> {
-          assert !mappingInformations.isEmpty();
-          for (MappingInformation mappingInformation : mappingInformations) {
-            consumer.accept("# " + mappingInformation.serialize()).accept("\n");
-          }
-        });
+    additionalMappings.forEach(info -> consumer.accept("# " + info.serialize()).accept("\n"));
 
     // Print field member namings.
     forAllFieldNaming(m -> consumer.accept("    ").accept(m.toString()).accept("\n"));
@@ -379,7 +367,7 @@
     }
   }
 
-  public Map<Signature, List<MappingInformation>> getAdditionalMappings() {
+  public List<MappingInformation> getAdditionalMappings() {
     return additionalMappings;
   }
 
diff --git a/src/main/java/com/android/tools/r8/naming/MapVersion.java b/src/main/java/com/android/tools/r8/naming/MapVersion.java
new file mode 100644
index 0000000..7069351
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/naming/MapVersion.java
@@ -0,0 +1,32 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.naming;
+
+import com.android.tools.r8.utils.structural.Ordered;
+
+public enum MapVersion implements Ordered<MapVersion> {
+  MapVersionNone("none"),
+  MapVersionExperimental("experimental");
+
+  public static final MapVersion STABLE = MapVersionNone;
+
+  private final String name;
+
+  MapVersion(String name) {
+    this.name = name;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public static MapVersion fromName(String name) {
+    for (MapVersion version : MapVersion.values()) {
+      if (version.getName().equals(name)) {
+        return version;
+      }
+    }
+    return null;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/naming/MemberNaming.java b/src/main/java/com/android/tools/r8/naming/MemberNaming.java
index 4a50244..bf0a8dd 100644
--- a/src/main/java/com/android/tools/r8/naming/MemberNaming.java
+++ b/src/main/java/com/android/tools/r8/naming/MemberNaming.java
@@ -168,40 +168,6 @@
     }
   }
 
-  public static class NoSignature extends Signature {
-
-    public static final NoSignature NO_SIGNATURE = new NoSignature();
-
-    private NoSignature() {
-      super("NO SIGNATURE");
-    }
-
-    @Override
-    Signature asRenamed(String renamedName) {
-      throw new Unreachable("Should not be called on NoSignature");
-    }
-
-    @Override
-    public SignatureKind kind() {
-      throw new Unreachable("Should not be called on NoSignature");
-    }
-
-    @Override
-    public boolean equals(Object o) {
-      return o == this;
-    }
-
-    @Override
-    public int hashCode() {
-      return 7;
-    }
-
-    @Override
-    void write(Writer builder) throws IOException {
-      throw new Unreachable("Should not be called on NoSignature");
-    }
-  }
-
   public static class FieldSignature extends Signature {
 
     public final String type;
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMap.java b/src/main/java/com/android/tools/r8/naming/ProguardMap.java
index 221f064..f56e3b8 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMap.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMap.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.naming;
 
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.naming.mappinginformation.ScopedMappingInformation;
 import com.android.tools.r8.position.Position;
 
 public interface ProguardMap {
@@ -13,6 +14,8 @@
         String renamedName, String originalName, Position position);
 
     abstract ProguardMap build();
+
+    abstract void addScopedMappingInformation(ScopedMappingInformation scopedMappingInformation);
   }
 
   boolean hasMapping(DexType type);
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java b/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java
index 0f94efa..d7ab9c8 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java
@@ -7,12 +7,15 @@
 import com.android.tools.r8.naming.MemberNaming.FieldSignature;
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
 import com.android.tools.r8.naming.MemberNaming.Signature;
+import com.android.tools.r8.naming.ProguardMap.Builder;
 import com.android.tools.r8.naming.mappinginformation.MappingInformation;
-import com.android.tools.r8.naming.mappinginformation.SignatureMappingInformation;
+import com.android.tools.r8.naming.mappinginformation.MetaInfMappingInformation;
+import com.android.tools.r8.naming.mappinginformation.ScopedMappingInformation.ClassScopeReference;
+import com.android.tools.r8.naming.mappinginformation.ScopedMappingInformation.ScopeReference;
 import com.android.tools.r8.position.TextPosition;
+import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.utils.IdentifierUtils;
 import com.android.tools.r8.utils.StringUtils;
-import com.google.common.collect.Maps;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
 import java.io.BufferedReader;
@@ -20,7 +23,6 @@
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Map;
 import java.util.Objects;
 
 /**
@@ -85,6 +87,8 @@
   private int lineNo = 0;
   private int lineOffset = 0;
   private String line;
+  private MapVersion version = MapVersion.MapVersionNone;
+  private ScopeReference implicitSingletonScope = null;
 
   private int peekCodePoint() {
     return lineOffset < line.length() ? line.codePointAt(lineOffset) : '\n';
@@ -225,7 +229,7 @@
       if (isCommentLineWithJsonBrace()) {
         // TODO(b/179665169): Parse the mapping information without doing anything with it, since we
         //  at this point do not have a global context.
-        MappingInformation.fromJsonObject(parseJsonInComment(), diagnosticsHandler, lineNo);
+        parseMappingInformation();
         // Skip reading the rest of the line.
         lineOffset = line.length();
         nextLine();
@@ -248,29 +252,42 @@
       expect(':');
       ClassNaming.Builder currentClassBuilder =
           mapBuilder.classNamingBuilder(after, before, getPosition());
+      implicitSingletonScope = new ClassScopeReference(Reference.classFromTypeName(after));
       skipWhitespace();
       if (nextLine()) {
-        parseMemberMappings(currentClassBuilder);
+        parseMemberMappings(mapBuilder, currentClassBuilder);
       }
     }
   }
 
-  private void parseMemberMappings(ClassNaming.Builder classNamingBuilder) throws IOException {
+  private MappingInformation parseMappingInformation() {
+    MappingInformation info =
+        MappingInformation.fromJsonObject(
+            version, parseJsonInComment(), diagnosticsHandler, lineNo, implicitSingletonScope);
+    if (info == null) {
+      return null;
+    }
+    MetaInfMappingInformation generatorInfo = info.asMetaInfMappingInformation();
+    if (generatorInfo != null) {
+      version = generatorInfo.getMapVersion();
+    }
+    return info;
+  }
+
+  private void parseMemberMappings(Builder mapBuilder, ClassNaming.Builder classNamingBuilder)
+      throws IOException {
     MemberNaming lastAddedNaming = null;
     MemberNaming activeMemberNaming = null;
     Range previousMappedRange = null;
-    Map<Signature, SignatureMappingInformation> mappingInformation = Maps.newHashMap();
     do {
       Object originalRange = null;
       Range mappedRange = null;
       // Try to parse any information added in comments above member namings
       if (isCommentLineWithJsonBrace()) {
-        MappingInformation mappingInfo =
-            MappingInformation.fromJsonObject(parseJsonInComment(), diagnosticsHandler, lineNo);
+        MappingInformation mappingInfo = parseMappingInformation();
         if (mappingInfo != null) {
-          if (mappingInfo.isSignatureMappingInformation()) {
-            SignatureMappingInformation sigMapInfo = mappingInfo.asSignatureMappingInformation();
-            mappingInformation.put(sigMapInfo.getSignature(), sigMapInfo);
+          if (mappingInfo.isScopedMappingInformation()) {
+            mapBuilder.addScopedMappingInformation(mappingInfo.asScopedMappingInformation());
           } else {
             classNamingBuilder.addMappingInformation(mappingInfo, diagnosticsHandler, lineNo);
           }
@@ -336,16 +353,8 @@
           }
         }
       }
-      if (mappingInformation.containsKey(signature)) {
-        activeMemberNaming =
-            new MemberNaming(
-                signature,
-                mappingInformation.get(signature).apply(signature, renamedName, diagnosticsHandler),
-                getPosition());
-      } else {
-        activeMemberNaming =
-            new MemberNaming(signature, signature.asRenamed(renamedName), getPosition());
-      }
+      activeMemberNaming =
+          new MemberNaming(signature, signature.asRenamed(renamedName), getPosition());
       previousMappedRange = mappedRange;
     } while (nextLine());
 
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java b/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java
index ec947e8..6516e22 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.StringConsumer;
 import com.android.tools.r8.Version;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.naming.mappinginformation.MetaInfMappingInformation;
 import com.android.tools.r8.utils.Box;
 import com.android.tools.r8.utils.ChainableStringConsumer;
 import com.android.tools.r8.utils.ExceptionUtils;
@@ -101,6 +102,17 @@
     builder.append("# " + MARKER_KEY_PG_MAP_ID + ": " + id.get() + "\n");
     // Turn off linting of the mapping file in some build systems.
     builder.append("# common_typos_disable" + "\n");
+    // Emit the R8 specific map-file version.
+    MapVersion mapVersion =
+        options.testing.enableExperimentalMapFileVersion
+            ? MapVersion.MapVersionExperimental
+            : MapVersion.STABLE;
+    if (mapVersion.isGreaterThan(MapVersion.MapVersionNone)) {
+      builder
+          .append("# ")
+          .append(new MetaInfMappingInformation(mapVersion).serialize())
+          .append("\n");
+    }
     consumer.accept(builder.toString(), reporter);
   }
 
diff --git a/src/main/java/com/android/tools/r8/naming/SeedMapper.java b/src/main/java/com/android/tools/r8/naming/SeedMapper.java
index 927cf6e..2e5b125 100644
--- a/src/main/java/com/android/tools/r8/naming/SeedMapper.java
+++ b/src/main/java/com/android/tools/r8/naming/SeedMapper.java
@@ -9,6 +9,7 @@
 
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.naming.MemberNaming.Signature;
+import com.android.tools.r8.naming.mappinginformation.ScopedMappingInformation;
 import com.android.tools.r8.position.Position;
 import com.android.tools.r8.utils.Reporter;
 import com.google.common.collect.ImmutableMap;
@@ -61,6 +62,11 @@
     }
 
     @Override
+    void addScopedMappingInformation(ScopedMappingInformation scopedMappingInformation) {
+      // Not needed.
+    }
+
+    @Override
     SeedMapper build() {
       reporter.failIfPendingErrors();
       return new SeedMapper(ImmutableMap.copyOf(map), mappedToDescriptorNames, reporter);
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/CompilerSynthesizedMappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/CompilerSynthesizedMappingInformation.java
index b0a13ba..d44e5e6 100644
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/CompilerSynthesizedMappingInformation.java
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/CompilerSynthesizedMappingInformation.java
@@ -5,15 +5,38 @@
 package com.android.tools.r8.naming.mappinginformation;
 
 import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.naming.MapVersion;
+import com.google.common.collect.ImmutableList;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonPrimitive;
 
-public class CompilerSynthesizedMappingInformation extends MappingInformation {
+public class CompilerSynthesizedMappingInformation extends ScopedMappingInformation {
 
   public static final String ID = "com.android.tools.r8.synthesized";
 
-  public CompilerSynthesizedMappingInformation() {
-    super(NO_LINE_NUMBER);
+  public static class Builder extends ScopedMappingInformation.Builder<Builder> {
+
+    @Override
+    public String getId() {
+      return ID;
+    }
+
+    @Override
+    public Builder self() {
+      return this;
+    }
+
+    public CompilerSynthesizedMappingInformation build() {
+      return new CompilerSynthesizedMappingInformation(buildScope());
+    }
+  }
+
+  private CompilerSynthesizedMappingInformation(ImmutableList<ScopeReference> scope) {
+    super(scope);
+  }
+
+  public static Builder builder() {
+    return new Builder();
   }
 
   @Override
@@ -32,14 +55,22 @@
   }
 
   @Override
-  public String serialize() {
-    JsonObject result = new JsonObject();
-    result.add(MAPPING_ID_KEY, new JsonPrimitive(ID));
-    return result.toString();
+  protected JsonObject serializeToJsonObject(JsonObject object) {
+    object.add(MAPPING_ID_KEY, new JsonPrimitive(ID));
+    return object;
   }
 
   public static CompilerSynthesizedMappingInformation deserialize(
-      JsonObject object, DiagnosticsHandler diagnosticsHandler, int lineNumber) {
-    return new CompilerSynthesizedMappingInformation();
+      MapVersion version,
+      JsonObject object,
+      DiagnosticsHandler diagnosticsHandler,
+      int lineNumber,
+      ScopeReference implicitSingletonScope) {
+    if (version.isLessThan(MapVersion.MapVersionExperimental)) {
+      return null;
+    }
+    return builder()
+        .deserializeFromJsonObject(object, implicitSingletonScope, diagnosticsHandler, lineNumber)
+        .build();
   }
 }
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/FileNameInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/FileNameInformation.java
index 87b3e7b..38eabbf 100644
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/FileNameInformation.java
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/FileNameInformation.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.naming.mappinginformation;
 
 import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.naming.MapVersion;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonPrimitive;
@@ -53,7 +54,11 @@
   }
 
   public static FileNameInformation build(
-      JsonObject object, DiagnosticsHandler diagnosticsHandler, int lineNumber) {
+      MapVersion version,
+      JsonObject object,
+      DiagnosticsHandler diagnosticsHandler,
+      int lineNumber) {
+    // Source file information is valid for all map file versions.
     try {
       JsonElement fileName =
           getJsonElementFromObject(object, diagnosticsHandler, lineNumber, FILE_NAME_KEY, ID);
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformation.java
index cb0708f..0ef03d0 100644
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformation.java
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformation.java
@@ -5,6 +5,8 @@
 package com.android.tools.r8.naming.mappinginformation;
 
 import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.naming.MapVersion;
+import com.android.tools.r8.naming.mappinginformation.ScopedMappingInformation.ScopeReference;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 
@@ -26,11 +28,19 @@
 
   public abstract String serialize();
 
-  public boolean isSignatureMappingInformation() {
+  public boolean isScopedMappingInformation() {
     return false;
   }
 
-  public SignatureMappingInformation asSignatureMappingInformation() {
+  public ScopedMappingInformation asScopedMappingInformation() {
+    return null;
+  }
+
+  public boolean isMetaInfMappingInformation() {
+    return false;
+  }
+
+  public MetaInfMappingInformation asMetaInfMappingInformation() {
     return null;
   }
 
@@ -42,14 +52,6 @@
     return null;
   }
 
-  public boolean isMethodSignatureChangedInformation() {
-    return false;
-  }
-
-  public MethodSignatureChangedInformation asMethodSignatureChangedInformation() {
-    return null;
-  }
-
   public boolean isCompilerSynthesizedMappingInformation() {
     return false;
   }
@@ -61,7 +63,11 @@
   public abstract boolean allowOther(MappingInformation information);
 
   public static MappingInformation fromJsonObject(
-      JsonObject object, DiagnosticsHandler diagnosticsHandler, int lineNumber) {
+      MapVersion version,
+      JsonObject object,
+      DiagnosticsHandler diagnosticsHandler,
+      int lineNumber,
+      ScopeReference implicitSingletonScope) {
     if (object == null) {
       diagnosticsHandler.info(MappingInformationDiagnostics.notValidJson(lineNumber));
       return null;
@@ -78,16 +84,28 @@
           MappingInformationDiagnostics.notValidString(lineNumber, MAPPING_ID_KEY));
       return null;
     }
-    switch (idString) {
-      case MethodSignatureChangedInformation.ID:
-        return MethodSignatureChangedInformation.build(object, diagnosticsHandler, lineNumber);
+    return deserialize(
+        idString, version, object, diagnosticsHandler, lineNumber, implicitSingletonScope);
+  }
+
+  private static MappingInformation deserialize(
+      String id,
+      MapVersion version,
+      JsonObject object,
+      DiagnosticsHandler diagnosticsHandler,
+      int lineNumber,
+      ScopeReference implicitSingletonScope) {
+    switch (id) {
+      case MetaInfMappingInformation.ID:
+        return MetaInfMappingInformation.deserialize(
+            version, object, diagnosticsHandler, lineNumber);
       case FileNameInformation.ID:
-        return FileNameInformation.build(object, diagnosticsHandler, lineNumber);
+        return FileNameInformation.build(version, object, diagnosticsHandler, lineNumber);
       case CompilerSynthesizedMappingInformation.ID:
         return CompilerSynthesizedMappingInformation.deserialize(
-            object, diagnosticsHandler, lineNumber);
+            version, object, diagnosticsHandler, lineNumber, implicitSingletonScope);
       default:
-        diagnosticsHandler.info(MappingInformationDiagnostics.noHandlerFor(lineNumber, idString));
+        diagnosticsHandler.info(MappingInformationDiagnostics.noHandlerFor(lineNumber, id));
         return null;
     }
   }
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/MetaInfMappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/MetaInfMappingInformation.java
new file mode 100644
index 0000000..ba6bb72
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/MetaInfMappingInformation.java
@@ -0,0 +1,71 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.naming.mappinginformation;
+
+import static com.android.tools.r8.naming.mappinginformation.MappingInformationDiagnostics.noKeyForObjectWithId;
+
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.naming.MapVersion;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonPrimitive;
+
+public class MetaInfMappingInformation extends MappingInformation {
+
+  public static final String ID = "com.android.tools.r8.metainf";
+  public static final String MAP_VERSION_KEY = "map-version";
+
+  private final MapVersion mapVersion;
+
+  public MetaInfMappingInformation(MapVersion mapVersion) {
+    super(NO_LINE_NUMBER);
+    this.mapVersion = mapVersion;
+  }
+
+  @Override
+  public boolean isMetaInfMappingInformation() {
+    return true;
+  }
+
+  @Override
+  public MetaInfMappingInformation asMetaInfMappingInformation() {
+    return this;
+  }
+
+  @Override
+  public boolean allowOther(MappingInformation information) {
+    return !information.isMetaInfMappingInformation();
+  }
+
+  public MapVersion getMapVersion() {
+    return mapVersion;
+  }
+
+  @Override
+  public String serialize() {
+    JsonObject result = new JsonObject();
+    result.add(MAPPING_ID_KEY, new JsonPrimitive(ID));
+    result.add(MAP_VERSION_KEY, new JsonPrimitive(mapVersion.getName()));
+    return result.toString();
+  }
+
+  public static MetaInfMappingInformation deserialize(
+      MapVersion version,
+      JsonObject object,
+      DiagnosticsHandler diagnosticsHandler,
+      int lineNumber) {
+    // Parsing the generator information must support parsing at all map versions as it itself is
+    // what establishes the version.
+    String mapVersion = object.get(MAP_VERSION_KEY).getAsString();
+    if (mapVersion == null) {
+      noKeyForObjectWithId(lineNumber, MAP_VERSION_KEY, MAPPING_ID_KEY, ID);
+      return null;
+    }
+    MapVersion mapVersion1 = MapVersion.fromName(mapVersion);
+    if (mapVersion1 == null) {
+      return null;
+    }
+    return new MetaInfMappingInformation(mapVersion1);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/MethodSignatureChangedInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/MethodSignatureChangedInformation.java
deleted file mode 100644
index 8bb023d..0000000
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/MethodSignatureChangedInformation.java
+++ /dev/null
@@ -1,258 +0,0 @@
-// Copyright (c) 2019, 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.naming.mappinginformation;
-
-import static com.android.tools.r8.naming.mappinginformation.MappingInformationDiagnostics.invalidParameterInformationObject;
-import static com.android.tools.r8.naming.mappinginformation.MappingInformationDiagnostics.invalidValueForObjectWithId;
-import static com.android.tools.r8.naming.mappinginformation.MappingInformationDiagnostics.tooManyEntriesForParameterInformation;
-import static com.android.tools.r8.naming.mappinginformation.MappingInformationDiagnostics.tooManyInformationalParameters;
-
-import com.android.tools.r8.DiagnosticsHandler;
-import com.android.tools.r8.naming.MemberNaming.MethodSignature;
-import com.android.tools.r8.naming.MemberNaming.Signature;
-import com.google.gson.JsonArray;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonPrimitive;
-
-/**
- * The MethodSignatureChangedInformation structure adds extra information regarding the mapped
- * method signature that is otherwise not available in the existing proguard mapping format. The
- * JSON-structure is as follows:
- *
- * <pre>
- *   {
- *     "id": "argumentsChanged",
- *     "signature": { methodSignature },
- *     "returnType": "java.lang.String",
- *     "receiver": false,
- *     "params": [
- *       [1], // <-- parameter with original index 1 (starting index based on receiver) is removed.
- *       [2, Foo] // <-- parameter with index 2 has type Foo
- *     ]
- *   }
- * </pre>
- */
-public class MethodSignatureChangedInformation extends SignatureMappingInformation {
-
-  private ParameterInformation[] argumentInfos;
-  private final boolean receiver;
-  private final String returnType;
-  private final MethodSignature signature;
-
-  public static final String ID = "methodSignatureChanged";
-  private static final String RETURN_TYPE_KEY = "returnType";
-  private static final String PARAMS_KEY = "params";
-  private static final String RECEIVER_KEY = "receiver";
-
-  @Override
-  public String serialize() {
-    JsonObject result = new JsonObject();
-    serializeMethodSignature(result, signature);
-    result.add(MAPPING_ID_KEY, new JsonPrimitive(ID));
-    result.add(RECEIVER_KEY, new JsonPrimitive(receiver));
-    result.add(RETURN_TYPE_KEY, new JsonPrimitive(returnType));
-    JsonArray arguments = new JsonArray();
-    for (ParameterInformation argInfo : argumentInfos) {
-      arguments.add(argInfo.serialize());
-    }
-    result.add(PARAMS_KEY, arguments);
-    return result.toString();
-  }
-
-  @Override
-  public boolean allowOther(MappingInformation information) {
-    return !information.isMethodSignatureChangedInformation();
-  }
-
-  @Override
-  public Signature getSignature() {
-    return signature;
-  }
-
-  @Override
-  public Signature apply(
-      Signature originalSignature, String renamedName, DiagnosticsHandler diagnosticsHandler) {
-    if (originalSignature == null || !originalSignature.isMethodSignature()) {
-      assert false : "Should only call apply for method signature";
-      return originalSignature;
-    }
-    MethodSignature signature = originalSignature.asMethodSignature();
-    String type = signature.type;
-    String[] parameters = signature.parameters;
-    int numberOfArgumentsRemoved = getNumberOfArgumentsRemoved();
-    if (numberOfArgumentsRemoved > parameters.length) {
-      // The mapping information is not up to date with the current signature.
-      diagnosticsHandler.warning(tooManyInformationalParameters(getLineNumber()));
-      return new MethodSignature(renamedName, type, parameters);
-    }
-    String[] newParameters = new String[parameters.length - numberOfArgumentsRemoved];
-    int insertIndex = 0;
-    for (int i = 0; i < parameters.length; i++) {
-      ParameterInformation argInfo = getParameterInformation(i);
-      if (argInfo != null && argInfo.getType() == null) {
-        // Argument has been removed.
-      } else {
-        if (insertIndex >= newParameters.length) {
-          // The mapping information is not up to date with the current signature.
-          diagnosticsHandler.warning(tooManyInformationalParameters(getLineNumber()));
-          return new MethodSignature(renamedName, type, parameters);
-        } else if (argInfo == null) {
-          // Unchanged, take current parameter.
-          newParameters[insertIndex++] = parameters[i];
-        } else {
-          newParameters[insertIndex++] = argInfo.getType();
-        }
-      }
-    }
-    assert insertIndex == newParameters.length;
-    return new MethodSignature(renamedName, getReturnType(), newParameters);
-  }
-
-  @Override
-  public boolean isMethodSignatureChangedInformation() {
-    return true;
-  }
-
-  public int getNumberOfArgumentsRemoved() {
-    int removedCount = 0;
-    for (ParameterInformation argInfo : argumentInfos) {
-      if (argInfo.type == null) {
-        removedCount++;
-      }
-    }
-    return removedCount;
-  }
-
-  public boolean hasReceiver() {
-    return receiver;
-  }
-
-  public String getReturnType() {
-    return returnType;
-  }
-
-  public ParameterInformation getParameterInformation(int index) {
-    int subtractIndex = receiver ? 1 : 0;
-    for (int i = 0; i < argumentInfos.length; i++) {
-      if (argumentInfos[i].index - subtractIndex == index) {
-        return argumentInfos[i];
-      }
-    }
-    return null;
-  }
-
-  @Override
-  public MethodSignatureChangedInformation asMethodSignatureChangedInformation() {
-    return this;
-  }
-
-  private MethodSignatureChangedInformation(
-      MethodSignature signature,
-      String returnType,
-      boolean hasReceiver,
-      ParameterInformation[] argumentInfos,
-      int lineNumber) {
-    super(lineNumber);
-    this.signature = signature;
-    this.argumentInfos = argumentInfos;
-    this.returnType = returnType;
-    this.receiver = hasReceiver;
-  }
-
-  public static MappingInformation build(
-      JsonObject object, DiagnosticsHandler diagnosticsHandler, int lineNumber) {
-    try {
-      JsonElement returnTypeElement =
-          getJsonElementFromObject(object, diagnosticsHandler, lineNumber, RETURN_TYPE_KEY, ID);
-      JsonElement receiverElement =
-          getJsonElementFromObject(object, diagnosticsHandler, lineNumber, RECEIVER_KEY, ID);
-      JsonElement argsElement =
-          getJsonElementFromObject(object, diagnosticsHandler, lineNumber, PARAMS_KEY, ID);
-      MethodSignature signature = getMethodSignature(object, ID, diagnosticsHandler, lineNumber);
-      if (signature == null
-          || returnTypeElement == null
-          || receiverElement == null
-          || argsElement == null) {
-        return null;
-      }
-      JsonArray argumentsArray = argsElement.getAsJsonArray();
-      if (argumentsArray == null) {
-        return null;
-      }
-      ParameterInformation[] args = new ParameterInformation[argumentsArray.size()];
-      for (int i = 0; i < argumentsArray.size(); i++) {
-        args[i] =
-            ParameterInformation.fromJsonArray(
-                argumentsArray.get(i).getAsJsonArray(), diagnosticsHandler, lineNumber);
-      }
-      return new MethodSignatureChangedInformation(
-          signature,
-          returnTypeElement.getAsString(),
-          receiverElement.getAsBoolean(),
-          args,
-          lineNumber);
-    } catch (UnsupportedOperationException | IllegalStateException ignored) {
-      diagnosticsHandler.info(invalidValueForObjectWithId(lineNumber, MAPPING_ID_KEY, ID));
-      return null;
-    }
-  }
-
-  public static class ParameterInformation {
-    private final int index;
-    private final String type;
-
-    public int getIndex() {
-      return index;
-    }
-
-    public String getType() {
-      return type;
-    }
-
-    private ParameterInformation(int index, String type) {
-      this.index = index;
-      this.type = type;
-    }
-
-    static ParameterInformation fromJsonArray(
-        JsonArray argumentInfo, DiagnosticsHandler diagnosticsHandler, int lineNumber) {
-      assert argumentInfo != null;
-      try {
-        if (argumentInfo.size() > 2) {
-          diagnosticsHandler.info(tooManyEntriesForParameterInformation(lineNumber));
-          return null;
-        }
-        int index = argumentInfo.get(0).getAsInt();
-        if (argumentInfo.size() == 1) {
-          // This is a removed argument - no type information
-          return new ParameterInformation(index, null);
-        } else {
-          return new ParameterInformation(index, argumentInfo.get(1).getAsString());
-        }
-      } catch (UnsupportedOperationException | IllegalStateException ignored) {
-        diagnosticsHandler.info(invalidParameterInformationObject(lineNumber));
-        return null;
-      }
-    }
-
-    public static ParameterInformation buildRemovedParameterInformation(int index) {
-      return new ParameterInformation(index, null);
-    }
-
-    public static ParameterInformation buildChangedParameterInformation(int index, String type) {
-      return new ParameterInformation(index, type);
-    }
-
-    JsonArray serialize() {
-      JsonArray serializedArray = new JsonArray();
-      serializedArray.add(index);
-      if (type != null) {
-        serializedArray.add(type);
-      }
-      return serializedArray;
-    }
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/ScopedMappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/ScopedMappingInformation.java
new file mode 100644
index 0000000..deb0440
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/ScopedMappingInformation.java
@@ -0,0 +1,126 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.naming.mappinginformation;
+
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.errors.Unimplemented;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.google.common.collect.ImmutableList;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import java.util.function.BiConsumer;
+
+public abstract class ScopedMappingInformation extends MappingInformation {
+
+  // Abstraction for the items referenced in a scope.
+  // We should consider passing in a scope reference factory.
+  // For reading we likely want to map directly to DexItem, whereas for writing we likely want
+  // to map to java.lang.String with the post-minification names.
+  public abstract static class ScopeReference {
+
+    public static ScopeReference fromReferenceString(String referenceString) {
+      if (DescriptorUtils.isClassDescriptor(referenceString)) {
+        return new ClassScopeReference(Reference.classFromDescriptor(referenceString));
+      }
+      throw new Unimplemented("No support for reference: " + referenceString);
+    }
+
+    public abstract String toReferenceString();
+
+    @Override
+    public String toString() {
+      return toReferenceString();
+    }
+  }
+
+  public static class ClassScopeReference extends ScopeReference {
+    final ClassReference reference;
+
+    public ClassScopeReference(ClassReference reference) {
+      this.reference = reference;
+    }
+
+    @Override
+    public String toReferenceString() {
+      return reference.getDescriptor();
+    }
+  }
+
+  public abstract static class Builder<B extends Builder<B>> {
+    public abstract String getId();
+
+    public abstract B self();
+
+    private final ImmutableList.Builder<ScopeReference> scope = ImmutableList.builder();
+
+    public B deserializeFromJsonObject(
+        JsonObject object,
+        ScopeReference implicitSingletonScope,
+        DiagnosticsHandler diagnosticsHandler,
+        int lineNumber) {
+      JsonArray scopeArray = object.getAsJsonArray(SCOPE_KEY);
+      if (scopeArray != null) {
+        for (JsonElement element : scopeArray) {
+          addScopeReference(ScopeReference.fromReferenceString(element.getAsString()));
+        }
+      } else if (implicitSingletonScope != null) {
+        addScopeReference(implicitSingletonScope);
+      } else {
+        diagnosticsHandler.info(
+            MappingInformationDiagnostics.noKeyForObjectWithId(
+                lineNumber, SCOPE_KEY, MAPPING_ID_KEY, getId()));
+      }
+      return self();
+    }
+
+    public B addScopeReference(ScopeReference reference) {
+      scope.add(reference);
+      return self();
+    }
+
+    public ImmutableList<ScopeReference> buildScope() {
+      return scope.build();
+    }
+  }
+
+  public static final String SCOPE_KEY = "scope";
+
+  private final ImmutableList<ScopeReference> scopeReferences;
+
+  public ScopedMappingInformation(ImmutableList<ScopeReference> scopeReferences) {
+    super(NO_LINE_NUMBER);
+    this.scopeReferences = scopeReferences;
+    assert !scopeReferences.isEmpty() : "Expected a scope. Global scope not yet in use.";
+  }
+
+  protected abstract JsonObject serializeToJsonObject(JsonObject object);
+
+  @Override
+  public final boolean isScopedMappingInformation() {
+    return true;
+  }
+
+  @Override
+  public final ScopedMappingInformation asScopedMappingInformation() {
+    return this;
+  }
+
+  public void forEach(BiConsumer<String, ScopedMappingInformation> fn) {
+    for (ScopeReference reference : scopeReferences) {
+      fn.accept(reference.toReferenceString(), this);
+    }
+  }
+
+  @Override
+  public final String serialize() {
+    JsonObject object = serializeToJsonObject(new JsonObject());
+    JsonArray scopeArray = new JsonArray();
+    scopeReferences.forEach(ref -> scopeArray.add(ref.toReferenceString()));
+    object.add(SCOPE_KEY, scopeArray);
+    return object.toString();
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/SignatureMappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/SignatureMappingInformation.java
deleted file mode 100644
index aba33bb..0000000
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/SignatureMappingInformation.java
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright (c) 2020, 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.naming.mappinginformation;
-
-import com.android.tools.r8.DiagnosticsHandler;
-import com.android.tools.r8.naming.MemberNaming.MethodSignature;
-import com.android.tools.r8.naming.MemberNaming.Signature;
-import com.google.gson.JsonArray;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-
-public abstract class SignatureMappingInformation extends MappingInformation {
-
-  private static final String SIGNATURE_KEY = "signature";
-
-  SignatureMappingInformation(int lineNumber) {
-    super(lineNumber);
-  }
-
-  @Override
-  public boolean isSignatureMappingInformation() {
-    return true;
-  }
-
-  @Override
-  public SignatureMappingInformation asSignatureMappingInformation() {
-    return this;
-  }
-
-  public abstract Signature getSignature();
-
-  public abstract Signature apply(
-      Signature originalSignature, String renamedName, DiagnosticsHandler diagnosticsHandler);
-
-  JsonObject serializeMethodSignature(JsonObject object, MethodSignature signature) {
-    JsonArray signatureArr = new JsonArray();
-    signatureArr.add(signature.type);
-    signatureArr.add(signature.name);
-    for (String parameter : signature.parameters) {
-      signatureArr.add(parameter);
-    }
-    object.add(SIGNATURE_KEY, signatureArr);
-    return object;
-  }
-
-  static MethodSignature getMethodSignature(
-      JsonObject object, String id, DiagnosticsHandler diagnosticsHandler, int lineNumber) {
-    JsonElement signatureElement =
-        getJsonElementFromObject(object, diagnosticsHandler, lineNumber, SIGNATURE_KEY, id);
-    if (signatureElement == null || !signatureElement.isJsonArray()) {
-      return null;
-    }
-    // Signature will be [returnType, name, param1, param2, ...].
-    JsonArray signature = signatureElement.getAsJsonArray();
-    String[] parameters = new String[signature.size() - 2];
-    for (int i = 2; i < signature.size(); i++) {
-      parameters[i - 2] = signature.get(i).getAsString();
-    }
-    return new MethodSignature(
-        signature.get(1).getAsString(), signature.get(0).getAsString(), parameters);
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceOptions.java b/src/main/java/com/android/tools/r8/retrace/RetraceOptions.java
index a8e5394..4784f09 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceOptions.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceOptions.java
@@ -4,9 +4,10 @@
 
 package com.android.tools.r8.retrace;
 
+import static com.android.tools.r8.retrace.internal.StackTraceRegularExpressionParser.DEFAULT_REGULAR_EXPRESSION;
+
 import com.android.tools.r8.DiagnosticsHandler;
 import com.android.tools.r8.Keep;
-import com.android.tools.r8.retrace.internal.StackTraceRegularExpressionParser;
 
 /**
  * The base options for running retrace with support for continuously retrace strings without
@@ -60,13 +61,17 @@
     return new Builder(diagnosticsHandler);
   }
 
+  public static String defaultRegularExpression() {
+    return DEFAULT_REGULAR_EXPRESSION;
+  }
+
   @Keep
   public static class Builder {
 
     private boolean isVerbose;
     private final DiagnosticsHandler diagnosticsHandler;
     private ProguardMapProducer proguardMapProducer;
-    private String regularExpression = StackTraceRegularExpressionParser.DEFAULT_REGULAR_EXPRESSION;
+    private String regularExpression = defaultRegularExpression();
 
     Builder(DiagnosticsHandler diagnosticsHandler) {
       this.diagnosticsHandler = diagnosticsHandler;
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java
index 15fdfdc..6bbc26a 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.retrace.internal;
 
-import static com.android.tools.r8.naming.MemberNaming.NoSignature.NO_SIGNATURE;
 import static com.android.tools.r8.retrace.internal.RetraceUtils.synthesizeFileName;
 
 import com.android.tools.r8.naming.ClassNamingForNameMapper;
@@ -234,15 +233,11 @@
 
     @Override
     public RetraceSourceFileResultImpl retraceSourceFile(String sourceFile) {
-      if (mapper != null && mapper.getAdditionalMappings().size() > 0) {
-        List<MappingInformation> mappingInformations =
-            mapper.getAdditionalMappings().get(NO_SIGNATURE);
-        if (mappingInformations != null) {
-          for (MappingInformation mappingInformation : mappingInformations) {
-            if (mappingInformation.isFileNameInformation()) {
-              return new RetraceSourceFileResultImpl(
-                  mappingInformation.asFileNameInformation().getFileName(), false);
-            }
+      if (mapper != null) {
+        for (MappingInformation mappingInformation : mapper.getAdditionalMappings()) {
+          if (mappingInformation.isFileNameInformation()) {
+            return new RetraceSourceFileResultImpl(
+                mappingInformation.asFileNameInformation().getFileName(), false);
           }
         }
       }
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 34c11ee..a561761 100644
--- a/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
+++ b/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
@@ -72,6 +72,10 @@
       DexDefinition holder,
       DexAnnotation annotation,
       boolean isAnnotationTypeLive) {
+    // If we cannot run the AnnotationRemover we are keeping the annotation.
+    if (!appView.options().isShrinking()) {
+      return true;
+    }
     ProguardKeepAttributes config =
         appView.options().getProguardConfiguration() != null
             ? appView.options().getProguardConfiguration().getKeepAttributes()
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java b/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
index 7181e84..523552a 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
@@ -42,7 +42,7 @@
   R(30),
   S(31);
 
-  public static final AndroidApiLevel LATEST = R;
+  public static final AndroidApiLevel LATEST = S;
 
   public static final int magicApiLevelUsedByAndroidPlatformBuild = 10000;
 
@@ -150,6 +150,8 @@
         return P;
       case 29:
         return Q;
+      case 30:
+        return R;
       default:
         return LATEST;
     }
diff --git a/src/main/java/com/android/tools/r8/utils/DexVersion.java b/src/main/java/com/android/tools/r8/utils/DexVersion.java
index e9557fa..f06f3d7 100644
--- a/src/main/java/com/android/tools/r8/utils/DexVersion.java
+++ b/src/main/java/com/android/tools/r8/utils/DexVersion.java
@@ -38,6 +38,7 @@
 
   public static DexVersion getDexVersion(AndroidApiLevel androidApiLevel) {
     switch (androidApiLevel) {
+      case S:
       case R:
       case Q:
       case P:
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 83a2245..ee29d30 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -1380,6 +1380,8 @@
     public Consumer<ProgramMethod> callSiteOptimizationInfoInspector = null;
 
     public Predicate<DexMethod> cfByteCodePassThrough = null;
+
+    public boolean enableExperimentalMapFileVersion = false;
   }
 
   @VisibleForTesting
diff --git a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
index f8ad5bb..aba61ee 100644
--- a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
+++ b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
@@ -49,6 +49,8 @@
 import com.android.tools.r8.naming.Range;
 import com.android.tools.r8.naming.mappinginformation.CompilerSynthesizedMappingInformation;
 import com.android.tools.r8.naming.mappinginformation.FileNameInformation;
+import com.android.tools.r8.naming.mappinginformation.ScopedMappingInformation.ClassScopeReference;
+import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.retrace.internal.RetraceUtils;
 import com.android.tools.r8.shaking.KeepInfoCollection;
 import com.android.tools.r8.utils.InternalOptions.LineNumberOptimization;
@@ -265,10 +267,7 @@
   }
 
   public static ClassNameMapper run(
-      AppView<AppInfoWithClassHierarchy> appView,
-      DexApplication application,
-      AndroidApp inputApp,
-      NamingLens namingLens) {
+      AppView<?> appView, DexApplication application, AndroidApp inputApp, NamingLens namingLens) {
     // For finding methods in kotlin files based on SourceDebugExtensions, we use a line method map.
     // We create it here to ensure it is only reading class files once.
     CfLineToMethodMapper cfLineToMethodMapper = new CfLineToMethodMapper(inputApp);
@@ -284,12 +283,12 @@
       // It depends on whether any methods/fields are renamed or some methods contain positions.
       // Create a supplier which creates a new, cached ClassNaming.Builder on-demand.
       DexType originalType = appView.graphLens().getOriginalType(clazz.type);
-      DexString renamedClassName = namingLens.lookupDescriptor(clazz.getType());
+      DexString renamedDescriptor = namingLens.lookupDescriptor(clazz.getType());
       Supplier<ClassNaming.Builder> onDemandClassNamingBuilder =
           Suppliers.memoize(
               () ->
                   classNameMapperBuilder.classNamingBuilder(
-                      DescriptorUtils.descriptorToJavaType(renamedClassName.toString()),
+                      DescriptorUtils.descriptorToJavaType(renamedDescriptor.toString()),
                       originalType.toSourceString(),
                       com.android.tools.r8.position.Position.UNKNOWN));
 
@@ -302,14 +301,19 @@
         }
       }
 
-      if (isSyntheticClass) {
+      if (isSyntheticClass && appView.options().testing.enableExperimentalMapFileVersion) {
         onDemandClassNamingBuilder
             .get()
-            .addMappingInformation(new CompilerSynthesizedMappingInformation());
+            .addMappingInformation(
+                CompilerSynthesizedMappingInformation.builder()
+                    .addScopeReference(
+                        new ClassScopeReference(
+                            Reference.classFromDescriptor(renamedDescriptor.toString())))
+                    .build());
       }
 
       // If the class is renamed add it to the classNamingBuilder.
-      addClassToClassNaming(originalType, renamedClassName, onDemandClassNamingBuilder);
+      addClassToClassNaming(originalType, renamedDescriptor, onDemandClassNamingBuilder);
 
       // First transfer renamed fields to classNamingBuilder.
       addFieldsToClassNaming(
@@ -462,10 +466,11 @@
   }
 
   private static boolean verifyMethodsAreKeptDirectlyOrIndirectly(
-      AppView<AppInfoWithClassHierarchy> appView, List<DexEncodedMethod> methods) {
-    if (appView.options().isGeneratingClassFiles()) {
+      AppView<?> appView, List<DexEncodedMethod> methods) {
+    if (appView.options().isGeneratingClassFiles() || !appView.appInfo().hasClassHierarchy()) {
       return true;
     }
+    AppInfoWithClassHierarchy appInfo = appView.appInfo().withClassHierarchy();
     KeepInfoCollection keepInfo = appView.getKeepInfo();
     boolean allSeenAreInstanceInitializers = true;
     DexString originalName = null;
@@ -487,7 +492,7 @@
       // We use the same name for interface names even if it has different types.
       DexProgramClass clazz = appView.definitionForProgramType(method.getHolderType());
       DexClassAndMethod lookupResult =
-          appView.appInfo().lookupMaximallySpecificMethod(clazz, method.getReference());
+          appInfo.lookupMaximallySpecificMethod(clazz, method.getReference());
       if (lookupResult == null) {
         // We cannot rename methods we cannot look up.
         continue;
diff --git a/src/test/examples/multidex002/ref-list-1.txt b/src/test/examples/multidex002/ref-list-1.txt
index 5fbe5c1..36de405 100644
--- a/src/test/examples/multidex002/ref-list-1.txt
+++ b/src/test/examples/multidex002/ref-list-1.txt
@@ -16,8 +16,13 @@
 Lmultidex002/MainActivity;
 Lmultidex002/Referenced;
 Lmultidex002/ReferencedByAnnotation;
+Lmultidex002/ReferencedByAnnotationWithOtherReferences$1;
+Lmultidex002/ReferencedByAnnotationWithOtherReferences$2;
 Lmultidex002/ReferencedByAnnotationWithOtherReferences;
+Lmultidex002/ReferencedByClassInAnnotation$1;
+Lmultidex002/ReferencedByClassInAnnotation$2;
 Lmultidex002/ReferencedByClassInAnnotation;
+Lmultidex002/ReferencedByEnum;
 Lmultidex002/ReferencedByInterface;
 Lmultidex002/TestApplication;
 Lmultidex002/fakelibrary/MultiDex$V14;
diff --git a/src/test/java/com/android/tools/r8/D8TestBuilder.java b/src/test/java/com/android/tools/r8/D8TestBuilder.java
index 67eeeb0..d299224 100644
--- a/src/test/java/com/android/tools/r8/D8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/D8TestBuilder.java
@@ -28,6 +28,8 @@
     return new D8TestBuilder(state, D8Command.builder(state.getDiagnosticsHandler()), backend);
   }
 
+  private StringBuilder proguardMapOutputBuilder = null;
+
   @Override
   D8TestBuilder self() {
     return this;
@@ -65,7 +67,12 @@
       Builder builder, Consumer<InternalOptions> optionsConsumer, Supplier<AndroidApp> app)
       throws CompilationFailedException {
     ToolHelper.runD8(builder, optionsConsumer);
-    return new D8TestCompileResult(getState(), app.get(), minApiLevel, getOutputMode());
+    return new D8TestCompileResult(
+        getState(), app.get(), minApiLevel, getOutputMode(), getMapContent());
+  }
+
+  private String getMapContent() {
+    return proguardMapOutputBuilder == null ? null : proguardMapOutputBuilder.toString();
   }
 
   public D8TestBuilder setIntermediate(boolean intermediate) {
@@ -106,4 +113,14 @@
     }
     return self();
   }
+
+  // TODO(b/183125319): Make this the default as part of API support in D8.
+  public D8TestBuilder internalEnableMappingOutput() {
+    assert proguardMapOutputBuilder == null;
+    proguardMapOutputBuilder = new StringBuilder();
+    // TODO(b/183125319): Use the API once supported in D8.
+    addOptionsModification(
+        o -> o.proguardMapConsumer = (s, h) -> proguardMapOutputBuilder.append(s));
+    return self();
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/D8TestCompileResult.java b/src/test/java/com/android/tools/r8/D8TestCompileResult.java
index b5fccb8..e36ff2d 100644
--- a/src/test/java/com/android/tools/r8/D8TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/D8TestCompileResult.java
@@ -9,8 +9,12 @@
 import java.util.Set;
 
 public class D8TestCompileResult extends TestCompileResult<D8TestCompileResult, D8TestRunResult> {
-  D8TestCompileResult(TestState state, AndroidApp app, int minApiLevel, OutputMode outputMode) {
+  private final String proguardMap;
+
+  D8TestCompileResult(
+      TestState state, AndroidApp app, int minApiLevel, OutputMode outputMode, String proguardMap) {
     super(state, app, minApiLevel, outputMode);
+    this.proguardMap = proguardMap;
   }
 
   @Override
@@ -38,8 +42,12 @@
     return state.getStderr();
   }
 
+  public String getProguardMap() {
+    return proguardMap;
+  }
+
   @Override
   public D8TestRunResult createRunResult(TestRuntime runtime, ProcessResult result) {
-    return new D8TestRunResult(app, runtime, result);
+    return new D8TestRunResult(app, runtime, result, proguardMap);
   }
 }
diff --git a/src/test/java/com/android/tools/r8/D8TestRunResult.java b/src/test/java/com/android/tools/r8/D8TestRunResult.java
index 4e13e54..d0fe6fb 100644
--- a/src/test/java/com/android/tools/r8/D8TestRunResult.java
+++ b/src/test/java/com/android/tools/r8/D8TestRunResult.java
@@ -4,17 +4,31 @@
 
 package com.android.tools.r8;
 
+import static org.junit.Assert.assertNotNull;
+
 import com.android.tools.r8.ToolHelper.ProcessResult;
 import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.io.IOException;
 
 public class D8TestRunResult extends SingleTestRunResult<D8TestRunResult> {
 
-  public D8TestRunResult(AndroidApp app, TestRuntime runtime, ProcessResult result) {
+  private final String proguardMap;
+
+  public D8TestRunResult(
+      AndroidApp app, TestRuntime runtime, ProcessResult result, String proguardMap) {
     super(app, runtime, result);
+    this.proguardMap = proguardMap;
   }
 
   @Override
   protected D8TestRunResult self() {
     return this;
   }
+
+  @Override
+  protected CodeInspector internalGetCodeInspector() throws IOException {
+    assertNotNull(app);
+    return proguardMap == null ? new CodeInspector(app) : new CodeInspector(app, proguardMap);
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/R8TestRunResult.java b/src/test/java/com/android/tools/r8/R8TestRunResult.java
index 028ed02..f35f686 100644
--- a/src/test/java/com/android/tools/r8/R8TestRunResult.java
+++ b/src/test/java/com/android/tools/r8/R8TestRunResult.java
@@ -57,23 +57,11 @@
   }
 
   @Override
-  public CodeInspector inspector() throws IOException, ExecutionException {
-    // See comment in base class.
-    assertSuccess();
+  protected CodeInspector internalGetCodeInspector() throws IOException {
     assertNotNull(app);
     return new CodeInspector(app, proguardMap);
   }
 
-  @Override
-  public <E extends Throwable> R8TestRunResult inspectFailure(
-      ThrowingConsumer<CodeInspector, E> consumer) throws IOException, ExecutionException, E {
-    assertFailure();
-    assertNotNull(app);
-    CodeInspector codeInspector = new CodeInspector(app, proguardMap);
-    consumer.accept(codeInspector);
-    return self();
-  }
-
   public <E extends Throwable> R8TestRunResult inspectOriginalStackTrace(
       ThrowingConsumer<StackTrace, E> consumer) throws E {
     consumer.accept(getOriginalStackTrace());
@@ -81,9 +69,8 @@
   }
 
   public <E extends Throwable> R8TestRunResult inspectOriginalStackTrace(
-      ThrowingBiConsumer<StackTrace, CodeInspector, E> consumer)
-      throws E, IOException, ExecutionException {
-    consumer.accept(getOriginalStackTrace(), new CodeInspector(app, proguardMap));
+      ThrowingBiConsumer<StackTrace, CodeInspector, E> consumer) throws E, IOException {
+    consumer.accept(getOriginalStackTrace(), internalGetCodeInspector());
     return self();
   }
 
@@ -100,7 +87,7 @@
 
   public <E extends Throwable> R8TestRunResult inspectStackTrace(
       ThrowingBiConsumer<StackTrace, CodeInspector, E> consumer) throws E, IOException {
-    consumer.accept(getStackTrace(), new CodeInspector(app, proguardMap));
+    consumer.accept(getStackTrace(), internalGetCodeInspector());
     return self();
   }
 
diff --git a/src/test/java/com/android/tools/r8/SingleTestRunResult.java b/src/test/java/com/android/tools/r8/SingleTestRunResult.java
index d532547..07e0736 100644
--- a/src/test/java/com/android/tools/r8/SingleTestRunResult.java
+++ b/src/test/java/com/android/tools/r8/SingleTestRunResult.java
@@ -90,12 +90,16 @@
     return self();
   }
 
+  protected CodeInspector internalGetCodeInspector() throws IOException {
+    assertNotNull(app);
+    return new CodeInspector(app);
+  }
+
   public CodeInspector inspector() throws IOException, ExecutionException {
     // Inspection post run implies success. If inspection of an invalid program is needed it should
     // be done on the compilation result or on the input.
     assertSuccess();
-    assertNotNull(app);
-    return new CodeInspector(app);
+    return internalGetCodeInspector();
   }
 
   @Override
@@ -107,10 +111,9 @@
   }
 
   public <E extends Throwable> RR inspectFailure(ThrowingConsumer<CodeInspector, E> consumer)
-      throws IOException, ExecutionException, E {
+      throws IOException, E {
     assertFailure();
-    assertNotNull(app);
-    CodeInspector inspector = new CodeInspector(app);
+    CodeInspector inspector = internalGetCodeInspector();
     consumer.accept(inspector);
     return self();
   }
diff --git a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
index a6c4924..766fb0f 100644
--- a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
@@ -224,6 +224,11 @@
     }
   }
 
+  public T enableExperimentalMapFileVersion() {
+    addOptionsModification(o -> o.testing.enableExperimentalMapFileVersion = true);
+    return self();
+  }
+
   @FunctionalInterface
   public interface DiagnosticsConsumer {
     void accept(TestDiagnosticMessages diagnostics);
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 18037be..e9a47e3 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -825,8 +825,6 @@
       case J_MR1:
       case J_MR2:
       case K_WATCH:
-        // TODO(b/1813562600): Add android jar for S.
-      case S:
         return false;
       default:
         return true;
diff --git a/src/test/java/com/android/tools/r8/cf/StackMapForAlwaysThrowingInitializerTest.java b/src/test/java/com/android/tools/r8/cf/StackMapForAlwaysThrowingInitializerTest.java
new file mode 100644
index 0000000..a3e284e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/cf/StackMapForAlwaysThrowingInitializerTest.java
@@ -0,0 +1,172 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.cf;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+/** This is a reproduction of b/183285081 */
+@RunWith(Parameterized.class)
+public class StackMapForAlwaysThrowingInitializerTest extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withCfRuntimes().withAllApiLevelsAlsoForCf().build();
+  }
+
+  public StackMapForAlwaysThrowingInitializerTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testRuntime() throws Exception {
+    testForRuntime(parameters)
+        .addProgramClassFileData(StackMapForThrowingInitializerTest$MainDump.dump())
+        .run(parameters.getRuntime(), StackMapForThrowingInitializerTest.Main.class, "")
+        .assertFailureWithErrorThatThrows(IllegalArgumentException.class);
+  }
+
+  /**
+   * The dump below checks what happens when we clobber the uninitialized this pointer with straight
+   * line code:
+   *
+   * <pre>
+   *     public Main(Object obj, String str) {
+   *       this = str           <-- clobber the uninitialized this pointer
+   *       throw new IllegalArgumentException();
+   *     }
+   * </pre>
+   */
+  public static class StackMapForThrowingInitializerTest$MainDump implements Opcodes {
+
+    public static byte[] dump() {
+
+      ClassWriter classWriter = new ClassWriter(0);
+      FieldVisitor fieldVisitor;
+      MethodVisitor methodVisitor;
+
+      classWriter.visit(
+          V1_8,
+          ACC_PUBLIC,
+          "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+          null,
+          "java/lang/Object",
+          null);
+
+      {
+        fieldVisitor =
+            classWriter.visitField(
+                ACC_PRIVATE | ACC_FINAL, "str", "Ljava/lang/String;", null, null);
+        fieldVisitor.visitEnd();
+      }
+      {
+        methodVisitor =
+            classWriter.visitMethod(ACC_PUBLIC, "<init>", "(Ljava/lang/String;)V", null, null);
+        methodVisitor.visitCode();
+        methodVisitor.visitVarInsn(ALOAD, 0);
+        methodVisitor.visitInsn(DUP);
+        methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
+        methodVisitor.visitVarInsn(ALOAD, 1);
+        methodVisitor.visitFieldInsn(
+            PUTFIELD,
+            "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+            "str",
+            "Ljava/lang/String;");
+        methodVisitor.visitInsn(RETURN);
+        methodVisitor.visitMaxs(2, 2);
+        methodVisitor.visitEnd();
+      }
+      {
+        methodVisitor =
+            classWriter.visitMethod(
+                ACC_PUBLIC, "<init>", "(Ljava/lang/Object;Ljava/lang/String;)V", null, null);
+        methodVisitor.visitCode();
+        methodVisitor.visitVarInsn(ALOAD, 2);
+        methodVisitor.visitVarInsn(ASTORE, 0);
+        methodVisitor.visitTypeInsn(NEW, "java/lang/IllegalArgumentException");
+        methodVisitor.visitInsn(DUP);
+        methodVisitor.visitMethodInsn(
+            INVOKESPECIAL, "java/lang/IllegalArgumentException", "<init>", "()V", false);
+        methodVisitor.visitInsn(ATHROW);
+        methodVisitor.visitMaxs(2, 3);
+        methodVisitor.visitEnd();
+      }
+      {
+        methodVisitor =
+            classWriter.visitMethod(
+                ACC_PUBLIC | ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
+        methodVisitor.visitCode();
+        methodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
+        methodVisitor.visitVarInsn(ALOAD, 0);
+        methodVisitor.visitInsn(ARRAYLENGTH);
+        Label label0 = new Label();
+        methodVisitor.visitJumpInsn(IFNE, label0);
+        methodVisitor.visitTypeInsn(
+            NEW, "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main");
+        methodVisitor.visitInsn(DUP);
+        methodVisitor.visitInsn(ACONST_NULL);
+        methodVisitor.visitLdcInsn("foo");
+        methodVisitor.visitMethodInsn(
+            INVOKESPECIAL,
+            "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+            "<init>",
+            "(Ljava/lang/Object;Ljava/lang/String;)V",
+            false);
+        Label label1 = new Label();
+        methodVisitor.visitJumpInsn(GOTO, label1);
+        methodVisitor.visitLabel(label0);
+        methodVisitor.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/io/PrintStream"});
+        methodVisitor.visitTypeInsn(
+            NEW, "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main");
+        methodVisitor.visitInsn(DUP);
+        methodVisitor.visitLdcInsn(
+            Type.getType("Lcom/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main;"));
+        methodVisitor.visitVarInsn(ALOAD, 0);
+        methodVisitor.visitInsn(ICONST_0);
+        methodVisitor.visitInsn(AALOAD);
+        methodVisitor.visitMethodInsn(
+            INVOKESPECIAL,
+            "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+            "<init>",
+            "(Ljava/lang/Object;Ljava/lang/String;)V",
+            false);
+        methodVisitor.visitMethodInsn(
+            INVOKEVIRTUAL,
+            "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+            "toString",
+            "()Ljava/lang/String;",
+            false);
+        methodVisitor.visitLabel(label1);
+        methodVisitor.visitFrame(
+            Opcodes.F_FULL,
+            1,
+            new Object[] {"[Ljava/lang/String;"},
+            2,
+            new Object[] {"java/io/PrintStream", "java/lang/Object"});
+        methodVisitor.visitMethodInsn(
+            INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/Object;)V", false);
+        methodVisitor.visitInsn(RETURN);
+        methodVisitor.visitMaxs(6, 1);
+        methodVisitor.visitEnd();
+      }
+      classWriter.visitEnd();
+
+      return classWriter.toByteArray();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/cf/StackMapForAlwaysThrowingInitializerWithControlFlowTest.java b/src/test/java/com/android/tools/r8/cf/StackMapForAlwaysThrowingInitializerWithControlFlowTest.java
new file mode 100644
index 0000000..2455984
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/cf/StackMapForAlwaysThrowingInitializerWithControlFlowTest.java
@@ -0,0 +1,194 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.cf;
+
+import static org.hamcrest.CoreMatchers.containsString;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+/** This is a reproduction of b/183285081 */
+@RunWith(Parameterized.class)
+public class StackMapForAlwaysThrowingInitializerWithControlFlowTest extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withCfRuntimes().withAllApiLevelsAlsoForCf().build();
+  }
+
+  public StackMapForAlwaysThrowingInitializerWithControlFlowTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testRuntime() throws Exception {
+    testForRuntime(parameters)
+        .addProgramClassFileData(StackMapForThrowingInitializerTest$MainDump.dump())
+        .run(parameters.getRuntime(), StackMapForThrowingInitializerTest.Main.class, "")
+        .assertFailureWithErrorThatThrows(VerifyError.class)
+        .assertFailureWithErrorThatMatches(
+            containsString("Current frame's flags are not assignable to stack map frame's"));
+  }
+
+  /**
+   * The dump below checks what happens when we clobber the uninitialized this pointer and have
+   * control flow:
+   *
+   * <pre>
+   *     public Main(Object obj, String str) {
+   *       this = str           <-- clobber the uninitialized this pointer
+   *       if (str.equals("foo")) {
+   *         throw new IllegalArgumentException();
+   *       } else {
+   *         throw new RuntimeException();
+   *       }
+   *     }
+   * </pre>
+   */
+  public static class StackMapForThrowingInitializerTest$MainDump implements Opcodes {
+
+    public static byte[] dump() {
+
+      ClassWriter classWriter = new ClassWriter(0);
+      FieldVisitor fieldVisitor;
+      MethodVisitor methodVisitor;
+
+      classWriter.visit(
+          V1_8,
+          ACC_PUBLIC,
+          "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+          null,
+          "java/lang/Object",
+          null);
+
+      {
+        fieldVisitor =
+            classWriter.visitField(
+                ACC_PRIVATE | ACC_FINAL, "str", "Ljava/lang/String;", null, null);
+        fieldVisitor.visitEnd();
+      }
+      {
+        methodVisitor =
+            classWriter.visitMethod(ACC_PUBLIC, "<init>", "(Ljava/lang/String;)V", null, null);
+        methodVisitor.visitCode();
+        methodVisitor.visitVarInsn(ALOAD, 0);
+        methodVisitor.visitInsn(DUP);
+        methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
+        methodVisitor.visitVarInsn(ALOAD, 1);
+        methodVisitor.visitFieldInsn(
+            PUTFIELD,
+            "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+            "str",
+            "Ljava/lang/String;");
+        methodVisitor.visitInsn(RETURN);
+        methodVisitor.visitMaxs(2, 2);
+        methodVisitor.visitEnd();
+      }
+      {
+        methodVisitor =
+            classWriter.visitMethod(
+                ACC_PUBLIC, "<init>", "(Ljava/lang/Object;Ljava/lang/String;)V", null, null);
+        methodVisitor.visitCode();
+        methodVisitor.visitVarInsn(ALOAD, 2);
+        methodVisitor.visitVarInsn(ASTORE, 0);
+        methodVisitor.visitVarInsn(ALOAD, 2);
+        methodVisitor.visitLdcInsn("foo");
+        methodVisitor.visitMethodInsn(
+            INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z", false);
+        Label label0 = new Label();
+        methodVisitor.visitJumpInsn(IFNE, label0);
+        methodVisitor.visitFrame(Opcodes.F_FULL, 0, new Object[] {}, 0, new Object[] {});
+        methodVisitor.visitTypeInsn(NEW, "java/lang/RuntimeException");
+        methodVisitor.visitInsn(DUP);
+        methodVisitor.visitMethodInsn(
+            INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "()V", false);
+        methodVisitor.visitInsn(ATHROW);
+        methodVisitor.visitLabel(label0);
+        methodVisitor.visitFrame(Opcodes.F_FULL, 0, new Object[] {}, 0, new Object[] {});
+        methodVisitor.visitTypeInsn(NEW, "java/lang/IllegalArgumentException");
+        methodVisitor.visitInsn(DUP);
+        methodVisitor.visitMethodInsn(
+            INVOKESPECIAL, "java/lang/IllegalArgumentException", "<init>", "()V", false);
+        methodVisitor.visitInsn(ATHROW);
+        methodVisitor.visitMaxs(2, 3);
+        methodVisitor.visitEnd();
+      }
+      {
+        methodVisitor =
+            classWriter.visitMethod(
+                ACC_PUBLIC | ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
+        methodVisitor.visitCode();
+        methodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
+        methodVisitor.visitVarInsn(ALOAD, 0);
+        methodVisitor.visitInsn(ARRAYLENGTH);
+        Label label0 = new Label();
+        methodVisitor.visitJumpInsn(IFNE, label0);
+        methodVisitor.visitTypeInsn(
+            NEW, "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main");
+        methodVisitor.visitInsn(DUP);
+        methodVisitor.visitInsn(ACONST_NULL);
+        methodVisitor.visitLdcInsn("foo");
+        methodVisitor.visitMethodInsn(
+            INVOKESPECIAL,
+            "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+            "<init>",
+            "(Ljava/lang/Object;Ljava/lang/String;)V",
+            false);
+        Label label1 = new Label();
+        methodVisitor.visitJumpInsn(GOTO, label1);
+        methodVisitor.visitLabel(label0);
+        methodVisitor.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/io/PrintStream"});
+        methodVisitor.visitTypeInsn(
+            NEW, "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main");
+        methodVisitor.visitInsn(DUP);
+        methodVisitor.visitLdcInsn(
+            Type.getType("Lcom/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main;"));
+        methodVisitor.visitVarInsn(ALOAD, 0);
+        methodVisitor.visitInsn(ICONST_0);
+        methodVisitor.visitInsn(AALOAD);
+        methodVisitor.visitMethodInsn(
+            INVOKESPECIAL,
+            "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+            "<init>",
+            "(Ljava/lang/Object;Ljava/lang/String;)V",
+            false);
+        methodVisitor.visitMethodInsn(
+            INVOKEVIRTUAL,
+            "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+            "toString",
+            "()Ljava/lang/String;",
+            false);
+        methodVisitor.visitLabel(label1);
+        methodVisitor.visitFrame(
+            Opcodes.F_FULL,
+            1,
+            new Object[] {"[Ljava/lang/String;"},
+            2,
+            new Object[] {"java/io/PrintStream", "java/lang/Object"});
+        methodVisitor.visitMethodInsn(
+            INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/Object;)V", false);
+        methodVisitor.visitInsn(RETURN);
+        methodVisitor.visitMaxs(6, 1);
+        methodVisitor.visitEnd();
+      }
+      classWriter.visitEnd();
+
+      return classWriter.toByteArray();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/cf/StackMapForThrowingInitializerTest.java b/src/test/java/com/android/tools/r8/cf/StackMapForThrowingInitializerTest.java
new file mode 100644
index 0000000..bea206e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/cf/StackMapForThrowingInitializerTest.java
@@ -0,0 +1,311 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.cf;
+
+import static org.hamcrest.CoreMatchers.containsString;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+/** This is a reproduction of b/183285081 */
+@RunWith(Parameterized.class)
+public class StackMapForThrowingInitializerTest extends TestBase {
+
+  private final TestParameters parameters;
+  private final String[] EXPECTED = new String[] {"Hello World"};
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withCfRuntimes().withAllApiLevelsAlsoForCf().build();
+  }
+
+  public StackMapForThrowingInitializerTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testRuntime() throws Exception {
+    testForRuntime(parameters)
+        .addProgramClassFileData(StackMapForThrowingInitializerTest$MainDump.dump())
+        .run(parameters.getRuntime(), Main.class, EXPECTED)
+        .assertSuccessWithOutputLines(EXPECTED);
+  }
+
+  @Test
+  public void testD8() throws Exception {
+    testForD8(parameters.getBackend())
+        .addProgramClassFileData(StackMapForThrowingInitializerTest$MainDump.dump())
+        .setMinApi(parameters.getApiLevel())
+        .run(parameters.getRuntime(), Main.class, EXPECTED)
+        .assertSuccessWithOutputLines(EXPECTED);
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
+        .addProgramClassFileData(StackMapForThrowingInitializerTest$MainDump.dump())
+        .addKeepClassAndMembersRules(Main.class)
+        .enableInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
+        .setMinApi(parameters.getApiLevel())
+        .run(parameters.getRuntime(), Main.class, EXPECTED)
+        // TODO(b/183285081): Should not have verification errors.
+        .assertFailureWithErrorThatMatches(
+            containsString("java.lang.VerifyError: Inconsistent stackmap frames at branch target"));
+  }
+
+  @NeverClassInline
+  public static class Main {
+
+    private final String str;
+
+    @NeverInline
+    public Main(String str) {
+      this.str = str;
+    }
+
+    public Main(Object obj, String str) {
+      this(str);
+      if (str.equals("foo")) {
+        throw new IllegalArgumentException();
+      }
+      if (obj == null) {
+        throw new RuntimeException();
+      }
+    }
+
+    @Override
+    public String toString() {
+      return str;
+    }
+
+    public static void main(String[] args) {
+      System.out.println(
+          args.length == 0 ? new Main(null, "foo") : new Main(Main.class, args[0]).toString());
+    }
+  }
+
+  /**
+   * The dump below is just the ASM code of the class above where:
+   *
+   * <pre>
+   *     public Main(Object obj, String str) {
+   *       this(str);
+   *       if (str.equals("foo")) {
+   *         throw new IllegalArgumentException();
+   *       }
+   *       if (obj == null) {
+   *         throw new RuntimeException();
+   *       }
+   *     }
+   * </pre>
+   *
+   * is changed to have the initializer call in the bottom:
+   *
+   * <pre>
+   *     public Main(Object obj, String str) {
+   *       if (str.equals("foo")) {
+   *         throw new IllegalArgumentException();
+   *       }
+   *       if (obj == null) {
+   *         throw new RuntimeException();
+   *       }
+   *       this(str);
+   *     }
+   * </pre>
+   */
+  public static class StackMapForThrowingInitializerTest$MainDump implements Opcodes {
+
+    public static byte[] dump() {
+
+      ClassWriter classWriter = new ClassWriter(0);
+      FieldVisitor fieldVisitor;
+      MethodVisitor methodVisitor;
+      AnnotationVisitor annotationVisitor0;
+
+      classWriter.visit(
+          V1_8,
+          ACC_PUBLIC | ACC_SUPER,
+          "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+          null,
+          "java/lang/Object",
+          null);
+
+      {
+        annotationVisitor0 =
+            classWriter.visitAnnotation("Lcom/android/tools/r8/NeverClassInline;", false);
+        annotationVisitor0.visitEnd();
+      }
+      classWriter.visitInnerClass(
+          "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+          "com/android/tools/r8/cf/StackMapForThrowingInitializerTest",
+          "Main",
+          ACC_PUBLIC | ACC_STATIC);
+
+      {
+        fieldVisitor =
+            classWriter.visitField(
+                ACC_PRIVATE | ACC_FINAL, "str", "Ljava/lang/String;", null, null);
+        fieldVisitor.visitEnd();
+      }
+      {
+        methodVisitor =
+            classWriter.visitMethod(ACC_PUBLIC, "<init>", "(Ljava/lang/String;)V", null, null);
+        {
+          annotationVisitor0 =
+              methodVisitor.visitAnnotation("Lcom/android/tools/r8/NeverInline;", false);
+          annotationVisitor0.visitEnd();
+        }
+        methodVisitor.visitCode();
+        methodVisitor.visitVarInsn(ALOAD, 0);
+        methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
+        methodVisitor.visitVarInsn(ALOAD, 0);
+        methodVisitor.visitVarInsn(ALOAD, 1);
+        methodVisitor.visitFieldInsn(
+            PUTFIELD,
+            "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+            "str",
+            "Ljava/lang/String;");
+        methodVisitor.visitInsn(RETURN);
+        methodVisitor.visitMaxs(2, 2);
+        methodVisitor.visitEnd();
+      }
+      {
+        methodVisitor =
+            classWriter.visitMethod(
+                ACC_PUBLIC, "<init>", "(Ljava/lang/Object;Ljava/lang/String;)V", null, null);
+        methodVisitor.visitCode();
+        methodVisitor.visitVarInsn(ALOAD, 2);
+        methodVisitor.visitLdcInsn("foo");
+        methodVisitor.visitMethodInsn(
+            INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z", false);
+        Label label0 = new Label();
+        methodVisitor.visitJumpInsn(IFEQ, label0);
+        methodVisitor.visitTypeInsn(NEW, "java/lang/IllegalArgumentException");
+        methodVisitor.visitInsn(DUP);
+        methodVisitor.visitMethodInsn(
+            INVOKESPECIAL, "java/lang/IllegalArgumentException", "<init>", "()V", false);
+        methodVisitor.visitInsn(ATHROW);
+        methodVisitor.visitLabel(label0);
+        methodVisitor.visitFrame(
+            Opcodes.F_FULL,
+            3,
+            new Object[] {Opcodes.UNINITIALIZED_THIS, "java/lang/Object", "java/lang/String"},
+            0,
+            new Object[] {});
+        methodVisitor.visitVarInsn(ALOAD, 1);
+        Label label1 = new Label();
+        methodVisitor.visitJumpInsn(IFNONNULL, label1);
+        methodVisitor.visitTypeInsn(NEW, "java/lang/RuntimeException");
+        methodVisitor.visitInsn(DUP);
+        methodVisitor.visitMethodInsn(
+            INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "()V", false);
+        methodVisitor.visitInsn(ATHROW);
+        methodVisitor.visitLabel(label1);
+        methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
+        methodVisitor.visitVarInsn(ALOAD, 0);
+        methodVisitor.visitVarInsn(ALOAD, 2);
+        methodVisitor.visitMethodInsn(
+            INVOKESPECIAL,
+            "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+            "<init>",
+            "(Ljava/lang/String;)V",
+            false);
+        methodVisitor.visitInsn(RETURN);
+        methodVisitor.visitMaxs(2, 3);
+        methodVisitor.visitEnd();
+      }
+      {
+        methodVisitor =
+            classWriter.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null);
+        methodVisitor.visitCode();
+        methodVisitor.visitVarInsn(ALOAD, 0);
+        methodVisitor.visitFieldInsn(
+            GETFIELD,
+            "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+            "str",
+            "Ljava/lang/String;");
+        methodVisitor.visitInsn(ARETURN);
+        methodVisitor.visitMaxs(1, 1);
+        methodVisitor.visitEnd();
+      }
+      {
+        methodVisitor =
+            classWriter.visitMethod(
+                ACC_PUBLIC | ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
+        methodVisitor.visitCode();
+        methodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
+        methodVisitor.visitVarInsn(ALOAD, 0);
+        methodVisitor.visitInsn(ARRAYLENGTH);
+        Label label0 = new Label();
+        methodVisitor.visitJumpInsn(IFNE, label0);
+        methodVisitor.visitTypeInsn(
+            NEW, "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main");
+        methodVisitor.visitInsn(DUP);
+        methodVisitor.visitInsn(ACONST_NULL);
+        methodVisitor.visitLdcInsn("foo");
+        methodVisitor.visitMethodInsn(
+            INVOKESPECIAL,
+            "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+            "<init>",
+            "(Ljava/lang/Object;Ljava/lang/String;)V",
+            false);
+        Label label1 = new Label();
+        methodVisitor.visitJumpInsn(GOTO, label1);
+        methodVisitor.visitLabel(label0);
+        methodVisitor.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/io/PrintStream"});
+        methodVisitor.visitTypeInsn(
+            NEW, "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main");
+        methodVisitor.visitInsn(DUP);
+        methodVisitor.visitLdcInsn(
+            Type.getType("Lcom/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main;"));
+        methodVisitor.visitVarInsn(ALOAD, 0);
+        methodVisitor.visitInsn(ICONST_0);
+        methodVisitor.visitInsn(AALOAD);
+        methodVisitor.visitMethodInsn(
+            INVOKESPECIAL,
+            "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+            "<init>",
+            "(Ljava/lang/Object;Ljava/lang/String;)V",
+            false);
+        methodVisitor.visitMethodInsn(
+            INVOKEVIRTUAL,
+            "com/android/tools/r8/cf/StackMapForThrowingInitializerTest$Main",
+            "toString",
+            "()Ljava/lang/String;",
+            false);
+        methodVisitor.visitLabel(label1);
+        methodVisitor.visitFrame(
+            Opcodes.F_FULL,
+            1,
+            new Object[] {"[Ljava/lang/String;"},
+            2,
+            new Object[] {"java/io/PrintStream", "java/lang/Object"});
+        methodVisitor.visitMethodInsn(
+            INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/Object;)V", false);
+        methodVisitor.visitInsn(RETURN);
+        methodVisitor.visitMaxs(6, 1);
+        methodVisitor.visitEnd();
+      }
+      classWriter.visitEnd();
+
+      return classWriter.toByteArray();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java b/src/test/java/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java
index e9d9d79..67db3d7 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java
@@ -80,7 +80,9 @@
         .assertWarningMessageThatMatches(containsString("is not supported by this compiler"))
         .run(parameters.getRuntime(), TestMathMultiplyExactLongInt.class)
         .assertFailureWithErrorThatMatches(
-            containsString("java.lang.NoSuchMethodError: No static method multiplyExact(JI)J"));
+            containsString(
+                "java.lang.NoSuchMethodError: No static method"
+                    + " parseInt(Ljava/lang/CharSequence;III)I"));
   }
 
   @Test
@@ -90,7 +92,9 @@
         .setMinApi(AndroidApiLevel.magicApiLevelUsedByAndroidPlatformBuild)
         .run(parameters.getRuntime(), TestMathMultiplyExactLongInt.class)
         .assertFailureWithErrorThatMatches(
-            containsString("java.lang.NoSuchMethodError: No static method multiplyExact(JI)J"));
+            containsString(
+                "java.lang.NoSuchMethodError: No static method"
+                    + " parseInt(Ljava/lang/CharSequence;III)I"));
   }
 
   // Test class for using: List List.of()
@@ -141,9 +145,9 @@
         .transformMethodInsnInMethod(
             "main",
             (opcode, owner, name, descriptor, isInterface, visitor) -> {
-              if (name.equals("Math_multiplyExact")) {
+              if (name.equals("Integer_parseInt")) {
                 visitor.visitMethodInsn(
-                    opcode, "java/lang/Math", "multiplyExact", descriptor, isInterface);
+                    opcode, "java/lang/Integer", "parseInt", descriptor, isInterface);
               } else {
                 visitor.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
               }
@@ -152,12 +156,12 @@
   }
 
   static class TestMathMultiplyExactLongInt {
-    public static long Math_multiplyExact(long l, int i) {
+    public static int Integer_parseInt(CharSequence s, int beginIndex, int endIndex, int radix) {
       throw null;
     }
 
     public static void main(String[] args) {
-      System.out.println(Math_multiplyExact(2L, 2));
+      System.out.println(Integer_parseInt("4", 0, 1, 10));
     }
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionInvokeVirtualTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionInvokeVirtualTest.java
index b968127..92f5365 100644
--- a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionInvokeVirtualTest.java
+++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultInterfaceMethodDesugaringWithPublicStaticResolutionInvokeVirtualTest.java
@@ -117,7 +117,7 @@
     if (isR8
         && parameters.isDexRuntime()
         && parameters.getDexRuntimeVersion().isNewerThan(Version.V6_0_1)) {
-      // TODO(b/1822553980: This should be EXPECTED.
+      // TODO(b/182255398): This should be EXPECTED.
       result.assertSuccessWithOutput(EXPECTED_R8);
       return;
     }
diff --git a/src/test/java/com/android/tools/r8/ir/DebugLocalStackMapTest.java b/src/test/java/com/android/tools/r8/ir/DebugLocalStackMapTest.java
new file mode 100644
index 0000000..ddda774
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/DebugLocalStackMapTest.java
@@ -0,0 +1,697 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir;
+
+import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
+import static org.hamcrest.CoreMatchers.allOf;
+import static org.hamcrest.CoreMatchers.containsString;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.google.common.collect.ImmutableList;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+@RunWith(Parameterized.class)
+public class DebugLocalStackMapTest extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withDexRuntimes().withAllApiLevels().build();
+  }
+
+  public DebugLocalStackMapTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testInvalidDebugLocals() throws Exception {
+    testForD8(parameters.getBackend())
+        .addProgramClassFileData(TestKtDump.dump())
+        .setMinApi(parameters.getApiLevel())
+        .compileWithExpectedDiagnostics(
+            diagnostics -> {
+              diagnostics.assertInfosMatch(
+                  ImmutableList.of(
+                      diagnosticMessage(
+                          containsString("Stripped invalid locals information from 1 method")),
+                      diagnosticMessage(
+                          allOf(
+                              containsString(
+                                  "java.lang.Object"
+                                      + " TestKt.suspendHere(kotlin.coroutines.Continuation)"),
+                              containsString(
+                                  "Information in locals-table is invalid with respect to the"
+                                      + " stack map table"))),
+                      diagnosticMessage(
+                          containsString(
+                              "Some warnings are typically a sign of using an outdated Java"
+                                  + " toolchain"))));
+            });
+  }
+
+  public static class TestKtDump implements Opcodes {
+
+    public static byte[] dump() {
+
+      ClassWriter classWriter = new ClassWriter(0);
+      MethodVisitor methodVisitor;
+      AnnotationVisitor annotationVisitor0;
+
+      classWriter.visit(
+          V1_8, ACC_PUBLIC | ACC_FINAL | ACC_SUPER, "TestKt", null, "java/lang/Object", null);
+
+      classWriter.visitSource(
+          "test.kt",
+          "SMAP\n"
+              + "test.kt\n"
+              + "Kotlin\n"
+              + "*S Kotlin\n"
+              + "*F\n"
+              + "+ 1 test.kt\n"
+              + "TestKt\n"
+              + "*L\n"
+              + "1#1,17:1\n"
+              + "4#1,4:18\n"
+              + "10#1:22\n"
+              + "4#1,4:23\n"
+              + "*S KotlinDebug\n"
+              + "*F\n"
+              + "+ 1 test.kt\n"
+              + "TestKt\n"
+              + "*L\n"
+              + "10#1:18,4\n"
+              + "12#1:22\n"
+              + "12#1:23,4\n"
+              + "*E\n");
+
+      {
+        annotationVisitor0 = classWriter.visitAnnotation("Lkotlin/Metadata;", true);
+        annotationVisitor0.visit("mv", new int[] {1, 5, 0});
+        annotationVisitor0.visit("k", new Integer(2));
+        annotationVisitor0.visit("xi", new Integer(50));
+        {
+          AnnotationVisitor annotationVisitor1 = annotationVisitor0.visitArray("d1");
+          annotationVisitor1.visit(
+              null,
+              "\u0000\u0012\n"
+                  + "\u0000\n"
+                  + "\u0002\u0010\u0002\n"
+                  + "\u0002\u0008\u0002\n"
+                  + "\u0002\u0010\u000e\n"
+                  + "\u0002\u0008\u0004\u001a\u0011\u0010\u0000\u001a\u00020\u0001H\u0086@\u00f8\u0001\u0000\u00a2\u0006\u0002\u0010\u0002\u001a\u0011\u0010\u0003\u001a\u00020\u0004H\u0086@\u00f8\u0001\u0000\u00a2\u0006\u0002\u0010\u0002\u001a\u0011\u0010\u0005\u001a\u00020\u0004H\u0086H\u00f8\u0001\u0000\u00a2\u0006\u0002\u0010\u0002\u001a\u0019\u0010\u0006\u001a\u00020\u00042\u0006\u0010\u0007\u001a\u00020\u0004H\u0086H\u00f8\u0001\u0000\u00a2\u0006\u0002\u0010\u0008\u0082\u0002\u0004\n"
+                  + "\u0002\u0008\u0019");
+          annotationVisitor1.visitEnd();
+        }
+        {
+          AnnotationVisitor annotationVisitor1 = annotationVisitor0.visitArray("d2");
+          annotationVisitor1.visit(null, "main");
+          annotationVisitor1.visit(null, "");
+          annotationVisitor1.visit(null, "(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;");
+          annotationVisitor1.visit(null, "mainSuspend");
+          annotationVisitor1.visit(null, "");
+          annotationVisitor1.visit(null, "suspendHere");
+          annotationVisitor1.visit(null, "suspendThere");
+          annotationVisitor1.visit(null, "v");
+          annotationVisitor1.visit(
+              null, "(Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;");
+          annotationVisitor1.visitEnd();
+        }
+        annotationVisitor0.visitEnd();
+      }
+      {
+        methodVisitor =
+            classWriter.visitMethod(
+                ACC_PUBLIC | ACC_FINAL | ACC_STATIC,
+                "suspendHere",
+                "(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;",
+                "(Lkotlin/coroutines/Continuation<-Ljava/lang/String;>;)Ljava/lang/Object;",
+                null);
+        {
+          annotationVisitor0 =
+              methodVisitor.visitAnnotation("Lorg/jetbrains/annotations/Nullable;", false);
+          annotationVisitor0.visitEnd();
+        }
+        methodVisitor.visitAnnotableParameterCount(1, false);
+        {
+          annotationVisitor0 =
+              methodVisitor.visitParameterAnnotation(
+                  0, "Lorg/jetbrains/annotations/NotNull;", false);
+          annotationVisitor0.visitEnd();
+        }
+        methodVisitor.visitCode();
+        methodVisitor.visitVarInsn(ALOAD, 0);
+        methodVisitor.visitTypeInsn(INSTANCEOF, "TestKt$suspendHere$1");
+        Label label0 = new Label();
+        methodVisitor.visitJumpInsn(IFEQ, label0);
+        methodVisitor.visitVarInsn(ALOAD, 0);
+        methodVisitor.visitTypeInsn(CHECKCAST, "TestKt$suspendHere$1");
+        methodVisitor.visitVarInsn(ASTORE, 13);
+        methodVisitor.visitVarInsn(ALOAD, 13);
+        methodVisitor.visitFieldInsn(GETFIELD, "TestKt$suspendHere$1", "label", "I");
+        methodVisitor.visitLdcInsn(new Integer(-2147483648));
+        methodVisitor.visitInsn(IAND);
+        methodVisitor.visitJumpInsn(IFEQ, label0);
+        methodVisitor.visitVarInsn(ALOAD, 13);
+        methodVisitor.visitInsn(DUP);
+        methodVisitor.visitFieldInsn(GETFIELD, "TestKt$suspendHere$1", "label", "I");
+        methodVisitor.visitLdcInsn(new Integer(-2147483648));
+        methodVisitor.visitInsn(ISUB);
+        methodVisitor.visitFieldInsn(PUTFIELD, "TestKt$suspendHere$1", "label", "I");
+        Label label1 = new Label();
+        methodVisitor.visitJumpInsn(GOTO, label1);
+        methodVisitor.visitLabel(label0);
+        methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
+        methodVisitor.visitTypeInsn(NEW, "TestKt$suspendHere$1");
+        methodVisitor.visitInsn(DUP);
+        methodVisitor.visitVarInsn(ALOAD, 0);
+        methodVisitor.visitMethodInsn(
+            INVOKESPECIAL,
+            "TestKt$suspendHere$1",
+            "<init>",
+            "(Lkotlin/coroutines/Continuation;)V",
+            false);
+        methodVisitor.visitVarInsn(ASTORE, 13);
+        methodVisitor.visitLabel(label1);
+        methodVisitor.visitFrame(
+            Opcodes.F_FULL,
+            14,
+            new Object[] {
+              "kotlin/coroutines/Continuation",
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              "TestKt$suspendHere$1"
+            },
+            0,
+            new Object[] {});
+        methodVisitor.visitVarInsn(ALOAD, 13);
+        methodVisitor.visitFieldInsn(
+            GETFIELD, "TestKt$suspendHere$1", "result", "Ljava/lang/Object;");
+        methodVisitor.visitVarInsn(ASTORE, 12);
+        Label label2 = new Label();
+        methodVisitor.visitLabel(label2);
+        methodVisitor.visitMethodInsn(
+            INVOKESTATIC,
+            "kotlin/coroutines/intrinsics/IntrinsicsKt",
+            "getCOROUTINE_SUSPENDED",
+            "()Ljava/lang/Object;",
+            false);
+        Label label3 = new Label();
+        methodVisitor.visitLabel(label3);
+        methodVisitor.visitLineNumber(10, label3);
+        methodVisitor.visitVarInsn(ASTORE, 14);
+        methodVisitor.visitVarInsn(ALOAD, 13);
+        methodVisitor.visitFieldInsn(GETFIELD, "TestKt$suspendHere$1", "label", "I");
+        Label label4 = new Label();
+        Label label5 = new Label();
+        Label label6 = new Label();
+        Label label7 = new Label();
+        methodVisitor.visitTableSwitchInsn(0, 2, label7, new Label[] {label4, label5, label6});
+        methodVisitor.visitLabel(label4);
+        methodVisitor.visitFrame(
+            Opcodes.F_FULL,
+            15,
+            new Object[] {
+              "kotlin/coroutines/Continuation",
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              "java/lang/Object",
+              "TestKt$suspendHere$1",
+              "java/lang/Object"
+            },
+            0,
+            new Object[] {});
+        methodVisitor.visitVarInsn(ALOAD, 12);
+        methodVisitor.visitMethodInsn(
+            INVOKESTATIC, "kotlin/ResultKt", "throwOnFailure", "(Ljava/lang/Object;)V", false);
+        methodVisitor.visitInsn(ICONST_0);
+        methodVisitor.visitVarInsn(ISTORE, 1);
+        Label label8 = new Label();
+        methodVisitor.visitLabel(label8);
+        methodVisitor.visitLineNumber(10, label8);
+        methodVisitor.visitLdcInsn("O");
+        methodVisitor.visitVarInsn(ASTORE, 2);
+        Label label9 = new Label();
+        methodVisitor.visitLabel(label9);
+        methodVisitor.visitInsn(ICONST_0);
+        methodVisitor.visitVarInsn(ISTORE, 3);
+        Label label10 = new Label();
+        methodVisitor.visitLabel(label10);
+        methodVisitor.visitLineNumber(18, label10);
+        methodVisitor.visitVarInsn(ALOAD, 13);
+        methodVisitor.visitVarInsn(ALOAD, 2);
+        methodVisitor.visitFieldInsn(PUTFIELD, "TestKt$suspendHere$1", "L$0", "Ljava/lang/Object;");
+        methodVisitor.visitVarInsn(ALOAD, 13);
+        methodVisitor.visitInsn(ICONST_1);
+        methodVisitor.visitFieldInsn(PUTFIELD, "TestKt$suspendHere$1", "label", "I");
+        methodVisitor.visitVarInsn(ALOAD, 13);
+        methodVisitor.visitTypeInsn(CHECKCAST, "kotlin/coroutines/Continuation");
+        methodVisitor.visitVarInsn(ASTORE, 4);
+        Label label11 = new Label();
+        methodVisitor.visitLabel(label11);
+        methodVisitor.visitInsn(ICONST_0);
+        methodVisitor.visitVarInsn(ISTORE, 5);
+        Label label12 = new Label();
+        methodVisitor.visitLabel(label12);
+        methodVisitor.visitLineNumber(19, label12);
+        methodVisitor.visitVarInsn(ALOAD, 4);
+        methodVisitor.visitVarInsn(ASTORE, 6);
+        methodVisitor.visitInsn(ICONST_0);
+        methodVisitor.visitVarInsn(ISTORE, 7);
+        methodVisitor.visitVarInsn(ALOAD, 6);
+        methodVisitor.visitFieldInsn(
+            GETSTATIC, "kotlin/Result", "Companion", "Lkotlin/Result$Companion;");
+        methodVisitor.visitVarInsn(ASTORE, 8);
+        methodVisitor.visitInsn(ICONST_0);
+        methodVisitor.visitVarInsn(ISTORE, 9);
+        methodVisitor.visitVarInsn(ALOAD, 2);
+        methodVisitor.visitMethodInsn(
+            INVOKESTATIC,
+            "kotlin/Result",
+            "constructor-impl",
+            "(Ljava/lang/Object;)Ljava/lang/Object;",
+            false);
+        methodVisitor.visitMethodInsn(
+            INVOKEINTERFACE,
+            "kotlin/coroutines/Continuation",
+            "resumeWith",
+            "(Ljava/lang/Object;)V",
+            true);
+        Label label13 = new Label();
+        methodVisitor.visitLabel(label13);
+        methodVisitor.visitLineNumber(20, label13);
+        methodVisitor.visitMethodInsn(
+            INVOKESTATIC,
+            "kotlin/coroutines/intrinsics/IntrinsicsKt",
+            "getCOROUTINE_SUSPENDED",
+            "()Ljava/lang/Object;",
+            false);
+        Label label14 = new Label();
+        methodVisitor.visitLabel(label14);
+        methodVisitor.visitLineNumber(18, label14);
+        methodVisitor.visitInsn(DUP);
+        methodVisitor.visitMethodInsn(
+            INVOKESTATIC,
+            "kotlin/coroutines/intrinsics/IntrinsicsKt",
+            "getCOROUTINE_SUSPENDED",
+            "()Ljava/lang/Object;",
+            false);
+        Label label15 = new Label();
+        methodVisitor.visitJumpInsn(IF_ACMPNE, label15);
+        methodVisitor.visitVarInsn(ALOAD, 13);
+        methodVisitor.visitTypeInsn(CHECKCAST, "kotlin/coroutines/Continuation");
+        methodVisitor.visitMethodInsn(
+            INVOKESTATIC,
+            "kotlin/coroutines/jvm/internal/DebugProbesKt",
+            "probeCoroutineSuspended",
+            "(Lkotlin/coroutines/Continuation;)V",
+            false);
+        methodVisitor.visitLabel(label15);
+        methodVisitor.visitFrame(
+            Opcodes.F_FULL,
+            15,
+            new Object[] {
+              "kotlin/coroutines/Continuation",
+              Opcodes.INTEGER,
+              "java/lang/String",
+              Opcodes.INTEGER,
+              "kotlin/coroutines/Continuation",
+              Opcodes.INTEGER,
+              "kotlin/coroutines/Continuation",
+              Opcodes.INTEGER,
+              "kotlin/Result$Companion",
+              Opcodes.INTEGER,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              "java/lang/Object",
+              "TestKt$suspendHere$1",
+              "java/lang/Object"
+            },
+            1,
+            new Object[] {"java/lang/Object"});
+        methodVisitor.visitInsn(DUP);
+        methodVisitor.visitVarInsn(ALOAD, 14);
+        Label label16 = new Label();
+        methodVisitor.visitJumpInsn(IF_ACMPNE, label16);
+        Label label17 = new Label();
+        methodVisitor.visitLabel(label17);
+        methodVisitor.visitLineNumber(10, label17);
+        methodVisitor.visitVarInsn(ALOAD, 14);
+        methodVisitor.visitInsn(ARETURN);
+        methodVisitor.visitLabel(label5);
+        methodVisitor.visitFrame(
+            Opcodes.F_FULL,
+            15,
+            new Object[] {
+              "kotlin/coroutines/Continuation",
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              "java/lang/Object",
+              "TestKt$suspendHere$1",
+              "java/lang/Object"
+            },
+            0,
+            new Object[] {});
+        methodVisitor.visitInsn(ICONST_0);
+        methodVisitor.visitVarInsn(ISTORE, 1);
+        methodVisitor.visitInsn(ICONST_0);
+        methodVisitor.visitVarInsn(ISTORE, 3);
+        methodVisitor.visitVarInsn(ALOAD, 13);
+        methodVisitor.visitFieldInsn(GETFIELD, "TestKt$suspendHere$1", "L$0", "Ljava/lang/Object;");
+        methodVisitor.visitTypeInsn(CHECKCAST, "java/lang/String");
+        methodVisitor.visitVarInsn(ASTORE, 2);
+        methodVisitor.visitVarInsn(ALOAD, 12);
+        methodVisitor.visitMethodInsn(
+            INVOKESTATIC, "kotlin/ResultKt", "throwOnFailure", "(Ljava/lang/Object;)V", false);
+        methodVisitor.visitVarInsn(ALOAD, 12);
+        methodVisitor.visitLabel(label16);
+        methodVisitor.visitLineNumber(21, label16);
+        methodVisitor.visitFrame(
+            Opcodes.F_FULL,
+            15,
+            new Object[] {
+              "kotlin/coroutines/Continuation",
+              Opcodes.INTEGER,
+              "java/lang/String",
+              Opcodes.INTEGER,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              "java/lang/Object",
+              "TestKt$suspendHere$1",
+              "java/lang/Object"
+            },
+            1,
+            new Object[] {"java/lang/Object"});
+        methodVisitor.visitInsn(NOP);
+        Label label18 = new Label();
+        methodVisitor.visitLabel(label18);
+        methodVisitor.visitTypeInsn(CHECKCAST, "java/lang/String");
+        Label label19 = new Label();
+        methodVisitor.visitLabel(label19);
+        methodVisitor.visitLineNumber(10, label19);
+        methodVisitor.visitLdcInsn("K");
+        methodVisitor.visitVarInsn(ASTORE, 2);
+        methodVisitor.visitVarInsn(ASTORE, 10);
+        Label label20 = new Label();
+        methodVisitor.visitLabel(label20);
+        methodVisitor.visitInsn(ICONST_0);
+        methodVisitor.visitVarInsn(ISTORE, 3);
+        Label label21 = new Label();
+        methodVisitor.visitLabel(label21);
+        methodVisitor.visitLineNumber(18, label21);
+        methodVisitor.visitVarInsn(ALOAD, 13);
+        methodVisitor.visitVarInsn(ALOAD, 2);
+        methodVisitor.visitFieldInsn(PUTFIELD, "TestKt$suspendHere$1", "L$0", "Ljava/lang/Object;");
+        methodVisitor.visitVarInsn(ALOAD, 13);
+        methodVisitor.visitVarInsn(ALOAD, 10);
+        methodVisitor.visitFieldInsn(PUTFIELD, "TestKt$suspendHere$1", "L$1", "Ljava/lang/Object;");
+        methodVisitor.visitVarInsn(ALOAD, 13);
+        methodVisitor.visitInsn(ICONST_2);
+        methodVisitor.visitFieldInsn(PUTFIELD, "TestKt$suspendHere$1", "label", "I");
+        methodVisitor.visitVarInsn(ALOAD, 13);
+        methodVisitor.visitTypeInsn(CHECKCAST, "kotlin/coroutines/Continuation");
+        methodVisitor.visitVarInsn(ASTORE, 4);
+        Label label22 = new Label();
+        methodVisitor.visitLabel(label22);
+        methodVisitor.visitInsn(ICONST_0);
+        methodVisitor.visitVarInsn(ISTORE, 5);
+        Label label23 = new Label();
+        methodVisitor.visitLabel(label23);
+        methodVisitor.visitLineNumber(19, label23);
+        methodVisitor.visitVarInsn(ALOAD, 4);
+        methodVisitor.visitVarInsn(ASTORE, 6);
+        methodVisitor.visitInsn(ICONST_0);
+        methodVisitor.visitVarInsn(ISTORE, 7);
+        methodVisitor.visitVarInsn(ALOAD, 6);
+        methodVisitor.visitFieldInsn(
+            GETSTATIC, "kotlin/Result", "Companion", "Lkotlin/Result$Companion;");
+        methodVisitor.visitVarInsn(ASTORE, 8);
+        methodVisitor.visitInsn(ICONST_0);
+        methodVisitor.visitVarInsn(ISTORE, 9);
+        methodVisitor.visitVarInsn(ALOAD, 2);
+        methodVisitor.visitMethodInsn(
+            INVOKESTATIC,
+            "kotlin/Result",
+            "constructor-impl",
+            "(Ljava/lang/Object;)Ljava/lang/Object;",
+            false);
+        methodVisitor.visitMethodInsn(
+            INVOKEINTERFACE,
+            "kotlin/coroutines/Continuation",
+            "resumeWith",
+            "(Ljava/lang/Object;)V",
+            true);
+        Label label24 = new Label();
+        methodVisitor.visitLabel(label24);
+        methodVisitor.visitLineNumber(20, label24);
+        methodVisitor.visitMethodInsn(
+            INVOKESTATIC,
+            "kotlin/coroutines/intrinsics/IntrinsicsKt",
+            "getCOROUTINE_SUSPENDED",
+            "()Ljava/lang/Object;",
+            false);
+        Label label25 = new Label();
+        methodVisitor.visitLabel(label25);
+        methodVisitor.visitLineNumber(18, label25);
+        methodVisitor.visitInsn(DUP);
+        methodVisitor.visitMethodInsn(
+            INVOKESTATIC,
+            "kotlin/coroutines/intrinsics/IntrinsicsKt",
+            "getCOROUTINE_SUSPENDED",
+            "()Ljava/lang/Object;",
+            false);
+        Label label26 = new Label();
+        methodVisitor.visitJumpInsn(IF_ACMPNE, label26);
+        methodVisitor.visitVarInsn(ALOAD, 13);
+        methodVisitor.visitTypeInsn(CHECKCAST, "kotlin/coroutines/Continuation");
+        methodVisitor.visitMethodInsn(
+            INVOKESTATIC,
+            "kotlin/coroutines/jvm/internal/DebugProbesKt",
+            "probeCoroutineSuspended",
+            "(Lkotlin/coroutines/Continuation;)V",
+            false);
+        methodVisitor.visitLabel(label26);
+        methodVisitor.visitFrame(
+            Opcodes.F_FULL,
+            15,
+            new Object[] {
+              "kotlin/coroutines/Continuation",
+              Opcodes.INTEGER,
+              "java/lang/String",
+              Opcodes.INTEGER,
+              "kotlin/coroutines/Continuation",
+              Opcodes.INTEGER,
+              "kotlin/coroutines/Continuation",
+              Opcodes.INTEGER,
+              "kotlin/Result$Companion",
+              Opcodes.INTEGER,
+              "java/lang/String",
+              Opcodes.TOP,
+              "java/lang/Object",
+              "TestKt$suspendHere$1",
+              "java/lang/Object"
+            },
+            1,
+            new Object[] {"java/lang/Object"});
+        methodVisitor.visitInsn(DUP);
+        methodVisitor.visitVarInsn(ALOAD, 14);
+        Label label27 = new Label();
+        methodVisitor.visitJumpInsn(IF_ACMPNE, label27);
+        Label label28 = new Label();
+        methodVisitor.visitLabel(label28);
+        methodVisitor.visitLineNumber(10, label28);
+        methodVisitor.visitVarInsn(ALOAD, 14);
+        methodVisitor.visitInsn(ARETURN);
+        methodVisitor.visitLabel(label6);
+        methodVisitor.visitFrame(
+            Opcodes.F_FULL,
+            15,
+            new Object[] {
+              "kotlin/coroutines/Continuation",
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              "java/lang/Object",
+              "TestKt$suspendHere$1",
+              "java/lang/Object"
+            },
+            0,
+            new Object[] {});
+        methodVisitor.visitInsn(ICONST_0);
+        methodVisitor.visitVarInsn(ISTORE, 1);
+        methodVisitor.visitInsn(ICONST_0);
+        methodVisitor.visitVarInsn(ISTORE, 3);
+        methodVisitor.visitVarInsn(ALOAD, 13);
+        methodVisitor.visitFieldInsn(GETFIELD, "TestKt$suspendHere$1", "L$1", "Ljava/lang/Object;");
+        methodVisitor.visitTypeInsn(CHECKCAST, "java/lang/String");
+        methodVisitor.visitVarInsn(ASTORE, 10);
+        methodVisitor.visitVarInsn(ALOAD, 13);
+        methodVisitor.visitFieldInsn(GETFIELD, "TestKt$suspendHere$1", "L$0", "Ljava/lang/Object;");
+        methodVisitor.visitTypeInsn(CHECKCAST, "java/lang/String");
+        methodVisitor.visitVarInsn(ASTORE, 2);
+        methodVisitor.visitVarInsn(ALOAD, 12);
+        methodVisitor.visitMethodInsn(
+            INVOKESTATIC, "kotlin/ResultKt", "throwOnFailure", "(Ljava/lang/Object;)V", false);
+        methodVisitor.visitVarInsn(ALOAD, 12);
+        methodVisitor.visitLabel(label27);
+        methodVisitor.visitLineNumber(21, label27);
+        methodVisitor.visitFrame(
+            Opcodes.F_FULL,
+            15,
+            new Object[] {
+              "kotlin/coroutines/Continuation",
+              Opcodes.INTEGER,
+              "java/lang/String",
+              Opcodes.INTEGER,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              "java/lang/String",
+              Opcodes.TOP,
+              "java/lang/Object",
+              "TestKt$suspendHere$1",
+              "java/lang/Object"
+            },
+            1,
+            new Object[] {"java/lang/Object"});
+        methodVisitor.visitInsn(NOP);
+        Label label29 = new Label();
+        methodVisitor.visitLabel(label29);
+        methodVisitor.visitVarInsn(ASTORE, 11);
+        methodVisitor.visitVarInsn(ALOAD, 10);
+        methodVisitor.visitVarInsn(ALOAD, 11);
+        Label label30 = new Label();
+        methodVisitor.visitLabel(label30);
+        methodVisitor.visitLineNumber(10, label30);
+        methodVisitor.visitMethodInsn(
+            INVOKESTATIC,
+            "kotlin/jvm/internal/Intrinsics",
+            "stringPlus",
+            "(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;",
+            false);
+        methodVisitor.visitInsn(ARETURN);
+        methodVisitor.visitLabel(label7);
+        methodVisitor.visitFrame(
+            Opcodes.F_FULL,
+            15,
+            new Object[] {
+              "kotlin/coroutines/Continuation",
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              Opcodes.TOP,
+              "java/lang/Object",
+              "TestKt$suspendHere$1",
+              "java/lang/Object"
+            },
+            0,
+            new Object[] {});
+        methodVisitor.visitTypeInsn(NEW, "java/lang/IllegalStateException");
+        methodVisitor.visitInsn(DUP);
+        methodVisitor.visitLdcInsn("call to 'resume' before 'invoke' with coroutine");
+        methodVisitor.visitMethodInsn(
+            INVOKESPECIAL,
+            "java/lang/IllegalStateException",
+            "<init>",
+            "(Ljava/lang/String;)V",
+            false);
+        methodVisitor.visitInsn(ATHROW);
+        methodVisitor.visitLocalVariable("v$iv", "Ljava/lang/String;", null, label9, label15, 2);
+        methodVisitor.visitLocalVariable("v$iv", "Ljava/lang/String;", null, label20, label26, 2);
+        methodVisitor.visitLocalVariable(
+            "x$iv", "Lkotlin/coroutines/Continuation;", null, label11, label14, 4);
+        methodVisitor.visitLocalVariable(
+            "x$iv", "Lkotlin/coroutines/Continuation;", null, label22, label25, 4);
+        methodVisitor.visitLocalVariable(
+            "$i$a$-suspendCoroutineUninterceptedOrReturn-TestKt$suspendThere$2$iv",
+            "I",
+            null,
+            label12,
+            label14,
+            5);
+        methodVisitor.visitLocalVariable("$i$f$suspendThere", "I", null, label10, label18, 3);
+        methodVisitor.visitLocalVariable(
+            "$i$a$-suspendCoroutineUninterceptedOrReturn-TestKt$suspendThere$2$iv",
+            "I",
+            null,
+            label23,
+            label25,
+            5);
+        methodVisitor.visitLocalVariable("$i$f$suspendThere", "I", null, label21, label29, 3);
+        methodVisitor.visitLocalVariable("$i$f$suspendHere", "I", null, label8, label7, 1);
+        methodVisitor.visitLocalVariable(
+            "$continuation", "Lkotlin/coroutines/Continuation;", null, label1, label7, 13);
+        methodVisitor.visitLocalVariable("$result", "Ljava/lang/Object;", null, label2, label7, 12);
+        methodVisitor.visitMaxs(3, 15);
+        methodVisitor.visitEnd();
+      }
+      classWriter.visitEnd();
+
+      return classWriter.toByteArray();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromThrowsClauseWithNoShrinkingTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromThrowsClauseWithNoShrinkingTest.java
new file mode 100644
index 0000000..b9d0ef6
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromThrowsClauseWithNoShrinkingTest.java
@@ -0,0 +1,77 @@
+// Copyright (c) 2020, 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.missingclasses;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionMethodContextImpl;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.google.common.collect.ImmutableList;
+import org.junit.Test;
+
+public class MissingClassReferencedFromThrowsClauseWithNoShrinkingTest
+    extends MissingClassesTestBase {
+
+  private static final String NEW_A_DESCRIPTOR = "Lfoo/a;";
+  private static final String NEW_B_DESCRIPTOR = "Lfoo/b;";
+
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionMethodContextImpl.builder()
+          .setMethodContext(
+              Reference.method(
+                  Reference.classFromDescriptor("Lfoo/a;"), "foo", ImmutableList.of(), null))
+          .setOrigin(Origin.unknown())
+          .build();
+
+  public MissingClassReferencedFromThrowsClauseWithNoShrinkingTest(TestParameters parameters) {
+    super(parameters);
+  }
+
+  @Test(expected = CompilationFailedException.class)
+  public void testNoShrinking() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        diagnostics -> inspectDiagnosticsWithNoRules(diagnostics, referencedFrom),
+        b -> {
+          b.addProgramClassFileData(
+              transformer(A.class)
+                  .setClassDescriptor(NEW_A_DESCRIPTOR)
+                  .removeInnerClasses()
+                  .transform(),
+              transformer(B.class)
+                  .setClassDescriptor(NEW_B_DESCRIPTOR)
+                  .removeInnerClasses()
+                  .replaceClassDescriptorInMethodInstructions(descriptor(A.class), NEW_A_DESCRIPTOR)
+                  .transform());
+          b.enableInliningAnnotations();
+          b.addKeepClassAndMembersRules(DescriptorUtils.descriptorToJavaType(NEW_A_DESCRIPTOR));
+          b.noTreeShaking();
+        });
+  }
+
+  public static class Main {
+
+    public static void main(String[] args) {}
+  }
+
+  public static class /* will be: foo.A */ A {
+
+    @NeverInline
+    public static void foo() throws MissingClass {
+      System.out.println("Hello World");
+    }
+  }
+
+  public static class /* will be: foo.B */ B {
+
+    public static void callFoo() {
+      A.foo();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/naming/MapReaderVersionTest.java b/src/test/java/com/android/tools/r8/naming/MapReaderVersionTest.java
new file mode 100644
index 0000000..36916ad
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/MapReaderVersionTest.java
@@ -0,0 +1,85 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.naming;
+
+import static junit.framework.TestCase.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.naming.mappinginformation.MappingInformation;
+import com.android.tools.r8.utils.StringUtils;
+import java.io.IOException;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class MapReaderVersionTest extends TestBase {
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withNoneRuntime().build();
+  }
+
+  public MapReaderVersionTest(TestParameters parameters) {
+    parameters.assertNoneRuntime();
+  }
+
+  @Test
+  public void testNoVersion() throws IOException {
+    ClassNameMapper mapper =
+        ClassNameMapper.mapperFromString(
+            StringUtils.joinLines(
+                "pkg.Foo -> a.a:", "# { id: \"com.android.tools.r8.synthesized\" }"));
+    assertMapping("a.a", "pkg.Foo", false, mapper);
+  }
+
+  @Test
+  public void testExperimentalVersion() throws IOException {
+    ClassNameMapper mapper =
+        ClassNameMapper.mapperFromString(
+            StringUtils.joinLines(
+                "# { id: 'com.android.tools.r8.metainf', map-version: 'experimental' }",
+                "pkg.Foo -> a.a:",
+                "# { id: 'com.android.tools.r8.synthesized' }"));
+    assertMapping("a.a", "pkg.Foo", true, mapper);
+  }
+
+  @Test
+  public void testConcatMapFiles() throws IOException {
+    ClassNameMapper mapper =
+        ClassNameMapper.mapperFromString(
+            StringUtils.joinLines(
+                // Default map-version is none.
+                "pkg.Foo -> a.a:",
+                "# { id: 'com.android.tools.r8.synthesized' }",
+                // Section with map-version experimental.
+                "# { id: 'com.android.tools.r8.metainf', map-version: 'experimental' }",
+                "pkg.Bar -> a.b:",
+                "# { id: 'com.android.tools.r8.synthesized' }",
+                // Section reverting map-version back to none (to support tooling that
+                // concatenates).
+                "# { id: 'com.android.tools.r8.metainf', map-version: 'none' }",
+                "pkg.Baz -> a.c:",
+                "# { id: 'com.android.tools.r8.synthesized' }"));
+    assertMapping("a.a", "pkg.Foo", false, mapper);
+    assertMapping("a.b", "pkg.Bar", true, mapper);
+    assertMapping("a.c", "pkg.Baz", false, mapper);
+  }
+
+  private void assertMapping(
+      String finalName, String originalName, boolean isSynthesized, ClassNameMapper mapper) {
+    ClassNamingForNameMapper naming = mapper.getClassNaming(finalName);
+    assertEquals(originalName, naming.originalName);
+    Assert.assertEquals(isSynthesized, isCompilerSynthesized(naming));
+  }
+
+  private boolean isCompilerSynthesized(ClassNamingForNameMapper naming) {
+    return naming.getAdditionalMappings().stream()
+        .anyMatch(MappingInformation::isCompilerSynthesizedMappingInformation);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/naming/ProguardMapReaderArgumentsTest.java b/src/test/java/com/android/tools/r8/naming/ProguardMapReaderArgumentsTest.java
index 8b68bd2..6c7156d 100644
--- a/src/test/java/com/android/tools/r8/naming/ProguardMapReaderArgumentsTest.java
+++ b/src/test/java/com/android/tools/r8/naming/ProguardMapReaderArgumentsTest.java
@@ -7,37 +7,40 @@
 import static com.android.tools.r8.DiagnosticsMatcher.diagnosticPosition;
 import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
 import static com.android.tools.r8.PositionMatcher.positionLine;
-import static junit.framework.TestCase.assertEquals;
-import static junit.framework.TestCase.assertFalse;
 import static junit.framework.TestCase.assertNotNull;
-import static junit.framework.TestCase.assertTrue;
 import static org.hamcrest.CoreMatchers.allOf;
 import static org.hamcrest.core.StringContains.containsString;
 
+import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestDiagnosticMessagesImpl;
-import com.android.tools.r8.naming.MemberNaming.MethodSignature;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.naming.mappinginformation.MappingInformationDiagnostics;
 import com.android.tools.r8.utils.Reporter;
 import com.android.tools.r8.utils.StringUtils;
 import com.google.common.collect.ImmutableList;
 import java.io.IOException;
-import java.util.List;
-import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
 
-public class ProguardMapReaderArgumentsTest {
+@RunWith(Parameterized.class)
+public class ProguardMapReaderArgumentsTest extends TestBase {
 
-  private Reporter reporter;
-  private TestDiagnosticMessagesImpl testDiagnosticMessages;
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withNoneRuntime().build();
+  }
 
-  @Before
-  public void setUp() {
-    testDiagnosticMessages = new TestDiagnosticMessagesImpl();
-    reporter = new Reporter(testDiagnosticMessages);
+  public ProguardMapReaderArgumentsTest(TestParameters parameters) {
+    parameters.assertNoneRuntime();
   }
 
   @Test
   public void testMethodCanParseMemberComments() throws IOException {
+    TestDiagnosticMessagesImpl testDiagnosticMessages = new TestDiagnosticMessagesImpl();
+    Reporter reporter = new Reporter(testDiagnosticMessages);
     String mapWithArgumentRemovalInformation =
         StringUtils.join(
             "\n",
@@ -69,158 +72,4 @@
                     diagnosticPosition(positionLine(8)))))
         .assertAllInfosMatch(diagnosticType(MappingInformationDiagnostics.class));
   }
-
-  @Test
-  public void testMethodWillReportWhenParsingArgumentsChangedMemberComments() throws IOException {
-    String mapWithArgumentRemovalInformation =
-        StringUtils.join(
-                "\n",
-                "android.constraint.Placeholder -> a.b.b.f:",
-                "# Just a comment", // Regular comment
-                "    int mContentId -> b",
-                // Valid JSON but missing signature
-                "# { 'id': 'methodSignatureChanged', "
-                    + "'signature': ['void', 'updatePreLayout', 'android.constraint.Layout'],"
-                    + "'returnType': [], 'receiver': true, 'params': []}",
-                "    147:161:void updatePreLayout(android.constraint.Layout) -> a",
-                // Valid JSON but not an argumentsChanged object
-                "# { 'id': 'methodSignatureChanged', "
-                    + "'signature': ['void', 'updatePreLayout', 'android.constraint.Layout'],"
-                    + "'returnType': [], 'receiver': true, 'params': []}",
-                "    147:161:void updatePreLayout(android.constraint.Layout) -> a",
-                // Valid JSON but not an arguments_changed object.
-                "# { 'id': 'methodSignatureChanged', "
-                    + "'signature': ['void','updatePreLayout','android.constraint.Layout'],"
-                    + "'returnType': 'foo', 'receiver': 1, 'params': 'foo' }",
-                "    194:204:void updatePostMeasure(android.constraint.Layout) -> a")
-            .replace("'", "\"");
-    ClassNameMapper cnm =
-        ClassNameMapper.mapperFromString(mapWithArgumentRemovalInformation, reporter);
-    ClassNamingForNameMapper classNaming = cnm.getClassNaming("a.b.b.f");
-    assertNotNull(classNaming);
-    testDiagnosticMessages.assertOnlyInfos();
-    testDiagnosticMessages
-        .assertInfosMatch(
-            ImmutableList.of(
-                allOf(
-                    diagnosticMessage(containsString("Could not decode")),
-                    diagnosticPosition(positionLine(4))),
-                allOf(
-                    diagnosticMessage(containsString("Could not decode")),
-                    diagnosticPosition(positionLine(6))),
-                allOf(
-                    diagnosticMessage(containsString("Could not decode")),
-                    diagnosticPosition(positionLine(8)))))
-        .assertAllInfosMatch(diagnosticType(MappingInformationDiagnostics.class));
-  }
-
-  @Test
-  public void testMethodCanParseArgumentRemoval() throws IOException {
-    String mapWithArgumentRemovalInformation =
-        StringUtils.lines(
-            "android.constraint.Placeholder -> a.b.b.f:",
-            "    int mContentId -> b",
-            "# { 'id': 'methodSignatureChanged',"
-                + "'signature': ["
-                + "'void','updatePreLayout','android.constraint.Layout','String','int'],"
-                + " 'returnType': 'void', 'receiver': true, 'params':[[1],[2]]}",
-            "    147:161:void updatePreLayout(android.constraint.Layout,String,int) -> a",
-            "# {'id':'methodSignatureChanged',"
-                + "'signature': ["
-                + "'void','updatePreMeasure','android.constraint.Layout','String','int'],"
-                + "'returnType': 'void', 'receiver': true, 'params':[[3]]}",
-            "    162:173:void updatePreMeasure(android.constraint.Layout,String,int) -> a",
-            "    194:204:void updatePostMeasure(android.constraint.Layout,String,int) -> a");
-    ClassNameMapper cnm = ClassNameMapper.mapperFromString(mapWithArgumentRemovalInformation);
-    ClassNamingForNameMapper classNaming = cnm.getClassNaming("a.b.b.f");
-    assertNotNull(classNaming);
-
-    List<MemberNaming> members = classNaming.lookupByOriginalName("mContentId");
-    assertFalse(members.isEmpty());
-    MemberNaming fieldContentId = members.get(0);
-    assertNotNull(fieldContentId);
-    assertTrue(!fieldContentId.isMethodNaming());
-
-    members = classNaming.lookupByOriginalName("updatePreLayout");
-    assertFalse(members.isEmpty());
-    MemberNaming updatePreLayout = members.get(0);
-    assertNotNull(updatePreLayout);
-    assertTrue(updatePreLayout.isMethodNaming());
-    MethodSignature renamedPreLayout = (MethodSignature) updatePreLayout.getRenamedSignature();
-    assertEquals(1, renamedPreLayout.parameters.length);
-    assertEquals("int", renamedPreLayout.parameters[0]);
-
-    members = classNaming.lookupByOriginalName("updatePreMeasure");
-    assertFalse(members.isEmpty());
-    MemberNaming updatePreMeasure = members.get(0);
-    assertNotNull(updatePreMeasure);
-    assertTrue(updatePreMeasure.isMethodNaming());
-    MethodSignature renamedPreMeasure = (MethodSignature) updatePreMeasure.getRenamedSignature();
-    assertEquals(2, renamedPreMeasure.parameters.length);
-    assertEquals("android.constraint.Layout", renamedPreMeasure.parameters[0]);
-    assertEquals("String", renamedPreMeasure.parameters[1]);
-
-    members = classNaming.lookupByOriginalName("updatePostMeasure");
-    assertFalse(members.isEmpty());
-    MemberNaming updatePostMeasure = members.get(0);
-    assertNotNull(updatePostMeasure);
-    assertTrue(updatePostMeasure.isMethodNaming());
-    MethodSignature renamedPostMeasure = (MethodSignature) updatePostMeasure.getRenamedSignature();
-    assertEquals(3, renamedPostMeasure.parameters.length);
-  }
-
-  @Test
-  public void testMethodCanParseArgumentChanged() throws IOException {
-    String mapWithArgumentRemovalInformation =
-        StringUtils.join(
-            "\n",
-            "android.constraint.Placeholder -> a.b.b.f:",
-            "# {'id':'methodSignatureChanged',"
-                + "'signature':["
-                + "'void','updatePreLayout','android.constraint.Layout','String','float'],"
-                + "'returnType': 'void',"
-                + "'receiver': true,"
-                + "'params':[[1,int],[2,Foo]]}",
-            "# {'id':'methodSignatureChanged',"
-                + "'signature':["
-                + "'void','updatePreMeasure','android.constraint.Layout','String','int'],"
-                + "'returnType': 'void', "
-                + "'receiver': true, "
-                + "'params':[[2,com.baz.Bar],[3]]}",
-            "  147:161:void updatePreLayout(android.constraint.Layout,String,float) -> a",
-            "  162:173:void updatePreMeasure(android.constraint.Layout,String,int) -> a",
-            "  194:204:void updatePostMeasure(android.constraint.Layout,String,int) -> a");
-    ClassNameMapper cnm = ClassNameMapper.mapperFromString(mapWithArgumentRemovalInformation);
-    ClassNamingForNameMapper classNaming = cnm.getClassNaming("a.b.b.f");
-    assertNotNull(classNaming);
-
-    List<MemberNaming> members = classNaming.lookupByOriginalName("updatePreLayout");
-    assertFalse(members.isEmpty());
-    MemberNaming updatePreLayout = members.get(0);
-    assertNotNull(updatePreLayout);
-    assertTrue(updatePreLayout.isMethodNaming());
-    MethodSignature renamedPreLayout = (MethodSignature) updatePreLayout.getRenamedSignature();
-    assertEquals(3, renamedPreLayout.parameters.length);
-    assertEquals("int", renamedPreLayout.parameters[0]);
-    assertEquals("Foo", renamedPreLayout.parameters[1]);
-    assertEquals("float", renamedPreLayout.parameters[2]);
-
-    members = classNaming.lookupByOriginalName("updatePreMeasure");
-    assertFalse(members.isEmpty());
-    MemberNaming updatePreMeasure = members.get(0);
-    assertNotNull(updatePreMeasure);
-    assertTrue(updatePreMeasure.isMethodNaming());
-    MethodSignature renamedPreMeasure = (MethodSignature) updatePreMeasure.getRenamedSignature();
-    assertEquals(2, renamedPreMeasure.parameters.length);
-    assertEquals("android.constraint.Layout", renamedPreMeasure.parameters[0]);
-    assertEquals("com.baz.Bar", renamedPreMeasure.parameters[1]);
-
-    members = classNaming.lookupByOriginalName("updatePostMeasure");
-    assertFalse(members.isEmpty());
-    MemberNaming updatePostMeasure = members.get(0);
-    assertNotNull(updatePostMeasure);
-    assertTrue(updatePostMeasure.isMethodNaming());
-    MethodSignature renamedPostMeasure = (MethodSignature) updatePostMeasure.getRenamedSignature();
-    assertEquals(3, renamedPostMeasure.parameters.length);
-  }
 }
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java b/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java
index 41d1c3f..25cbfbe 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java
@@ -13,14 +13,17 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assume.assumeTrue;
 
+import com.android.tools.r8.SingleTestRunResult;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.naming.retrace.StackTrace;
 import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
 import com.google.common.collect.ImmutableList;
+import java.io.IOException;
 import java.util.Collection;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -51,10 +54,34 @@
 
   @Test
   public void testReference() throws Exception {
-    testForRuntime(parameters)
+    assumeTrue(parameters.isCfRuntime());
+    testForJvm()
         .addInnerClasses(getClass())
         .run(parameters.getRuntime(), Main.class)
-        .assertFailureWithErrorThatMatches(containsString("Hello World!"))
+        .apply(this::checkRunResult)
+        .apply(this::checkNoOutputSynthetics)
+        .inspectStackTrace(
+            stackTrace ->
+                assertThat(
+                    stackTrace,
+                    isSameExceptForFileNameAndLineNumber(
+                        StackTrace.builder()
+                            .addWithoutFileNameAndLineNumber(Main.class, JAVAC_LAMBDA_METHOD)
+                            .addWithoutFileNameAndLineNumber(Main.class, "runIt")
+                            .addWithoutFileNameAndLineNumber(Main.class, "main")
+                            .build())));
+  }
+
+  @Test
+  public void testD8() throws Exception {
+    testForD8(parameters.getBackend())
+        .internalEnableMappingOutput()
+        .addInnerClasses(getClass())
+        .setMinApi(parameters.getApiLevel())
+        .enableExperimentalMapFileVersion()
+        .run(parameters.getRuntime(), Main.class)
+        .apply(this::checkRunResult)
+        .apply(this::checkOneOutputSynthetic)
         .inspectStackTrace(
             stackTrace ->
                 assertThat(
@@ -63,45 +90,14 @@
                         StackTrace.builder()
                             .addWithoutFileNameAndLineNumber(Main.class, JAVAC_LAMBDA_METHOD)
                             // TODO(b/172014416): Support a D8 mapping and prune the synthetic.
-                            .applyIf(
-                                parameters.isDexRuntime(),
-                                b ->
-                                    b.addWithoutFileNameAndLineNumber(
-                                        SyntheticItemsTestUtils.syntheticLambdaClass(Main.class, 0),
-                                        "run"))
+                            .addWithoutFileNameAndLineNumber(
+                                SyntheticItemsTestUtils.syntheticLambdaClass(Main.class, 0), "run")
                             .addWithoutFileNameAndLineNumber(Main.class, "runIt")
                             .addWithoutFileNameAndLineNumber(Main.class, "main")
                             .build())));
   }
 
   @Test
-  public void testMappingInformation() throws Exception {
-    assumeTrue("R8/CF does not desugar", parameters.isDexRuntime());
-    testForR8(parameters.getBackend())
-        .addInnerClasses(getClass())
-        .addKeepAttributeSourceFile()
-        .addKeepAttributeLineNumberTable()
-        .noTreeShaking()
-        .noMinification()
-        .setMinApi(parameters.getApiLevel())
-        .run(parameters.getRuntime(), Main.class)
-        .assertFailureWithErrorThatMatches(containsString("Hello World!"))
-        .inspectFailure(
-            inspector -> {
-              Collection<ClassReference> inputs =
-                  ImmutableList.of(classFromClass(MyRunner.class), classFromClass(Main.class));
-              for (FoundClassSubject clazz : inspector.allClasses()) {
-                if (inputs.contains(clazz.getFinalReference())) {
-                  assertThat(clazz, not(isCompilerSynthesized()));
-                } else {
-                  assertThat(clazz, isCompilerSynthesized());
-                }
-              }
-              assertEquals(inputs.size() + 1, inspector.allClasses().size());
-            });
-  }
-
-  @Test
   public void testEverythingInlined() throws Exception {
     testForR8(parameters.getBackend())
         .addInnerClasses(getClass())
@@ -110,18 +106,25 @@
         .addKeepAttributeLineNumberTable()
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), Main.class)
-        .assertFailureWithErrorThatMatches(containsString("Hello World!"))
+        .apply(this::checkRunResult)
+        .inspectFailure(
+            inspector ->
+                assertEquals(parameters.isCfRuntime() ? 2 : 1, inspector.allClasses().size()))
         .inspectStackTrace(
             stackTrace -> {
               int frames = parameters.isCfRuntime() ? 2 : 1;
               checkRawStackTraceFrameCount(stackTrace, frames, "Expected everything to be inlined");
-              checkCurrentlyIncorrectStackTrace(stackTrace, JAVAC_LAMBDA_METHOD);
+              checkCurrentlyIncorrectStackTrace(stackTrace);
             });
   }
 
   @Test
   public void testNothingInlined() throws Exception {
+    assumeTrue(
+        "Skip R8/CF for min-api > 1 (R8/CF does not desugar)",
+        parameters.isDexRuntime() || parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
     testForR8(parameters.getBackend())
+        .enableExperimentalMapFileVersion()
         .addInnerClasses(getClass())
         .addKeepMainRule(Main.class)
         .addKeepPackageNamesRule(getClass().getPackage())
@@ -130,15 +133,46 @@
         .addKeepAttributeLineNumberTable()
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), Main.class)
-        .assertFailureWithErrorThatMatches(containsString("Hello World!"))
+        .apply(this::checkRunResult)
+        .applyIf(
+            parameters.isCfRuntime(), this::checkNoOutputSynthetics, this::checkOneOutputSynthetic)
         .inspectStackTrace(
             stackTrace -> {
               int frames = parameters.isCfRuntime() ? 3 : 5;
               checkRawStackTraceFrameCount(stackTrace, frames, "Expected nothing to be inlined");
-              checkCurrentlyIncorrectStackTrace(stackTrace, "lambda$main$0");
+              checkCurrentlyIncorrectStackTrace(stackTrace);
             });
   }
 
+  private void checkRunResult(SingleTestRunResult<?> runResult) {
+    runResult.assertFailureWithErrorThatMatches(containsString("Hello World!"));
+  }
+
+  private void checkNoOutputSynthetics(SingleTestRunResult<?> runResult) throws IOException {
+    checkOutputSynthetics(runResult, 0);
+  }
+
+  private void checkOneOutputSynthetic(SingleTestRunResult<?> runResult) throws IOException {
+    checkOutputSynthetics(runResult, 1);
+  }
+
+  private void checkOutputSynthetics(SingleTestRunResult<?> runResult, int expectedSyntheticsCount)
+      throws IOException {
+    runResult.inspectFailure(
+        inspector -> {
+          Collection<ClassReference> inputs =
+              ImmutableList.of(classFromClass(MyRunner.class), classFromClass(Main.class));
+          for (FoundClassSubject clazz : inspector.allClasses()) {
+            if (inputs.contains(clazz.getOriginalReference())) {
+              assertThat(clazz, not(isCompilerSynthesized()));
+            } else {
+              assertThat(clazz, isCompilerSynthesized());
+            }
+          }
+          assertEquals(inputs.size() + expectedSyntheticsCount, inspector.allClasses().size());
+        });
+  }
+
   private void checkRawStackTraceFrameCount(
       StackTrace stackTrace, int expectedFrames, String message) {
     int linesFromTest = 0;
@@ -150,12 +184,12 @@
     assertEquals(message + stackTrace.getOriginalStderr(), expectedFrames, linesFromTest);
   }
 
-  private void checkCurrentlyIncorrectStackTrace(StackTrace stackTrace, String javacLambdaMethod) {
+  private void checkCurrentlyIncorrectStackTrace(StackTrace stackTrace) {
     assertThat(
         stackTrace,
         isSameExceptForFileNameAndLineNumber(
             StackTrace.builder()
-                .addWithoutFileNameAndLineNumber(Main.class, javacLambdaMethod)
+                .addWithoutFileNameAndLineNumber(Main.class, RetraceLambdaTest.JAVAC_LAMBDA_METHOD)
                 .applyIf(
                     parameters.isDexRuntime(),
                     b ->
diff --git a/src/test/java/com/android/tools/r8/testing/ToolHelperTest.java b/src/test/java/com/android/tools/r8/testing/ToolHelperTest.java
index 5492f54..b0e1ab2 100644
--- a/src/test/java/com/android/tools/r8/testing/ToolHelperTest.java
+++ b/src/test/java/com/android/tools/r8/testing/ToolHelperTest.java
@@ -30,9 +30,7 @@
         ToolHelper.getFirstSupportedAndroidJar(AndroidApiLevel.K_WATCH), AndroidApiLevel.L);
     // All android.jar's for API level L are present.
     for (AndroidApiLevel androidApiLevel : AndroidApiLevel.values()) {
-      // TODO(b/181356260): Add AndroidJar for S.
-      if (androidApiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.L)
-          && androidApiLevel.isLessThan(AndroidApiLevel.S)) {
+      if (androidApiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.L)) {
         checkExpectedAndroidJar(
             ToolHelper.getFirstSupportedAndroidJar(androidApiLevel), androidApiLevel);
       }
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 1763108..769760b 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
@@ -26,7 +26,6 @@
 import com.android.tools.r8.naming.MemberNaming;
 import com.android.tools.r8.naming.MemberNaming.FieldSignature;
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
-import com.android.tools.r8.naming.MemberNaming.NoSignature;
 import com.android.tools.r8.naming.MemberNaming.Signature;
 import com.android.tools.r8.naming.mappinginformation.MappingInformation;
 import com.android.tools.r8.naming.signature.GenericSignatureParser;
@@ -46,7 +45,6 @@
 import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
@@ -419,15 +417,7 @@
     if (naming == null) {
       return false;
     }
-    Map<Signature, List<MappingInformation>> additionalMappings = naming.getAdditionalMappings();
-    if (additionalMappings == null) {
-      return false;
-    }
-    List<MappingInformation> infos = additionalMappings.get(NoSignature.NO_SIGNATURE);
-    if (infos == null) {
-      return false;
-    }
-    for (MappingInformation info : infos) {
+    for (MappingInformation info : naming.getAdditionalMappings()) {
       if (info.isCompilerSynthesizedMappingInformation()) {
         return true;
       }
diff --git a/third_party/android_jar/lib-v31.tar.gz.sha1 b/third_party/android_jar/lib-v31.tar.gz.sha1
new file mode 100644
index 0000000..20eb896
--- /dev/null
+++ b/third_party/android_jar/lib-v31.tar.gz.sha1
@@ -0,0 +1 @@
+758bc25bf1aa97fab86205b0dd5db396f9b129cd
\ No newline at end of file