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;
}