Merge "Don't consider local-associated SSA values as constants."
diff --git a/build.gradle b/build.gradle
index dfb4623..d8402bc 100644
--- a/build.gradle
+++ b/build.gradle
@@ -109,6 +109,7 @@
         "third_party": [
                 "android_jar/lib-v14.tar.gz",
                 "android_jar/lib-v19.tar.gz",
+                "android_jar/lib-v21.tar.gz",
                 "android_jar/lib-v24.tar.gz",
                 "android_jar/lib-v25.tar.gz",
                 "android_jar/lib-v26.tar.gz",
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index fbcd34c..11cc9bc 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -207,7 +207,6 @@
       RootSet rootSet;
       byte[] proguardSeedsData = null;
       timing.begin("Strip unused code");
-      Set<DexType> mainDexBaseClasses = null;
       try {
         Set<DexType> missingClasses = appInfo.getMissingClasses();
         missingClasses = filterMissingClasses(missingClasses, options.dontWarnPatterns);
@@ -281,7 +280,7 @@
         // Lets find classes which may have code executed before secondary dex files installation.
         RootSet mainDexRootSet =
             new RootSetBuilder(application, appInfo, options.mainDexKeepRules).run(executorService);
-        mainDexBaseClasses = enqueuer.traceMainDex(mainDexRootSet, timing);
+        Set<DexType> mainDexBaseClasses = enqueuer.traceMainDex(mainDexRootSet, timing);
 
         // Calculate the automatic main dex list according to legacy multidex constraints.
         // Add those classes to an eventual manual list of classes.
@@ -309,7 +308,8 @@
         }
       }
 
-      if (!rootSet.checkDiscarded.isEmpty()) {
+      // Only perform discard-checking if tree-shaking is turned on.
+      if (options.useTreeShaking && !rootSet.checkDiscarded.isEmpty()) {
         new DiscardedChecker(rootSet, application).run();
       }
 
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
index d7fb9f8..1636c56 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -6,6 +6,7 @@
 import com.android.tools.r8.dex.VirtualFile.FilePerClassDistributor;
 import com.android.tools.r8.dex.VirtualFile.FillFilesDistributor;
 import com.android.tools.r8.dex.VirtualFile.PackageMapDistributor;
+import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.DexAnnotation;
 import com.android.tools.r8.graph.DexAnnotationSet;
@@ -124,6 +125,16 @@
         assert packageDistribution == null :
             "Cannot combine package distribution definition with file-per-class option.";
         distributor = new FilePerClassDistributor(this);
+      } else if (options.minApiLevel < Constants.ANDROID_L_API
+            && options.mainDexKeepRules.isEmpty()
+            && application.mainDexList.isEmpty()) {
+        if (packageDistribution != null) {
+          throw new CompilationError("Cannot apply package distribution. Multidex is not"
+              + " supported with API level " + options.minApiLevel +"."
+              + " For API level < " + Constants.ANDROID_L_API + ", main dex classes list or"
+              + " rules must be specified.");
+        }
+        distributor = new VirtualFile.MonoDexDistributor(this);
       } else if (packageDistribution != null) {
         assert !options.minimalMainDex :
             "Cannot combine package distribution definition with minimal-main-dex option.";
diff --git a/src/main/java/com/android/tools/r8/dex/Constants.java b/src/main/java/com/android/tools/r8/dex/Constants.java
index 9527a97..3ea63bb 100644
--- a/src/main/java/com/android/tools/r8/dex/Constants.java
+++ b/src/main/java/com/android/tools/r8/dex/Constants.java
@@ -10,8 +10,8 @@
 
   public static final int ANDROID_O_API = 26;
   public static final int ANDROID_N_API = 24;
-  public static final int ANDROID_K_API = 19;
   public static final int ANDROID_L_API = 21;
+  public static final int ANDROID_K_API = 19;
   public static final int DEFAULT_ANDROID_API = 1;
 
   /** dex file version number for Android O (API level 26) */
diff --git a/src/main/java/com/android/tools/r8/dex/VirtualFile.java b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
index 55511fd..0e89d4a 100644
--- a/src/main/java/com/android/tools/r8/dex/VirtualFile.java
+++ b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
@@ -325,6 +325,27 @@
     }
   }
 
