Add caller-preserving positions to CfSourceCode and enable CF in test.

... in the test DebugInfoWhenInlining.

Change-Id: I54f926420bc7ac61d1d84168c81df3b9975c78c8
diff --git a/src/main/java/com/android/tools/r8/graph/CfCode.java b/src/main/java/com/android/tools/r8/graph/CfCode.java
index b8e0bd8..776cc42 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -19,6 +19,7 @@
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.InternalOptions.LineNumberOptimization;
 import java.util.Collections;
 import java.util.List;
 import org.objectweb.asm.Label;
@@ -230,7 +231,13 @@
       throw new Unimplemented(
           "Converting CfCode to IR not supported for DEX output of synchronized methods.");
     }
-    CfSourceCode source = new CfSourceCode(this, encodedMethod, callerPosition, origin);
+    CfSourceCode source =
+        new CfSourceCode(
+            this,
+            encodedMethod,
+            callerPosition,
+            origin,
+            options.lineNumberOptimization == LineNumberOptimization.ON);
     IRBuilder builder =
         (generator == null)
             ? new IRBuilder(encodedMethod, appInfo, source, options)
diff --git a/src/main/java/com/android/tools/r8/ir/code/CanonicalPositions.java b/src/main/java/com/android/tools/r8/ir/code/CanonicalPositions.java
index 8db07f6..66456cd 100644
--- a/src/main/java/com/android/tools/r8/ir/code/CanonicalPositions.java
+++ b/src/main/java/com/android/tools/r8/ir/code/CanonicalPositions.java
@@ -18,13 +18,14 @@
   private final Map<Position, Position> canonicalPositions;
   private final Position preamblePosition;
 
