Merge branch '2.0' of https://r8.googlesource.com/r8 into cherryDesugLib2.0
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 2f5e023..9fe7c0d 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
@@ -477,7 +477,7 @@ if (!value.onlyDependsOnArgument()) { builder.setInstanceFieldInitializationMayDependOnEnvironment(); } - if (value == receiver) { + if (couldBeReceiverValue(value, receiver, aliasesThroughAssumeAndCheckCasts)) { builder.setReceiverMayEscapeOutsideConstructorChain(); } } @@ -505,7 +505,7 @@ for (int i = 1; i < invoke.arguments().size(); i++) { Value argument = invoke.arguments().get(i).getAliasedValue(aliasesThroughAssumeAndCheckCasts); - if (argument == receiver) { + if (couldBeReceiverValue(argument, receiver, aliasesThroughAssumeAndCheckCasts)) { // 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 // that the receiver escapes from this constructor. @@ -523,7 +523,7 @@ .markAllFieldsAsRead() .setMayHaveOtherSideEffectsThanInstanceFieldAssignments(); for (Value inValue : invoke.inValues()) { - if (inValue.getAliasedValue(aliasesThroughAssumeAndCheckCasts) == receiver) { + if (couldBeReceiverValue(inValue, receiver, aliasesThroughAssumeAndCheckCasts)) { builder.setReceiverMayEscapeOutsideConstructorChain(); break; } @@ -539,7 +539,7 @@ builder.setMayHaveOtherSideEffectsThanInstanceFieldAssignments(); } for (Value argument : invoke.arguments()) { - if (argument.getAliasedValue(aliasesThroughAssumeAndCheckCasts) == receiver) { + if (couldBeReceiverValue(argument, receiver, aliasesThroughAssumeAndCheckCasts)) { builder.setReceiverMayEscapeOutsideConstructorChain(); break; } @@ -556,7 +556,7 @@ .markAllFieldsAsRead() .setMayHaveOtherSideEffectsThanInstanceFieldAssignments(); for (Value argument : invoke.arguments()) { - if (argument.getAliasedValue(aliasesThroughAssumeAndCheckCasts) == receiver) { + if (couldBeReceiverValue(argument, receiver, aliasesThroughAssumeAndCheckCasts)) { builder.setReceiverMayEscapeOutsideConstructorChain(); break; } @@ -605,6 +605,18 @@ return builder.build(); } + private static boolean couldBeReceiverValue( + Value value, Value receiver, AliasedValueConfiguration aliasing) { + if (value.isPhi() && receiver.hasPhiUsers()) { + // Conservatively assume that the receiver might be an input dependency of the phi value. + return true; + } + if (value.getAliasedValue(aliasing) == receiver) { + return true; + } + return false; + } + private void identifyInvokeSemanticsForInlining( DexEncodedMethod method, IRCode code, AppView<?> appView, OptimizationFeedback feedback) { if (method.isStatic()) {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerInstanceEscapeViaPhiTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerInstanceEscapeViaPhiTest.java new file mode 100644 index 0000000..147d2ed --- /dev/null +++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerInstanceEscapeViaPhiTest.java
@@ -0,0 +1,69 @@ +// Copyright (c) 2019, 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.optimize.classinliner; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +/** Reproduction of b/160901582 where we inline class with escaping instance variable. */ +@RunWith(Parameterized.class) +public class ClassInlinerInstanceEscapeViaPhiTest extends TestBase { + + private final TestParameters parameters; + + @Parameters(name = "{0}") + public static TestParametersCollection data() { + return getTestParameters().withAllRuntimesAndApiLevels().build(); + } + + public ClassInlinerInstanceEscapeViaPhiTest(TestParameters parameters) { + this.parameters = parameters; + } + + @Test + public void testReference() throws Exception { + testForRuntime(parameters) + .addInnerClasses(ClassInlinerInstanceEscapeViaPhiTest.class) + .run(parameters.getRuntime(), TestClass.class) + .assertSuccessWithOutputLines("false"); + } + + @Test + public void testR8() throws Exception { + testForR8(parameters.getBackend()) + .addInnerClasses(ClassInlinerInstanceEscapeViaPhiTest.class) + .addKeepMainRule(TestClass.class) + .setMinApi(parameters.getApiLevel()) + .compile() + .run(parameters.getRuntime(), TestClass.class) + .assertSuccessWithOutputLines("false"); + } + + static class A { + + public A() { + B.foo(System.nanoTime() > 0 ? this : null); + } + } + + static class B { + + static void foo(A a) { + System.out.println((System.nanoTime() > 0 ? a : null) == null); + } + } + + static class TestClass { + + public static void main(String[] args) { + new A(); + } + } +}