Fix optimization of Objects.requireNonNullElseGet
Fixes: 196945191
Change-Id: I1bd37f1b375d0e57b1d99ba3f37c32c0b9de2505
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectsMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectsMethodOptimizer.java
index 08199da..4b7cffb 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectsMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectsMethodOptimizer.java
@@ -183,16 +183,8 @@
}
instructionIterator.removeOrReplaceByDebugLocalRead();
} else if (singleTarget.getReference() == objectsMethods.requireNonNullElseGet) {
- // Optimize Objects.requireNonNullElseGet(null, supplier) into supplier.get().
- if (invoke.hasOutValue()) {
- invoke.outValue().replaceUsers(invoke.getLastArgument(), affectedValues);
- }
- instructionIterator.replaceCurrentInstruction(
- InvokeVirtual.builder()
- .setMethod(dexItemFactory.supplierMembers.get)
- .setOutValue(invoke.outValue())
- .setSingleArgument(invoke.getLastArgument())
- .build());
+ // Don't optimize Objects.requireNonNullElseGet. The result of calling supplier.get() still
+ // needs a null-check, so two invokes will be needed.
}
}
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/library/ObjectsRequireNonNullElseGetTest.java b/src/test/java/com/android/tools/r8/ir/optimize/library/ObjectsRequireNonNullElseGetTest.java
index e0a4c6d..aadd5dd 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/library/ObjectsRequireNonNullElseGetTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/library/ObjectsRequireNonNullElseGetTest.java
@@ -41,7 +41,17 @@
}
@Test
- public void test() throws Exception {
+ public void testD8() throws Exception {
+ testForD8(parameters.getBackend())
+ .addProgramClassFileData(getProgramClassFileData())
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("Foo", "Bar", "Expected NPE");
+ }
+
+ @Test
+ public void testR8() throws Exception {
testForR8(parameters.getBackend())
.addProgramClassFileData(getProgramClassFileData())
.addKeepMainRule(Main.class)
@@ -65,10 +75,12 @@
assertThat(testNullArgumentMethodSubject, isPresent());
assertThat(
testNullArgumentMethodSubject,
- not(invokesMethodWithName("requireNonNullElseGet")));
+ parameters.getApiLevel().isGreaterThan(AndroidApiLevel.Q)
+ ? invokesMethodWithName("requireNonNullElseGet")
+ : not(invokesMethodWithName("requireNonNullElseGet")));
})
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines("Foo", "Bar");
+ .assertSuccessWithOutputLines("Foo", "Bar", "Expected NPE");
}
private byte[] getProgramClassFileData() throws IOException {
@@ -83,6 +95,12 @@
public static void main(String[] args) {
testNonNullArgument();
testNullArgument();
+ try {
+ testNullArgumentAndNullSupplier();
+ System.out.println("Unexpected");
+ } catch (NullPointerException e) {
+ System.out.println("Expected NPE");
+ }
}
@NeverInline
@@ -94,6 +112,11 @@
static void testNullArgument() {
System.out.println(Mock.requireNonNullElseGet(null, () -> "Bar"));
}
+
+ @NeverInline
+ static void testNullArgumentAndNullSupplier() {
+ System.out.println(Mock.requireNonNullElseGet(null, () -> null));
+ }
}
// References to this class are rewritten to java.util.Objects by transformation.