-  /**
-   * For callerPosition and preserveCaller see canonicalizeCallerPosition. initialCapacity will be
-   * passed to the HashMap constructor.
-   */
+  /** For callerPosition and preserveCaller see canonicalizeCallerPosition. */
   public CanonicalPositions(
-      Position callerPosition, boolean preserveCaller, int initialCapacity, DexMethod method) {
-    canonicalPositions = new HashMap<>(initialCapacity);
+      Position callerPosition,
+      boolean preserveCaller,
+      int expectedPositionsCount,
+      DexMethod method) {
+    canonicalPositions =
+        new HashMap<>(1 + (callerPosition == null ? 0 : 1) + expectedPositionsCount);
     this.preserveCaller = preserveCaller;
     this.callerPosition = callerPosition;
     if (callerPosition != null) {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
index 4cbebcf..92645c4 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
@@ -21,6 +21,7 @@
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.code.CanonicalPositions;
 import com.android.tools.r8.ir.code.CatchHandlers;
 import com.android.tools.r8.ir.code.Position;
 import com.android.tools.r8.ir.code.ValueType;
@@ -184,8 +185,6 @@
   private final Position callerPosition;
   private final Origin origin;
 
-  // Synthetic position with line = 0.
-  private final Position preamblePosition;
   private final Reference2IntMap<CfLabel> labelOffsets = new Reference2IntOpenHashMap<>();
   private TryHandlerList cachedTryHandlerList;
   private LocalVariableList cachedLocalVariableList;
@@ -196,21 +195,31 @@
   private Int2ReferenceMap<Int2ObjectMap<DebugLocalInfo>> definitelyLiveIncomingLocals =
       new Int2ReferenceOpenHashMap<>();
   private Int2ReferenceMap<CfState.Snapshot> incomingState = new Int2ReferenceOpenHashMap<>();
+  private final CanonicalPositions canonicalPositions;
 
   public CfSourceCode(
-      CfCode code, DexEncodedMethod method, Position callerPosition, Origin origin) {
+      CfCode code,
+      DexEncodedMethod method,
+      Position callerPosition,
+      Origin origin,
+      boolean preserveCaller) {
     this.code = code;
     this.method = method;
     this.callerPosition = callerPosition;
     this.origin = origin;
-    preamblePosition = Position.synthetic(0, method.method, null);
+    int cfPositionCount = 0;
     for (int i = 0; i < code.getInstructions().size(); i++) {
       CfInstruction instruction = code.getInstructions().get(i);
       if (instruction instanceof CfLabel) {
         labelOffsets.put((CfLabel) instruction, instructionOffset(i));
       }
+      if (instruction instanceof CfPosition) {
+        ++cfPositionCount;
+      }
     }
     this.state = new CfState(origin);
+    canonicalPositions =
+        new CanonicalPositions(callerPosition, preserveCaller, cfPositionCount, this.method.method);
   }
 
   @Override
@@ -383,7 +392,21 @@
       }
       state.clear();
     } else {
-      instruction.buildIR(builder, state, this);
+      if (instruction instanceof CfPosition) {
+        CfPosition cfPosition = (CfPosition) instruction;
+        Position position = cfPosition.getPosition();
+        Position newPosition =
+            canonicalPositions.getCanonical(
+                new Position(
+                    position.line,
+                    position.file,
+                    position.method,
+                    canonicalPositions.canonicalizeCallerPosition(position.callerPosition)));
+        CfPosition newCfPosition = new CfPosition(cfPosition.getLabel(), newPosition);
+        newCfPosition.buildIR(builder, state, this);
+      } else {
+        instruction.buildIR(builder, state, this);
+      }
       ensureDebugValueLiveness(builder);
       if (builder.getCFG().containsKey(currentInstructionIndex + 1)) {
         recordStateForTarget(currentInstructionIndex + 1, state.getSnapshot());
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
index e0c47da..9a9b836 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
@@ -93,7 +93,7 @@
         new CanonicalPositions(
             callerPosition,
             preserveCaller,
-            1 + (callerPosition == null ? 0 : 1) + (debugEntries == null ? 0 : debugEntries.size()),
+            debugEntries == null ? 0 : debugEntries.size(),
             this.method);
   }
 
diff --git a/src/test/java/com/android/tools/r8/debug/DebugInfoWhenInliningTest.java b/src/test/java/com/android/tools/r8/debug/DebugInfoWhenInliningTest.java
index f2e96b3..f010357 100644
--- a/src/test/java/com/android/tools/r8/debug/DebugInfoWhenInliningTest.java
+++ b/src/test/java/com/android/tools/r8/debug/DebugInfoWhenInliningTest.java
@@ -3,11 +3,13 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.debug;
 
+
 import com.android.tools.r8.CompilationMode;
 import com.android.tools.r8.OutputMode;
 import com.android.tools.r8.R8Command;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.debug.DebugTestBase.JUnit3Wrapper.Command;
+import com.android.tools.r8.debug.DebugTestConfig.RuntimeKind;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.InternalOptions.LineNumberOptimization;
 import com.google.common.collect.ImmutableList;
@@ -25,45 +27,64 @@
 @RunWith(Parameterized.class)
 public class DebugInfoWhenInliningTest extends DebugTestBase {
 
+  public enum Config {
+    CF,
+    DEX_NO_FORCE_JUMBO,
+    DEX_FORCE_JUMBO
+  };
+
   private static final String SOURCE_FILE = "Inlining1.java";
 
   private DebugTestConfig makeConfig(
       LineNumberOptimization lineNumberOptimization,
-      boolean writeProguardMap)
+      boolean writeProguardMap,
+      RuntimeKind runtimeKind)
       throws Exception {
-    AndroidApiLevel minSdk = ToolHelper.getMinApiLevelForDexVm();
+    DebugTestConfig config = null;
     Path outdir = temp.newFolder().toPath();
-    Path outjar = outdir.resolve("dex_r8_compiled.jar");
-    Path proguardMapPath = writeProguardMap ? outdir.resolve("proguard.map") : null;
+    Path outjar = outdir.resolve("r8_compiled.jar");
     R8Command.Builder builder =
-        R8Command.builder()
-            .addProgramFiles(DEBUGGEE_JAR)
-            .setMinApiLevel(minSdk.getLevel())
-            .addLibraryFiles(ToolHelper.getAndroidJar(minSdk))
-            .setMode(CompilationMode.RELEASE)
-            .setOutput(outjar, OutputMode.DexIndexed);
-    if (proguardMapPath != null) {
-      builder.setProguardMapOutputPath(proguardMapPath);
+        R8Command.builder().addProgramFiles(DEBUGGEE_JAR).setMode(CompilationMode.RELEASE);
+
+    if (runtimeKind == RuntimeKind.DEX) {
+      AndroidApiLevel minSdk = ToolHelper.getMinApiLevelForDexVm();
+      builder
+          .setMinApiLevel(minSdk.getLevel())
+          .addLibraryFiles(ToolHelper.getAndroidJar(minSdk))
+          .setOutput(outjar, OutputMode.DexIndexed);
+      config = new DexDebugTestConfig(outjar);
+    } else {
+      assert (runtimeKind == RuntimeKind.CF);
+      builder.setOutput(outjar, OutputMode.ClassFile);
+      config = new CfDebugTestConfig(outjar);
     }
+
+    if (writeProguardMap) {
+      Path proguardMapPath = outdir.resolve("proguard.map");
+      builder.setProguardMapOutputPath(proguardMapPath);
+      config.setProguardMap(proguardMapPath);
+    }
+
     ToolHelper.runR8(
         builder.build(), options -> {
           options.lineNumberOptimization = lineNumberOptimization;
           options.testing.forceJumboStringProcessing = forceJumboStringProcessing;
         });
-    DebugTestConfig config = new DexDebugTestConfig(outjar);
-    config.setProguardMap(proguardMapPath);
+
     return config;
   }
 
   private boolean forceJumboStringProcessing;
+  private RuntimeKind runtimeKind;
 
-  @Parameters(name="forceJumbo: {0}")
-  public static Collection<Boolean> data() {
-    return Arrays.asList(true, false);
+  @Parameters(name = "config: {0}")
+  public static Collection<Config> data() {
+    return Arrays.asList(Config.values());
   }
 
-  public DebugInfoWhenInliningTest(boolean forceJumboStringProcessing) {
-    this.forceJumboStringProcessing = forceJumboStringProcessing;
+  public DebugInfoWhenInliningTest(Config config) {
+    this.forceJumboStringProcessing = config == Config.DEX_FORCE_JUMBO;
+    this.runtimeKind = config == Config.CF ? RuntimeKind.CF : RuntimeKind.DEX;
   }
 
   @Test
@@ -75,7 +96,7 @@
     // (innermost callee) the line numbers are actually 7, 7, 32, 32, ... but even if the positions
     // are emitted duplicated in the dex code, the debugger stops only when there's a change.
     int[] lineNumbers = {7, 32, 11, 7};
-    testEachLine(makeConfig(LineNumberOptimization.OFF, false), lineNumbers);
+    testEachLine(makeConfig(LineNumberOptimization.OFF, false, runtimeKind), lineNumbers);
   }
 
   @Test
@@ -87,13 +108,13 @@
     // (innermost callee) the line numbers are actually 7, 7, 32, 32, ... but even if the positions
     // are emitted duplicated in the dex code, the debugger stops only when there's a change.
     int[] lineNumbers = {7, 32, 11, 7};
-    testEachLine(makeConfig(LineNumberOptimization.OFF, true), lineNumbers);
+    testEachLine(makeConfig(LineNumberOptimization.OFF, true, runtimeKind), lineNumbers);
   }
 
   @Test
   public void testEachLineOptimized() throws Throwable {
     int[] lineNumbers = {1, 2, 3, 4, 5, 6, 7, 8};
-    testEachLine(makeConfig(LineNumberOptimization.ON, false), lineNumbers);
+    testEachLine(makeConfig(LineNumberOptimization.ON, false, runtimeKind), lineNumbers);
   }
 
   @Test
@@ -130,7 +151,7 @@
                 new SignatureAndLine("void Inlining2.differentFileMultilevelInliningLevel1()", 36),
                 new SignatureAndLine("void main(java.lang.String[])", 26)));
     testEachLine(
-        makeConfig(LineNumberOptimization.ON, true), lineNumbers, inlineFramesList);
+        makeConfig(LineNumberOptimization.ON, true, runtimeKind), lineNumbers, inlineFramesList);
   }
 
   private void testEachLine(DebugTestConfig config, int[] lineNumbers) throws Throwable {