Merge "Check parsing of SynthesizedClassMapMessage"
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index 0f0b38f..9b79616 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -9,8 +9,6 @@
 import com.android.tools.r8.dex.ApplicationWriter;
 import com.android.tools.r8.dex.Marker;
 import com.android.tools.r8.dex.Marker.Tool;
-import com.android.tools.r8.errors.CompilationError;
-import com.android.tools.r8.errors.DexOverflowException;
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.ir.conversion.IRConverter;
@@ -168,8 +166,6 @@
       AndroidApp inputApp, InternalOptions options, ExecutorService executor)
       throws IOException, CompilationException {
     try {
-      assert !inputApp.hasPackageDistribution();
-
       // Disable global optimizations.
       options.skipMinification = true;
       options.inlineAccessors = false;
@@ -191,7 +187,7 @@
           new CompilationResult(
               new ApplicationWriter(
                   app, appInfo, options, marker, null, NamingLens.getIdentityLens(), null)
-                  .write(null, executor),
+                  .write(executor),
               app,
               appInfo);
 
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 1306e3b..0b16963 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -23,7 +23,6 @@
 import com.android.tools.r8.naming.Minifier;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.optimize.BridgeMethodAnalysis;
-import com.android.tools.r8.optimize.DebugStripper;
 import com.android.tools.r8.optimize.MemberRebindingAnalysis;
 import com.android.tools.r8.optimize.VisibilityBridgeRemover;
 import com.android.tools.r8.shaking.AbstractMethodRemover;
@@ -45,7 +44,6 @@
 import com.android.tools.r8.utils.CfgPrinter;
 import com.android.tools.r8.utils.FileUtils;
 import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.PackageDistribution;
 import com.android.tools.r8.utils.ThreadUtils;
 import com.android.tools.r8.utils.Timing;
 import com.google.common.io.ByteStreams;
@@ -63,9 +61,7 @@
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.nio.file.StandardOpenOption;
-import java.util.ArrayList;
 import java.util.HashSet;
-import java.util.List;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
@@ -98,14 +94,13 @@
       byte[] deadCode,
       NamingLens namingLens,
       byte[] proguardSeedsData,
-      PackageDistribution packageDistribution,
       InternalOptions options)
       throws ExecutionException, DexOverflowException {
     try {
       Marker marker = getMarker(options);
       return new ApplicationWriter(
           application, appInfo, options, marker, deadCode, namingLens, proguardSeedsData)
-          .write(packageDistribution, executorService);
+          .write(executorService);
     } catch (IOException e) {
       throw new RuntimeException("Cannot write dex application", e);
     }
@@ -142,17 +137,6 @@
       timing.end();
     }
 
-    if (!options.skipDebugInfoOpt && (application.getProguardMap() != null)) {
-      try {
-        timing.begin("DebugStripper");
-        DebugStripper stripper =
-            new DebugStripper(application.getProguardMap(), options, appInfo.dexItemFactory);
-        application.classes().forEach(stripper::processClass);
-      } finally {
-        timing.end();
-      }
-    }
-
     if (options.printCfg) {
       if (options.printCfgFile == null || options.printCfgFile.isEmpty()) {
         System.out.print(printer.toString());
@@ -373,13 +357,6 @@
         return null;
       }
 
-      PackageDistribution packageDistribution = null;
-      if (inputApp.hasPackageDistribution()) {
-        try (Closer closer = Closer.create()) {
-          packageDistribution = PackageDistribution.load(inputApp.getPackageDistribution(closer));
-        }
-      }
-
       // Generate the resulting application resources.
       AndroidApp androidApp =
           writeApplication(
@@ -389,7 +366,6 @@
               application.deadCode,
               namingLens,
               proguardSeedsData,
-              packageDistribution,
               options);
 
       options.printWarnings();
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 301c266..4076a5a 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -37,7 +37,6 @@
     private Optional<Boolean> minification = Optional.empty();
     private boolean ignoreMissingClasses = false;
     private Path printMappingFile = null;
-    private Path packageDistributionFile = null;
 
     private Builder() {
       super(CompilationMode.RELEASE);
@@ -160,14 +159,6 @@
     }
 
     /**
-     * Set a package distribution file resource.
-     */
-    public Builder setPackageDistributionFile(Path path) {
-      packageDistributionFile = path;
-      return self();
-    }
-
-    /**
      * Deprecated flag to avoid failing if classes are missing during compilation.
      *
      * <p>TODO: Make compilation safely assume this flag to be true and remove the flag.
@@ -189,10 +180,6 @@
         throw new CompilationException(
             "Option --main-dex-list-output require --main-dex-rules and/or --main-dex-list");
       }
-      if (getMode() == CompilationMode.DEBUG && packageDistributionFile != null) {
-        throw new CompilationException(
-            "Package distribution file is not supported in debug mode");
-      }
     }
 
     @Override
@@ -237,10 +224,6 @@
 
       // TODO(b/64802420): setProguardMapFile if configuration.hasApplyMappingFile
 
-      if (packageDistributionFile != null) {
-        getAppBuilder().setPackageDistributionFile(packageDistributionFile);
-      }
-
       boolean useTreeShaking = treeShaking.orElse(configuration.isShrinking());
       boolean useDiscardedChecker = discardedChecker.orElse(true);
       boolean useMinification = minification.orElse(configuration.isObfuscating());
@@ -280,7 +263,6 @@
       "  --min-api                # Minimum Android API level compatibility.",
       "  --pg-conf <file>         # Proguard configuration <file> (implies tree",
       "                           # shaking/minification).",
-      "  --pg-map <file>          # Proguard map <file>.",
       "  --print-mapping <file>   # Write name/line mapping to <file>.",
       "  --no-tree-shaking        # Force disable tree shaking of unreachable classes.",
       "  --no-discarded-checker   # Force disable the discarded checker (when tree shaking).",
@@ -367,8 +349,6 @@
         builder.setMainDexListOutputPath(Paths.get(args[++i]));
       } else if (arg.equals("--pg-conf")) {
         builder.addProguardConfigurationFiles(Paths.get(args[++i]));
-      } else if (arg.equals("--pg-map")) {
-        builder.setProguardMapFile(Paths.get(args[++i]));
       } else if (arg.equals("--ignore-missing-classes")) {
         builder.setIgnoreMissingClasses(true);
       } else if (arg.equals("--print-mapping")) {
@@ -460,6 +440,14 @@
     assert !internal.debug;
     internal.debug = getMode() == CompilationMode.DEBUG;
     internal.minApiLevel = getMinApiLevel();
+    // -dontoptimize disables optimizations by flipping related flags.
+    if (!proguardConfiguration.isOptimizing()) {
+      internal.skipDebugLineNumberOpt = true;
+      internal.skipClassMerging = true;
+      internal.inlineAccessors = false;
+      internal.removeSwitchMaps = false;
+      internal.outline.enabled = false;
+    }
     assert !internal.skipMinification;
     internal.skipMinification = !useMinification() || !proguardConfiguration.isObfuscating();
     assert internal.useTreeShaking;
diff --git a/src/main/java/com/android/tools/r8/bisect/Bisect.java b/src/main/java/com/android/tools/r8/bisect/Bisect.java
index 81d5f9a..b2c02b0 100644
--- a/src/main/java/com/android/tools/r8/bisect/Bisect.java
+++ b/src/main/java/com/android/tools/r8/bisect/Bisect.java
@@ -179,7 +179,7 @@
     InternalOptions options = new InternalOptions();
     AppInfo appInfo = new AppInfo(app);
     ApplicationWriter writer = new ApplicationWriter(app, appInfo, options, null, null, null, null);
-    AndroidApp outApp = writer.write(null, executor);
+    AndroidApp outApp = writer.write(executor);
     outApp.writeToDirectory(output, OutputMode.Indexed);
   }
 
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 58c3a5b..6f92740 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -26,7 +26,6 @@
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.OutputMode;
-import com.android.tools.r8.utils.PackageDistribution;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.PrintStream;
@@ -126,7 +125,7 @@
     this.proguardSeedsData = proguardSeedsData;
   }
 
-  public AndroidApp write(PackageDistribution packageDistribution, ExecutorService executorService)
+  public AndroidApp write(ExecutorService executorService)
       throws IOException, ExecutionException, DexOverflowException {
     application.timing.begin("DexApplication.write");
     try {
@@ -139,24 +138,11 @@
       // Distribute classes into dex files.
       VirtualFile.Distributor distributor = null;
       if (options.outputMode == OutputMode.FilePerInputClass) {
-        assert packageDistribution == null :
-            "Cannot combine package distribution definition with file-per-class option.";
         distributor = new VirtualFile.FilePerInputClassDistributor(this);
       } else if (!options.canUseMultidex()
           && 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.";
-        distributor =
-            new VirtualFile.PackageMapDistributor(this, packageDistribution, executorService);
       } else {
         distributor = new VirtualFile.FillFilesDistributor(this, options.minimalMainDex);
       }
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 32fb175..746c62e 100644
--- a/src/main/java/com/android/tools/r8/dex/VirtualFile.java
+++ b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
@@ -24,16 +24,11 @@
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.FileUtils;
-import com.android.tools.r8.utils.PackageDistribution;
-import com.android.tools.r8.utils.ThreadUtils;
+
 import com.google.common.collect.Iterators;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -44,13 +39,10 @@
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
 import java.util.function.Function;
 
 public class VirtualFile {
@@ -402,95 +394,6 @@
     }
   }
 
-  public static class PackageMapDistributor extends DistributorBase {
-    private final PackageDistribution packageDistribution;
-    private final ExecutorService executorService;
-
-    PackageMapDistributor(
-        ApplicationWriter writer,
-        PackageDistribution packageDistribution,
-        ExecutorService executorService) {
-      super(writer);
-      this.packageDistribution = packageDistribution;
-      this.executorService = executorService;
-    }
-
-    @Override
-    public Map<Integer, VirtualFile> run()
-        throws ExecutionException, IOException, DexOverflowException {
-      // Strategy for distributing classes for write out:
-      // 1. Place all files in the package distribution file in the proposed files (if any).
-      // 2. Place the remaining files based on their packages in sorted order.
-
-      assert nameToFileMap.size() == 1;
-      assert nameToFileMap.containsKey(0);
-      int maxReferencedIndex = packageDistribution.maxReferencedIndex();
-      for (int index = 1; index <= maxReferencedIndex; index++) {
-        VirtualFile file = new VirtualFile(index, writer.namingLens);
-        nameToFileMap.put(index, file);
-      }
-
-      // First fill required classes into the main dex file.
-      fillForMainDexList(classes);
-
-      // Sort the remaining classes based on the original names.
-      // This with make classes from the same package be adjacent.
-      classes = sortClassesByPackage(classes, originalNames);
-
-      Set<String> usedPrefixes = fillForDistribution(classes, originalNames);
-
-      // TODO(zerny): Add the package map to AndroidApp and refactor its generation.
-      Map<String, Integer> newAssignments;
-      if (classes.isEmpty()) {
-        newAssignments = Collections.emptyMap();
-      } else {
-        newAssignments =
-            new PackageSplitPopulator(
-                nameToFileMap, classes, originalNames, usedPrefixes, application.dexItemFactory,
-                FillStrategy.LEAVE_SPACE_FOR_GROWTH, writer.namingLens)
-                .call();
-        if (!newAssignments.isEmpty() && nameToFileMap.size() > 1) {
-          System.err.println(" * The used package map is missing entries. The following default "
-              + "mappings have been used:");
-          writeAssignments(newAssignments, new OutputStreamWriter(System.err));
-          System.err.println(" * Consider updating the map.");
-        }
-      }
-
-      Path newPackageMap = Paths.get("package.map");
-      System.out.println(" - " + newPackageMap.toString());
-      PackageDistribution.writePackageToFileMap(newPackageMap, newAssignments, packageDistribution);
-
-      return nameToFileMap;
-    }
-
-    private Set<String> fillForDistribution(Set<DexProgramClass> classes,
-        Map<DexProgramClass, String> originalNames) throws ExecutionException {
-      Set<String> usedPrefixes = null;
-      if (packageDistribution != null) {
-        ArrayList<Future<List<DexProgramClass>>> futures = new ArrayList<>(nameToFileMap.size());
-        usedPrefixes = packageDistribution.getFiles();
-        for (VirtualFile file : nameToFileMap.values()) {
-          PackageMapPopulator populator =
-              new PackageMapPopulator(file, classes, packageDistribution, originalNames);
-          futures.add(executorService.submit(populator));
-        }
-        ThreadUtils.awaitFutures(futures).forEach(classes::removeAll);
-      }
-      return usedPrefixes;
-    }
-
-    private void writeAssignments(Map<String, Integer> assignments, Writer output)
-        throws IOException{
-      for (Entry<String, Integer> entry : assignments.entrySet()) {
-        output.write("    ");
-        PackageDistribution.formatEntry(entry, output);
-        output.write("\n");
-      }
-      output.flush();
-    }
-  }
-
   private static class VirtualFileIndexedItemCollection implements IndexedItemCollection {
 
     final int id;
@@ -719,96 +622,6 @@
   }
 
   /**
-   * Adds all classes from the given set that are covered by a corresponding package map
-   * specification to the given file.
-   */
-  private static class PackageMapPopulator implements Callable<List<DexProgramClass>> {
-
-    private final VirtualFile file;
-    private final Collection<DexProgramClass> classes;
-    private final PackageDistribution packageDistribution;
-    private final Map<DexProgramClass, String> originalNames;
-
-    PackageMapPopulator(
-        VirtualFile file,
-        Collection<DexProgramClass> classes,
-        PackageDistribution packageDistribution,
-        Map<DexProgramClass, String> originalNames) {
-      this.file = file;
-      this.classes = classes;
-      this.packageDistribution = packageDistribution;
-      this.originalNames = originalNames;
-    }
-
-    @Override
-    public List<DexProgramClass> call() {
-      String currentPrefix = null;
-      int currentFileId = -1;
-      List<DexProgramClass> inserted = new ArrayList<>();
-      for (DexProgramClass clazz : classes) {
-        String originalName = originalNames.get(clazz);
-        assert originalName != null;
-        if (!coveredByPrefix(originalName, currentPrefix)) {
-          if (currentPrefix != null) {
-            file.commitTransaction();
-          }
-          currentPrefix = lookupPrefixFor(originalName);
-          if (currentPrefix == null) {
-            currentFileId = -1;
-          } else {
-            currentFileId = packageDistribution.get(currentPrefix);
-          }
-        }
-        if (currentFileId == file.id) {
-          file.addClass(clazz);
-          inserted.add(clazz);
-        }
-        if (file.isFull()) {
-          throw new CompilationError(
-              "Cannot fit package " + currentPrefix
-                  + " in requested dex file, consider removing mapping.");
-        }
-      }
-      file.commitTransaction();
-      return inserted;
-    }
-
-    private String lookupPrefixFor(String originalName) {
-      // First, check whether we have a match on the full package name.
-      int lastIndexOfDot = originalName.lastIndexOf('.');
-      if (lastIndexOfDot < 0) {
-        return null;
-      }
-      String prefix = originalName.substring(0, lastIndexOfDot);
-      if (packageDistribution.containsFile(prefix)) {
-        return prefix;
-      }
-      // Second, look for .* qualified entries.
-      int index;
-      prefix = originalName;
-      while ((index = prefix.lastIndexOf('.')) != -1) {
-        prefix = prefix.substring(0, index);
-        if (packageDistribution.containsFile(prefix + ".*")) {
-          return prefix + ".*";
-        }
-      }
-      return null;
-    }
-
-    static boolean coveredByPrefix(String originalName, String currentPrefix) {
-      if (currentPrefix == null) {
-        return false;
-      }
-      if (currentPrefix.endsWith(".*")) {
-        return originalName.startsWith(currentPrefix.substring(0, currentPrefix.length() - 2));
-      } else {
-        return originalName.startsWith(currentPrefix)
-            && originalName.lastIndexOf('.') == currentPrefix.length();
-      }
-    }
-  }
-
-  /**
    * Helper class to cycle through the set of virtual files.
    *
    * Iteration starts at the first file and iterates through all files.
@@ -915,6 +728,18 @@
       this.cycler = new VirtualFileCycler(files, namingLens, fillStrategy);
     }
 
+    static boolean coveredByPrefix(String originalName, String currentPrefix) {
+      if (currentPrefix == null) {
+        return false;
+      }
+      if (currentPrefix.endsWith(".*")) {
+        return originalName.startsWith(currentPrefix.substring(0, currentPrefix.length() - 2));
+      } else {
+        return originalName.startsWith(currentPrefix)
+            && originalName.lastIndexOf('.') == currentPrefix.length();
+      }
+    }
+
     private String getOriginalName(DexProgramClass clazz) {
       return originalNames != null ? originalNames.get(clazz) : clazz.toString();
     }
@@ -931,7 +756,7 @@
       for (int classIndex = 0; classIndex < classes.size(); classIndex++) {
         DexProgramClass clazz = classes.get(classIndex);
         String originalName = getOriginalName(clazz);
-        if (!PackageMapPopulator.coveredByPrefix(originalName, currentPrefix)) {
+        if (!coveredByPrefix(originalName, currentPrefix)) {
           if (currentPrefix != null) {
             current.commitTransaction();
             // Reset the cycler to again iterate over all files, starting with the current one.
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java b/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java
index c1dad50..14e5288 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java
@@ -63,11 +63,6 @@
     this.factory = factory;
   }
 
-  // Public method for the DebugStripper.
-  public void setPosition(int pc, int line) {
-    emitDebugPosition(pc, line, null);
-  }
-
   /** Add events at pc for instruction. */
   public void add(int pc, Instruction instruction) {
     // Initialize locals state on block entry.
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 7dca5bd..716db5e 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
@@ -133,9 +133,9 @@
   }
 
   /**
-   * Create an IR converter for processing methods without full program optimization enabled.
+   * Create an IR converter for processing methods with full program optimization disabled.
    *
-   * The argument <code>enableDesugaring</code> if desugaing is enabled.
+   * The argument <code>enableDesugaring</code> if desugaring is enabled.
    */
   public IRConverter(
       DexApplication application,
diff --git a/src/main/java/com/android/tools/r8/optimize/DebugStripper.java b/src/main/java/com/android/tools/r8/optimize/DebugStripper.java
deleted file mode 100644
index 0eda1e5..0000000
--- a/src/main/java/com/android/tools/r8/optimize/DebugStripper.java
+++ /dev/null
@@ -1,186 +0,0 @@
-// Copyright (c) 2016, 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.optimize;
-
-import com.android.tools.r8.graph.DexCode;
-import com.android.tools.r8.graph.DexDebugEntry;
-import com.android.tools.r8.graph.DexDebugEventBuilder;
-import com.android.tools.r8.graph.DexDebugInfo;
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.naming.ClassNameMapper;
-import com.android.tools.r8.naming.ClassNaming;
-import com.android.tools.r8.naming.MemberNaming;
-import com.android.tools.r8.naming.MemberNaming.Range;
-import com.android.tools.r8.naming.MemberNaming.Signature;
-import com.android.tools.r8.utils.InternalOptions;
-
-import it.unimi.dsi.fastutil.objects.Reference2IntMap;
-import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
-
-import java.util.List;
-
-public class DebugStripper {
-
-  private static final int USED_MORE_THAN_ONCE = 0;
-  private static final int USED_ONCE = -1;
-
-  private final ClassNameMapper classNameMapper;
-  private final InternalOptions options;
-  private final DexItemFactory dexItemFactory;
-
-  public DebugStripper(
-      ClassNameMapper classNameMapper, InternalOptions options, DexItemFactory dexItemFactory) {
-    this.classNameMapper = classNameMapper;
-    this.options = options;
-    this.dexItemFactory = dexItemFactory;
-  }
-
-  private String descriptorToName(String descriptor) {
-    // The format is L<name>; and '/' is used as package separator.
-    return descriptor.substring(1, descriptor.length() - 1).replace('/', '.');
-  }
-
-  private Range findRange(int value, List<Range> ranges, Range defaultRange) {
-    for (Range range : ranges) {
-      if (range.contains(value)) {
-        return range;
-      }
-    }
-    return defaultRange;
-  }
-
-  private static class NumberedDebugInfo {
-
-    final int numberOfEntries;
-    final DexDebugInfo info;
-
-    public NumberedDebugInfo(int numberOfEntries, DexDebugInfo info) {
-      this.numberOfEntries = numberOfEntries;
-      this.info = info;
-    }
-  }
-
-  private NumberedDebugInfo processDebugInfo(
-      DexEncodedMethod method, DexDebugInfo info, MemberNaming naming, int startLine) {
-    if (info == null || naming == null) {
-      return new NumberedDebugInfo(0, null);
-    }
-    List<Range> ranges = naming.getInlineRanges();
-    // Maintain line and address but only when entering or leaving a range of line numbers
-    // that pertains to a different method body.
-    Range currentRange = naming.topLevelRange;
-    DexDebugEventBuilder builder = new DexDebugEventBuilder(method, dexItemFactory);
-    // Below we insert the start-line at pc-0 except if another entry already defines pc-0.
-    int entryCount = 0;
-    for (DexDebugEntry entry : info.computeEntries()) {
-      boolean addEntry = false;
-      // We are in a range, check whether we have left it.
-      if (currentRange != null && !currentRange.contains(entry.line)) {
-        currentRange = null;
-        addEntry = true;
-      }
-      // We have no range (because we left the old one or never were in a range).
-      if (currentRange == null) {
-        currentRange = findRange(entry.line, ranges, naming.topLevelRange);
-        // We entered a new Range, emit this entry.
-        if (currentRange != null) {
-          addEntry = true;
-        }
-      }
-      if (addEntry) {
-        if (entryCount == 0 && entry.address > 0) {
-          ++entryCount;
-          builder.setPosition(0, startLine);
-        }
-        int line = options.skipDebugLineNumberOpt
-            ? entry.line
-            : startLine + ranges.indexOf(currentRange) + 1;
-        builder.setPosition(entry.address, line);
-        ++entryCount;
-      }
-    }
-    if (entryCount == 0) {
-      ++entryCount;
-      builder.setPosition(0, startLine);
-    }
-    return new NumberedDebugInfo(entryCount, builder.build());
-  }
-
-  private void processCode(DexEncodedMethod encodedMethod, MemberNaming naming,
-      Reference2IntMap<DexString> nameCounts) {
-    if (encodedMethod.getCode() == null) {
-      return;
-    }
-    DexCode code = encodedMethod.getCode().asDexCode();
-    DexString name = encodedMethod.method.name;
-    DexDebugInfo originalInfo = code.getDebugInfo();
-    if (originalInfo == null) {
-      return;
-    }
-    int startLine;
-    boolean isUsedOnce = false;
-    if (options.skipDebugLineNumberOpt) {
-      startLine = originalInfo.startLine;
-    } else {
-      int nameCount = nameCounts.getInt(name);
-      if (nameCount == USED_ONCE) {
-        isUsedOnce = true;
-        startLine = 0;
-      } else {
-        startLine = nameCount;
-      }
-    }
-
-    NumberedDebugInfo numberedInfo =
-        processDebugInfo(encodedMethod, originalInfo, naming, startLine);
-    DexDebugInfo newInfo = numberedInfo.info;
-    if (!options.skipDebugLineNumberOpt) {
-      // Fix up the line information.
-      int previousCount = nameCounts.getInt(name);
-      nameCounts.put(name, previousCount + numberedInfo.numberOfEntries);
-      // If we don't actually need line information and there are no debug entries, throw it away.
-      if (newInfo != null && isUsedOnce && newInfo.events.length == 0) {
-        newInfo = null;
-      } else if (naming != null && newInfo != null) {
-        naming.setCollapsedStartLineNumber(startLine);
-        // Preserve the line number information we had.
-        naming.setOriginalStartLineNumber(originalInfo.startLine);
-      }
-    }
-    code.setDebugInfo(newInfo);
-  }
-
-  private void processMethod(DexEncodedMethod method, ClassNaming classNaming,
-      Reference2IntMap<DexString> nameCounts) {
-    MemberNaming naming = null;
-    if (classNaming != null) {
-      Signature renamedSignature = classNameMapper.getRenamedMethodSignature(method.method);
-      naming = classNaming.lookup(renamedSignature);
-    }
-    processCode(method, naming, nameCounts);
-  }
-
-  public void processClass(DexProgramClass clazz) {
-    if (!clazz.hasMethodsOrFields()) {
-      return;
-    }
-    String name = descriptorToName(clazz.type.toDescriptorString());
-    ClassNaming naming = classNameMapper == null ? null : classNameMapper.getClassNaming(name);
-    Reference2IntMap<DexString> nameCounts = new Reference2IntOpenHashMap<>();
-    clazz.forEachMethod(method -> setIntialNameCounts(nameCounts, method));
-    clazz.forEachMethod(method -> processMethod(method, naming, nameCounts));
-  }
-
-  private void setIntialNameCounts(Reference2IntMap<DexString> nameCounts,
-      DexEncodedMethod method) {
-    if (nameCounts.containsKey(method.method.name)) {
-      nameCounts.put(method.method.name, USED_MORE_THAN_ONCE);
-    } else {
-      nameCounts.put(method.method.name, USED_ONCE);
-    }
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
index 87a36e6..87b425b 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
@@ -24,7 +24,7 @@
     private String packagePrefix = "";
     private boolean allowAccessModification = false;
     private boolean ignoreWarnings = false;
-    private boolean optimize = true;
+    private boolean optimizing = true;
     private boolean obfuscating = true;
     private boolean shrinking = true;
     private boolean printUsage = false;
@@ -79,8 +79,8 @@
       this.ignoreWarnings = ignoreWarnings;
     }
 
-    public void setOptimize(boolean optimize) {
-      this.optimize = optimize;
+    public void setOptimizing(boolean optimizing) {
+      this.optimizing = optimizing;
     }
 
     public void setObfuscating(boolean obfuscate) {
@@ -172,6 +172,7 @@
           packagePrefix,
           allowAccessModification,
           ignoreWarnings,
+          optimizing,
           obfuscating,
           shrinking,
           printUsage,
@@ -200,6 +201,7 @@
   private final String packagePrefix;
   private final boolean allowAccessModification;
   private final boolean ignoreWarnings;
+  private final boolean optimizing;
   private final boolean obfuscating;
   private final boolean shrinking;
   private final boolean printUsage;
@@ -227,6 +229,7 @@
       String packagePrefix,
       boolean allowAccessModification,
       boolean ignoreWarnings,
+      boolean optimizing,
       boolean obfuscating,
       boolean shrinking,
       boolean printUsage,
@@ -252,6 +255,7 @@
     this.packagePrefix = packagePrefix;
     this.allowAccessModification = allowAccessModification;
     this.ignoreWarnings = ignoreWarnings;
+    this.optimizing = optimizing;
     this.obfuscating = obfuscating;
     this.shrinking = shrinking;
     this.printUsage = printUsage;
@@ -327,6 +331,10 @@
     return ignoreWarnings;
   }
 
+  public boolean isOptimizing() {
+    return optimizing;
+  }
+
   public boolean isObfuscating() {
     return obfuscating;
   }
@@ -393,6 +401,7 @@
           ""                    /* package prefix */,
           false                 /* allowAccessModification */,
           false                 /* ignoreWarnings */,
+          true                  /* optimizing */,
           false                 /* obfuscating */,
           false                 /* shrinking */,
           false                 /* printUsage */,
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
index 9a90c68..bcbfc8b 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -168,8 +168,7 @@
         ProguardWhyAreYouKeepingRule rule = parseWhyAreYouKeepingRule();
         configurationBuilder.addRule(rule);
       } else if (acceptString("dontoptimize")) {
-        configurationBuilder.setOptimize(false);
-        warnIgnoringOptions("dontoptimize");
+        configurationBuilder.setOptimizing(false);
       } else if (acceptString("optimizationpasses")) {
         skipWhitespace();
         Integer expectedOptimizationPasses = acceptInteger();
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApp.java b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
index 9b99be5..439c1d9 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApp.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
@@ -63,7 +63,6 @@
   private final Resource deadCode;
   private final Resource proguardMap;
   private final Resource proguardSeeds;
-  private final Resource packageDistribution;
   private final List<Resource> mainDexListResources;
   private final List<String> mainDexClasses;
   private final Resource mainDexListOutput;
@@ -78,7 +77,6 @@
       Resource deadCode,
       Resource proguardMap,
       Resource proguardSeeds,
-      Resource packageDistribution,
       List<Resource> mainDexListResources,
       List<String> mainDexClasses,
       Resource mainDexListOutput) {
@@ -90,7 +88,6 @@
     this.deadCode = deadCode;
     this.proguardMap = proguardMap;
     this.proguardSeeds = proguardSeeds;
-    this.packageDistribution = packageDistribution;
     this.mainDexListResources = mainDexListResources;
     this.mainDexClasses = mainDexClasses;
     this.mainDexListOutput = mainDexListOutput;
@@ -255,20 +252,6 @@
   }
 
   /**
-   * True if the package distribution resource exists.
-   */
-  public boolean hasPackageDistribution() {
-    return packageDistribution != null;
-  }
-
-  /**
-   * Get the input stream of the package distribution resource if it exists.
-   */
-  public InputStream getPackageDistribution(Closer closer) throws IOException {
-    return packageDistribution == null ? null : closer.register(packageDistribution.getStream());
-  }
-
-  /**
    * True if the main dex list resources exists.
    */
   public boolean hasMainDexList() {
@@ -464,7 +447,6 @@
     private Resource deadCode;
     private Resource proguardMap;
     private Resource proguardSeeds;
-    private Resource packageDistribution;
     private List<Resource> mainDexListResources = new ArrayList<>();
     private List<String> mainDexListClasses = new ArrayList<>();
     private Resource mainDexListOutput;
@@ -484,7 +466,6 @@
       deadCode = app.deadCode;
       proguardMap = app.proguardMap;
       proguardSeeds = app.proguardSeeds;
-      packageDistribution = app.packageDistribution;
       mainDexListResources = app.mainDexListResources;
       mainDexListClasses = app.mainDexClasses;
       mainDexListOutput = app.mainDexListOutput;
@@ -685,14 +666,6 @@
     }
 
     /**
-     * Set the package-distribution file.
-     */
-    public Builder setPackageDistributionFile(Path file) {
-      packageDistribution = file == null ? null : Resource.fromFile(null, file);
-      return this;
-    }
-
-    /**
      * Add a main-dex list file.
      */
     public Builder addMainDexListFiles(Path... files) throws IOException {
@@ -773,7 +746,6 @@
           deadCode,
           proguardMap,
           proguardSeeds,
-          packageDistribution,
           mainDexListResources,
           mainDexListClasses,
           mainDexListOutput);
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index c03c3d6..36e19bf 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -45,10 +45,13 @@
   public final int NOT_SPECIFIED = -1;
 
   public boolean printTimes = false;
-  // Skipping optimizations.
-  public boolean skipDebugInfoOpt = false;
+
+  // Optimization-related flags. These should conform to -dontoptimize.
   public boolean skipDebugLineNumberOpt = false;
   public boolean skipClassMerging = true;
+  public boolean inlineAccessors = true;
+  public boolean removeSwitchMaps = true;
+  public final OutlineOptions outline = new OutlineOptions();
 
   // Number of threads to use while processing the dex files.
   public int numberOfThreads = NOT_SPECIFIED;
@@ -99,10 +102,7 @@
   public Path printMainDexListFile;
   public boolean ignoreMissingClasses = false;
   public boolean skipMinification = false;
-  public boolean inlineAccessors = true;
-  public boolean removeSwitchMaps = true;
   public boolean disableAssertions = true;
-  public final OutlineOptions outline = new OutlineOptions();
   public boolean debugKeepRules = false;
   public final AttributeRemovalOptions attributeRemoval = new AttributeRemovalOptions();
   public boolean allowParameterName = false;
diff --git a/src/main/java/com/android/tools/r8/utils/PackageDistribution.java b/src/main/java/com/android/tools/r8/utils/PackageDistribution.java
deleted file mode 100644
index b242b9d..0000000
--- a/src/main/java/com/android/tools/r8/utils/PackageDistribution.java
+++ /dev/null
@@ -1,171 +0,0 @@
-// Copyright (c) 2017, 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.utils;
-
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Writer;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-public class PackageDistribution {
-
-  private static final String OLDFILE_PREFIX_TEXT =
-      "\n"
-          + "# Below follow the original package to file mapping rules. These have not been\n"
-          + "# changed by R8.\n"
-          + "\n";
-
-  private static final String APPENDED_PREFIX_TEXT =
-      "# The following packages had no mapping in the supplied package file. The\n"
-          + "# mapping rules provided below reflect the mapping that was used by R8. Please\n"
-          + "# use this updated map moving forward to ensure stability of package placement\n"
-          + "# in DEX files (and thus minimize patch size).\n"
-          + "#\n"
-          + "# Note that the updated package placement might not be optimal. Shifting the new\n"
-          + "# packages to DEX files that contain related packages might yield smaller DEX\n"
-          + "# file sizes.\n"
-          + "\n";
-
-  private static final String NEW_PACKAGE_MAP_PREFIX_TEXT =
-      "# This file provides a mapping of classes to DEX files in an Android multi-dex\n"
-          +"# application. It is used in conjunction with the R8 DEX file optimizer\n"
-          + "# to enforce a fixed distribution of classes to DEX files.\n"
-          + "#\n"
-          + "# Fixing the class distribution serves two purposes:\n"
-          + "#\n"
-          + "# 1. Keeping classes in the same DEX file reduces the size of patches between\n"
-          + "#    two versions of an application.\n"
-          + "# 2. Co-locating classes with their uses can reduce DEX file size. For example,\n"
-          + "#    one might want to place the helper classes for credit card processing in\n"
-          + "#    the same DEX file that contains the payment related logic.\n"
-          + "#\n"
-          + "# Entries in this file have the following form:\n"
-          + "#\n"
-          + "# <packageSpec>:<file number>\n"
-          + "#\n"
-          + "# Where packageSpec is either the name of a package, e.g., 'com.google.foo', or\n"
-          + "# a package wildcard of the form 'com.google.bar.*'. The former matches exactly\n"
-          + "# the classes in the given package, whereas the latter also matches classes in\n"
-          + "# subpackages. PackageSpec entries may not overlap.\n"
-          + "#\n"
-          + "# Empty lines and lines starting with a '#' are ignored.\n"
-          + "\n";
-
-  private static final String NO_PACKAGE_MAP_REQUIRED_TEXT =
-      "\n"
-          +  "# Intentionally empty, as the output only has a single DEX file.\n"
-          + "\n";
-
-  private final Map<String, Integer> map;
-
-  private PackageDistribution(Map<String, Integer> map) {
-    this.map = map;
-  }
-
-  public static PackageDistribution load(InputStream input) throws IOException {
-    return read(new BufferedReader(new InputStreamReader(input)));
-  }
-
-  public static PackageDistribution load(Path path) {
-    try (BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
-      return read(reader);
-    } catch (IOException e) {
-      throw new RuntimeException("Error reading file " + path, e);
-    }
-  }
-
-  private static PackageDistribution read(BufferedReader reader) throws IOException {
-    String line = null;
-    try {
-      Map<String, Integer> result = new HashMap<>();
-      while ((line = reader.readLine()) != null) {
-        if (line.length() == 0 || line.startsWith("#")) {
-          continue;
-        }
-        String[] parts = line.split(":");
-        if (parts.length != 2) {
-          throw new RuntimeException("Error parsing package map line " + line);
-        }
-        String prefix = parts[0];
-        if (result.containsKey(prefix)) {
-          throw new RuntimeException("Prefix is assigned twice: " + prefix);
-        }
-        int file = Integer.parseInt(parts[1]);
-        result.put(prefix, file);
-      }
-      return new PackageDistribution(result);
-    } catch (NumberFormatException e) {
-      throw new RuntimeException("Error parsing package map line " + line, e);
-    }
-  }
-
-  public static void formatEntry(Entry<String, Integer> entry, Writer writer) throws IOException {
-    writer.write(entry.getKey());
-    writer.write(":");
-    writer.write(entry.getValue().toString());
-  }
-
-  public static void writePackageToFileMap(
-      Path target, Map<String, Integer> mappings, PackageDistribution original) throws IOException {
-    BufferedWriter writer = Files.newBufferedWriter(target, StandardCharsets.UTF_8);
-    if (mappings.isEmpty()) {
-      if (original != null) {
-        copyOriginalPackageMap(original, writer);
-      } else {
-        writer.write(NEW_PACKAGE_MAP_PREFIX_TEXT);
-        writer.write(NO_PACKAGE_MAP_REQUIRED_TEXT);
-      }
-      writer.close();
-      return;
-    }
-    if (original == null) {
-      writer.write(NEW_PACKAGE_MAP_PREFIX_TEXT);
-    } else {
-      writer.write(APPENDED_PREFIX_TEXT);
-    }
-    for (Entry<String, Integer> entry : mappings.entrySet()) {
-      formatEntry(entry, writer);
-      writer.newLine();
-    }
-    if (original != null) {
-      // Copy the original
-      writer.write(OLDFILE_PREFIX_TEXT);
-      copyOriginalPackageMap(original, writer);
-    }
-    writer.close();
-  }
-
-  private static void copyOriginalPackageMap(PackageDistribution original, BufferedWriter writer)
-      throws IOException {
-    for (Entry<String, Integer> entry : original.map.entrySet()) {
-      formatEntry(entry, writer);
-      writer.newLine();
-    }
-  }
-
-  public int maxReferencedIndex() {
-    return map.values().stream().max(Integer::compare).orElse(0);
-  }
-
-  public Set<String> getFiles() {
-    return map.keySet();
-  }
-
-  public int get(String file) {
-    return map.getOrDefault(file, -1);
-  }
-
-  public boolean containsFile(String file) {
-    return map.containsKey(file);
-  }
-}
diff --git a/src/test/examples/classmerging/keep-rules-dontoptimize.txt b/src/test/examples/classmerging/keep-rules-dontoptimize.txt
new file mode 100644
index 0000000..b2c1ff4
--- /dev/null
+++ b/src/test/examples/classmerging/keep-rules-dontoptimize.txt
@@ -0,0 +1,11 @@
+# Copyright (c) 2017, 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.
+
+# Keep the application entry point. Get rid of everything that is not
+# reachable from there.
+-keep public class classmerging.Test {
+  public static void main(...);
+}
+
+-dontoptimize
diff --git a/src/test/examples/classmerging/keep-rules.txt b/src/test/examples/classmerging/keep-rules.txt
index 58b262b..f83adbd 100644
--- a/src/test/examples/classmerging/keep-rules.txt
+++ b/src/test/examples/classmerging/keep-rules.txt
@@ -7,6 +7,3 @@
 -keep public class classmerging.Test {
   public static void main(...);
 }
-
-# allow access modification to enable minification
--allowaccessmodification
diff --git a/src/test/examples/memberrebinding/package.map b/src/test/examples/memberrebinding/package.map
deleted file mode 100644
index e9bfd68..0000000
--- a/src/test/examples/memberrebinding/package.map
+++ /dev/null
@@ -1,4 +0,0 @@
-#
-# package.map file used by java/com/android/tools/r8/dex/ExtraFileTest.java
-#
-memberrebinding.subpackage:1
diff --git a/src/test/java/com/android/tools/r8/JctfTestSpecifications.java b/src/test/java/com/android/tools/r8/JctfTestSpecifications.java
index 932a61f..718cde9 100644
--- a/src/test/java/com/android/tools/r8/JctfTestSpecifications.java
+++ b/src/test/java/com/android/tools/r8/JctfTestSpecifications.java
@@ -4513,7 +4513,7 @@
           // java.lang.AssertionError: Destroyed thread group was not finalized
 
           .put("lang.ThreadGroup.destroy.ThreadGroup_destroy_A01",
-              match(D8_COMPILER, runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
+              match(D8_COMPILER, runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1, DexVm.ART_4_4_4)))
           // 1) t02
           // java.lang.IllegalThreadStateException: Thread group still contains threads: Test group
           // 2) t04
@@ -4793,6 +4793,12 @@
           // 1) t02
           // java.lang.AssertionError: java.lang.AssertionError: expected:<7> but was:<6>
 
+          .put("lang.ref.PhantomReference.clear.PhantomReference_clear_A01",
+              match(runtimes(DexVm.ART_4_4_4)))
+          .put("lang.ref.SoftReference.clear.SoftReference_clear_A01",
+              match(runtimes(DexVm.ART_4_4_4)))
+          // Passes or fails randomly. Have seen out of memory and assertion errors.
+
           .put("lang.ref.PhantomReference.isEnqueued.PhantomReference_isEnqueued_A01",
               match(runtimes(DexVm.ART_4_4_4)))
           .put("lang.ref.WeakReference.isEnqueued.WeakReference_isEnqueued_A01",
diff --git a/src/test/java/com/android/tools/r8/classmerging/ClassMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/ClassMergingTest.java
index 7bd18e0..a1692c8 100644
--- a/src/test/java/com/android/tools/r8/classmerging/ClassMergingTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/ClassMergingTest.java
@@ -1,16 +1,21 @@
 package com.android.tools.r8.classmerging;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
 import com.android.tools.r8.CompilationException;
 import com.android.tools.r8.R8Command;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.shaking.ProguardRuleParserException;
 import com.android.tools.r8.utils.DexInspector;
+import com.android.tools.r8.utils.InternalOptions;
+import com.google.common.collect.ImmutableList;
 import java.io.IOException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.List;
 import java.util.concurrent.ExecutionException;
-import org.junit.Assert;
-import org.junit.Before;
+import java.util.function.Consumer;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
@@ -21,54 +26,76 @@
       .resolve("classmerging.jar");
   private static final Path EXAMPLE_KEEP = Paths.get(ToolHelper.EXAMPLES_DIR)
       .resolve("classmerging").resolve("keep-rules.txt");
+  private static final Path DONT_OPTIMIZE = Paths.get(ToolHelper.EXAMPLES_DIR)
+      .resolve("classmerging").resolve("keep-rules-dontoptimize.txt");
 
   @Rule
   public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
 
-  @Before
-  public void runR8()
+  private void configure(InternalOptions options) {
+    options.skipClassMerging = false;
+  }
+
+  private void runR8(Path proguardConfig, Consumer<InternalOptions> optionsConsumer)
       throws IOException, ProguardRuleParserException, ExecutionException, CompilationException {
-    // Disable access modification, as it otherwise is difficult to test visibility bridge methods.
     ToolHelper.runR8(
         R8Command.builder()
             .setOutputPath(Paths.get(temp.getRoot().getCanonicalPath()))
             .addProgramFiles(EXAMPLE_JAR)
-            .addProguardConfigurationFiles(EXAMPLE_KEEP)
+            .addProguardConfigurationFiles(proguardConfig)
             .setMinification(false)
-            .build(), o -> {
-          o.skipClassMerging = false;
-        });
+            .build(),
+        optionsConsumer);
     inspector = new DexInspector(
         Paths.get(temp.getRoot().getCanonicalPath()).resolve("classes.dex"));
   }
 
   private DexInspector inspector;
 
+  private final List<String> CAN_BE_MERGED = ImmutableList.of(
+      "classmerging.GenericInterface",
+      "classmerging.GenericAbstractClass",
+      "classmerging.Outer$SuperClass",
+      "classmerging.SuperClass"
+  );
+
   @Test
-  public void testClassesHaveBeenMerged() throws IOException, ExecutionException {
+  public void testClassesHaveBeenMerged()
+      throws IOException, ExecutionException, CompilationException, ProguardRuleParserException {
+    runR8(EXAMPLE_KEEP, this::configure);
     // GenericInterface should be merged into GenericInterfaceImpl.
-    Assert.assertFalse(inspector.clazz("classmerging.GenericInterface").isPresent());
-    Assert.assertTrue(inspector.clazz("classmerging.GenericInterfaceImpl").isPresent());
-    Assert.assertFalse(inspector.clazz("classmerging.GenericAbstractClass").isPresent());
-    Assert.assertTrue(inspector.clazz("classmerging.GenericInterfaceImpl").isPresent());
-    Assert.assertFalse(inspector.clazz("classmerging.Outer$SuperClass").isPresent());
-    Assert.assertTrue(inspector.clazz("classmerging.Outer$SubClass").isPresent());
-    Assert.assertFalse(inspector.clazz("classmerging.SuperClass").isPresent());
-    Assert.assertTrue(inspector.clazz("classmerging.SubClass").isPresent());
-  }
-
-
-  @Test
-  public void testConflictWasDetected() throws IOException, ExecutionException {
-    Assert.assertTrue(inspector.clazz("classmerging.ConflictingInterface").isPresent());
-    Assert.assertTrue(inspector.clazz("classmerging.ConflictingInterfaceImpl").isPresent());
+    for (String candidate : CAN_BE_MERGED) {
+      assertFalse(inspector.clazz(candidate).isPresent());
+    }
+    assertTrue(inspector.clazz("classmerging.GenericInterfaceImpl").isPresent());
+    assertTrue(inspector.clazz("classmerging.GenericInterfaceImpl").isPresent());
+    assertTrue(inspector.clazz("classmerging.Outer$SubClass").isPresent());
+    assertTrue(inspector.clazz("classmerging.SubClass").isPresent());
   }
 
   @Test
-  public void testSuperCallWasDetected() throws IOException, ExecutionException {
-    Assert.assertTrue(inspector.clazz("classmerging.SuperClassWithReferencedMethod").isPresent());
-    Assert
-        .assertTrue(inspector.clazz("classmerging.SubClassThatReferencesSuperMethod").isPresent());
+  public void testClassesShouldNotMerged()
+      throws IOException, ExecutionException, CompilationException, ProguardRuleParserException {
+    runR8(DONT_OPTIMIZE, null);
+    for (String candidate : CAN_BE_MERGED) {
+      assertTrue(inspector.clazz(candidate).isPresent());
+    }
+  }
+
+  @Test
+  public void testConflictWasDetected()
+      throws IOException, ExecutionException, CompilationException, ProguardRuleParserException {
+    runR8(EXAMPLE_KEEP, this::configure);
+    assertTrue(inspector.clazz("classmerging.ConflictingInterface").isPresent());
+    assertTrue(inspector.clazz("classmerging.ConflictingInterfaceImpl").isPresent());
+  }
+
+  @Test
+  public void testSuperCallWasDetected()
+      throws IOException, ExecutionException, CompilationException, ProguardRuleParserException {
+    runR8(EXAMPLE_KEEP, this::configure);
+    assertTrue(inspector.clazz("classmerging.SuperClassWithReferencedMethod").isPresent());
+    assertTrue(inspector.clazz("classmerging.SubClassThatReferencesSuperMethod").isPresent());
   }
 
 }
diff --git a/src/test/java/com/android/tools/r8/dex/ExtraFileTest.java b/src/test/java/com/android/tools/r8/dex/ExtraFileTest.java
deleted file mode 100644
index 6114f61..0000000
--- a/src/test/java/com/android/tools/r8/dex/ExtraFileTest.java
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright (c) 2016, 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.dex;
-
-import com.android.tools.r8.CompilationException;
-import com.android.tools.r8.CompilationMode;
-import com.android.tools.r8.R8Command;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.shaking.ProguardRuleParserException;
-import com.google.common.collect.ImmutableList;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.ExecutionException;
-import org.junit.Assert;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.rules.TemporaryFolder;
-
-public class ExtraFileTest {
-
-  private static final String EXAMPLE_DIR = ToolHelper.EXAMPLES_BUILD_DIR;
-  private static final String EXAMPLE_DEX = "memberrebinding/classes.dex";
-  private static final String EXAMPLE_LIB = "memberrebindinglib/classes.dex";
-  private static final String EXAMPLE_CLASS = "memberrebinding.Memberrebinding";
-  private static final String EXAMPLE_PACKAGE_MAP = "memberrebinding/package.map";
-  private static final String EXAMPLE_PROGUARD_MAP = "memberrebinding/proguard.map";
-
-  @Rule
-  public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
-
-  @Rule
-  public ExpectedException thrown = ExpectedException.none();
-
-  @Test
-  public void splitMemberRebindingTwoFilesRelease()
-      throws IOException, ProguardRuleParserException, ExecutionException, CompilationException {
-    if (!ToolHelper.artSupported()) {
-      return;
-    }
-
-    Path out = temp.getRoot().toPath();
-    Path original = Paths.get(EXAMPLE_DIR, EXAMPLE_DEX);
-    Path packageMap = Paths.get(ToolHelper.EXAMPLES_DIR, EXAMPLE_PACKAGE_MAP);
-    Path proguardMap = Paths.get(ToolHelper.EXAMPLES_DIR, EXAMPLE_PROGUARD_MAP);
-    R8Command command =
-        R8Command.builder()
-            .addProgramFiles(original)
-            .setMode(CompilationMode.RELEASE)
-            .setOutputPath(out)
-            .setMinApiLevel(Constants.ANDROID_L_API) // Allow native multidex.
-            .setProguardMapFile(proguardMap)
-            .setPackageDistributionFile(packageMap)
-            .build();
-    ToolHelper.runR8(command);
-    List<String> outs =
-        new ArrayList<>(
-            ImmutableList.of(
-                out.resolve("classes.dex").toString(),
-                out.resolve("classes2.dex").toString(),
-                EXAMPLE_DIR + EXAMPLE_LIB));
-    outs.forEach(f -> Assert.assertTrue("Failed to find file " + f, Files.exists(Paths.get(f))));
-    ToolHelper.checkArtOutputIdentical(
-        ImmutableList.of(original.toString(), EXAMPLE_DIR + EXAMPLE_LIB),
-        outs,
-        EXAMPLE_CLASS,
-        null,
-        null);
-  }
-
-  @Test
-  public void splitMemberRebindingTwoFilesDebug()
-      throws IOException, ProguardRuleParserException, ExecutionException, CompilationException {
-    thrown.expect(CompilationException.class);
-    Path out = temp.getRoot().toPath();
-    Path original = Paths.get(EXAMPLE_DIR, EXAMPLE_DEX);
-    Path packageMap = Paths.get(ToolHelper.EXAMPLES_DIR, EXAMPLE_PACKAGE_MAP);
-    Path proguardMap = Paths.get(ToolHelper.EXAMPLES_DIR, EXAMPLE_PROGUARD_MAP);
-    R8Command command =
-        R8Command.builder()
-            .addProgramFiles(original)
-            .setMode(CompilationMode.DEBUG)
-            .setOutputPath(out)
-            .setMinApiLevel(Constants.ANDROID_L_API) // Allow native multidex.
-            .setProguardMapFile(proguardMap)
-            .setPackageDistributionFile(packageMap)
-            .build();
-    ToolHelper.runR8(command);
-  }
-}
diff --git a/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java b/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java
index 92a755e..9da8e0e 100644
--- a/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java
+++ b/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java
@@ -98,7 +98,6 @@
             null,
             NamingLens.getIdentityLens(),
             null,
-            null,
             options);
     return runOnArt(outputApp, main);
   }
@@ -183,7 +182,6 @@
           null,
           NamingLens.getIdentityLens(),
           null,
-          null,
           options);
     } catch (ExecutionException e) {
       throw new RuntimeException(e);
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 a316969..0acd445 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -597,7 +597,7 @@
         application, appInfo, options, null, null, NamingLens.getIdentityLens(), null);
     ExecutorService executor = ThreadUtils.getExecutorService(options);
     try {
-      return writer.write(null, executor);
+      return writer.write(executor);
     } finally {
       executor.shutdown();
     }
diff --git a/src/test/java/com/android/tools/r8/optimize/R8DebugStrippingTest.java b/src/test/java/com/android/tools/r8/optimize/R8DebugStrippingTest.java
deleted file mode 100644
index 6609ff2..0000000
--- a/src/test/java/com/android/tools/r8/optimize/R8DebugStrippingTest.java
+++ /dev/null
@@ -1,239 +0,0 @@
-// Copyright (c) 2016, 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.optimize;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import com.android.tools.r8.CompilationException;
-import com.android.tools.r8.R8Command;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.DexVm;
-import com.android.tools.r8.graph.DexCode;
-import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.naming.ClassNameMapper;
-import com.android.tools.r8.naming.ClassNaming;
-import com.android.tools.r8.naming.MemberNaming;
-import com.android.tools.r8.naming.MemberNaming.InlineInformation;
-import com.android.tools.r8.naming.MemberNaming.MethodSignature;
-import com.android.tools.r8.naming.MemberNaming.Signature;
-import com.android.tools.r8.naming.ProguardMapReader;
-import com.android.tools.r8.shaking.ProguardRuleParserException;
-import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.DexInspector;
-import com.android.tools.r8.utils.DexInspector.ClassSubject;
-import com.google.common.collect.BiMap;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameter;
-import org.junit.runners.Parameterized.Parameters;
-
-@RunWith(Parameterized.class)
-public class R8DebugStrippingTest {
-
-  private static final String ROOT = ToolHelper.EXAMPLES_BUILD_DIR;
-  private static final String EXAMPLE_DEX = "throwing/classes.dex";
-  private static final String EXAMPLE_MAP = "throwing/throwing.map";
-  private static final String EXAMPLE_CLASS = "throwing.Throwing";
-  private static final String EXAMPLE_JAVA = "Throwing.java";
-
-  private static final String MAIN_NAME = "main";
-  private static final String[] MAIN_PARAMETERS = new String[]{"java.lang.String[]"};
-  private static final String VOID_RETURN = "void";
-
-  private static final String OTHER_NAME = "throwInAFunctionThatIsNotInlinedAndCalledTwice";
-  private static final String[] NO_PARAMETERS = new String[0];
-  private static final String INT_RETURN = "int";
-
-  private static final String THIRD_NAME = "aFunctionThatCallsAnInlinedMethodThatThrows";
-  private static final String[] LIST_PARAMETER = new String[]{"java.util.List"};
-
-  private static final String FORTH_NAME = "anotherFunctionThatCallsAnInlinedMethodThatThrows";
-  private static final String[] STRING_PARAMETER = new String[]{"java.lang.String"};
-
-  private static final Map<String, Signature> SIGNATURE_MAP = ImmutableMap.of(
-      MAIN_NAME, new MethodSignature(MAIN_NAME, VOID_RETURN, MAIN_PARAMETERS),
-      OTHER_NAME, new MethodSignature(OTHER_NAME, INT_RETURN, NO_PARAMETERS),
-      THIRD_NAME, new MethodSignature(THIRD_NAME, INT_RETURN, LIST_PARAMETER),
-      FORTH_NAME, new MethodSignature(FORTH_NAME, INT_RETURN, STRING_PARAMETER)
-  );
-
-  private ClassNameMapper mapper;
-
-  @Parameter(0)
-  public boolean compressRanges;
-
-  @Rule
-  public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
-
-  @Before
-  public void loadRangeInformation() throws IOException {
-    mapper = ProguardMapReader.mapperFromFile(Paths.get(ROOT, EXAMPLE_MAP));
-  }
-
-  @Parameters(name = "compressLineNumers={0}")
-  public static Object[] parameters() {
-    return new Object[]{true, false};
-  }
-
-  @Test
-  public void testStackTraces()
-      throws IOException, ProguardRuleParserException, ExecutionException, CompilationException {
-
-    // Temporary directory for R8 output.
-    Path out = temp.getRoot().toPath();
-
-    R8Command command =
-        R8Command.builder()
-            .addProgramFiles(Paths.get(ROOT, EXAMPLE_DEX))
-            .setOutputPath(out)
-            .setProguardMapFile(Paths.get(ROOT, EXAMPLE_MAP))
-            .build();
-
-    // Generate R8 processed version.
-    AndroidApp result =
-        ToolHelper.runR8(command, (options) -> options.skipDebugLineNumberOpt = !compressRanges);
-
-    ClassNameMapper classNameMapper;
-    try (InputStream is = result.getProguardMap()) {
-      classNameMapper = ProguardMapReader.mapperFromInputStream(is);
-    }
-    if (compressRanges) {
-      classNameMapper.forAllClassNamings(this::ensureRangesAreUniquePerClass);
-    }
-
-    if (!ToolHelper.artSupported()) {
-      return;
-    }
-    // Run art on original.
-    String originalOutput =
-        ToolHelper.runArtNoVerificationErrors(ROOT + EXAMPLE_DEX, EXAMPLE_CLASS);
-    // Run art on R8 processed version.
-    String otherOutput =
-        ToolHelper.runArtNoVerificationErrors(out + "/classes.dex", EXAMPLE_CLASS);
-    // Check that exceptions are in same range
-    assertStacktracesMatchRanges(originalOutput, otherOutput, classNameMapper);
-
-    // Check that we have debug information in all the places required.
-    DexInspector inspector = new DexInspector(out.resolve("classes.dex"));
-    BiMap<String, String> obfuscationMap
-        = classNameMapper.getObfuscatedToOriginalMapping().inverse();
-    ClassSubject overloaded = inspector.clazz(obfuscationMap.get("throwing.Overloaded"));
-    assertTrue(overloaded.isPresent());
-    ensureDebugInfosExist(overloaded);
-  }
-
-  private void ensureDebugInfosExist(ClassSubject overloaded) {
-    final Map<DexString, Boolean> hasDebugInfo = Maps.newIdentityHashMap();
-    overloaded.forAllMethods(method -> {
-          if (!method.isAbstract()) {
-            DexCode code = method.getMethod().getCode().asDexCode();
-            DexString name = method.getMethod().method.name;
-            Boolean previous = hasDebugInfo.get(name);
-            boolean current = code.getDebugInfo() != null;
-            // If we have seen one before, it should be the same as now.
-            assertTrue(previous == null || (previous == current));
-            hasDebugInfo.put(name, current);
-          }
-        }
-    );
-  }
-
-  private void ensureRangesAreUniquePerClass(ClassNaming naming) {
-    final Map<String, Set<Integer>> rangeMap = new HashMap<>();
-    naming.forAllMemberNaming(memberNaming -> {
-      if (memberNaming.isMethodNaming()) {
-        if (memberNaming.topLevelRange != MemberNaming.fakeZeroRange) {
-          int startLine = memberNaming.topLevelRange.from;
-          Set<Integer> used = rangeMap
-              .computeIfAbsent(memberNaming.getRenamedName(), any -> new HashSet<>());
-          assertFalse(used.contains(startLine));
-          used.add(startLine);
-        }
-      }
-    });
-  }
-
-  private String extractRangeIndex(String line, ClassNameMapper mapper) {
-    int position = line.lastIndexOf(EXAMPLE_JAVA);
-    if (position == -1 && ToolHelper.getDexVm() == DexVm.ART_4_4_4) {
-      assert line.contains("dalvik.system.NativeStart.main(Native Method)");
-      return "Native Method";
-    }
-    assertNotSame("Malformed stackframe: " + line, -1, position);
-    String numberPart = line.substring(position + EXAMPLE_JAVA.length() + 1, line.lastIndexOf(')'));
-    int number = Integer.parseInt(numberPart);
-    // Search the signature map for all signatures that actually match. We do this by first looking
-    // up the renamed signature and then checking whether it is contained in the line. We prepend
-    // the class name to make sure we do not match random characters in the line.
-    for (Entry<String, Signature> entry : SIGNATURE_MAP.entrySet()) {
-      MemberNaming naming = mapper.getClassNaming(EXAMPLE_CLASS)
-          .lookupByOriginalSignature(entry.getValue());
-      if (!line.contains(EXAMPLE_CLASS + "." + naming.getRenamedName())) {
-        continue;
-      }
-      if (naming.topLevelRange.contains(number)) {
-        return entry.getKey() + ":" + 0;
-      }
-      int rangeNo = 1;
-      for (InlineInformation inlineInformation : naming.inlineInformation) {
-        if (inlineInformation.inlinedRange.contains(number)) {
-          return entry.getKey() + ":" + rangeNo;
-        }
-        rangeNo++;
-      }
-    }
-    fail("Number not in any range " + number);
-    return null;
-  }
-
-  private MemberNaming selectRanges(String line, ClassNameMapper mapper) {
-    Signature signature;
-    for (Entry<String, Signature> entry : SIGNATURE_MAP.entrySet()) {
-      if (line.contains(entry.getKey())) {
-        return mapper.getClassNaming(EXAMPLE_CLASS).lookup(entry.getValue());
-      }
-    }
-    Assert.fail("unknown method in line " + line);
-    return null;
-  }
-
-  private void assertStacktracesMatchRanges(String before, String after,
-      ClassNameMapper newMapper) {
-    String[] beforeLines = before.split("\n");
-    String[] afterLines = after.split("\n");
-    assertEquals("Output length differs", beforeLines.length,
-        afterLines.length);
-    for (int i = 0; i < beforeLines.length; i++) {
-      if (!beforeLines[i].startsWith("FRAME:")) {
-        continue;
-      }
-      String beforeLine = beforeLines[i];
-      String expected = extractRangeIndex(beforeLine, mapper);
-      String afterLine = afterLines[i];
-      String generated = extractRangeIndex(afterLine, newMapper);
-      assertEquals("Ranges match", expected, generated);
-    }
-  }
-}
diff --git a/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java b/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java
index 2e3088a..42e289a 100644
--- a/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java
+++ b/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java
@@ -588,7 +588,6 @@
           null,
           NamingLens.getIdentityLens(),
           null,
-          null,
           options);
     } catch (ExecutionException e) {
       throw new RuntimeException(e);
diff --git a/src/test/java/com/android/tools/r8/utils/D8CommandTest.java b/src/test/java/com/android/tools/r8/utils/D8CommandTest.java
index 92ad06d..941ba84 100644
--- a/src/test/java/com/android/tools/r8/utils/D8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/utils/D8CommandTest.java
@@ -54,7 +54,6 @@
     assertFalse(ToolHelper.getApp(command).hasMainDexListResources());
     assertFalse(ToolHelper.getApp(command).hasProguardMap());
     assertFalse(ToolHelper.getApp(command).hasProguardSeeds());
-    assertFalse(ToolHelper.getApp(command).hasPackageDistribution());
     assertNull(command.getOutputPath());
     assertEquals(CompilationMode.DEBUG, command.getMode());
   }