+  public static class MonoDexDistributor extends DistributorBase {
+    public MonoDexDistributor(ApplicationWriter writer) {
+      super(writer);
+    }
+
+    @Override
+    public Map<Integer, VirtualFile> run() throws ExecutionException, IOException {
+      VirtualFile mainDexFile = new VirtualFile(0, writer.namingLens);
+      nameToFileMap.put(0, mainDexFile);
+
+      for (DexProgramClass programClass : classes) {
+        mainDexFile.addClass(programClass);
+        if (mainDexFile.isFull()) {
+          throw new CompilationError("Cannot fit all classes in a single dex file.");
+        }
+      }
+      mainDexFile.commitTransaction();
+      return nameToFileMap;
+    }
+  }
+
   public static class PackageMapDistributor extends DistributorBase {
     private final PackageDistribution packageDistribution;
     private final ExecutorService executorService;
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 04c01be..dca5e02 100644
--- a/src/main/java/com/android/tools/r8/graph/Code.java
+++ b/src/main/java/com/android/tools/r8/graph/Code.java
@@ -19,7 +19,7 @@
 
   public abstract String toString();
 
-  public abstract String toString(ClassNameMapper naming);
+  public abstract String toString(DexEncodedMethod method, ClassNameMapper naming);
 
   public boolean isDexCode() {
     return false;
diff --git a/src/main/java/com/android/tools/r8/graph/DexApplication.java b/src/main/java/com/android/tools/r8/graph/DexApplication.java
index e7485aa..eea0169 100644
--- a/src/main/java/com/android/tools/r8/graph/DexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/DexApplication.java
@@ -174,7 +174,7 @@
         ps.println("Bytecode for");
         ps.println("Class: '" + clazzName + "'");
         ps.println("Method: '" + methodName + "':");
-        ps.println(method.getCode().toString(naming));
+        ps.println(method.getCode().toString(method, naming));
       } catch (IOException e) {
         e.printStackTrace();
       } finally {
diff --git a/src/main/java/com/android/tools/r8/graph/DexCode.java b/src/main/java/com/android/tools/r8/graph/DexCode.java
index ebfd388..f48e7db 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCode.java
@@ -15,9 +15,11 @@
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.StringUtils;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Hashtable;
+import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
 
@@ -157,10 +159,10 @@
   }
 
   public String toString() {
-    return toString(null);
+    return toString(null, null);
   }
 
-  public String toString(ClassNameMapper naming) {
+  public String toString(DexEncodedMethod method, ClassNameMapper naming) {
     StringBuilder builder = new StringBuilder();
     builder.append("registers: ").append(registerSize);
     builder.append(", inputs: ").append(incomingRegisterSize);
@@ -168,12 +170,22 @@
     builder.append("------------------------------------------------------------\n");
     builder.append("inst#  offset  instruction         arguments\n");
     builder.append("------------------------------------------------------------\n");
+    DexDebugEntry debugInfo = null;
+    Iterator<DexDebugEntry> debugInfoIterator = Collections.emptyIterator();
+    if (getDebugInfo() != null && method != null) {
+      debugInfoIterator = new DexDebugEntryBuilder(method, new DexItemFactory()).build().iterator();
+      debugInfo = debugInfoIterator.hasNext() ? debugInfoIterator.next() : null;
+    }
     int instructionNumber = 0;
     for (Instruction insn : instructions) {
       StringUtils.appendLeftPadded(builder, Integer.toString(instructionNumber++), 5);
       builder.append(": ")
           .append(insn.toString(naming))
           .append('\n');
+      if (debugInfo != null && debugInfo.address == insn.getOffset()) {
+        builder.append("      ").append(debugInfo).append("\n");
+        debugInfo = debugInfoIterator.hasNext() ? debugInfoIterator.next() : null;
+      }
     }
     if (tries.length > 0) {
       builder.append("Tries (numbers are offsets)\n");
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugEntryBuilder.java b/src/main/java/com/android/tools/r8/graph/DexDebugEntryBuilder.java
index f6d8fb4..4410f2a 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugEntryBuilder.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugEntryBuilder.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.graph;
 
+import com.android.tools.r8.ir.code.MoveType;
 import com.google.common.collect.ImmutableMap;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -60,19 +61,19 @@
     DexCode code = method.getCode().asDexCode();
     DexDebugInfo info = code.getDebugInfo();
     int argumentRegister = code.registerSize - code.incomingRegisterSize;
-    int argumentCount = code.incomingRegisterSize;
     if (!method.accessFlags.isStatic()) {
-      --argumentCount;
       DexString name = factory.thisName;
       DexType type = method.method.getHolder();
-      startLocal(argumentRegister++, name, type, null);
+      startLocal(argumentRegister, name, type, null);
+      argumentRegister += MoveType.fromDexType(type).requiredRegisters();
     }
     DexType[] types = method.method.proto.parameters.values;
     DexString[] names = info.parameters;
-    for (int i = 0; i < argumentCount; i++) {
+    for (int i = 0; i < types.length; i++) {
       // If null, the parameter has a parameterized type and the local is introduced in the stream.
       if (names[i] != null) {
-        startLocal(argumentRegister++, names[i], types[i], null);
+        startLocal(argumentRegister, names[i], types[i], null);
+        argumentRegister += MoveType.fromDexType(types[i]).requiredRegisters();
       }
     }
     currentLine = info.startLine;
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 35ebaf2..3df2fab 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -348,7 +348,7 @@
   }
 
   public String codeToString() {
-    return code == null ? "<no code>" : code.toString();
+    return code == null ? "<no code>" : code.toString(this, null);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/graph/JarCode.java b/src/main/java/com/android/tools/r8/graph/JarCode.java
index 2766684..9a367ff 100644
--- a/src/main/java/com/android/tools/r8/graph/JarCode.java
+++ b/src/main/java/com/android/tools/r8/graph/JarCode.java
@@ -112,7 +112,7 @@
   }
 
   @Override
-  public String toString(ClassNameMapper naming) {
+  public String toString(DexEncodedMethod method, ClassNameMapper naming) {
     return toString();
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java b/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java
index 0da5b43..6c5fbb7 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java
@@ -90,7 +90,7 @@
   @Override
   public void buildDex(DexBuilder builder) {
     if (!dest().needsRegister()) {
-      builder.addNop(this);
+      builder.addFallThrough(this);
       return;
     }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/DebugPosition.java b/src/main/java/com/android/tools/r8/ir/code/DebugPosition.java
index 4e078a5..28d6b2b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/DebugPosition.java
+++ b/src/main/java/com/android/tools/r8/ir/code/DebugPosition.java
@@ -35,7 +35,7 @@
 
   @Override
   public void buildDex(DexBuilder builder) {
-    builder.addNop(this);
+    builder.addDebugPosition(this);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java
index 50afe5f..a306bbd 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java
@@ -44,6 +44,7 @@
 import com.android.tools.r8.ir.code.Argument;
 import com.android.tools.r8.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.CatchHandlers;
+import com.android.tools.r8.ir.code.DebugPosition;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.If;
 import com.android.tools.r8.ir.code.InstructionIterator;
@@ -331,8 +332,13 @@
   public void addGoto(com.android.tools.r8.ir.code.Goto jump) {
     if (jump.getTarget() != nextBlock) {
       add(jump, new GotoInfo(jump));
+      return;
+    }
+    List<com.android.tools.r8.ir.code.Instruction> instructions = jump.getBlock().getInstructions();
+    if (instructions.size() > 1) {
+      addFallThroughOrNop(jump, instructions.get(instructions.size() - 2), nextBlock.entry());
     } else {
-      addNop(jump);
+      addFallThrough(jump);
     }
   }
 
@@ -345,10 +351,32 @@
     add(move, new MoveInfo(move));
   }
 
-  public void addNop(com.android.tools.r8.ir.code.Instruction instruction) {
+  public void addFallThrough(com.android.tools.r8.ir.code.Instruction instruction) {
     add(instruction, new FallThroughInfo(instruction));
   }
 
+  private void addFallThroughOrNop(
+      com.android.tools.r8.ir.code.Instruction key,
+      com.android.tools.r8.ir.code.Instruction instruction,
+      com.android.tools.r8.ir.code.Instruction nextInstruction) {
+    if (nextInstruction != null
+        && instruction.isDebugPosition()
+        && nextInstruction.isDebugPosition()) {
+      add(key, new FixedSizeInfo(key, new Nop()));
+    } else {
+      addFallThrough(key);
+    }
+  }
+
+  public void addDebugPosition(DebugPosition position) {
+    BasicBlock block = position.getBlock();
+    int nextIndex = block.getInstructions().indexOf(position) + 1;
+    List<com.android.tools.r8.ir.code.Instruction> instructions = block.getInstructions();
+    com.android.tools.r8.ir.code.Instruction nextInstruction =
+        nextIndex < instructions.size() ? instructions.get(nextIndex) : null;
+    addFallThroughOrNop(position, position, nextInstruction);
+  }
+
   public void add(com.android.tools.r8.ir.code.Instruction ir, Instruction dex) {
     assert !ir.isGoto();
     add(ir, new FixedSizeInfo(ir, dex));
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 5984820..f58ea72 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -560,7 +560,7 @@
     // Always perform dead code elimination before register allocation. The register allocator
     // does not allow dead code (to make sure that we do not waste registers for unneeded values).
     DeadCodeRemover.removeDeadCode(code, codeRewriter, options);
-    LinearScanRegisterAllocator registerAllocator = new LinearScanRegisterAllocator(code);
+    LinearScanRegisterAllocator registerAllocator = new LinearScanRegisterAllocator(code, options);
     registerAllocator.allocateRegisters(options.debug);
     printMethod(code, "After register allocation (non-SSA)");
     printLiveRanges(registerAllocator, "Final live ranges.");
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
index baaf7d0..c3f2d08 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
@@ -166,7 +166,7 @@
 
   private boolean isInMainDexList(DexType iface) {
     ImmutableSet<DexType> list = converter.application.mainDexList;
-    return list != null && list.contains(iface);
+    return list.contains(iface);
   }
 
   // Represent a static interface method as a method of companion class.
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
index 4ab72f6..0ea5761 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
@@ -991,7 +991,7 @@
     }
 
     @Override
-    public String toString(ClassNameMapper naming) {
+    public String toString(DexEncodedMethod method, ClassNameMapper naming) {
       return null;
     }
   }
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
index a30f574..9276f45 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
@@ -25,6 +25,7 @@
 import com.android.tools.r8.ir.code.Xor;
 import com.android.tools.r8.logging.Log;
 import com.android.tools.r8.utils.CfgPrinter;
+import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.StringUtils;
 import com.google.common.collect.HashMultiset;
@@ -109,6 +110,8 @@
   private final IRCode code;
   // Number of registers used for arguments.
   private final int numberOfArgumentRegisters;
+  // Compiler options.
+  private final InternalOptions options;
 
   // Mapping from basic blocks to the set of values live at entry to that basic block.
   private Map<BasicBlock, Set<Value>> liveAtEntrySets = new IdentityHashMap<>();
@@ -144,8 +147,9 @@
   // register.
   private boolean hasDedicatedMoveExceptionRegister = false;
 
-  public LinearScanRegisterAllocator(IRCode code) {
+  public LinearScanRegisterAllocator(IRCode code, InternalOptions options) {
     this.code = code;
+    this.options = options;
     int argumentRegisters = 0;
     for (Instruction instruction : code.blocks.getFirst().getInstructions()) {
       if (instruction.isArgument()) {
@@ -919,6 +923,13 @@
     if (mode == ArgumentReuseMode.ALLOW_ARGUMENT_REUSE) {
       // The sentinel registers cannot be used and we block them.
       freePositions.set(0, 0, false);
+      if (options.debug && !code.method.accessFlags.isStatic()) {
+        // If we are generating debug information, we pin the this value register since the
+        // debugger expects to always be able to find it in the input register.
+        assert numberOfArgumentRegisters > 0;
+        assert preArgumentSentinelValue.getNextConsecutive().requiredRegisters() == 1;
+        freePositions.set(1, 0, false);
+      }
       int lastSentinelRegister = numberOfArgumentRegisters + NUMBER_OF_SENTINEL_REGISTERS - 1;
       if (lastSentinelRegister <= registerConstraint) {
         freePositions.set(lastSentinelRegister, 0, false);
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/SynthesizedCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/SynthesizedCode.java
index 7716663..3d3f9f1 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/SynthesizedCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/SynthesizedCode.java
@@ -37,7 +37,7 @@
 
   @Override
   public final String toString() {
-    return toString(null);
+    return toString(null, null);
   }
 
   private static void registerReachableDefinitionsDefault(UseRegistry registry) {
@@ -61,7 +61,7 @@
   }
 
   @Override
-  public final String toString(ClassNameMapper naming) {
+  public final String toString(DexEncodedMethod method, ClassNameMapper naming) {
     return "SynthesizedCode: " + sourceCode.toString();
   }
 }
diff --git a/src/test/java/com/android/tools/r8/JctfTestSpecifications.java b/src/test/java/com/android/tools/r8/JctfTestSpecifications.java
index f7cbee8..d548e11 100644
--- a/src/test/java/com/android/tools/r8/JctfTestSpecifications.java
+++ b/src/test/java/com/android/tools/r8/JctfTestSpecifications.java
@@ -7,6 +7,7 @@
 import static com.android.tools.r8.TestCondition.D8_COMPILER;
 import static com.android.tools.r8.TestCondition.R8_AFTER_D8_COMPILER;
 import static com.android.tools.r8.TestCondition.R8_COMPILER;
+import static com.android.tools.r8.TestCondition.R8_NOT_AFTER_D8_COMPILER;
 import static com.android.tools.r8.TestCondition.any;
 import static com.android.tools.r8.TestCondition.match;
 import static com.android.tools.r8.TestCondition.runtimes;
@@ -4415,7 +4416,7 @@
           // 1) t02
           // java.lang.AssertionError: Failed to load serialization resource file: serialization/com/google/jctf/test/lib/java/util/concurrent/PriorityBlockingQueue/serialization/PriorityBlockingQueue_serialization_A01.golden.0.ser
 
-          .put("lang.ThreadGroup.destroy.ThreadGroup_destroy_A01", match(R8_COMPILER))
+          .put("lang.ThreadGroup.destroy.ThreadGroup_destroy_A01", match(R8_NOT_AFTER_D8_COMPILER))
           // 1) t05
           // java.lang.AssertionError: Destroyed thread group was not finalized
 
diff --git a/src/test/java/com/android/tools/r8/compatdx/CompatDxTests.java b/src/test/java/com/android/tools/r8/compatdx/CompatDxTests.java
index bd97a3b..81f660a 100644
--- a/src/test/java/com/android/tools/r8/compatdx/CompatDxTests.java
+++ b/src/test/java/com/android/tools/r8/compatdx/CompatDxTests.java
@@ -103,7 +103,7 @@
   public void singleDexProgramIsTooLarge() throws IOException, ExecutionException {
     // Generate an application that will not fit into a single dex file.
     AndroidApp generated = MainDexListTests.generateApplication(
-        ImmutableList.of("A", "B"), Constants.DEFAULT_ANDROID_API, Constants.U16BIT_MAX / 2 + 1);
+        ImmutableList.of("A", "B"), Constants.ANDROID_L_API, Constants.U16BIT_MAX / 2 + 1);
     Path applicationJar = temp.newFile("application.jar").toPath();
     generated.write(applicationJar, OutputMode.Indexed, true);
     thrown.expect(CompilationError.class);
diff --git a/src/test/java/com/android/tools/r8/debuginfo/BackBranchToSelfTestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/BackBranchToSelfTestRunner.java
index ebd1b0b..24eae68 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/BackBranchToSelfTestRunner.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/BackBranchToSelfTestRunner.java
@@ -27,14 +27,8 @@
   }
 
   private void checkBackBranchToSelf(DebugInfoInspector info, boolean dx) {
-    if (dx) {
-      info.checkStartLine(10);
-      // b/37494646 D8/R8 if-simplification has replaced if by a goto and lost this position.
-      info.checkLineHasExactLocals(10, "loop", "boolean");
-    } else {
-      // D8/R8 will always start at the first debuggable line.
-      info.checkStartLine(13);
-    }
+    info.checkStartLine(10);
+    info.checkLineHasExactLocals(10, "loop", "boolean");
     info.checkNoLine(11);
     info.checkNoLine(12);
     info.checkLineHasExactLocals(13, "loop", "boolean");
diff --git a/src/test/java/com/android/tools/r8/dex/ExtraFileTest.java b/src/test/java/com/android/tools/r8/dex/ExtraFileTest.java
index 376577c..d1e46f3 100644
--- a/src/test/java/com/android/tools/r8/dex/ExtraFileTest.java
+++ b/src/test/java/com/android/tools/r8/dex/ExtraFileTest.java
@@ -47,6 +47,7 @@
         R8Command.builder()
             .addProgramFiles(original)
             .setOutputPath(out)
+            .setMinApiLevel(Constants.ANDROID_L_API) // Allow native multidex.
             .setProguardMapFile(proguardMap)
             .setPackageDistributionFile(packageMap)
             .build();
diff --git a/src/test/java/com/android/tools/r8/internal/CompilationTestBase.java b/src/test/java/com/android/tools/r8/internal/CompilationTestBase.java
index 2841779..d5e66b8 100644
--- a/src/test/java/com/android/tools/r8/internal/CompilationTestBase.java
+++ b/src/test/java/com/android/tools/r8/internal/CompilationTestBase.java
@@ -11,6 +11,7 @@
 import com.android.tools.r8.R8Command;
 import com.android.tools.r8.R8RunArtTestsTest.CompilerUnderTest;
 import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.shaking.ProguardRuleParserException;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.ArtErrorParser;
@@ -70,6 +71,7 @@
       outputApp = ToolHelper.runR8(builder.build(),
                   options -> {
                     options.printSeeds = false;
+                    options.minApiLevel = Constants.ANDROID_L_API;
                   });
     } else {
       assert compiler == CompilerUnderTest.D8;
@@ -78,6 +80,7 @@
               D8Command.builder()
                   .addProgramFiles(ListUtils.map(inputs, Paths::get))
                   .setMode(mode)
+                  .setMinApiLevel(Constants.ANDROID_L_API)
                   .build());
     }
     Path out = temp.getRoot().toPath().resolve("all.zip");
diff --git a/src/test/java/com/android/tools/r8/internal/R8GMSCoreDeterministicTest.java b/src/test/java/com/android/tools/r8/internal/R8GMSCoreDeterministicTest.java
index 755fcab..74f9ef9 100644
--- a/src/test/java/com/android/tools/r8/internal/R8GMSCoreDeterministicTest.java
+++ b/src/test/java/com/android/tools/r8/internal/R8GMSCoreDeterministicTest.java
@@ -10,6 +10,7 @@
 import com.android.tools.r8.R8Command;
 import com.android.tools.r8.Resource;
 import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.ir.conversion.CallGraph;
 import com.android.tools.r8.shaking.ProguardRuleParserException;
@@ -43,6 +44,7 @@
           options.testing.irOrdering = this::shuffle;
           // Only use one thread to process to process in the order decided by the callback.
           options.numberOfThreads = 1;
+          options.minApiLevel = Constants.ANDROID_L_API;
         });
   }
 
diff --git a/src/test/java/com/android/tools/r8/internal/R8GMSCoreFixedPointTest.java b/src/test/java/com/android/tools/r8/internal/R8GMSCoreFixedPointTest.java
index b6d3dac..376ccf3 100644
--- a/src/test/java/com/android/tools/r8/internal/R8GMSCoreFixedPointTest.java
+++ b/src/test/java/com/android/tools/r8/internal/R8GMSCoreFixedPointTest.java
@@ -7,6 +7,7 @@
 
 import com.android.tools.r8.CompilationException;
 import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.shaking.ProguardRuleParserException;
 import com.android.tools.r8.utils.AndroidApp;
 import java.io.IOException;
@@ -21,14 +22,18 @@
       throws ExecutionException, IOException, ProguardRuleParserException, CompilationException {
     // First compilation.
     AndroidApp app = AndroidApp.fromProgramDirectory(Paths.get(GMSCORE_V7_DIR));
-    AndroidApp app1 = ToolHelper.runR8(app);
+    AndroidApp app1 =
+        ToolHelper.runR8(app, options -> options.minApiLevel = Constants.ANDROID_L_API);
 
     // Second compilation.
     // Add option --skip-outline-opt for second compilation. The second compilation can find
     // additional outlining opportunities as member rebinding from the first compilation can move
     // methods.
     // See b/33410508 and b/33475705.
-    AndroidApp app2 = ToolHelper.runR8(app1, options -> options.outline.enabled = false);
+    AndroidApp app2 = ToolHelper.runR8(app1, options -> {
+      options.outline.enabled = false;
+      options.minApiLevel = Constants.ANDROID_L_API;
+    });
 
     // TODO: Require that the results of the two compilations are the same.
     assertEquals(
diff --git a/src/test/java/com/android/tools/r8/jasmin/JumpSubroutineDebugInfoTests.java b/src/test/java/com/android/tools/r8/jasmin/JumpSubroutineDebugInfoTests.java
index d0d1e83..f5254fc 100644
--- a/src/test/java/com/android/tools/r8/jasmin/JumpSubroutineDebugInfoTests.java
+++ b/src/test/java/com/android/tools/r8/jasmin/JumpSubroutineDebugInfoTests.java
@@ -60,8 +60,7 @@
     assertEquals(expected, artResult);
 
     DebugInfoInspector info = new DebugInfoInspector(d8App, clazz.name, foo);
-    // The first debuggable line will be line 3.
-    info.checkStartLine(3);
+    info.checkStartLine(1);
     // Check the subroutine line is duplicated 3 times.
     assertEquals(3, info.checkLineHasExactLocals(3, "x", "int"));
   }
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
index 4eb8545..a0a77d1 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -396,6 +396,7 @@
       throws IOException, ExecutionException {
     Timing timing = new Timing("MainDexListTests");
     InternalOptions options = new InternalOptions();
+    options.minApiLevel = minApi;
     DexItemFactory factory = options.itemFactory;
     DexApplication.Builder builder = new DexApplication.Builder(factory, timing);
     for (String clazz : classes) {
@@ -419,7 +420,7 @@
                 DexAnnotationSetRefList.empty(),
                 code);
         IRCode ir = code.buildIR(method, options);
-        RegisterAllocator allocator = new LinearScanRegisterAllocator(ir);
+        RegisterAllocator allocator = new LinearScanRegisterAllocator(ir, options);
         method.setCode(ir, allocator, factory);
         directMethods[i] = method;
       }
diff --git a/third_party/android_jar/lib-v21.tar.gz.sha1 b/third_party/android_jar/lib-v21.tar.gz.sha1
new file mode 100644
index 0000000..8d42abc
--- /dev/null
+++ b/third_party/android_jar/lib-v21.tar.gz.sha1
@@ -0,0 +1 @@
+83d20da35ba7b7b1a8b48a2da8dfe3b95d59392a
\ No newline at end of file
diff --git a/tools/gmscore_data.py b/tools/gmscore_data.py
index 4b9c430..9939e1c 100644
--- a/tools/gmscore_data.py
+++ b/tools/gmscore_data.py
@@ -20,6 +20,7 @@
 
 V10_BASE = os.path.join(BASE, 'gmscore_v10')
 V10_PREFIX = os.path.join(V10_BASE, 'GmsCore_prod_alldpi_release_all_locales')
+ANDROID_L_API = '21'
 
 # NOTE: we always use android.jar for SDK v25, later we might want to revise it
 #       to use proper android.jar version for each of gmscore version separately.
@@ -32,6 +33,7 @@
       'pgmap' : os.path.join(V4_BASE, 'proguard.map'),
       'libraries' : [ANDROID_JAR],
       'r8-flags': '--ignore-missing-classes',
+      'min-sdk-version' : ANDROID_L_API,
     }
   },
   'v5': {
@@ -40,6 +42,7 @@
       'pgmap' : os.path.join(V5_BASE, 'proguard.map'),
       'libraries' : [ANDROID_JAR],
       'r8-flags': '--ignore-missing-classes',
+      'min-sdk-version' : ANDROID_L_API,
     }
   },
   'v6': {
@@ -48,6 +51,7 @@
       'pgmap' : os.path.join(V6_BASE, 'proguard.map'),
       'libraries' : [ANDROID_JAR],
       'r8-flags': '--ignore-missing-classes',
+      'min-sdk-version' : ANDROID_L_API,
     }
   },
   'v7': {
@@ -56,6 +60,7 @@
       'pgmap' : os.path.join(V7_BASE, 'proguard.map'),
       'libraries' : [ANDROID_JAR],
       'r8-flags': '--ignore-missing-classes',
+      'min-sdk-version' : ANDROID_L_API,
     }
   },
   'v8': {
@@ -64,6 +69,7 @@
       'pgmap' : os.path.join(V8_BASE, 'proguard.map'),
       'libraries' : [ANDROID_JAR],
       'r8-flags': '--ignore-missing-classes',
+      'min-sdk-version' : ANDROID_L_API,
     }
   },
   'v9': {
@@ -72,15 +78,18 @@
       'pgmap': '%s_proguard.map' % V9_PREFIX,
       'libraries' : [ANDROID_JAR],
       'r8-flags': '--ignore-missing-classes',
+      'min-sdk-version' : ANDROID_L_API,
     },
     'deploy' : {
       'pgconf': ['%s_proguard.config' % V9_PREFIX],
-      'inputs': ['%s_deploy.jar' % V9_PREFIX]
+      'inputs': ['%s_deploy.jar' % V9_PREFIX],
+      'min-sdk-version' : ANDROID_L_API,
     },
     'proguarded' : {
       'inputs': ['%s_proguard.jar' % V9_PREFIX],
-      'pgmap': '%s_proguard.map' % V9_PREFIX
-    }
+      'pgmap': '%s_proguard.map' % V9_PREFIX,
+      'min-sdk-version' : ANDROID_L_API,
+     }
   },
   'v10': {
     'dex' : {
@@ -88,14 +97,17 @@
       'pgmap': '%s_proguard.map' % V10_PREFIX,
       'libraries' : [ANDROID_JAR],
       'r8-flags': '--ignore-missing-classes',
+      'min-sdk-version' : ANDROID_L_API,
     },
     'deploy' : {
       'inputs': ['%s_deploy.jar' % V10_PREFIX],
       'pgconf': ['%s_proguard.config' % V10_PREFIX],
+      'min-sdk-version' : ANDROID_L_API,
     },
     'proguarded' : {
       'inputs': ['%s_proguard.jar' % V10_PREFIX],
-      'pgmap': '%s_proguard.map' % V10_PREFIX
+      'pgmap': '%s_proguard.map' % V10_PREFIX,
+      'min-sdk-version' : ANDROID_L_API,
     }
   },
 }
diff --git a/tools/run_on_app.py b/tools/run_on_app.py
index ddc1e47..312f4b0a 100755
--- a/tools/run_on_app.py
+++ b/tools/run_on_app.py
@@ -125,6 +125,8 @@
     inputs = values['inputs']
 
   args.extend(['--output', outdir])
+  if 'min-sdk-version' in values:
+    args.extend(['--min-sdk-version', values['min-sdk-version']])
 
   if options.compiler == 'r8':
     if 'pgmap' in values:
diff --git a/tools/youtube_data.py b/tools/youtube_data.py
index b32a372..5ec6bee 100644
--- a/tools/youtube_data.py
+++ b/tools/youtube_data.py
@@ -7,6 +7,7 @@
 import utils
 
 THIRD_PARTY = os.path.join(utils.REPO_ROOT, 'third_party')
+ANDROID_L_API = '21'
 BASE = os.path.join(THIRD_PARTY, 'youtube')
 
 V12_10_BASE = os.path.join(BASE, 'youtube.android_12.10')
@@ -29,15 +30,18 @@
       'pgmap': '%s_proguard.map' % V12_10_PREFIX,
       'libraries' : [ANDROID_JAR],
       'r8-flags': '--ignore-missing-classes',
+      'min-sdk-version' : ANDROID_L_API,
     },
     'deploy' : {
       'inputs': ['%s_deploy.jar' % V12_10_PREFIX],
       'pgconf': ['%s_proguard.config' % V12_10_PREFIX,
                  '%s/proguardsettings/YouTubeRelease_proguard.config' % THIRD_PARTY],
+      'min-sdk-version' : ANDROID_L_API,
     },
     'proguarded' : {
       'inputs': ['%s_proguard.jar' % V12_10_PREFIX],
-      'pgmap': '%s_proguard.map' % V12_10_PREFIX
+      'pgmap': '%s_proguard.map' % V12_10_PREFIX,
+      'min-sdk-version' : ANDROID_L_API,
     }
   },
   '12.17': {
@@ -46,15 +50,18 @@
       'pgmap': '%s_proguard.map' % V12_17_PREFIX,
       'libraries' : [ANDROID_JAR],
       'r8-flags': '--ignore-missing-classes',
+      'min-sdk-version' : ANDROID_L_API,
     },
     'deploy' : {
       'inputs': ['%s_deploy.jar' % V12_17_PREFIX],
       'pgconf': ['%s_proguard.config' % V12_17_PREFIX,
                  '%s/proguardsettings/YouTubeRelease_proguard.config' % THIRD_PARTY],
+      'min-sdk-version' : ANDROID_L_API,
     },
     'proguarded' : {
       'inputs': ['%s_proguard.jar' % V12_17_PREFIX],
-      'pgmap': '%s_proguard.map' % V12_17_PREFIX
+      'pgmap': '%s_proguard.map' % V12_17_PREFIX,
+      'min-sdk-version' : ANDROID_L_API,
     }
   },
   '12.22': {
@@ -63,6 +70,7 @@
       'pgmap': '%s_proguard.map' % V12_22_PREFIX,
       'libraries' : [ANDROID_JAR],
       'r8-flags': '--ignore-missing-classes',
+      'min-sdk-version' : ANDROID_L_API,
     },
     'deploy' : {
       'inputs': ['%s_deploy.jar' % V12_22_PREFIX],
@@ -73,10 +81,12 @@
           os.path.join(V12_22_BASE, 'mainDexClasses.rules'),
           os.path.join(V12_22_BASE, 'main-dex-classes-release.cfg'),
           os.path.join(V12_22_BASE, 'main_dex_YouTubeRelease_proguard.cfg')],
+      'min-sdk-version' : ANDROID_L_API,
     },
     'proguarded' : {
       'inputs': ['%s_proguard.jar' % V12_22_PREFIX],
-      'pgmap': '%s_proguard.map' % V12_22_PREFIX
+      'pgmap': '%s_proguard.map' % V12_22_PREFIX,
+      'min-sdk-version' : ANDROID_L_API,
     }
   },
 }