Merge "Implement -alwaysinline directive."
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index a6da2ec..575b09f 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -55,6 +55,7 @@
  */
 public final class D8 {
 
+  private static final String kVersion = "v0.0.1";
   private static final int STATUS_ERROR = 1;
 
   private D8() {}
@@ -109,7 +110,7 @@
       return;
     }
     if (command.isPrintVersion()) {
-      System.out.println("D8 v0.0.1");
+      System.out.println("D8 " + kVersion);
       return;
     }
     run(command);
@@ -159,7 +160,9 @@
     if (options.customizedMarker != null) {
       return options.customizedMarker;
     }
-    return new Marker(Tool.D8);
+    return new Marker(Tool.D8)
+        .put("version", kVersion)
+        .put("min-api", options.minApiLevel);
   }
 
   private static CompilationResult runForTesting(
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 4393a3e..620faf8 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -71,6 +71,7 @@
 
 public class R8 {
 
+  private static final String kVersion = "v0.0.1";
   private final Timing timing = new Timing("R8");
   private final InternalOptions options;
 
@@ -84,7 +85,9 @@
     if (options.customizedMarker != null) {
       return options.customizedMarker;
     }
-    return new Marker(Tool.R8);
+    return new Marker(Tool.R8)
+        .put("version", kVersion)
+        .put("min-api", options.minApiLevel);
   }
 
   public static AndroidApp writeApplication(
@@ -497,7 +500,7 @@
       return;
     }
     if (command.isPrintVersion()) {
-      System.out.println("R8 v0.0.1");
+      System.out.println("R8 " + kVersion);
       return;
     }
     run(command);
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 e6ec968..1e2e2c9 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -156,8 +156,7 @@
         distributor =
             new VirtualFile.PackageMapDistributor(this, packageDistribution, executorService);
       } else {
-        boolean minimal = options.minimalMainDex && !application.mainDexList.isEmpty();
-        distributor = new VirtualFile.FillFilesDistributor(this, minimal);
+        distributor = new VirtualFile.FillFilesDistributor(this, options.minimalMainDex);
       }
       Map<Integer, VirtualFile> newFiles = distributor.run();
 
