Fix non-deternism in class staticizer

Bug: 161727616
Bug: 163097346
Change-Id: Id640b20abbe86691740bf4c647fe79a704a1a376
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) ||