Fix NullPointerException when inlining outline
Bug: b/514117718
Change-Id: Iafcc8cfc8a95576d8c53927a7a829192c855dea2
diff --git a/src/main/java/com/android/tools/r8/graph/Code.java b/src/main/java/com/android/tools/r8/graph/Code.java
index 91739b4..ace93b2 100644
--- a/src/main/java/com/android/tools/r8/graph/Code.java
+++ b/src/main/java/com/android/tools/r8/graph/Code.java
@@ -241,6 +241,21 @@
translatedPosition = result;
}
}
+ // Translation can fail for non-throwing outline instructions. In this case, pick the best
+ // position.
+ if (translatedPosition == null) {
+ int bestLine = Integer.MAX_VALUE;
+ Position bestPosition = null;
+ for (int i = 0; i < translation.size(); i++) {
+ int currentLine = translation.getKey(i);
+ Position currentPosition = translation.getValue(i);
+ if (outlineLine < currentLine && currentLine < bestLine && currentPosition != null) {
+ bestLine = currentLine;
+ bestPosition = currentPosition;
+ }
+ }
+ translatedPosition = bestPosition;
+ }
assert translatedPosition != null;
// If the caller has outer frames compose them with the translated position.
if (callerPosition.hasCallerPosition()) {
diff --git a/src/main/java/com/android/tools/r8/utils/Int2StructuralItemArrayMap.java b/src/main/java/com/android/tools/r8/utils/Int2StructuralItemArrayMap.java
index 8f5f5d3..05c00c3 100644
--- a/src/main/java/com/android/tools/r8/utils/Int2StructuralItemArrayMap.java
+++ b/src/main/java/com/android/tools/r8/utils/Int2StructuralItemArrayMap.java
@@ -32,6 +32,14 @@
return this;
}
+ public int getKey(int index) {
+ return keys[index];
+ }
+
+ public T getValue(int index) {
+ return values.get(index);
+ }
+
@Override
public StructuralMapping<Int2StructuralItemArrayMap<T>> getStructuralMapping() {
return Int2StructuralItemArrayMap::specify;
@@ -57,6 +65,10 @@
}
}
+ public int size() {
+ return keys.length;
+ }
+
@SuppressWarnings("unchecked")
@Override
public boolean equals(Object other) {
diff --git a/src/test/java8/ir/com/android/tools/r8/ir/optimize/inliner/SingleCallerInlineOutlineWithNonThrowingPreludeTest.java b/src/test/java8/ir/com/android/tools/r8/ir/optimize/inliner/SingleCallerInlineOutlineWithNonThrowingPreludeTest.java
index 3e90293..700ca3e 100644
--- a/src/test/java8/ir/com/android/tools/r8/ir/optimize/inliner/SingleCallerInlineOutlineWithNonThrowingPreludeTest.java
+++ b/src/test/java8/ir/com/android/tools/r8/ir/optimize/inliner/SingleCallerInlineOutlineWithNonThrowingPreludeTest.java
@@ -11,7 +11,6 @@
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.codeinspector.AssertUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import com.android.tools.r8.utils.internal.BooleanUtils;
@@ -39,62 +38,57 @@
@Test
public void test() throws Exception {
- AssertUtils.assertFailsCompilationIf(
- allowInliningOfOutlines,
- () ->
- testForR8(parameters)
- .addInnerClasses(getClass())
- .addKeepMainRule(Main.class)
- .addOptionsModification(
- options -> {
- options.outline.threshold = 2;
- options.outline.minSize = 2;
- options.getTestingOptions().allowInliningOfOutlines = allowInliningOfOutlines;
- })
- .collectSyntheticItems()
- .enableInliningAnnotations()
- .compile()
- .inspectWithSyntheticItems(
- (inspector, syntheticItems) -> {
- ClassSubject printerClassSubject = inspector.clazz(Printer.class);
- assertThat(printerClassSubject, isPresent());
+ testForR8(parameters)
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .addOptionsModification(
+ options -> {
+ options.outline.threshold = 2;
+ options.outline.minSize = 2;
+ options.getTestingOptions().allowInliningOfOutlines = allowInliningOfOutlines;
+ })
+ .collectSyntheticItems()
+ .enableInliningAnnotations()
+ .compile()
+ .inspectWithSyntheticItems(
+ (inspector, syntheticItems) -> {
+ ClassSubject printerClassSubject = inspector.clazz(Printer.class);
+ assertThat(printerClassSubject, isPresent());
- MethodSubject helloMethodSubject =
- printerClassSubject.uniqueMethodWithOriginalName("hello");
- assertThat(helloMethodSubject, isPresent());
+ MethodSubject helloMethodSubject =
+ printerClassSubject.uniqueMethodWithOriginalName("hello");
+ assertThat(helloMethodSubject, isPresent());
- MethodSubject worldMethodSubject =
- printerClassSubject.uniqueMethodWithOriginalName("world");
- assertThat(worldMethodSubject, isPresent());
+ MethodSubject worldMethodSubject =
+ printerClassSubject.uniqueMethodWithOriginalName("world");
+ assertThat(worldMethodSubject, isPresent());
- ClassSubject mainClassSubject = inspector.clazz(Main.class);
- assertThat(mainClassSubject, isPresent());
+ ClassSubject mainClassSubject = inspector.clazz(Main.class);
+ assertThat(mainClassSubject, isPresent());
- MethodSubject outlineCandidateMethodSubject =
- mainClassSubject.uniqueMethodWithOriginalName("outlineCandidate");
- assertThat(outlineCandidateMethodSubject, isPresent());
+ MethodSubject outlineCandidateMethodSubject =
+ mainClassSubject.uniqueMethodWithOriginalName("outlineCandidate");
+ assertThat(outlineCandidateMethodSubject, isPresent());
- ClassSubject outlineClassSubject =
- inspector.clazz(syntheticItems.syntheticOutlineClass(Main.class, 0));
- // Note that the outline class is present even when `allowInliningOfOutlines`
- // is true, since we do not run another round of tree shaking after the single
- // caller inliner pass.
- assertThat(outlineClassSubject, isPresent());
+ ClassSubject outlineClassSubject =
+ inspector.clazz(syntheticItems.syntheticOutlineClass(Main.class, 0));
+ // Note that the outline class is present even when `allowInliningOfOutlines`
+ // is true, since we do not run another round of tree shaking after the single
+ // caller inliner pass.
+ assertThat(outlineClassSubject, isPresent());
- if (allowInliningOfOutlines) {
- assertThat(
- outlineCandidateMethodSubject,
- allOf(
- invokesMethod(helloMethodSubject),
- invokesMethod(worldMethodSubject)));
- } else {
- assertThat(
- outlineCandidateMethodSubject,
- invokesMethod(outlineClassSubject.uniqueMethod()));
- }
- })
- .run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines("Hello 3.0, world!"));
+ if (allowInliningOfOutlines) {
+ assertThat(
+ outlineCandidateMethodSubject,
+ allOf(invokesMethod(helloMethodSubject), invokesMethod(worldMethodSubject)));
+ } else {
+ assertThat(
+ outlineCandidateMethodSubject,
+ invokesMethod(outlineClassSubject.uniqueMethod()));
+ }
+ })
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("Hello 3.0, world!");
}
static class Main {