Synthesize null-check to enable inlining of invokes with nullable receiver
Bug: 130202534, 113859358
Change-Id: I28d37f8e109fc4080617bf68ee6d3e41c12465bf
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 25dd6e8..b451490 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -144,8 +144,7 @@
public boolean enableNonNullTracking = true;
public boolean enableInlining =
!Version.isDev() || System.getProperty("com.android.tools.r8.disableinlining") == null;
- // TODO(b/130202534): Enable this once code size regressions are fixed.
- public boolean enableInliningOfInvokesWithNullableReceivers = false;
+ public boolean enableInliningOfInvokesWithNullableReceivers = true;
public boolean enableClassInlining = true;
public boolean enableClassStaticizer = true;
public boolean enableInitializedClassesAnalysis = true;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineInvokeWithNullableReceiverTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineInvokeWithNullableReceiverTest.java
index bb42f7c..c00b563 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineInvokeWithNullableReceiverTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineInvokeWithNullableReceiverTest.java
@@ -6,8 +6,9 @@
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.TestBase;
@@ -66,16 +67,14 @@
assertThat(methodSubject, isPresent());
// A `throw` instruction should have been synthesized into main().
- // TODO(b/130202534): Allow inlining.
- assertFalse(methodSubject.streamInstructions().anyMatch(InstructionSubject::isThrow));
+ assertTrue(methodSubject.streamInstructions().anyMatch(InstructionSubject::isThrow));
// Class A is still present because the instance flows into a phi that has a null-check.
ClassSubject otherClassSubject = inspector.clazz(A.class);
assertThat(otherClassSubject, isPresent());
// Method A.m() should no longer be present due to inlining.
- // TODO(b/130202534): Allow inlining.
- assertThat(otherClassSubject.uniqueMethodWithName("m"), isPresent());
+ assertThat(otherClassSubject.uniqueMethodWithName("m"), not(isPresent()));
}
static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/naming/b130791310/B130791310.java b/src/test/java/com/android/tools/r8/naming/b130791310/B130791310.java
index 40482d3..40cd981 100644
--- a/src/test/java/com/android/tools/r8/naming/b130791310/B130791310.java
+++ b/src/test/java/com/android/tools/r8/naming/b130791310/B130791310.java
@@ -7,17 +7,20 @@
import static com.android.tools.r8.utils.codeinspector.Matchers.isRenamed;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assume.assumeFalse;
import com.android.tools.r8.ProguardTestBuilder;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ir.optimize.Inliner.Reason;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -86,14 +89,16 @@
);
private final boolean enableClassMerging;
+ private final boolean onlyForceInlining;
- @Parameterized.Parameters(name = "enable class merging: {0}")
- public static Boolean[] data() {
- return BooleanUtils.values();
+ @Parameterized.Parameters(name = "enable class merging: {0}, only force inlining: {1}")
+ public static List<Object[]> data() {
+ return buildParameters(BooleanUtils.values(), BooleanUtils.values());
}
- public B130791310(boolean enableClassMerging) {
+ public B130791310(boolean enableClassMerging, boolean onlyForceInlining) {
this.enableClassMerging = enableClassMerging;
+ this.onlyForceInlining = onlyForceInlining;
}
private void inspect(CodeInspector inspector, boolean isR8) {
@@ -101,18 +106,28 @@
assertThat(holder, isPresent());
assertThat(holder, not(isRenamed()));
MethodSubject someMethod = holder.uniqueMethodWithName("someMethod");
- if (enableClassMerging && !isR8) {
- // Note that the method is not entirely gone, but merged to the implementer, along with some
- // method signature modification.
- assertThat(someMethod, not(isPresent()));
+ if (isR8) {
+ if (onlyForceInlining) {
+ assertThat(someMethod, isPresent());
+ assertThat(someMethod, not(isRenamed()));
+ } else {
+ assertThat(someMethod, not(isPresent()));
+ }
} else {
- assertThat(someMethod, isPresent());
- assertThat(someMethod, not(isRenamed()));
+ if (enableClassMerging) {
+ // Note that the method is not entirely gone, but merged to the implementer, along with some
+ // method signature modification.
+ assertThat(someMethod, not(isPresent()));
+ } else {
+ assertThat(someMethod, isPresent());
+ assertThat(someMethod, not(isRenamed()));
+ }
}
}
@Test
public void testProguard() throws Exception {
+ assumeFalse(onlyForceInlining);
ProguardTestBuilder builder =
testForProguard()
.addProgramClasses(CLASSES)
@@ -138,6 +153,10 @@
if (!enableClassMerging) {
builder.addOptionsModification(o -> o.enableVerticalClassMerging = false);
}
+ if (onlyForceInlining) {
+ builder.addOptionsModification(
+ o -> o.testing.validInliningReasons = ImmutableSet.of(Reason.FORCE));
+ }
builder
.compile()
.inspect(inspector -> inspect(inspector, true));