Introduce a clinit field in DexItemFactory

Change-Id: I4cc830861cd048ef633881db4ff9a23363f36388
Bug: 150349055
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java b/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
index 5618178..6b507da 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
@@ -510,13 +510,13 @@
     if (clazz.isProgramClass()) {
       if (lookUpwards) {
         DexEncodedMethod resolutionResult =
-            resolveMethod(type, dexItemFactory().objectMethods.finalize).getSingleTarget();
+            resolveMethod(type, dexItemFactory().objectMembers.finalize).getSingleTarget();
         if (resolutionResult != null && resolutionResult.isProgramMethod(this)) {
           mayHaveFinalizeMethodDirectlyOrIndirectlyCache.put(type, true);
           return true;
         }
       } else {
-        if (clazz.lookupVirtualMethod(dexItemFactory().objectMethods.finalize) != null) {
+        if (clazz.lookupVirtualMethod(dexItemFactory().objectMembers.finalize) != null) {
           mayHaveFinalizeMethodDirectlyOrIndirectlyCache.put(type, true);
           return true;
         }
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index c474718..0fd4536 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -859,7 +859,7 @@
   }
 
   public boolean definesFinalizer(DexItemFactory factory) {
-    return lookupVirtualMethod(factory.objectMethods.finalize) != null;
+    return lookupVirtualMethod(factory.objectMembers.finalize) != null;
   }
 
   public boolean defaultValuesForStaticFieldsMayTriggerAllocation() {
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index 0f317ec..c9491e3 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -406,7 +406,7 @@
       new StringBuildingMethods(stringBufferType);
   public final BooleanMembers booleanMembers = new BooleanMembers();
   public final ObjectsMethods objectsMethods = new ObjectsMethods();
-  public final ObjectMethods objectMethods = new ObjectMethods();
+  public final ObjectMembers objectMembers = new ObjectMembers();
   public final StringMethods stringMethods = new StringMethods();
   public final LongMethods longMethods = new LongMethods();
   public final DoubleMethods doubleMethods = new DoubleMethods();
@@ -595,8 +595,8 @@
   public Map<DexMethod, Predicate<InvokeMethod>> libraryMethodsWithoutSideEffects =
       Streams.<Pair<DexMethod, Predicate<InvokeMethod>>>concat(
               Stream.of(new Pair<>(enumMethods.constructor, alwaysTrue())),
-              Stream.of(new Pair<>(objectMethods.constructor, alwaysTrue())),
-              Stream.of(new Pair<>(objectMethods.getClass, alwaysTrue())),
+              Stream.of(new Pair<>(objectMembers.constructor, alwaysTrue())),
+              Stream.of(new Pair<>(objectMembers.getClass, alwaysTrue())),
               mapToPredicate(classMethods.getNames, alwaysTrue()),
               mapToPredicate(
                   stringBufferMethods.constructorMethods,
@@ -735,7 +735,14 @@
     }
   }
 
-  public class ObjectMethods {
+  public class ObjectMembers {
+
+    /**
+     * This field is not on {@link Object}, but will be synthesized on program classes as a static
+     * field, for the compiler to have a principled way to trigger the initialization of a given
+     * class.
+     */
+    public final DexField clinitField = createField(objectType, intType, "$r8$clinit");
 
     public final DexMethod clone;
     public final DexMethod getClass;
@@ -743,7 +750,7 @@
     public final DexMethod finalize;
     public final DexMethod toString;
 
-    private ObjectMethods() {
+    private ObjectMembers() {
       // The clone method is installed on each array, so one has to use method.match(clone).
       clone = createMethod(objectType, createProto(objectType), cloneMethodName);
       getClass = createMethod(objectDescriptor,
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/modeling/LibraryMethodReadSetModeling.java b/src/main/java/com/android/tools/r8/ir/analysis/modeling/LibraryMethodReadSetModeling.java
index 57f8d2e..34ab168 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/modeling/LibraryMethodReadSetModeling.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/modeling/LibraryMethodReadSetModeling.java
@@ -36,7 +36,7 @@
     // Modeling of other library methods.
     DexType holder = invokedMethod.holder;
     if (holder == dexItemFactory.objectType) {
-      if (invokedMethod == dexItemFactory.objectMethods.constructor) {
+      if (invokedMethod == dexItemFactory.objectMembers.constructor) {
         return EmptyFieldSet.getInstance();
       }
     }
diff --git a/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java b/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
index 69c6281..a8e99cf 100644
--- a/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
@@ -210,7 +210,7 @@
         DexItemFactory dexItemFactory = appInfo.dexItemFactory();
         DexEncodedMethod resolutionResult =
             appInfo
-                .resolveMethod(clazz.type, dexItemFactory.objectMethods.finalize)
+                .resolveMethod(clazz.type, dexItemFactory.objectMembers.finalize)
                 .getSingleTarget();
         return resolutionResult != null && resolutionResult.isProgramMethod(appInfo);
       }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java b/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
index e0043b9..0499be1 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
@@ -157,7 +157,7 @@
     }
 
     if (getInvokedMethod().holder.isArrayType()
-        && getInvokedMethod().match(appView.dexItemFactory().objectMethods.clone)) {
+        && getInvokedMethod().match(appView.dexItemFactory().objectMembers.clone)) {
       return false;
     }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewInstance.java b/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
index a8fa713..de95e53 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
@@ -180,11 +180,11 @@
     // Verify that the object does not have a finalizer.
     DexItemFactory dexItemFactory = appView.dexItemFactory();
     ResolutionResult finalizeResolutionResult =
-        appView.appInfo().resolveMethod(clazz, dexItemFactory.objectMethods.finalize);
+        appView.appInfo().resolveMethod(clazz, dexItemFactory.objectMembers.finalize);
     if (finalizeResolutionResult.isSingleResolution()) {
       DexMethod finalizeMethod = finalizeResolutionResult.getSingleTarget().method;
       if (finalizeMethod != dexItemFactory.enumMethods.finalize
-          && finalizeMethod != dexItemFactory.objectMethods.finalize) {
+          && finalizeMethod != dexItemFactory.objectMembers.finalize) {
         return true;
       }
     }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaConstructorSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaConstructorSourceCode.java
index 2900761..a8161d4 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaConstructorSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaConstructorSourceCode.java
@@ -22,7 +22,7 @@
   @Override
   protected void prepareInstructions() {
     // Super constructor call (always java.lang.Object.<init>()).
-    DexMethod objectInitMethod = factory().objectMethods.constructor;
+    DexMethod objectInitMethod = factory().objectMembers.constructor;
     add(
         builder -> {
           assert builder.getReceiverValue() != null;
@@ -55,7 +55,7 @@
     // be treated as equal, since it only has one call to super constructor,
     // which is always java.lang.Object.<init>().
     return captures().length == 0
-        ? System.identityHashCode(factory().objectMethods.constructor)
+        ? System.identityHashCode(factory().objectMembers.constructor)
         : super.hashCode();
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaConstructorSynthesizedCode.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaConstructorSynthesizedCode.java
index 906e15f..1809d69 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaConstructorSynthesizedCode.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaConstructorSynthesizedCode.java
@@ -22,7 +22,7 @@
   @Override
   public Consumer<UseRegistry> getRegistryCallback() {
     return registry -> {
-      registry.registerInvokeDirect(dexItemFactory().objectMethods.constructor);
+      registry.registerInvokeDirect(dexItemFactory().objectMembers.constructor);
       DexType[] capturedTypes = captures();
       for (int i = 0; i < capturedTypes.length; i++) {
         registry.registerInstanceFieldWrite(lambda.getCaptureField(i));
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/ObjectsMethodRewrites.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/ObjectsMethodRewrites.java
index 911faa5..de16e98 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/backports/ObjectsMethodRewrites.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/ObjectsMethodRewrites.java
@@ -35,7 +35,7 @@
       DexItemFactory factory,
       Set<Value> affectedValues) {
     InvokeVirtual getClass =
-        new InvokeVirtual(factory.objectMethods.getClass, null, invoke.inValues());
+        new InvokeVirtual(factory.objectMembers.getClass, null, invoke.inValues());
     if (invoke.hasOutValue()) {
       affectedValues.addAll(invoke.outValue().affectedValues());
       invoke.outValue().replaceUsers(invoke.inValues().get(0));
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index 80c36cc..d8d503d 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -3280,8 +3280,9 @@
         iterator = isNotNullBlock.listIterator(code);
         iterator.setInsertionPosition(position);
         value = code.createValue(TypeLatticeElement.classClassType(appView, definitelyNotNull()));
-        iterator.add(new InvokeVirtual(dexItemFactory.objectMethods.getClass, value,
-            ImmutableList.of(arguments.get(i))));
+        iterator.add(
+            new InvokeVirtual(
+                dexItemFactory.objectMembers.getClass, value, ImmutableList.of(arguments.get(i))));
         iterator.add(new InvokeVirtual(print, null, ImmutableList.of(out, value)));
       }
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DynamicTypeOptimization.java b/src/main/java/com/android/tools/r8/ir/optimize/DynamicTypeOptimization.java
index e48fb6f..0a314aa 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/DynamicTypeOptimization.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/DynamicTypeOptimization.java
@@ -73,7 +73,7 @@
         }
 
         if (invokedMethod.holder.isArrayType()
-            && invokedMethod.match(appView.dexItemFactory().objectMethods.clone)) {
+            && invokedMethod.match(appView.dexItemFactory().objectMembers.clone)) {
           dynamicUpperBoundType =
               TypeLatticeElement.fromDexType(invokedMethod.holder, definitelyNotNull(), appView);
           dynamicLowerBoundType = null;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
index 0403117..c9bf058 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -757,7 +757,7 @@
           DexMethod requireNonNullMethod = appView.dexItemFactory().objectsMethods.requireNonNull;
           iterator.add(new InvokeStatic(requireNonNullMethod, null, ImmutableList.of(receiver)));
         } else {
-          DexMethod getClassMethod = appView.dexItemFactory().objectMethods.getClass;
+          DexMethod getClassMethod = appView.dexItemFactory().objectMembers.getClass;
           iterator.add(new InvokeVirtual(getClassMethod, null, ImmutableList.of(receiver)));
         }
       } else {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
index a28181f..48b8637 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
@@ -382,7 +382,7 @@
       DexMethod requireNonNullMethod = appView.dexItemFactory().objectsMethods.requireNonNull;
       replacement = new InvokeStatic(requireNonNullMethod, null, ImmutableList.of(receiver));
     } else {
-      DexMethod getClassMethod = appView.dexItemFactory().objectMethods.getClass;
+      DexMethod getClassMethod = appView.dexItemFactory().objectMembers.getClass;
       replacement = new InvokeVirtual(getClassMethod, null, ImmutableList.of(receiver));
     }
     iterator.replaceCurrentInstruction(replacement);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
index fa41f21..055eeca 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
@@ -83,7 +83,7 @@
     DexItemFactory dexItemFactory = appView.dexItemFactory();
     DexMethod invokedMethod = invoke.getInvokedMethod();
     // Class<?> Object#getClass() is final and cannot be overridden.
-    if (invokedMethod != dexItemFactory.objectMethods.getClass) {
+    if (invokedMethod != dexItemFactory.objectMembers.getClass) {
       return null;
     }
     Value in = invoke.getReceiver();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
index 291f4d5..6707fe1 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
@@ -343,7 +343,7 @@
     DexItemFactory dexItemFactory = appView.dexItemFactory();
     for (DexEncodedMethod method : clazz.virtualMethods()) {
       if (method.method.name == dexItemFactory.finalizeMethodName
-          && method.method.proto == dexItemFactory.objectMethods.finalize.proto) {
+          && method.method.proto == dexItemFactory.objectMembers.finalize.proto) {
         return EligibilityStatus.HAS_FINALIZER;
       }
     }
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 5612322..22344de 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
@@ -446,7 +446,7 @@
             }
 
             DexMethod invokedMethod = invoke.getInvokedMethod();
-            if (invokedMethod == dexItemFactory.objectMethods.constructor) {
+            if (invokedMethod == dexItemFactory.objectMembers.constructor) {
               continue;
             }
 
@@ -498,7 +498,7 @@
         if (instruction.isInvokeMethodWithReceiver()) {
           InvokeMethodWithReceiver invoke = instruction.asInvokeMethodWithReceiver();
           DexMethod invokedMethod = invoke.getInvokedMethod();
-          if (invokedMethod == dexItemFactory.objectMethods.constructor) {
+          if (invokedMethod == dexItemFactory.objectMembers.constructor) {
             continue;
           }
 
@@ -557,7 +557,7 @@
         // Remove the call to java.lang.Object.<init>().
         if (user.isInvokeDirect()) {
           if (root.isNewInstance()
-              && invoke.getInvokedMethod() == dexItemFactory.objectMethods.constructor) {
+              && invoke.getInvokedMethod() == dexItemFactory.objectMembers.constructor) {
             removeInstruction(invoke);
             continue;
           }
@@ -743,7 +743,7 @@
 
     // Check that the entire constructor chain can be inlined into the current context.
     DexMethod parent = instanceInitializerInfo.getParent();
-    while (parent != dexItemFactory.objectMethods.constructor) {
+    while (parent != dexItemFactory.objectMembers.constructor) {
       if (parent == null) {
         return null;
       }
@@ -1177,7 +1177,7 @@
   }
 
   private boolean isInstanceInitializerEligibleForClassInlining(DexMethod method) {
-    if (method == dexItemFactory.objectMethods.constructor) {
+    if (method == dexItemFactory.objectMembers.constructor) {
       return true;
     }
     DexEncodedMethod encodedMethod = appView.definitionFor(method);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java
index 908d125..30766c5 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java
@@ -107,7 +107,7 @@
           DexEncodedMethod singleTarget =
               appView
                   .appInfo()
-                  .resolveMethodOnClass(valueInfo.type, factory.objectMethods.toString)
+                  .resolveMethodOnClass(valueInfo.type, factory.objectMembers.toString)
                   .getSingleTarget();
           if (singleTarget != null && singleTarget.method != factory.enumMethods.toString) {
             continue;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
index d015712..9213a28 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
@@ -517,7 +517,7 @@
                 }
                 // java.lang.Enum.<init>() and java.lang.Object.<init>() are considered trivial.
                 if (invokedMethod == dexItemFactory.enumMethods.constructor
-                    || invokedMethod == dexItemFactory.objectMethods.constructor) {
+                    || invokedMethod == dexItemFactory.objectMembers.constructor) {
                   builder.setParent(invokedMethod);
                   break;
                 }
@@ -984,12 +984,12 @@
         ResolutionResult resolutionResult =
             appView
                 .appInfo()
-                .resolveMethodOnClass(clazz, appView.dexItemFactory().objectMethods.finalize);
+                .resolveMethodOnClass(clazz, appView.dexItemFactory().objectMembers.finalize);
 
         DexEncodedMethod target = resolutionResult.getSingleTarget();
         if (target != null
             && target.method != dexItemFactory.enumMethods.finalize
-            && target.method != dexItemFactory.objectMethods.finalize) {
+            && target.method != dexItemFactory.objectMembers.finalize) {
             return true;
         }
         return false;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/JStyleLambdaGroup.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/JStyleLambdaGroup.java
index df6f812..fbd189c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/JStyleLambdaGroup.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/JStyleLambdaGroup.java
@@ -170,7 +170,7 @@
         throws LambdaStructureError {
       if (!(instructions[index] instanceof com.android.tools.r8.code.InvokeDirect
               || instructions[index] instanceof com.android.tools.r8.code.InvokeDirectRange)
-          || instructions[index].getMethod() != kotlin.factory.objectMethods.constructor) {
+          || instructions[index].getMethod() != kotlin.factory.objectMembers.constructor) {
         throw structureError(LAMBDA_INIT_CODE_VERIFICATION_FAILED);
       }
       index++;
@@ -218,7 +218,7 @@
         DexMethod method,
         Position callerPosition) {
       super(lambdaGroupType, idField, fieldGenerator, method, callerPosition);
-      this.objectInitializer = factory.objectMethods.constructor;
+      this.objectInitializer = factory.objectMembers.constructor;
     }
 
     @Override
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 5af6c6f..8978657 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
@@ -591,7 +591,7 @@
             assert user.isInvokeDirect();
             if (ignoreSuperClassInitInvoke
                 && ListUtils.lastIndexMatching(invoke.inValues(), isAliasedValue) == 0
-                && methodReferenced == factory.objectMethods.constructor) {
+                && methodReferenced == factory.objectMembers.constructor) {
               // If we are inside candidate constructor and analyzing usages
               // of the receiver, we want to ignore invocations of superclass
               // constructor which will be removed after staticizing.