Preserve line information when targeting VMs with PC reporting.
Bug: b/279555568
Change-Id: I47457625f511799530b90d530f4c8ac56bd1c327
diff --git a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
index e54e691..b3b5680 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
@@ -1195,7 +1195,8 @@
|| keep.localVariableTable
|| keep.localVariableTypeTable
|| reachabilitySensitive;
- boolean lineInfo = keep.lineNumberTable;
+ boolean lineInfo =
+ (keep.lineNumberTable || application.options.canUseNativeDexPcInsteadOfDebugInfo());
boolean methodParaeters = keep.methodParameters;
if (!localsInfo && !lineInfo && !methodParaeters) {
diff --git a/src/test/java/com/android/tools/r8/debuginfo/NoKeepLineAttributeTest.java b/src/test/java/com/android/tools/r8/debuginfo/NoKeepLineAttributeTest.java
new file mode 100644
index 0000000..35ae932
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/debuginfo/NoKeepLineAttributeTest.java
@@ -0,0 +1,71 @@
+// Copyright (c) 2023, 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 static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class NoKeepLineAttributeTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters()
+ // Only run the test on VMs that have native pc support.
+ .withDexRuntimesStartingFromExcluding(Version.V7_0_0)
+ .withAllApiLevels()
+ .build();
+ }
+
+ public NoKeepLineAttributeTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(NoKeepLineAttributeTest.class)
+ .addKeepMainRule(TestClass.class)
+ .setMinApi(parameters)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertFailureWithErrorThatThrows(RuntimeException.class)
+ .inspectStackTrace(
+ stacktrace -> {
+ List<StackTraceLine> stackTraceLines = stacktrace.getStackTraceLines();
+ assertEquals(1, stackTraceLines.size());
+ StackTraceLine stackTraceLine = stackTraceLines.get(0);
+ // The frame will always have a line as the VM is reporting the PC.
+ assertTrue(stackTraceLine.hasLineNumber());
+ if (parameters.getApiLevel().isLessThan(apiLevelWithPcAsLineNumberSupport())) {
+ // If the compile-time API is before native support then no line info is present.
+ // The "line" will be the PC and thus small.
+ assertTrue(stackTraceLine.lineNumber < 10);
+ } else {
+ // If the compile-time API is after native support then the compiler will retain and
+ // emit the mapping from PC to original line. Here line 50 is to ensure it is not a
+ // low PC value.
+ assertTrue(stackTraceLine.lineNumber > 50);
+ }
+ });
+ }
+
+ static class TestClass {
+
+ public static void main(String[] args) {
+ throw new RuntimeException("My Exception!");
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java b/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java
index cba424a..d32f6f9 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java
@@ -212,8 +212,11 @@
private boolean canSharePrintCallInSuccessorBlock() {
// With API level >= Q we get a register assignment that allows us to share the print call in a
// successor block. See also InternalOptions.canHaveThisJitCodeDebuggingBug().
+ // Due to including line-info (b/279555568) this is always false. Keeping the conflicting
+ // predicates here for documentation of the previously witnessed difference.
return parameters.isDexRuntime()
- && parameters.getApiLevel().getLevel() >= AndroidApiLevel.Q.getLevel();
+ && parameters.getApiLevel().getLevel() >= AndroidApiLevel.Q.getLevel()
+ && parameters.getApiLevel().isLessThan(apiLevelWithPcAsLineNumberSupport());
}
@Test
@@ -241,6 +244,7 @@
NonNullParamAfterInvokeInterface.class,
NonNullParamInterfaceImpl.class))
.addOptionsModification(this::disableDevirtualization)
+ .addKeepAttributeLineNumberTable()
.enableAlwaysInliningAnnotations()
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
@@ -252,8 +256,7 @@
MethodSubject checkViaCall = mainSubject.uniqueMethodWithOriginalName("checkViaCall");
assertThat(checkViaCall, isPresent());
assertEquals(0, countActCall(checkViaCall));
- // The DEX backend reuses the System.out.println invoke.
- assertEquals(parameters.isCfRuntime() ? 2 : 1, countPrintCall(checkViaCall));
+ assertEquals(2, countPrintCall(checkViaCall));
}
private long countCallToParamNullCheck(MethodSubject method) {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/StringBuilderTests.java b/src/test/java/com/android/tools/r8/ir/optimize/string/StringBuilderTests.java
index 7464aec..a78dbbf 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/string/StringBuilderTests.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/string/StringBuilderTests.java
@@ -222,10 +222,14 @@
FoundMethodSubject foundMethodSubject = method.asFoundMethodSubject();
assertEquals(
stringBuilderTest.stringBuilders, countStringBuilderInits(foundMethodSubject));
- if (parameters.isCfRuntime()
+ if ((parameters.isCfRuntime()
+ || parameters
+ .getApiLevel()
+ .isGreaterThanOrEqualTo(apiLevelWithPcAsLineNumberSupport()))
&& (stringBuilderTest.getMethodName().equals("diamondWithUseTest")
|| stringBuilderTest.getMethodName().equals("intoPhiTest"))) {
- // We are not doing block suffix optimization in CF.
+ // We are not doing block suffix optimization in CF and line/pc info prohibits
+ // sharing.
assertEquals(
stringBuilderTest.appends + 1, countStringBuilderAppends(foundMethodSubject));
} else {
diff --git a/src/test/java/com/android/tools/r8/regress/Regress160394262Test.java b/src/test/java/com/android/tools/r8/regress/Regress160394262Test.java
index d56e49c..c4fa84b 100644
--- a/src/test/java/com/android/tools/r8/regress/Regress160394262Test.java
+++ b/src/test/java/com/android/tools/r8/regress/Regress160394262Test.java
@@ -59,7 +59,13 @@
private void checkJoinerIsClassInlined(CodeInspector inspector) {
assertThat(inspector.clazz(Joiner.class.getTypeName() + "$1"), isAbsent());
// TODO(b/160640028): Joiner should be class inlined.
- assertThat(inspector.clazz(Joiner.class), isPresent());
+ // When line info tables are kept we appear to successfully inline Joiner. Reason unknown.
+ if (parameters.isCfRuntime()
+ || parameters.getApiLevel().isLessThan(apiLevelWithPcAsLineNumberSupport())) {
+ assertThat(inspector.clazz(Joiner.class), isPresent());
+ } else {
+ assertThat(inspector.clazz(Joiner.class), isAbsent());
+ }
}
static class TestClass {