Maintain method optimization info for staticized methods.

Although `this` pointer is removed, code itself is not changed, and thus
we can maintain some of method optimization info, e.g., anythings that
are about method's return, like constant, nullability, dynamic types, etc.

Bug: 120920488, 142401154
Change-Id: Ia21bf322c50b5490ca0e3cf55e82d4121f27e981
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 09a2c32..200240c 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -1008,7 +1008,10 @@
     checkIfObsolete();
     assert !accessFlags.isStatic();
     Builder builder =
-        builder(this).promoteToStatic().unsetOptimizationInfo().withoutThisParameter();
+        builder(this)
+            .promoteToStatic()
+            .withoutThisParameter()
+            .adjustOptimizationInfoAfterRemovingThisParameter();
     DexEncodedMethod method = builder.build();
     method.copyMetadata(this);
     setObsolete();
@@ -1271,11 +1274,6 @@
       return this;
     }
 
-    public Builder unsetOptimizationInfo() {
-      optimizationInfo = DefaultMethodOptimizationInfo.DEFAULT_INSTANCE;
-      return this;
-    }
-
     public Builder withoutThisParameter() {
       assert code != null;
       if (code.isDexCode()) {
@@ -1286,6 +1284,14 @@
       return this;
     }
 
+    public Builder adjustOptimizationInfoAfterRemovingThisParameter() {
+      if (optimizationInfo.isUpdatableMethodOptimizationInfo()) {
+        optimizationInfo.asUpdatableMethodOptimizationInfo()
+            .adjustOptimizationInfoAfterRemovingThisParameter();
+      }
+      return this;
+    }
+
     public void setCode(Code code) {
       this.code = code;
     }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
index 3279d51..9283234 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
@@ -37,8 +37,8 @@
   static ParameterUsagesInfo UNKNOWN_PARAMETER_USAGE_INFO = null;
   static boolean UNKNOWN_MAY_HAVE_SIDE_EFFECTS = true;
   static boolean UNKNOWN_RETURN_VALUE_ONLY_DEPENDS_ON_ARGUMENTS = false;
-  private static BitSet NO_NULL_PARAMETER_OR_THROW_FACTS = null;
-  private static BitSet NO_NULL_PARAMETER_ON_NORMAL_EXITS_FACTS = null;
+  static BitSet NO_NULL_PARAMETER_OR_THROW_FACTS = null;
+  static BitSet NO_NULL_PARAMETER_ON_NORMAL_EXITS_FACTS = null;
 
   private DefaultMethodOptimizationInfo() {}
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/UpdatableMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/UpdatableMethodOptimizationInfo.java
index 4a34157..06e7332 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/UpdatableMethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/UpdatableMethodOptimizationInfo.java
@@ -66,7 +66,8 @@
   // invocation with null throwing code if an always-null argument is passed. Also used by Inliner
   // to give a credit to null-safe code, e.g., Kotlin's null safe argument.
   // Note that this bit set takes into account the receiver for instance methods.
-  private BitSet nonNullParamOrThrow = null;
+  private BitSet nonNullParamOrThrow =
+      DefaultMethodOptimizationInfo.NO_NULL_PARAMETER_OR_THROW_FACTS;
   // Stores information about nullability facts per parameter. If set, that means, the method
   // somehow (e.g., null check, such as arg != null, or NPE-throwing instructions such as array
   // access or another invocation) ensures the corresponding parameter is not null, and that is
@@ -74,7 +75,8 @@
   // normally, the recorded parameter is definitely not null. These facts are used to propagate
   // non-null information through {@link NonNullTracker}.
   // Note that this bit set takes into account the receiver for instance methods.
-  private BitSet nonNullParamOnNormalExits = null;
+  private BitSet nonNullParamOnNormalExits =
+      DefaultMethodOptimizationInfo.NO_NULL_PARAMETER_ON_NORMAL_EXITS_FACTS;
   private boolean reachabilitySensitive = false;
   private boolean returnValueHasBeenPropagated = false;
 
@@ -435,4 +437,53 @@
     assert this != DefaultMethodOptimizationInfo.DEFAULT_INSTANCE;
     return new UpdatableMethodOptimizationInfo(this);
   }
