Enable uninstantiated type optimization for interfaces
Bug: 214496607
Change-Id: I37b8bb48d86a90028e9430b0bd79dc47863ddb12
diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java
index 8315b20..547fd3f 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -150,21 +150,17 @@
}
public boolean isAlwaysNull(AppView<AppInfoWithLiveness> appView) {
- return isAlwaysNull(appView.appInfo());
- }
-
- public boolean isAlwaysNull(AppInfoWithLiveness appInfo) {
if (!isClassType()) {
return false;
}
- DexProgramClass clazz = asProgramClassOrNull(appInfo.definitionFor(this));
+ DexProgramClass clazz = asProgramClassOrNull(appView.definitionFor(this));
if (clazz == null) {
return false;
}
- if (appInfo.options().enableUninstantiatedTypeOptimizationForInterfaces) {
- return !appInfo.isInstantiatedDirectlyOrIndirectly(clazz);
+ if (clazz.isInterface() && appView.getOpenClosedInterfacesCollection().isMaybeOpen(clazz)) {
+ return false;
}
- return !clazz.isInterface() && !appInfo.isInstantiatedDirectlyOrIndirectly(clazz);
+ return !appView.appInfo().isInstantiatedDirectlyOrIndirectly(clazz);
}
public boolean isSamePackage(DexType other) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java
index 5d34c84..04b738c 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java
@@ -351,7 +351,7 @@
}
// Record access.
- if (field.isProgramField() && appView.appInfo().mayPropagateValueFor(field)) {
+ if (field.isProgramField() && appView.appInfo().mayPropagateValueFor(appView, field)) {
if (field.getAccessFlags().isStatic() == isStatic) {
if (isWrite) {
recordFieldAccessContext(definition, writtenFields, readFields);
@@ -396,7 +396,7 @@
private void recordAccessThatCannotBeOptimized(
DexClassAndField field, DexEncodedField definition) {
constantFields.remove(definition);
- if (field.isProgramField() && appView.appInfo().mayPropagateValueFor(field)) {
+ if (field.isProgramField() && appView.appInfo().mayPropagateValueFor(appView, field)) {
destroyFieldAccessContexts(definition);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
index b4584c4..08edc70 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
@@ -124,7 +124,7 @@
private boolean mayPropagateValueFor(DexClassAndField field) {
if (field.isProgramField()) {
- return appView.appInfo().mayPropagateValueFor(field.getReference());
+ return appView.appInfo().mayPropagateValueFor(appView, field.getReference());
}
return appView.appInfo().assumedValues.containsKey(field.getReference())
|| appView.appInfo().noSideEffects.containsKey(field.getReference());
@@ -132,7 +132,7 @@
private boolean mayPropagateValueFor(DexClassAndMethod method) {
if (method.isProgramMethod()) {
- return appView.appInfo().mayPropagateValueFor(method.getReference());
+ return appView.appInfo().mayPropagateValueFor(appView, method.getReference());
}
return appView.appInfo().assumedValues.containsKey(method.getReference())
|| appView.appInfo().noSideEffects.containsKey(method.getReference());
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
index 715dfdd..d758988 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
@@ -40,6 +40,7 @@
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoCollection;
import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfo;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.google.common.collect.Sets;
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
@@ -448,11 +449,13 @@
}
private void handleInvokeDirect(InvokeDirect invoke) {
- if (!appView.enableWholeProgramOptimizations()) {
+ if (!appView.hasLiveness()) {
killAllNonFinalActiveFields();
return;
}
+ AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
+
DexClassAndMethod singleTarget = invoke.lookupSingleTarget(appView, method);
if (singleTarget == null || !singleTarget.getDefinition().isInstanceInitializer()) {
killAllNonFinalActiveFields();
@@ -470,7 +473,9 @@
fieldInitializationInfos.forEachWithDeterministicOrder(
appView,
(field, info) -> {
- if (!appView.appInfo().withLiveness().mayPropagateValueFor(field.getReference())) {
+ if (!appViewWithLiveness
+ .appInfo()
+ .mayPropagateValueFor(appViewWithLiveness, field.getReference())) {
return;
}
if (info.isArgumentInitializationInfo()) {
@@ -485,7 +490,7 @@
}
} else if (info.isSingleValue()) {
SingleValue value = info.asSingleValue();
- if (value.isMaterializableInContext(appView.withLiveness(), method)) {
+ if (value.isMaterializableInContext(appViewWithLiveness, method)) {
Value object = invoke.getReceiver().getAliasedValue();
FieldAndObject fieldAndObject = new FieldAndObject(field.getReference(), object);
if (field.isFinal()) {
@@ -782,12 +787,13 @@
}
private void applyObjectState(Value value, ObjectState objectState) {
+ AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
objectState.forEachAbstractFieldValue(
(field, fieldValue) -> {
- if (appView.appInfoWithLiveness().mayPropagateValueFor(field)
+ if (appViewWithLiveness.appInfo().mayPropagateValueFor(appViewWithLiveness, field)
&& fieldValue.isSingleValue()) {
SingleValue singleFieldValue = fieldValue.asSingleValue();
- if (singleFieldValue.isMaterializableInContext(appView.withLiveness(), method)) {
+ if (singleFieldValue.isMaterializableInContext(appViewWithLiveness, method)) {
activeState.putFinalInstanceField(
new FieldAndObject(field, value), new MaterializableValue(singleFieldValue));
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
index 65b9aaa..8853607 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
@@ -155,7 +155,7 @@
.getFieldAccessInfoCollection()
.get(field.getReference())
.hasReflectiveAccess();
- if (appView.appInfo().mayPropagateValueFor(field.getReference())) {
+ if (appView.appInfo().mayPropagateValueFor(appView, field.getReference())) {
getFieldOptimizationInfoForUpdating(field).setAbstractValue(abstractValue);
}
}
@@ -192,7 +192,7 @@
@Override
public synchronized void methodReturnsAbstractValue(
DexEncodedMethod method, AppView<AppInfoWithLiveness> appView, AbstractValue value) {
- if (appView.appInfo().mayPropagateValueFor(method.getReference())) {
+ if (appView.appInfo().mayPropagateValueFor(appView, method.getReference())) {
getMethodOptimizationInfoForUpdating(method).markReturnsAbstractValue(value);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
index a9e3cba..5b65a8a 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
@@ -63,7 +63,7 @@
@Override
public void recordFieldHasAbstractValue(
DexEncodedField field, AppView<AppInfoWithLiveness> appView, AbstractValue abstractValue) {
- if (appView.appInfo().mayPropagateValueFor(field.getReference())) {
+ if (appView.appInfo().mayPropagateValueFor(appView, field.getReference())) {
field.getMutableOptimizationInfo().setAbstractValue(abstractValue);
}
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java
index cca53b7..4599085 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java
@@ -435,7 +435,7 @@
// OK, this can be rewritten to have void return type.
continue;
}
- if (!appView.appInfo().mayPropagateValueFor(method)) {
+ if (!appView.appInfo().mayPropagateValueFor(appView, method)) {
return null;
}
AbstractValue returnValueForMethod =
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/collection/NonEmptyOpenClosedInterfacesCollection.java b/src/main/java/com/android/tools/r8/optimize/interfaces/collection/NonEmptyOpenClosedInterfacesCollection.java
index da3fce8..b3382e0 100644
--- a/src/main/java/com/android/tools/r8/optimize/interfaces/collection/NonEmptyOpenClosedInterfacesCollection.java
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/collection/NonEmptyOpenClosedInterfacesCollection.java
@@ -11,7 +11,6 @@
import com.android.tools.r8.utils.SetUtils;
import java.util.Set;
-/** Computed oracle that may respond "definitely closed" for some or all interfaces. */
public class NonEmptyOpenClosedInterfacesCollection extends OpenClosedInterfacesCollection {
private final Set<DexType> openInterfaceTypes;
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/collection/OpenClosedInterfacesCollection.java b/src/main/java/com/android/tools/r8/optimize/interfaces/collection/OpenClosedInterfacesCollection.java
index 1db6a4c..5b009ba 100644
--- a/src/main/java/com/android/tools/r8/optimize/interfaces/collection/OpenClosedInterfacesCollection.java
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/collection/OpenClosedInterfacesCollection.java
@@ -32,6 +32,10 @@
public abstract boolean isDefinitelyClosed(DexClass clazz);
+ public final boolean isMaybeOpen(DexClass clazz) {
+ return !isDefinitelyClosed(clazz);
+ }
+
public final boolean isDefinitelyInstanceOfStaticType(
AppView<AppInfoWithLiveness> appView, Value value) {
return isDefinitelyInstanceOfStaticType(
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index a55baf7..d601873 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -1038,28 +1038,33 @@
&& !keepInfo.getMethodInfo(method).isPinned(options());
}
- public boolean mayPropagateValueFor(DexClassAndMember<?, ?> member) {
+ public boolean mayPropagateValueFor(
+ AppView<AppInfoWithLiveness> appView, DexClassAndMember<?, ?> member) {
assert checkIfObsolete();
- return member.getReference().apply(this::mayPropagateValueFor, this::mayPropagateValueFor);
+ return member
+ .getReference()
+ .apply(
+ field -> mayPropagateValueFor(appView, field),
+ method -> mayPropagateValueFor(appView, method));
}
- public boolean mayPropagateValueFor(DexField field) {
+ public boolean mayPropagateValueFor(AppView<AppInfoWithLiveness> appView, DexField field) {
assert checkIfObsolete();
if (neverPropagateValue.contains(field)) {
return false;
}
- if (isPinned(field) && !field.getType().isAlwaysNull(this)) {
+ if (isPinned(field) && !field.getType().isAlwaysNull(appView)) {
return false;
}
return true;
}
- public boolean mayPropagateValueFor(DexMethod method) {
+ public boolean mayPropagateValueFor(AppView<AppInfoWithLiveness> appView, DexMethod method) {
assert checkIfObsolete();
if (neverPropagateValue.contains(method)) {
return false;
}
- if (!method.getReturnType().isAlwaysNull(this)
+ if (!method.getReturnType().isAlwaysNull(appView)
&& !getKeepInfo().getMethodInfo(method, this).isOptimizationAllowed(options())) {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 7246240..a11e201 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -331,8 +331,6 @@
public final OutlineOptions outline = new OutlineOptions();
public boolean enableInitializedClassesInInstanceMethodsAnalysis = true;
public boolean enableRedundantFieldLoadElimination = true;
- // Currently disabled, see b/146957343.
- public boolean enableUninstantiatedTypeOptimizationForInterfaces = false;
// TODO(b/138917494): Disable until we have numbers on potential performance penalties.
public boolean enableRedundantConstNumberOptimization = false;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenUninstantiatedInterfaceAlwaysNullTest.java b/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenUninstantiatedInterfaceAlwaysNullTest.java
new file mode 100644
index 0000000..816da5a
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenUninstantiatedInterfaceAlwaysNullTest.java
@@ -0,0 +1,117 @@
+// 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.ir.optimize.interfaces;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.NoVerticalClassMerging;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.google.common.collect.ImmutableList;
+import java.io.IOException;
+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;
+import org.objectweb.asm.Opcodes;
+
+@RunWith(Parameterized.class)
+public class OpenUninstantiatedInterfaceAlwaysNullTest extends TestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ @Test
+ public void testJvm() throws Exception {
+ assumeTrue(parameters.isCfRuntime());
+ testForRuntime(parameters)
+ .addProgramClasses(getProgramClasses())
+ .addProgramClassFileData(getTransformedMainClass())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines(getExpectedOutputLines());
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ assumeTrue(parameters.isDexRuntime());
+ testForD8(parameters.getBackend())
+ .addProgramClasses(getProgramClasses())
+ .addProgramClassFileData(getTransformedMainClass())
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines(getExpectedOutputLines());
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(getProgramClasses())
+ .addProgramClassFileData(getTransformedMainClass())
+ .addKeepClassAndMembersRules(Main.class)
+ .addOptionsModification(
+ options -> options.getOpenClosedInterfacesOptions().suppressAllOpenInterfaces())
+ // TODO(b/214496607): I should not be merged into A in the first place, since I is open.
+ .enableNoVerticalClassMergingAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines(getExpectedOutputLines());
+ }
+
+ private List<Class<?>> getProgramClasses() {
+ return ImmutableList.of(I.class, A.class, B.class);
+ }
+
+ private byte[] getTransformedMainClass() throws IOException {
+ return transformer(Main.class)
+ .transformTypeInsnInMethod(
+ "getB",
+ (opcode, type, visitor) -> {
+ assertEquals(opcode, Opcodes.NEW);
+ assertEquals(type, binaryName(A.class));
+ visitor.visitTypeInsn(opcode, binaryName(B.class));
+ })
+ .transformMethodInsnInMethod(
+ "getB",
+ (opcode, owner, name, descriptor, isInterface, visitor) -> {
+ assertEquals(opcode, Opcodes.INVOKESPECIAL);
+ assertEquals(owner, binaryName(A.class));
+ assertEquals(name, "<init>");
+ visitor.visitMethodInsn(opcode, binaryName(B.class), name, descriptor, isInterface);
+ })
+ .transform();
+ }
+
+ private List<String> getExpectedOutputLines() {
+ return ImmutableList.of("false");
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ I b = getB();
+ System.out.println(b == null);
+ }
+
+ static I getB() {
+ return new A(); // transformed into new B().
+ }
+ }
+
+ @NoVerticalClassMerging
+ interface I {}
+
+ static class A implements I {}
+
+ static class B {}
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/B146957343.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/B146957343.java
index 3200360..82755bc 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/B146957343.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/B146957343.java
@@ -33,7 +33,7 @@
}
@Test
- public void testWithoutR8() throws Exception {
+ public void testRuntime() throws Exception {
testForRuntime(parameters)
.addProgramClasses(I.class, J.class, Main.class)
.addProgramClassFileData(getAimplementsI())
@@ -42,36 +42,15 @@
}
@Test
- public void testWithUninstantiatedTypeOptimizationForInterfaces() throws Exception {
+ public void testR8() throws Exception {
testForR8(parameters.getBackend())
.addProgramClasses(I.class, J.class, Main.class)
.addProgramClassFileData(getAimplementsI())
.addKeepMainRule(Main.class)
+ .addOptionsModification(
+ options -> options.getOpenClosedInterfacesOptions().suppressAllOpenInterfaces())
.enableInliningAnnotations()
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(
- options -> {
- options.getOpenClosedInterfacesOptions().suppressAllOpenInterfaces();
- options.enableUninstantiatedTypeOptimizationForInterfaces = true;
- })
- .compile()
- .run(parameters.getRuntime(), Main.class)
- .assertFailureWithErrorThatThrows(NullPointerException.class);
- }
-
- @Test
- public void testWithoutUninstantiatedTypeOptimizationForInterfaces() throws Exception {
- testForR8(parameters.getBackend())
- .addProgramClasses(I.class, J.class, Main.class)
- .addProgramClassFileData(getAimplementsI())
- .addKeepMainRule(Main.class)
- .enableInliningAnnotations()
- .setMinApi(parameters.getApiLevel())
- .addOptionsModification(
- options -> {
- options.getOpenClosedInterfacesOptions().suppressAllOpenInterfaces();
- options.enableUninstantiatedTypeOptimizationForInterfaces = false;
- })
.compile()
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutputLines("In A.f()");
diff --git a/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java b/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java
index 2e1ed26..9d3e55f 100644
--- a/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java
@@ -16,7 +16,6 @@
import com.android.tools.r8.R8TestRunResult;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRunResult;
-import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.jasmin.JasminBuilder;
import com.android.tools.r8.jasmin.JasminBuilder.ClassBuilder;
@@ -40,8 +39,7 @@
D8,
JAVAC,
PROGUARD,
- R8,
- R8_ENABLE_UNININSTANTATED_TYPE_OPTIMIZATION_FOR_INTERFACES
+ R8
}
private enum Mode {
@@ -68,8 +66,16 @@
}
switch (compiler) {
- case D8:
+ case JAVAC:
+ return StringUtils.joinLines("Hello!", "Goodbye!", "");
+
case DX:
+ case D8:
+ case R8:
+ if (parameters.isCfRuntime()) {
+ assert compiler == Compiler.R8;
+ return StringUtils.joinLines("Hello!", "Goodbye!", "");
+ }
switch (parameters.getDexRuntimeVersion()) {
case V4_0_4:
case V4_4_4:
@@ -77,6 +83,14 @@
case V12_0_0:
return StringUtils.joinLines("Hello!", "Goodbye!", "");
+ case V5_1_1:
+ case V6_0_1:
+ case V8_1_0:
+ case V9_0_0:
+ case DEFAULT:
+ return StringUtils.joinLines(
+ "Hello!", "Unexpected outcome of checkcast", "Goodbye!", "");
+
case V7_0_0:
case V13_MASTER:
return StringUtils.joinLines(
@@ -87,50 +101,13 @@
"");
default:
- // Fallthrough.
+ throw new Unreachable();
}
case PROGUARD:
return StringUtils.joinLines(
"Hello!", "Unexpected outcome of checkcast", "Goodbye!", "");
- case R8:
- if (parameters.isDexRuntime()) {
- if (parameters
- .getDexRuntimeVersion()
- .isEqualToOneOf(
- Version.V5_1_1,
- Version.V6_0_1,
- Version.V8_1_0,
- Version.V9_0_0,
- Version.DEFAULT)) {
- return StringUtils.joinLines(
- "Hello!", "Unexpected outcome of checkcast", "Goodbye!", "");
- }
- if (parameters
- .getDexRuntimeVersion()
- .isEqualToOneOf(Version.V7_0_0, Version.V13_MASTER)) {
- return StringUtils.joinLines(
- "Hello!",
- "Unexpected outcome of checkcast",
- "Unexpected outcome of instanceof",
- "Goodbye!",
- "");
- }
- }
- return StringUtils.joinLines("Hello!", "Goodbye!", "");
-
- case R8_ENABLE_UNININSTANTATED_TYPE_OPTIMIZATION_FOR_INTERFACES:
- return StringUtils.joinLines(
- "Hello!",
- "Unexpected outcome of getstatic",
- "Unexpected outcome of checkcast",
- "Goodbye!",
- "");
-
- case JAVAC:
- return StringUtils.joinLines("Hello!", "Goodbye!", "");
-
default:
throw new Unreachable();
}
@@ -152,7 +129,6 @@
switch (compiler) {
case R8:
- case R8_ENABLE_UNININSTANTATED_TYPE_OPTIMIZATION_FOR_INTERFACES:
case PROGUARD:
// The unverifiable method has been removed as a result of tree shaking, so the code
// does not fail with a verification error when trying to load class UnverifiableClass.
@@ -344,39 +320,6 @@
+ " type check and will be assumed to be unreachable.")))
.run(parameters.getRuntime(), mainClass.name);
checkTestRunResult(r8Result, Compiler.R8);
-
- R8TestRunResult r8ResultWithUninstantiatedTypeOptimizationForInterfaces =
- testForR8(parameters.getBackend())
- .addProgramFiles(inputJar)
- .addKeepMainRule(mainClass.name)
- .addKeepRules(
- "-keep class TestClass { public static I g; }",
- "-neverinline class TestClass { public static void m(); }")
- .enableProguardTestOptions()
- .addOptionsModification(
- options -> {
- if (mode == Mode.INVOKE_UNVERIFIABLE_METHOD) {
- options.testing.allowTypeErrors = true;
- options.getOpenClosedInterfacesOptions().suppressAllOpenInterfaces();
- } else if (mode == Mode.INVOKE_VERIFIABLE_METHOD_ON_UNVERIFIABLE_CLASS) {
- options.getOpenClosedInterfacesOptions().suppressAllOpenInterfaces();
- }
- options.enableUninstantiatedTypeOptimizationForInterfaces = true;
- })
- .allowDiagnosticWarningMessages(allowDiagnosticWarningMessages)
- .setMinApi(parameters.getApiLevel())
- .compile()
- .applyIf(
- allowDiagnosticWarningMessages,
- result ->
- result.assertAllWarningMessagesMatch(
- equalTo(
- "The method `void UnverifiableClass.unverifiableMethod()` does not"
- + " type check and will be assumed to be unreachable.")))
- .run(parameters.getRuntime(), mainClass.name);
- checkTestRunResult(
- r8ResultWithUninstantiatedTypeOptimizationForInterfaces,
- Compiler.R8_ENABLE_UNININSTANTATED_TYPE_OPTIMIZATION_FOR_INTERFACES);
}
private void checkTestRunResult(TestRunResult<?> result, Compiler compiler) {
@@ -390,7 +333,6 @@
result.assertSuccessWithOutput(getExpectedOutput(compiler));
} else {
if (compiler == Compiler.R8
- || compiler == Compiler.R8_ENABLE_UNININSTANTATED_TYPE_OPTIMIZATION_FOR_INTERFACES
|| compiler == Compiler.PROGUARD) {
result.assertSuccessWithOutput(getExpectedOutput(compiler));
} else {
@@ -405,8 +347,7 @@
if (useInterface) {
result.assertSuccessWithOutput(getExpectedOutput(compiler));
} else {
- if (compiler == Compiler.R8
- || compiler == Compiler.R8_ENABLE_UNININSTANTATED_TYPE_OPTIMIZATION_FOR_INTERFACES) {
+ if (compiler == Compiler.R8) {
result
.assertFailureWithOutput(getExpectedOutput(compiler))
.assertFailureWithErrorThatMatches(