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