Merge commit '33ae86d80351efc4d632452331d06cb97e42f2a7' into dev-release
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/icce/AlwaysThrowingInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/icce/AlwaysThrowingInstructionDesugaring.java
index b288d9a..a6384e1 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/icce/AlwaysThrowingInstructionDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/icce/AlwaysThrowingInstructionDesugaring.java
@@ -24,7 +24,6 @@
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringCollection;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.DesugarDescription;
-import com.android.tools.r8.ir.desugar.DesugarDescription.ScanCallback;
import com.android.tools.r8.ir.desugar.FreshLocalProvider;
import com.android.tools.r8.ir.desugar.LocalStackAllocator;
import com.android.tools.r8.ir.optimize.UtilityMethodsForCodeOptimizations;
@@ -106,46 +105,46 @@
getThrowInstructions(
appView,
invoke,
+ resolutionResult,
localStackAllocator,
eventConsumer,
context,
- methodProcessingContext,
- getMethodSynthesizerForThrowing(appView, invoke, resolutionResult, context)))
+ methodProcessingContext))
.build();
}
- public static DesugarDescription computeInvokeAsThrowNSMERewrite(
- AppView<?> appView, CfInvoke invoke, ScanCallback scanCallback) {
- DesugarDescription.Builder builder =
- DesugarDescription.builder()
- .setDesugarRewrite(
- (freshLocalProvider,
- localStackAllocator,
- eventConsumer,
- context,
- methodProcessingContext,
- dexItemFactory) ->
- getThrowInstructions(
- appView,
- invoke,
- localStackAllocator,
- eventConsumer,
- context,
- methodProcessingContext,
- UtilityMethodsForCodeOptimizations
- ::synthesizeThrowNoSuchMethodErrorMethod));
- builder.addScanEffect(scanCallback);
- return builder.build();
- }
-
private static Collection<CfInstruction> getThrowInstructions(
AppView<?> appView,
CfInvoke invoke,
+ MethodResolutionResult resolutionResult,
LocalStackAllocator localStackAllocator,
CfInstructionDesugaringEventConsumer eventConsumer,
ProgramMethod context,
- MethodProcessingContext methodProcessingContext,
- MethodSynthesizerConsumer methodSynthesizerConsumer) {
+ MethodProcessingContext methodProcessingContext) {
+ MethodSynthesizerConsumer methodSynthesizerConsumer = null;
+ if (resolutionResult == null) {
+ methodSynthesizerConsumer =
+ UtilityMethodsForCodeOptimizations::synthesizeThrowNoSuchMethodErrorMethod;
+ } else if (resolutionResult.isSingleResolution()) {
+ if (resolutionResult.getResolvedMethod().isStatic() != invoke.isInvokeStatic()) {
+ methodSynthesizerConsumer =
+ UtilityMethodsForCodeOptimizations::synthesizeThrowIncompatibleClassChangeErrorMethod;
+ }
+ } else if (resolutionResult.isFailedResolution()) {
+ FailedResolutionResult failedResolutionResult = resolutionResult.asFailedResolution();
+ AppInfoWithClassHierarchy appInfo = appView.appInfoForDesugaring();
+ if (failedResolutionResult.isIllegalAccessErrorResult(context.getHolder(), appInfo)) {
+ methodSynthesizerConsumer =
+ UtilityMethodsForCodeOptimizations::synthesizeThrowIllegalAccessErrorMethod;
+ } else if (failedResolutionResult.isNoSuchMethodErrorResult(context.getHolder(), appInfo)) {
+ methodSynthesizerConsumer =
+ UtilityMethodsForCodeOptimizations::synthesizeThrowNoSuchMethodErrorMethod;
+ } else if (failedResolutionResult.isIncompatibleClassChangeErrorResult()) {
+ methodSynthesizerConsumer =
+ UtilityMethodsForCodeOptimizations::synthesizeThrowIncompatibleClassChangeErrorMethod;
+ }
+ }
+
if (methodSynthesizerConsumer == null) {
assert false;
return null;
@@ -199,32 +198,4 @@
}
return replacement;
}
-
- private static MethodSynthesizerConsumer getMethodSynthesizerForThrowing(
- AppView<?> appView,
- CfInvoke invoke,
- MethodResolutionResult resolutionResult,
- ProgramMethod context) {
- if (resolutionResult == null) {
- return UtilityMethodsForCodeOptimizations::synthesizeThrowNoSuchMethodErrorMethod;
- } else if (resolutionResult.isSingleResolution()) {
- if (resolutionResult.getResolvedMethod().isStatic() != invoke.isInvokeStatic()) {
- return UtilityMethodsForCodeOptimizations
- ::synthesizeThrowIncompatibleClassChangeErrorMethod;
- }
- } else if (resolutionResult.isFailedResolution()) {
- FailedResolutionResult failedResolutionResult = resolutionResult.asFailedResolution();
- AppInfoWithClassHierarchy appInfo = appView.appInfoForDesugaring();
- if (failedResolutionResult.isIllegalAccessErrorResult(context.getHolder(), appInfo)) {
- return UtilityMethodsForCodeOptimizations::synthesizeThrowIllegalAccessErrorMethod;
- } else if (failedResolutionResult.isNoSuchMethodErrorResult(context.getHolder(), appInfo)) {
- return UtilityMethodsForCodeOptimizations::synthesizeThrowNoSuchMethodErrorMethod;
- } else if (failedResolutionResult.isIncompatibleClassChangeErrorResult()) {
- return UtilityMethodsForCodeOptimizations
- ::synthesizeThrowIncompatibleClassChangeErrorMethod;
- }
- }
-
- return null;
- }
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
index 8e8541b..bc8ebd0 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
@@ -44,7 +44,6 @@
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.position.MethodPosition;
import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.android.tools.r8.utils.structural.Ordered;
import com.google.common.collect.Iterables;
@@ -712,23 +711,7 @@
}
}
- DesugarDescription emulatedInterfaceDesugaring =
- computeEmulatedInterfaceInvokeSpecial(clazz, invokedMethod, context);
- if (!emulatedInterfaceDesugaring.needsDesugaring() && context.isDefaultMethod()) {
- return AlwaysThrowingInstructionDesugaring.computeInvokeAsThrowNSMERewrite(
- appView,
- invoke,
- () ->
- appView
- .reporter()
- .warning(
- new StringDiagnostic(
- "Interface method desugaring has inserted NoSuchMethodError replacing a"
- + " super call in "
- + context.toSourceString(),
- context.getOrigin())));
- }
- return emulatedInterfaceDesugaring;
+ return computeEmulatedInterfaceInvokeSpecial(clazz, invokedMethod, context);
}
private DesugarDescription computeEmulatedInterfaceInvokeSpecial(
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 295dc47..f7d3e74 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -3923,10 +3923,31 @@
}
}
+ BiConsumer<LambdaClass, ProgramMethod> lambdaCallback = this::recordLambdaSynthesizingContext;
+ // TODO(b/233868787): If a lambda implements unknown interfaces its methods won't be live and if
+ // the tree-pruner is disabled they won't be removed. Workaround this by making them live.
+ if (!options.isShrinking()) {
+ lambdaCallback =
+ lambdaCallback.andThen(
+ (clazz, context) -> {
+ for (DexType itf : clazz.getLambdaProgramClass().getInterfaces()) {
+ if (definitionFor(itf, context) == null) {
+ for (ProgramMethod method :
+ clazz.getLambdaProgramClass().virtualProgramMethods()) {
+ synchronized (additions) {
+ additions.addLiveMethod(method);
+ }
+ }
+ break;
+ }
+ }
+ });
+ }
+
R8CfInstructionDesugaringEventConsumer eventConsumer =
CfInstructionDesugaringEventConsumer.createForR8(
appView,
- this::recordLambdaSynthesizingContext,
+ lambdaCallback,
this::recordConstantDynamicSynthesizingContext,
this::recordTwrCloseResourceMethodSynthesizingContext,
additions,
diff --git a/src/test/java/com/android/tools/r8/debuginfo/Regress233857593Test.java b/src/test/java/com/android/tools/r8/debuginfo/Regress233857593Test.java
new file mode 100644
index 0000000..d786a12
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/debuginfo/Regress233857593Test.java
@@ -0,0 +1,58 @@
+// Copyright (c) 2022, 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.debuginfo;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class Regress233857593Test extends TestBase {
+
+ @Parameter() public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static List<Object[]> data() {
+ return buildParameters(getTestParameters().withDexRuntimes().withAllApiLevels().build());
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ testForD8(parameters.getBackend())
+ .addProgramClasses(TestClass.class)
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(
+ // TODO(b/233857593): There used to be only one goto.
+ inspector -> {
+ assertEquals(
+ 2,
+ inspector
+ .clazz(TestClass.class)
+ .uniqueMethodWithName("testLoopPhiWithNullFirstInput")
+ .streamInstructions()
+ .filter(InstructionSubject::isGoto)
+ .count());
+ });
+ }
+
+ static class TestClass {
+ private void testLoopPhiWithNullFirstInput(boolean cond) {
+ TestClass a = null;
+ while (a == null) {
+ if (cond) {
+ a = new TestClass();
+ }
+ }
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultMethodInvokeSuperOnDefaultLibraryMethodTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultMethodInvokeSuperOnDefaultLibraryMethodTest.java
deleted file mode 100644
index 0cb64c8..0000000
--- a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultMethodInvokeSuperOnDefaultLibraryMethodTest.java
+++ /dev/null
@@ -1,175 +0,0 @@
-// Copyright (c) 2022, 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.desugaring.interfacemethods;
-
-import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
-import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
-import static org.hamcrest.CoreMatchers.allOf;
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assume.assumeTrue;
-
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.errors.InterfaceDesugarMissingTypeDiagnostic;
-import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.StringDiagnostic;
-import com.android.tools.r8.utils.StringUtils;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.function.Consumer;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameter;
-import org.junit.runners.Parameterized.Parameters;
-
-@RunWith(Parameterized.class)
-public class DefaultMethodInvokeSuperOnDefaultLibraryMethodTest extends TestBase {
-
- @Parameter() public TestParameters parameters;
-
- @Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return getTestParameters().withDexRuntimes().build();
- }
-
- private static final String EXPECTED_OUTPUT = StringUtils.lines("1", "2");
-
- private boolean runtimeHasConsumerInterface(TestParameters parameters) {
- // java,util.function.Consumer was introduced at API level 24.
- return parameters.asDexRuntime().getMinApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N);
- }
-
- @Test
- public void testD8WithDefaultInterfaceMethodDesugaringWithAPIInLibrary() throws Exception {
- testForD8(parameters.getBackend())
- .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.T))
- .addInnerClasses(getClass())
- .setMinApi(AndroidApiLevel.I_MR1)
- .compileWithExpectedDiagnostics(
- diagnostics ->
- diagnostics
- .assertOnlyWarnings()
- .assertWarningsMatch(
- allOf(
- diagnosticType(StringDiagnostic.class),
- diagnosticMessage(
- containsString(
- "Interface method desugaring has inserted NoSuchMethodError"
- + " replacing a super call in")),
- diagnosticMessage(containsString("forEachPrint")))))
- .run(parameters.getRuntime(), TestClass.class)
- .applyIf(
- // If the platform does not have java.util.function.Consumer the lambda instantiation
- // will throw NoClassDefFoundError as it implements java.util.function.Consumer.
- // Otherwise, the generated code will throw NoSuchMethodError.
- runtimeHasConsumerInterface(parameters),
- b -> b.assertFailureWithErrorThatThrows(NoSuchMethodError.class),
- b -> b.assertFailureWithErrorThatThrows(NoClassDefFoundError.class));
- }
-
- @Test
- public void testD8WithDefaultInterfaceMethodDesugaringWithoutAPIInLibrary() throws Exception {
- testForD8(parameters.getBackend())
- .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.M))
- .addInnerClasses(getClass())
- .setMinApi(AndroidApiLevel.I_MR1)
- .compileWithExpectedDiagnostics(
- diagnostics ->
- diagnostics
- .assertOnlyWarnings()
- .assertWarningsMatch(
- diagnosticType(InterfaceDesugarMissingTypeDiagnostic.class)))
- .run(parameters.getRuntime(), TestClass.class)
- .applyIf(
- // If the platform does not have java.util.function.Consumer the lambda instantiation
- // will throw NoClassDefFoundError as it implements java.util.function.Consumer.
- // Otherwise, the generated code will throw NoSuchMethodError.
- runtimeHasConsumerInterface(parameters),
- b -> b.assertFailureWithErrorThatThrows(NoSuchMethodError.class),
- b -> b.assertFailureWithErrorThatThrows(NoClassDefFoundError.class));
- }
-
- @Test
- public void testD8WithDefaultInterfaceMethodSupport() throws Exception {
- assumeTrue(
- parameters.asDexRuntime().getMinApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N));
- testForD8(parameters.getBackend())
- .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.T))
- .addInnerClasses(getClass())
- .setMinApi(AndroidApiLevel.N)
- .run(parameters.getRuntime(), TestClass.class)
- .assertSuccessWithOutput(EXPECTED_OUTPUT);
- }
-
- @Test
- public void testR8WithDefaultInterfaceMethodDesugaringWithAPIInLibrary() throws Exception {
- testForR8(parameters.getBackend())
- .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.T))
- .addInnerClasses(getClass())
- .setMinApi(AndroidApiLevel.I_MR1)
- .addKeepMainRule(TestClass.class)
- .run(parameters.getRuntime(), TestClass.class)
- .assertFailureWithErrorThatThrows(NoSuchMethodError.class);
- }
-
- @Test
- public void testR8WithDefaultInterfaceMethodDesugaringWithoutAPIInLibrary() throws Exception {
- testForR8(parameters.getBackend())
- .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.M))
- .addInnerClasses(getClass())
- .setMinApi(AndroidApiLevel.I_MR1)
- .addKeepMainRule(TestClass.class)
- .addDontWarn(Consumer.class)
- .run(parameters.getRuntime(), TestClass.class)
- .applyIf(
- // If the platform does not have java.util.function.Consumer the lambda instantiation
- // will throw NoClassDefFoundError as it implements java.util.function.Consumer.
- // Otherwise, the generated code will throw NoSuchMethodError.
- runtimeHasConsumerInterface(parameters),
- b -> b.assertFailureWithErrorThatThrows(NoSuchMethodError.class),
- b -> b.assertFailureWithErrorThatThrows(NoClassDefFoundError.class));
- }
-
- @Test
- public void testR8WithDefaultInterfaceMethodSupport() throws Exception {
- assumeTrue(
- parameters.asDexRuntime().getMinApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N));
- testForR8(parameters.getBackend())
- .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.T))
- .addInnerClasses(getClass())
- .setMinApi(AndroidApiLevel.N)
- .addKeepMainRule(TestClass.class)
- .run(parameters.getRuntime(), TestClass.class)
- .assertSuccessWithOutput(EXPECTED_OUTPUT);
- }
-
- interface IntegerIterable extends Iterable<Integer> {
- default void forEachPrint() {
- Iterable.super.forEach(System.out::println);
- }
- }
-
- static class IntegerIterable1And2 implements IntegerIterable {
-
- @Override
- public Iterator<Integer> iterator() {
- List<Integer> result = new ArrayList<>();
- result.add(1);
- result.add(2);
- return result.iterator();
- }
- }
-
- static class TestClass {
-
- public static void main(String[] args) {
- new IntegerIterable1And2().forEachPrint();
- }
- }
-}
diff --git a/src/test/java/com/android/tools/r8/regress/UndefinedLambdaInterfaceRegress232379893.java b/src/test/java/com/android/tools/r8/regress/UndefinedLambdaInterfaceRegress232379893.java
new file mode 100644
index 0000000..b27e96a
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/regress/UndefinedLambdaInterfaceRegress232379893.java
@@ -0,0 +1,62 @@
+// Copyright (c) 2022, 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.regress;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class UndefinedLambdaInterfaceRegress232379893 extends TestBase {
+
+ static final String EXPECTED = StringUtils.lines("Hello, world");
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimes().withAllApiLevels().build();
+ }
+
+ public UndefinedLambdaInterfaceRegress232379893(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(TestClass.class)
+ .addProgramClassesAndInnerClasses(UserOfUndefinedInterface.class)
+ .addKeepMainRule(TestClass.class)
+ .addDontWarn(UndefinedInterface.class)
+ .addDontShrink()
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED);
+ }
+
+ interface UndefinedInterface {
+ void foo();
+ }
+
+ static class UserOfUndefinedInterface {
+ public static void bar(UndefinedInterface i) {
+ throw new RuntimeException("unused method");
+ }
+ }
+
+ static class TestClass {
+ public static void main(String[] args) {
+ if (System.nanoTime() < 0) {
+ UserOfUndefinedInterface.bar(() -> System.out.println("unused lambda"));
+ } else {
+ System.out.println("Hello, world");
+ }
+ }
+ }
+}