Clean-up parsing kotlin metadata to not throw exception in thread

Bug: b/267334465
Change-Id: I42c5e986d3b0ea9448bc7a6512934283f88f92c9
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
index 7bae38e..a9d515a 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin;
 
+import static com.android.tools.r8.kotlin.KotlinMetadataUtils.getInvalidKotlinInfo;
 import static com.android.tools.r8.kotlin.KotlinMetadataUtils.getNoKotlinInfo;
 import static com.android.tools.r8.kotlin.KotlinSyntheticClassInfo.getFlavour;
 
@@ -18,9 +19,11 @@
 import com.android.tools.r8.graph.DexValue;
 import com.android.tools.r8.graph.DexValue.DexValueArray;
 import com.android.tools.r8.kotlin.KotlinSyntheticClassInfo.Flavour;
+import com.android.tools.r8.utils.StringDiagnostic;
 import java.util.IdentityHashMap;
 import java.util.Map;
 import java.util.function.Consumer;
+import java.util.function.Supplier;
 import kotlin.Metadata;
 import kotlinx.metadata.InconsistentKotlinMetadataException;
 import kotlinx.metadata.jvm.KotlinClassMetadata;
@@ -34,16 +37,58 @@
   private static final int SYNTHETIC_CLASS_KIND = 3;
 
   public static KotlinClassLevelInfo getKotlinInfo(
-      DexClass clazz, AppView<?> appView, Consumer<DexEncodedMethod> keepByteCode)
-      throws KotlinMetadataException {
+      AppView<?> appView,
+      DexClass clazz,
+      Consumer<DexEncodedMethod> keepByteCode,
+      Supplier<Boolean> reportUnknownMetadata) {
     DexAnnotation meta =
         clazz.annotations().getFirstMatching(appView.dexItemFactory().kotlinMetadataType);
-    return meta != null ? getKotlinInfo(clazz, appView, keepByteCode, meta) : getNoKotlinInfo();
+    if (meta == null) {
+      return getNoKotlinInfo();
+    }
+    return getKotlinInfoFromAnnotation(appView, clazz, meta, keepByteCode, reportUnknownMetadata);
   }
 