+
+  public void adjustOptimizationInfoAfterRemovingThisParameter() {
+    // cannotBeKept: doesn't depend on `this`
+    // classInitializerMayBePostponed: `this` could trigger <clinit> of the previous holder.
+    classInitializerMayBePostponed = false;
+    // hasBeenInlinedIntoSingleCallSite: then it should not be staticized.
+    hasBeenInlinedIntoSingleCallSite = false;
+    // initializedClassesOnNormalExit: `this` could trigger <clinit> of the previous holder.
+    initializedClassesOnNormalExit =
+        DefaultMethodOptimizationInfo.UNKNOWN_INITIALIZED_CLASSES_ON_NORMAL_EXIT;
+    // TODO(b/142401154): adjustable
+    returnedArgument = DefaultMethodOptimizationInfo.UNKNOWN_RETURNED_ARGUMENT;
+    // mayHaveSideEffects: `this` Argument didn't have side effects, so removing it doesn't affect
+    //   whether or not the method may have side effects.
+    // returnValueOnlyDependsOnArguments:
+    //   if the method did before, so it does even after removing `this` Argument
+    // code is not changed, and thus the following *return* info is not changed either.
+    //   * neverReturnsNull
+    //   * neverReturnsNormally
+    //   * returnsConstantNumber
+    //   * returnedConstantNumber
+    //   * returnsConstantString
+    //   * returnedConstantString
+    //   * returnsObjectOfType
+    //   * returnsObjectWithLowerBoundType
+    // inlining: it is not inlined, and thus staticized. No more chance of inlining, though.
+    inlining = InlinePreference.Default;
+    // useIdentifierNameString: code is not changed.
+    // checksNullReceiverBeforeAnySideEffect: no more receiver.
+    checksNullReceiverBeforeAnySideEffect =
+        DefaultMethodOptimizationInfo.UNKNOWN_CHECKS_NULL_RECEIVER_BEFORE_ANY_SIDE_EFFECT;
+    // triggersClassInitBeforeAnySideEffect: code is not changed.
+    triggersClassInitBeforeAnySideEffect =
+        DefaultMethodOptimizationInfo.UNKNOWN_TRIGGERS_CLASS_INIT_BEFORE_ANY_SIDE_EFFECT;
+    // classInlinerEligibility: chances are the method is not an instance method anymore.
+    classInlinerEligibility = DefaultMethodOptimizationInfo.UNKNOWN_CLASS_INLINER_ELIGIBILITY;
+    // trivialInitializerInfo: chances are the enclosing class is
+    trivialInitializerInfo = DefaultMethodOptimizationInfo.UNKNOWN_TRIVIAL_INITIALIZER;
+    // initializerEnablingJavaAssertions: `this` could trigger <clinit> of the previous holder.
+    initializerEnablingJavaAssertions =
+        DefaultMethodOptimizationInfo.UNKNOWN_INITIALIZER_ENABLING_JAVA_ASSERTIONS;
+    // TODO(b/142401154): adjustable
+    parametersUsages = DefaultMethodOptimizationInfo.UNKNOWN_PARAMETER_USAGE_INFO;
+    nonNullParamOrThrow = DefaultMethodOptimizationInfo.NO_NULL_PARAMETER_OR_THROW_FACTS;
+    nonNullParamOnNormalExits =
+        DefaultMethodOptimizationInfo.NO_NULL_PARAMETER_ON_NORMAL_EXITS_FACTS;
+    // reachabilitySensitive: doesn't depend on `this`
+    // returnValueHasBeenPropagated: doesn't depend on `this`
+  }
 }