diff --git a/src/test/java/com/android/tools/r8/utils/R8CommandTest.java b/src/test/java/com/android/tools/r8/utils/R8CommandTest.java
index 322f15e..2054b22 100644
--- a/src/test/java/com/android/tools/r8/utils/R8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/utils/R8CommandTest.java
@@ -56,7 +56,6 @@
     assertFalse(ToolHelper.getApp(command).hasMainDexListResources());
     assertFalse(ToolHelper.getApp(command).hasProguardMap());
     assertFalse(ToolHelper.getApp(command).hasProguardSeeds());
-    assertFalse(ToolHelper.getApp(command).hasPackageDistribution());
     assertNull(command.getOutputPath());
     assertFalse(command.useMinification());
     assertFalse(command.useTreeShaking());
diff --git a/src/test/java/com/android/tools/r8/utils/Smali.java b/src/test/java/com/android/tools/r8/utils/Smali.java
index 93edf4d..6a26a1a 100644
--- a/src/test/java/com/android/tools/r8/utils/Smali.java
+++ b/src/test/java/com/android/tools/r8/utils/Smali.java
@@ -106,7 +106,7 @@
           app, options, new Timing("smali")).read(executor);
       ApplicationWriter writer = new ApplicationWriter(
           dexApp, null, options, null, null, NamingLens.getIdentityLens(), null);
-      AndroidApp trimmed = writer.write(null, executor);
+      AndroidApp trimmed = writer.write(executor);
       return ByteStreams.toByteArray(trimmed.getDexProgramResources().get(0).getStream());
     } finally {
       executor.shutdown();