-  public static KotlinClassLevelInfo getKotlinInfo(
-      DexClass clazz,
+  public static KotlinClassLevelInfo getKotlinInfoFromAnnotation(
       AppView<?> appView,
+      DexClass clazz,
+      DexAnnotation meta,
+      Consumer<DexEncodedMethod> keepByteCode,
+      Supplier<Boolean> reportUnknownMetadata) {
+    try {
+      return getKotlinInfo(appView, clazz, keepByteCode, meta);
+    } catch (KotlinMetadataException e) {
+      if (reportUnknownMetadata.get()) {
+        appView.reporter().warning(KotlinMetadataDiagnostic.unknownMetadataVersion());
+      }
+      appView
+          .reporter()
+          .info(
+              new StringDiagnostic(
+                  "Class "
+                      + clazz.type.toSourceString()
+                      + " has malformed kotlin.Metadata: "
+                      + e.getMessage()));
+      return getInvalidKotlinInfo();
+    } catch (Throwable e) {
+      if (reportUnknownMetadata.get()) {
+        appView.reporter().warning(KotlinMetadataDiagnostic.unknownMetadataVersion());
+      }
+      appView
+          .reporter()
+          .info(
+              new StringDiagnostic(
+                  "Unexpected error while reading "
+                      + clazz.type.toSourceString()
+                      + "'s kotlin.Metadata: "
+                      + e.getMessage()));
+      return getNoKotlinInfo();
+    }
+  }
+
+  private static KotlinClassLevelInfo getKotlinInfo(
+      AppView<?> appView,
+      DexClass clazz,
       Consumer<DexEncodedMethod> keepByteCode,
       DexAnnotation annotation)
       throws KotlinMetadataException {
@@ -55,8 +100,8 @@
     return createKotlinInfo(kotlin, clazz, kMetadata, appView, keepByteCode);
   }
 
-  public static boolean isLambda(AppView<?> appView, DexClass clazz)
-      throws KotlinMetadataException {
+  public static boolean isLambda(
+      AppView<?> appView, DexClass clazz, Supplier<Boolean> reportUnknownMetadata) {
     DexItemFactory dexItemFactory = appView.dexItemFactory();
     Kotlin kotlin = dexItemFactory.kotlin;
     Flavour flavour = getFlavour(clazz, kotlin);
@@ -69,16 +114,31 @@
       return false;
     }
     Map<DexString, DexAnnotationElement> elementMap = toElementMap(metadataAnnotation.annotation);
-    if (getKind(kotlin, elementMap) == SYNTHETIC_CLASS_KIND) {
-      KotlinClassMetadata kMetadata = toKotlinClassMetadata(kotlin, elementMap);
-      if (kMetadata instanceof SyntheticClass) {
-        return ((SyntheticClass) kMetadata).isLambda();
+    try {
+      if (getKind(kotlin, elementMap) == SYNTHETIC_CLASS_KIND) {
+        KotlinClassMetadata kMetadata = toKotlinClassMetadata(kotlin, elementMap);
+        if (kMetadata instanceof SyntheticClass) {
+          return ((SyntheticClass) kMetadata).isLambda();
+        }
       }
+      assert toKotlinClassMetadata(kotlin, elementMap) instanceof SyntheticClass
+              == (getKind(kotlin, elementMap) == SYNTHETIC_CLASS_KIND)
+          : "Synthetic class kinds should agree";
+      return false;
+    } catch (KotlinMetadataException exception) {
+      if (reportUnknownMetadata.get()) {
+        appView.reporter().warning(KotlinMetadataDiagnostic.unknownMetadataVersion());
+      }
+      appView
+          .reporter()
+          .info(
+              new StringDiagnostic(
+                  "Class "
+                      + clazz.type.toSourceString()
+                      + " has malformed kotlin.Metadata: "
+                      + exception.getMessage()));
+      return false;
     }
-    assert toKotlinClassMetadata(kotlin, elementMap) instanceof SyntheticClass
-            == (getKind(kotlin, elementMap) == SYNTHETIC_CLASS_KIND)
-        : "Synthetic class kinds should agree";
-    return false;
   }
 
   public static boolean hasKotlinClassMetadataAnnotation(
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java
index 6b5d589..dd7f94a 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java
@@ -5,7 +5,6 @@
 package com.android.tools.r8.kotlin;
 
 import static com.android.tools.r8.kotlin.KotlinClassMetadataReader.hasKotlinClassMetadataAnnotation;
-import static com.android.tools.r8.kotlin.KotlinMetadataUtils.getInvalidKotlinInfo;
 import static com.android.tools.r8.kotlin.KotlinMetadataUtils.getNoKotlinInfo;
 
 import com.android.tools.r8.errors.Unreachable;
@@ -27,9 +26,9 @@
 import com.android.tools.r8.shaking.Enqueuer;
 import com.android.tools.r8.shaking.Enqueuer.EnqueuerDefinitionSupplier;
 import com.android.tools.r8.shaking.KeepClassInfo;
-import com.android.tools.r8.utils.StringDiagnostic;
 import com.google.common.collect.Sets;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 public class KotlinMetadataEnqueuerExtension extends EnqueuerAnalysis {
 
@@ -38,7 +37,7 @@
   private final AppView<?> appView;
   private final EnqueuerDefinitionSupplier enqueuerDefinitionSupplier;
   private final Set<DexType> prunedTypes;
-  private boolean reportedUnknownMetadataVersion;
+  private final AtomicBoolean reportedUnknownMetadataVersion = new AtomicBoolean(false);
 
   public KotlinMetadataEnqueuerExtension(
       AppView<?> appView,
@@ -69,52 +68,30 @@
       enqueuer.forAllLiveClasses(
           clazz -> {
             assert clazz.getKotlinInfo().isNoKotlinInformation();
-            try {
-              if (enqueuer
-                  .getKeepInfo(clazz)
-                  .isKotlinMetadataRemovalAllowed(appView.options(), keepKotlinMetadata)) {
-                if (KotlinClassMetadataReader.isLambda(appView, clazz)
-                    && clazz.hasClassInitializer()) {
-                  feedback.classInitializerMayBePostponed(clazz.getClassInitializer());
-                }
-                clazz.clearKotlinInfo();
-                clazz.removeAnnotations(
-                    annotation ->
-                        annotation.getAnnotationType()
-                            == appView.dexItemFactory().kotlinMetadataType);
-              } else {
-                clazz.setKotlinInfo(
-                    KotlinClassMetadataReader.getKotlinInfo(
-                        clazz,
-                        appView,
-                        method -> keepByteCodeFunctions.add(method.getReference())));
-                if (clazz.getEnclosingMethodAttribute() != null
-                    && clazz.getEnclosingMethodAttribute().getEnclosingMethod() != null) {
-                  localOrAnonymousClasses.add(clazz);
-                }
+            if (enqueuer
+                .getKeepInfo(clazz)
+                .isKotlinMetadataRemovalAllowed(appView.options(), keepKotlinMetadata)) {
+              if (KotlinClassMetadataReader.isLambda(
+                      appView, clazz, () -> reportedUnknownMetadataVersion.getAndSet(true))
+                  && clazz.hasClassInitializer()) {
+                feedback.classInitializerMayBePostponed(clazz.getClassInitializer());
               }
-            } catch (KotlinMetadataException e) {
-              appView
-                  .reporter()
-                  .info(
-                      new StringDiagnostic(
-                          "Class "
-                              + clazz.type.toSourceString()
-                              + " has malformed kotlin.Metadata: "
-                              + e.getMessage()));
-              clazz.setKotlinInfo(getInvalidKotlinInfo());
-              reportUnknownMetadataVersion();
-            } catch (Throwable e) {
-              appView
-                  .reporter()
-                  .info(
-                      new StringDiagnostic(
-                          "Unexpected error while reading "
-                              + clazz.type.toSourceString()
-                              + "'s kotlin.Metadata: "
-                              + e.getMessage()));
-              clazz.setKotlinInfo(getNoKotlinInfo());
-              reportUnknownMetadataVersion();
+              clazz.clearKotlinInfo();
+              clazz.removeAnnotations(
+                  annotation ->
+                      annotation.getAnnotationType()
+                          == appView.dexItemFactory().kotlinMetadataType);
+            } else {
+              clazz.setKotlinInfo(
+                  KotlinClassMetadataReader.getKotlinInfo(
+                      appView,
+                      clazz,
+                      method -> keepByteCodeFunctions.add(method.getReference()),
+                      () -> reportedUnknownMetadataVersion.getAndSet(true)));
+              if (clazz.getEnclosingMethodAttribute() != null
+                  && clazz.getEnclosingMethodAttribute().getEnclosingMethod() != null) {
+                localOrAnonymousClasses.add(clazz);
+              }
             }
           });
       for (DexProgramClass localOrAnonymousClass : localOrAnonymousClasses) {
@@ -167,13 +144,6 @@
         });
   }
 
-  private void reportUnknownMetadataVersion() {
-    if (!reportedUnknownMetadataVersion) {
-      reportedUnknownMetadataVersion = true;
-      appView.reporter().warning(KotlinMetadataDiagnostic.unknownMetadataVersion());
-    }
-  }
-
   public class KotlinMetadataDefinitionSupplier implements DexDefinitionSupplier {
 
     private final ProgramDefinition context;
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
index e57fc63..858a57c 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
@@ -20,6 +20,7 @@
 import com.android.tools.r8.graph.DexValue.DexValueArray;
 import com.android.tools.r8.graph.DexValue.DexValueInt;
 import com.android.tools.r8.graph.DexValue.DexValueString;
+import com.android.tools.r8.utils.BooleanBox;
 import com.android.tools.r8.utils.ConsumerUtils;
 import com.android.tools.r8.utils.Pair;
 import com.android.tools.r8.utils.ThreadUtils;
@@ -130,6 +131,7 @@
       return;
     }
     final WriteMetadataFieldInfo writeMetadataFieldInfo = WriteMetadataFieldInfo.rewriteAll();
+    BooleanBox reportedUnknownMetadataVersion = new BooleanBox();
     ThreadUtils.processItems(
         appView.appInfo().classes(),
         clazz -> {
@@ -138,8 +140,12 @@
             return;
           }
           KotlinClassLevelInfo kotlinInfo =
-              KotlinClassMetadataReader.getKotlinInfo(
-                  clazz, appView, ConsumerUtils.emptyConsumer(), metadata);
+              KotlinClassMetadataReader.getKotlinInfoFromAnnotation(
+                  appView,
+                  clazz,
+                  metadata,
+                  ConsumerUtils.emptyConsumer(),
+                  reportedUnknownMetadataVersion::getAndSet);
           if (kotlinInfo == getNoKotlinInfo()) {
             return;
           }
diff --git a/src/main/java/com/android/tools/r8/utils/BooleanBox.java b/src/main/java/com/android/tools/r8/utils/BooleanBox.java
index 5ad9494..554176e 100644
--- a/src/main/java/com/android/tools/r8/utils/BooleanBox.java
+++ b/src/main/java/com/android/tools/r8/utils/BooleanBox.java
@@ -59,4 +59,10 @@
   public boolean isAssigned() {
     return assigned;
   }
+
+  public Boolean getAndSet() {
+    boolean current = get();
+    set();
+    return current;
+  }
 }