Merge "Allow larger line ranges in map files for class file output"
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 734e421..4f472c6 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -63,7 +63,6 @@
import com.android.tools.r8.utils.ExceptionUtils;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.InternalOptions.LineNumberOptimization;
import com.android.tools.r8.utils.LineNumberOptimizer;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.SelfRetraceTest;
@@ -634,12 +633,7 @@
// When line number optimization is turned off the identity mapping for line numbers is
// used. We still run the line number optimizer to collect line numbers and inline frame
// information for the mapping file.
- ClassNameMapper classNameMapper =
- LineNumberOptimizer.run(
- application,
- appView.graphLense(),
- namingLens,
- options.lineNumberOptimization == LineNumberOptimization.OFF);
+ ClassNameMapper classNameMapper = LineNumberOptimizer.run(appView, application, namingLens);
timing.end();
proguardMapSupplier = ProguardMapSupplier.fromClassNameMapper(classNameMapper, options);
diff --git a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
index f5a4b81..427341f 100644
--- a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
+++ b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
@@ -5,6 +5,8 @@
import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.cf.code.CfPosition;
+import com.android.tools.r8.graph.AppInfoWithSubtyping;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DexApplication;
@@ -39,6 +41,7 @@
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.naming.Range;
+import com.android.tools.r8.utils.InternalOptions.LineNumberOptimization;
import com.google.common.base.Suppliers;
import java.util.ArrayList;
import java.util.IdentityHashMap;
@@ -66,13 +69,33 @@
}
private static class OptimizingPositionRemapper implements PositionRemapper {
- private int nextLineNumber = 1;
+ private final int maxLineDelta;
+ private DexMethod previousMethod = null;
+ private int previousSourceLine = -1;
+ private int nextOptimizedLineNumber = 1;
+
+ OptimizingPositionRemapper(InternalOptions options) {
+ // TODO(113198295): For dex using "Constants.DBG_LINE_RANGE + Constants.DBG_LINE_BASE"
+ // instead of 1 creates a ~30% smaller map file but the dex files gets larger due to reduced
+ // debug info canonicalization.
+ maxLineDelta = options.isGeneratingClassFiles() ? Integer.MAX_VALUE : 1;
+ }
@Override
public Position createRemappedPosition(
int line, DexString file, DexMethod method, Position callerPosition) {
- Position newPosition = new Position(nextLineNumber, file, method, null);
- ++nextLineNumber;
+ assert method != null;
+ if (previousMethod == method) {
+ assert previousSourceLine >= 0;
+ if (line > previousSourceLine && line - previousSourceLine <= maxLineDelta) {
+ nextOptimizedLineNumber += (line - previousSourceLine) - 1;
+ }
+ }
+
+ Position newPosition = new Position(nextOptimizedLineNumber, file, method, null);
+ ++nextOptimizedLineNumber;
+ previousSourceLine = line;
+ previousMethod = method;
return newPosition;
}
}
@@ -138,10 +161,9 @@
}
public static ClassNameMapper run(
+ AppView<AppInfoWithSubtyping> appView,
DexApplication application,
- GraphLense graphLense,
- NamingLens namingLens,
- boolean identityMapping) {
+ NamingLens namingLens) {
ClassNameMapper.Builder classNameMapperBuilder = ClassNameMapper.builder();
// Collect which files contain which classes that need to have their line numbers optimized.
for (DexProgramClass clazz : application.classes()) {
@@ -151,7 +173,7 @@
// At this point we don't know if we really need to add this class to the builder.
// It depends on whether any methods/fields are renamed or some methods contain positions.
// Create a supplier which creates a new, cached ClassNaming.Builder on-demand.
- DexType originalType = graphLense.getOriginalType(clazz.type);
+ DexType originalType = appView.graphLense().getOriginalType(clazz.type);
DexString renamedClassName = namingLens.lookupDescriptor(clazz.getType());
Supplier<ClassNaming.Builder> onDemandClassNamingBuilder =
Suppliers.memoize(
@@ -164,7 +186,7 @@
addClassToClassNaming(originalType, renamedClassName, onDemandClassNamingBuilder);
// First transfer renamed fields to classNamingBuilder.
- addFieldsToClassNaming(graphLense, namingLens, clazz, onDemandClassNamingBuilder);
+ addFieldsToClassNaming(appView.graphLense(), namingLens, clazz, onDemandClassNamingBuilder);
// Then process the methods, ordered by renamed name.
List<DexString> renamedMethodNames = new ArrayList<>(methodsByRenamedName.keySet());
@@ -179,8 +201,12 @@
sortMethods(methods);
}
+ boolean identityMapping =
+ appView.options().lineNumberOptimization == LineNumberOptimization.OFF;
PositionRemapper positionRemapper =
- identityMapping ? new IdentityPositionRemapper() : new OptimizingPositionRemapper();
+ identityMapping
+ ? new IdentityPositionRemapper()
+ : new OptimizingPositionRemapper(appView.options());
for (DexEncodedMethod method : methods) {
List<MappedPosition> mappedPositions = new ArrayList<>();
@@ -194,7 +220,7 @@
}
}
- DexMethod originalMethod = graphLense.getOriginalMethodSignature(method.method);
+ DexMethod originalMethod = appView.graphLense().getOriginalMethodSignature(method.method);
MethodSignature originalSignature =
MethodSignature.fromDexMethod(originalMethod, originalMethod.holder != clazz.type);
@@ -217,7 +243,7 @@
signatures.put(originalMethod, originalSignature);
Function<DexMethod, MethodSignature> getOriginalMethodSignature =
m -> {
- DexMethod original = graphLense.getOriginalMethodSignature(m);
+ DexMethod original = appView.graphLense().getOriginalMethodSignature(m);
return signatures.computeIfAbsent(
original,
key ->
diff --git a/src/test/java/com/android/tools/r8/naming/retrace/LineDeltaTest.java b/src/test/java/com/android/tools/r8/naming/retrace/LineDeltaTest.java
new file mode 100644
index 0000000..4e64e7e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/retrace/LineDeltaTest.java
@@ -0,0 +1,102 @@
+// Copyright (c) 2019, 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.naming.retrace;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.ForceInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Test;
+
+public class LineDeltaTest extends TestBase {
+ public String runTest(Backend backend) throws Exception {
+ return testForR8(backend)
+ .enableInliningAnnotations()
+ .addProgramClasses(LineDeltaTestClass.class)
+ .addKeepMainRule(LineDeltaTestClass.class)
+ .addKeepRules("-keepattributes LineNumberTable")
+ .run(LineDeltaTestClass.class)
+ .assertSuccessWithOutput(StringUtils.lines(
+ "In test1() - 1",
+ "In test1() - 2",
+ "In test1() - 3",
+ "In test1() - 4",
+ "In test2() - 1",
+ "In test2() - 2",
+ "In test2() - 3",
+ "In test2() - 4"
+ ))
+ .proguardMap();
+ }
+
+ private long mapLines(String map) {
+ return StringUtils.splitLines(map).stream().filter(line -> !line.startsWith("#")).count();
+ }
+
+ @Test
+ public void testDex() throws Exception {
+ assertEquals(17, mapLines(runTest(Backend.DEX)));
+ }
+
+ @Test
+ public void testCf() throws Exception {
+ assertEquals(5, mapLines(runTest(Backend.CF)));
+ }
+}
+
+class LineDeltaTestClass {
+ @ForceInline
+ static void test1() {
+ System.out.println("In test1() - 1");
+ // One line comment.
+ System.out.println("In test1() - 2");
+ // Two line comments.
+ //
+ System.out.println("In test1() - 3");
+ // Four line comments.
+ //
+ //
+ //
+ System.out.println("In test1() - 4");
+ }
+
+ @ForceInline
+ static void test2() {
+ System.out.println("In test2() - 1");
+ // Seven line comments.
+ //
+ //
+ //
+ //
+ //
+ //
+ System.out.println("In test2() - 2");
+ // Eight line comments.
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ System.out.println("In test2() - 3");
+ // Nine line comments.
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ System.out.println("In test2() - 4");
+ }
+
+ public static void main(String[] args) {
+ test1();
+ test2();
+ }
+}