Version 2.0.50

Cherry pick: Fix instance initializer escape analysis
CL: https://r8-review.googlesource.com/c/r8/+/49594/

This also merges the AliasedValueConfiguration from master, which is a prerequisite for the above cherry-pick.

Change-Id: I2f5c2f0aa7fe601f52f9347ced94fb4b33010a1d
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index b78cf12..7d55176 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.0.49";
+  public static final String LABEL = "2.0.50";
 
   private Version() {
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/AliasedValueConfiguration.java b/src/main/java/com/android/tools/r8/ir/code/AliasedValueConfiguration.java
new file mode 100644
index 0000000..008d363
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/code/AliasedValueConfiguration.java
@@ -0,0 +1,12 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.code;
+
+public interface AliasedValueConfiguration {
+
+  boolean isIntroducingAnAlias(Instruction instruction);
+
+  Value getAliasForOutValue(Instruction instruction);
+}
diff --git a/src/main/java/com/android/tools/r8/ir/code/AssumeAndCheckCastAliasedValueConfiguration.java b/src/main/java/com/android/tools/r8/ir/code/AssumeAndCheckCastAliasedValueConfiguration.java
new file mode 100644
index 0000000..8a6517b
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/code/AssumeAndCheckCastAliasedValueConfiguration.java
@@ -0,0 +1,30 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.code;
+
+import com.android.tools.r8.utils.ListUtils;
+
+public class AssumeAndCheckCastAliasedValueConfiguration implements AliasedValueConfiguration {
+
+  private static final AssumeAndCheckCastAliasedValueConfiguration INSTANCE =
+      new AssumeAndCheckCastAliasedValueConfiguration();
+
+  private AssumeAndCheckCastAliasedValueConfiguration() {}
+
+  public static AssumeAndCheckCastAliasedValueConfiguration getInstance() {
+    return INSTANCE;
+  }
+
+  @Override
+  public boolean isIntroducingAnAlias(Instruction instruction) {
+    return instruction.isAssume() || instruction.isCheckCast();
+  }
+
+  @Override
+  public Value getAliasForOutValue(Instruction instruction) {
+    assert instruction.isAssume() || instruction.isCheckCast();
+    return ListUtils.first(instruction.inValues());
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/code/DefaultAliasedValueConfiguration.java b/src/main/java/com/android/tools/r8/ir/code/DefaultAliasedValueConfiguration.java
new file mode 100644
index 0000000..b147deb
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/code/DefaultAliasedValueConfiguration.java
@@ -0,0 +1,28 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.code;
+
+public class DefaultAliasedValueConfiguration implements AliasedValueConfiguration {
+
+  private static final DefaultAliasedValueConfiguration INSTANCE =
+      new DefaultAliasedValueConfiguration();
+
+  private DefaultAliasedValueConfiguration() {}
+
+  public static DefaultAliasedValueConfiguration getInstance() {
+    return INSTANCE;
+  }
+
+  @Override
+  public boolean isIntroducingAnAlias(Instruction instruction) {
+    return instruction.isAssume();
+  }
+
+  @Override
+  public Value getAliasForOutValue(Instruction instruction) {
+    assert instruction.isAssume();
+    return instruction.asAssume().src();
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Value.java b/src/main/java/com/android/tools/r8/ir/code/Value.java
index d6372b5..819e684 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Value.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Value.java
@@ -264,25 +264,31 @@
    * <p>This method is useful to find the "true" definition of a value inside the current method.
    */
   public Value getAliasedValue() {
-    return getAliasedValue(Predicates.alwaysFalse());
+    return getAliasedValue(
+        DefaultAliasedValueConfiguration.getInstance(), Predicates.alwaysFalse());
   }
 
-  public Value getAliasedValue(Predicate<Value> stoppingCriterion) {
+  public Value getAliasedValue(AliasedValueConfiguration configuration) {
+    return getAliasedValue(configuration, Predicates.alwaysFalse());
+  }
+
+  public Value getAliasedValue(
+      AliasedValueConfiguration configuration, Predicate<Value> stoppingCriterion) {
     assert stoppingCriterion != null;
     Set<Value> visited = Sets.newIdentityHashSet();
     Value lastAliasedValue;
     Value aliasedValue = this;
     do {
-      if (stoppingCriterion.test(aliasedValue)) {
-        return aliasedValue;
-      }
       lastAliasedValue = aliasedValue;
       if (aliasedValue.isPhi()) {
         return aliasedValue;
       }
+      if (stoppingCriterion.test(aliasedValue)) {
+        return aliasedValue;
+      }
       Instruction definitionOfAliasedValue = aliasedValue.definition;
-      if (definitionOfAliasedValue.isIntroducingAnAlias()) {
-        aliasedValue = definitionOfAliasedValue.getAliasForOutValue();
+      if (configuration.isIntroducingAnAlias(definitionOfAliasedValue)) {
+        aliasedValue = configuration.getAliasForOutValue(definitionOfAliasedValue);
 
         // There shouldn't be a cycle.
         assert visited.add(aliasedValue);
@@ -293,7 +299,8 @@
   }
 
   public Value getSpecificAliasedValue(Predicate<Value> stoppingCriterion) {
-    Value aliasedValue = getAliasedValue(stoppingCriterion);
+    Value aliasedValue =
+        getAliasedValue(DefaultAliasedValueConfiguration.getInstance(), stoppingCriterion);
     return stoppingCriterion.test(aliasedValue) ? aliasedValue : null;
   }
 
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 8238723..2f5e023 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
@@ -59,6 +59,8 @@
 import com.android.tools.r8.ir.analysis.type.Nullability;
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.code.AliasedValueConfiguration;
+import com.android.tools.r8.ir.code.AssumeAndCheckCastAliasedValueConfiguration;
 import com.android.tools.r8.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.DominatorTree;
 import com.android.tools.r8.ir.code.FieldInstruction;
@@ -384,6 +386,8 @@
       return null;
     }
 
+    AliasedValueConfiguration aliasesThroughAssumeAndCheckCasts =
+        AssumeAndCheckCastAliasedValueConfiguration.getInstance();
     NonTrivialInstanceInitializerInfo.Builder builder = NonTrivialInstanceInitializerInfo.builder();
     Value receiver = code.getThis();
     boolean hasCatchHandler = false;
@@ -460,12 +464,14 @@
               if (field == null) {
                 return null;
               }
-              if (instancePut.object().getAliasedValue() != receiver
+              Value object =
+                  instancePut.object().getAliasedValue(aliasesThroughAssumeAndCheckCasts);
+              if (object != receiver
                   || instancePut.instructionInstanceCanThrow(appView, clazz.type).isThrowing()) {
                 builder.setMayHaveOtherSideEffectsThanInstanceFieldAssignments();
               }
 
-              Value value = instancePut.value().getAliasedValue();
+              Value value = instancePut.value().getAliasedValue(aliasesThroughAssumeAndCheckCasts);
               // TODO(b/142762134): Replace the use of onlyDependsOnArgument() by
               //  ValueMayDependOnEnvironmentAnalysis.
               if (!value.onlyDependsOnArgument()) {
@@ -497,7 +503,8 @@
                 }
                 builder.merge(singleTarget.getOptimizationInfo().getInstanceInitializerInfo());
                 for (int i = 1; i < invoke.arguments().size(); i++) {
-                  Value argument = invoke.arguments().get(i).getAliasedValue();
+                  Value argument =
+                      invoke.arguments().get(i).getAliasedValue(aliasesThroughAssumeAndCheckCasts);
                   if (argument == receiver) {
                     // In the analysis of the parent constructor, we don't consider the non-receiver
                     // arguments as being aliases of the receiver. Therefore, we explicitly mark
@@ -516,7 +523,7 @@
                     .markAllFieldsAsRead()
                     .setMayHaveOtherSideEffectsThanInstanceFieldAssignments();
                 for (Value inValue : invoke.inValues()) {
-                  if (inValue.getAliasedValue() == receiver) {
+                  if (inValue.getAliasedValue(aliasesThroughAssumeAndCheckCasts) == receiver) {
                     builder.setReceiverMayEscapeOutsideConstructorChain();
                     break;
                   }
@@ -532,7 +539,7 @@
                 builder.setMayHaveOtherSideEffectsThanInstanceFieldAssignments();
               }
               for (Value argument : invoke.arguments()) {
-                if (argument.getAliasedValue() == receiver) {
+                if (argument.getAliasedValue(aliasesThroughAssumeAndCheckCasts) == receiver) {
                   builder.setReceiverMayEscapeOutsideConstructorChain();
                   break;
                 }
@@ -549,7 +556,7 @@
                   .markAllFieldsAsRead()
                   .setMayHaveOtherSideEffectsThanInstanceFieldAssignments();
               for (Value argument : invoke.arguments()) {
-                if (argument.getAliasedValue() == receiver) {
+                if (argument.getAliasedValue(aliasesThroughAssumeAndCheckCasts) == receiver) {
                   builder.setReceiverMayEscapeOutsideConstructorChain();
                   break;
                 }