@@ -167,6 +166,7 @@
       for (int i = 0; i < newFiles.size(); i++) {
         VirtualFile newFile = newFiles.get(i);
         assert newFile.getId() == i;
+        assert !newFile.isEmpty();
         if (!newFile.isEmpty()) {
           dexDataFutures.put(newFile, executorService.submit(() -> writeDexFile(newFile)));
         }
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 9391af9..f06aa45 100644
--- a/src/main/java/com/android/tools/r8/dex/VirtualFile.java
+++ b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
@@ -57,9 +57,6 @@
 
   // The fill strategy determine how to distribute classes into dex files.
   enum FillStrategy {
-    // Only put classes matches by the main dex rules into the first dex file. Distribute remaining
-    // classes in additional dex files filling each dex file as much as possible.
-    MINIMAL_MAIN_DEX,
     // Distribute classes in as few dex files as possible filling each dex file as much as possible.
     FILL_MAX,
     // Distribute classes keeping some space for future growth. This is mainly useful together with
@@ -114,7 +111,8 @@
       if (!next.startsWith(prefix)) {
         throw new RuntimeException("Input filenames lack common prefix.");
       }
-      String numberPart = next.substring(prefix.length(), next.length() - FileUtils.DEX_EXTENSION.length());
+      String numberPart =
+          next.substring(prefix.length(), next.length() - FileUtils.DEX_EXTENSION.length());
       if (Integer.parseInt(numberPart) != index++) {
         throw new RuntimeException("DEX files are not numbered consecutively.");
       }
@@ -233,6 +231,11 @@
       for (DexProgramClass clazz : application.classes()) {
         VirtualFile file = new VirtualFile(nameToFileMap.size(), writer.namingLens);
         nameToFileMap.put(nameToFileMap.size(), file);
+        // Write the marker string to all files in files-per-class mode.
+        // TODO(sgjesse): Get rid of this (currently some tests fails without it).
+        if (writer.markerString != null) {
+          file.transaction.addString(writer.markerString);
+        }
         file.addClass(clazz);
         file.commitTransaction();
       }
@@ -243,16 +246,25 @@
   public abstract static class DistributorBase extends Distributor {
     protected Set<DexProgramClass> classes;
     protected Map<DexProgramClass, String> originalNames;
+    protected final VirtualFile mainDexFile;
 
     DistributorBase(ApplicationWriter writer) {
       super(writer);
 
+      // Create the primary dex file. The distribution will add more if needed.
+      mainDexFile = new VirtualFile(0, writer.namingLens);
+      nameToFileMap.put(0, mainDexFile);
+      if (writer.markerString != null) {
+        mainDexFile.transaction.addString(writer.markerString);
+        mainDexFile.commitTransaction();
+      }
+
       classes = Sets.newHashSet(application.classes());
       originalNames = computeOriginalNameMapping(classes, application.getProguardMap());
     }
 
     protected void fillForMainDexList(Set<DexProgramClass> classes) {
-      if (application.mainDexList != null) {
+      if (!application.mainDexList.isEmpty()) {
         VirtualFile mainDexFile = nameToFileMap.get(0);
         for (DexType type : application.mainDexList) {
           DexClass clazz = application.definitionFor(type);
@@ -306,34 +318,38 @@
   }
 
   public static class FillFilesDistributor extends DistributorBase {
+    boolean minimalMainDex;
     private final FillStrategy fillStrategy;
 
     FillFilesDistributor(ApplicationWriter writer, boolean minimalMainDex) {
       super(writer);
-      this.fillStrategy = minimalMainDex ? FillStrategy.MINIMAL_MAIN_DEX : FillStrategy.FILL_MAX;
+      this.minimalMainDex = minimalMainDex;
+      this.fillStrategy = FillStrategy.FILL_MAX;
     }
 
     public Map<Integer, VirtualFile> run() throws ExecutionException, IOException {
-      // Strategy for distributing classes for write out:
-      // 1. Place the remaining files based on their packages in sorted order.
-
-      // Start with 1 file. The package populator will add more if needed.
-      VirtualFile main = new VirtualFile(0, writer.namingLens);
-      nameToFileMap.put(0, main);
-      if (writer.markerString != null) {
-        main.transaction.addString(writer.markerString);
-        main.commitTransaction();
-      }
-
       // First fill required classes into the main dex file.
       fillForMainDexList(classes);
+      if (classes.isEmpty()) {
+        // All classes ended up in the main dex file, no more to do.
+        return nameToFileMap;
+      }
+
+      Map<Integer, VirtualFile> filesForDistribution = nameToFileMap;
+      if (minimalMainDex && !mainDexFile.isEmpty()) {
+        assert !nameToFileMap.get(0).isEmpty();
+        // The main dex file is filtered out, so create ensure at least one file for the remaining
+        // classes
+        nameToFileMap.put(1, new VirtualFile(1, writer.namingLens));
+        filesForDistribution = Maps.filterKeys(filesForDistribution, key -> key != 0);
+      }
 
       // Sort the remaining classes based on the original names.
       // This with make classes from the same package be adjacent.
       classes = sortClassesByPackage(classes, originalNames);
 
       new PackageSplitPopulator(
-          nameToFileMap, classes, originalNames, null, application.dexItemFactory,
+          filesForDistribution, classes, originalNames, null, application.dexItemFactory,
           fillStrategy, writer.namingLens)
           .call();
       return nameToFileMap;
@@ -347,13 +363,7 @@
 
     @Override
     public Map<Integer, VirtualFile> run() throws ExecutionException, IOException {
-      VirtualFile mainDexFile = new VirtualFile(0, writer.namingLens);
-      nameToFileMap.put(0, mainDexFile);
-      if (writer.markerString != null) {
-        mainDexFile.transaction.addString(writer.markerString);
-        mainDexFile.commitTransaction();
-      }
-
+      // Add all classes to the main dex file.
       for (DexProgramClass programClass : classes) {
         mainDexFile.addClass(programClass);
       }
@@ -381,8 +391,10 @@
       // 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 = 0; index <= maxReferencedIndex; index++) {
+      for (int index = 1; index <= maxReferencedIndex; index++) {
         VirtualFile file = new VirtualFile(index, writer.namingLens);
         nameToFileMap.put(index, file);
       }
@@ -791,14 +803,7 @@
       this.namingLens = namingLens;
       this.fillStrategy = fillStrategy;
 
-      nextFileId = files.size();
-      if (fillStrategy == FillStrategy.MINIMAL_MAIN_DEX) {
-        // The main dex file is filtered out, so ensure at least one file for the remaining
-        // classes
-        files.put(nextFileId, new VirtualFile(nextFileId, namingLens));
-        this.files = Maps.filterKeys(files, key -> key != 0);
-        nextFileId++;
-      }
+      nextFileId = Collections.max(files.keySet()) + 1;
 
       reset();
     }
@@ -814,7 +819,6 @@
 
     VirtualFile next() {
       VirtualFile next = activeFiles.next();
-      assert fillStrategy != FillStrategy.MINIMAL_MAIN_DEX || next.getId() != 0;
       return next;
     }