Version 2.1.62

Cherry-pick: Fix non-deternism in class staticizer
CL: https://r8-review.googlesource.com/c/r8/+/52840

Bug: 161727616
Bug: 163097346
Change-Id: I81b04ff8e1dc2ae479d5fe67b2390f5a757ad3ea
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 571ec73..317ddf9 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
 
   // This field is accessed from release scripts using simple pattern matching.
   // Therefore, changing this field could break our release scripts.
-  public static final String LABEL = "2.1.61";
+  public static final String LABEL = "2.1.62";
 
   private Version() {
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizer.java b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizer.java
index 323dd11..19aa4c2 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizer.java
@@ -274,8 +274,8 @@
       if (instruction.isNewInstance()) {
         // Check the class being initialized against valid staticizing candidates.
         NewInstance newInstance = instruction.asNewInstance();
-        CandidateInfo candidateInfo = processInstantiation(context, iterator, newInstance);
-        if (candidateInfo != null) {
+        CandidateInfo info = processInstantiation(context, iterator, newInstance);
+        if (info != null) {
           alreadyProcessed.addAll(newInstance.outValue().aliasedUsers());
           // For host class initializers having eligible instantiation we also want to
           // ensure that the rest of the initializer consist of code w/o side effects.
@@ -283,15 +283,13 @@
           // effects, otherwise we can still staticize, but cannot remove singleton reads.
           while (iterator.hasNext()) {
             if (!isAllowedInHostClassInitializer(context.getHolderType(), iterator.next(), code)) {
-              candidateInfo.preserveRead.set(true);
+              info.preserveRead.set(true);
               iterator.previous();
               break;
             }
             // Ignore just read instruction.
           }
-          referencedFrom
-              .computeIfAbsent(candidateInfo, ignore -> LongLivedProgramMethodSetBuilder.create())
-              .add(context);
+          addReferencedFrom(info, context);
         }
         continue;
       }
@@ -311,9 +309,7 @@
         // Check the field being read: make sure all usages are valid.
         CandidateInfo info = processStaticFieldRead(instruction.asStaticGet());
         if (info != null) {
-          referencedFrom
-              .computeIfAbsent(info, ignore -> LongLivedProgramMethodSetBuilder.create())
-              .add(context);
+          addReferencedFrom(info, context);
           // If the candidate is still valid, ignore all usages in further analysis.
           Value value = instruction.outValue();
           if (value != null) {
@@ -327,9 +323,7 @@
         // Check if it is a static singleton getter.
         CandidateInfo info = processInvokeStatic(instruction.asInvokeStatic());
         if (info != null) {
-          referencedFrom
-              .computeIfAbsent(info, ignore -> LongLivedProgramMethodSetBuilder.create())
-              .add(context);
+          addReferencedFrom(info, context);
           // If the candidate is still valid, ignore all usages in further analysis.
           Value value = instruction.outValue();
           if (value != null) {
@@ -368,6 +362,14 @@
     }
   }
 
+  private void addReferencedFrom(CandidateInfo info, ProgramMethod context) {
+    LongLivedProgramMethodSetBuilder builder =
+        referencedFrom.computeIfAbsent(info, ignore -> LongLivedProgramMethodSetBuilder.create());
+    synchronized (builder) {
+      builder.add(context);
+    }
+  }
+
   private boolean isAllowedInHostClassInitializer(
       DexType host, Instruction insn, IRCode code) {
     return (insn.isStaticPut() && insn.asStaticPut().getField().holder == host) ||