Merge "Silence deprecation warning."
diff --git a/.gitignore b/.gitignore
index 0090fb9..1241f78 100644
--- a/.gitignore
+++ b/.gitignore
@@ -54,6 +54,8 @@
 third_party/framework.tar.gz
 third_party/goyt
 third_party/goyt.tar.gz
+third_party/ddmlib
+third_party/ddmlib.tar.gz
 src/test/jack/ub-jack
 gradle-app.setting
 gradlew
diff --git a/build.gradle b/build.gradle
index 1ad9b98..9539df2 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1068,7 +1068,9 @@
     if (project.hasProperty('dex_vm') && project.property('dex_vm') != 'default') {
         println "Running with non default vm: " + project.property('dex_vm')
         systemProperty 'dex_vm', project.property('dex_vm')
-        if (project.property('dex_vm') == '5.1.1' || project.property('dex_vm') == '6.0.1') {
+        if (project.property('dex_vm').startsWith('4.4.4') ||
+            project.property('dex_vm').startsWith('5.1.1') ||
+            project.property('dex_vm').startsWith('6.0.1')) {
             // R8 and D8 compute the dex file version number based on the input.
             // Jack generates dex files with version 37 which art 5.1.1 and 6.0.1 will not run.
             // Therefore we skip the jack generated art tests with those art versions.
@@ -1183,6 +1185,8 @@
 //    out/host/linux-x86/bin directory of the android checkout. Currently this is version pre 2.2.1,
 //    if that is updated the call to smali in "task "${smaliToDexTask}"(type: Exec)" below might
 //    need to change as smali got a completely new command line interface in version 2.2.1.
+//    After Android O, Jack is no longer alive, do not forget to uncomment call to buildArtTest for
+//    Jack if you build an android version using Jack.
 //
 //    PATH=$HOME/android/master/out/host/linux-x86/bin:$PATH tools/gradle.py -Pandroid_source buildArtTests
 //
@@ -1301,7 +1305,8 @@
                     if (!(name in skippedTestsDx)) {
                         dependsOn buildArtTest(androidCheckoutDir, artTestBuildDir, dir, DexTool.DX);
                     }
-                    dependsOn buildArtTest(androidCheckoutDir, artTestBuildDir, dir, DexTool.JACK);
+                    // After Android O, Jack is no longer alive
+                    //dependsOn buildArtTest(androidCheckoutDir, artTestBuildDir, dir, DexTool.JACK);
                 }
             }
         }
@@ -1424,7 +1429,13 @@
     }
 
     task "${smaliToDexTask}"(type: Exec) {
-        workingDir "${testDir}/smali"
+        // Directory that contains smali files is either smali, or smali/art
+        def smali_dir = file("${dir}/smali/art")
+        if (smali_dir.exists()) {
+            workingDir "${testDir}/smali/art"
+        } else  {
+            workingDir "${testDir}/smali"
+        }
         executable "/bin/bash"
         // This is the command line options for smali prior to 2.2.1, where smali got a new
         // command line interface.
diff --git a/src/main/java/com/android/tools/r8/CompilationException.java b/src/main/java/com/android/tools/r8/CompilationException.java
index c7477b6..8e1e56c 100644
--- a/src/main/java/com/android/tools/r8/CompilationException.java
+++ b/src/main/java/com/android/tools/r8/CompilationException.java
@@ -9,7 +9,7 @@
  * This is always an expected error and considered a user input issue.
  * A user-understandable message must be provided.
  */
-public class CompilationException extends Exception implements Diagnostic {
+public class CompilationException extends Exception {
   private static final long serialVersionUID = 1L;
 
   /**
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index 19f478a..8a92ef0 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -60,26 +60,18 @@
   /**
    * Main API entry for the D8 dexer.
    *
-   * <p>If the D8Command contains a DiagnosticsHandler that does not throw a CompilationException
-   * on error this method returns null if the run fails.
-   *
    * @param command D8 command.
    * @return the compilation result.
    */
   public static D8Output run(D8Command command) throws IOException, CompilationException {
     InternalOptions options = command.getInternalOptions();
-    try {
-      CompilationResult result = runForTesting(command.getInputApp(), options);
-      assert result != null;
-      D8Output output = new D8Output(result.androidApp, command.getOutputMode());
-      if (command.getOutputPath() != null) {
-        output.write(command.getOutputPath());
-      }
-      return output;
-    } catch (CompilationException e) {
-      options.diagnosticsHandler.error(e);
-      return null;
+    CompilationResult result = runForTesting(command.getInputApp(), options);
+    assert result != null;
+    D8Output output = new D8Output(result.androidApp, command.getOutputMode());
+    if (command.getOutputPath() != null) {
+      output.write(command.getOutputPath());
     }
+    return output;
   }
 
   /**
@@ -88,9 +80,6 @@
    * <p>The D8 dexer API is intentionally limited and should "do the right thing" given a set of
    * inputs. If the API does not suffice please contact the R8 team.
    *
-   * <p>If the D8Command contains a DiagnosticsHandler that does not throw a CompilationException
-   * on error this method returns null if the run fails.
-   *
    * @param command D8 command.
    * @param executor executor service from which to get threads for multi-threaded processing.
    * @return the compilation result
@@ -98,19 +87,14 @@
   public static D8Output run(D8Command command, ExecutorService executor)
       throws IOException, CompilationException {
     InternalOptions options = command.getInternalOptions();
-    try {
-      CompilationResult result = runForTesting(
-          command.getInputApp(), options, executor);
-      assert result != null;
-      D8Output output = new D8Output(result.androidApp, command.getOutputMode());
-      if (command.getOutputPath() != null) {
-        output.write(command.getOutputPath());
-      }
-      return output;
-    } catch (CompilationException e) {
-      options.diagnosticsHandler.error(e);
-      return null;
+    CompilationResult result = runForTesting(
+        command.getInputApp(), options, executor);
+    assert result != null;
+    D8Output output = new D8Output(result.androidApp, command.getOutputMode());
+    if (command.getOutputPath() != null) {
+      output.write(command.getOutputPath());
     }
+    return output;
   }
 
   private static void run(String[] args) throws IOException, CompilationException {
diff --git a/src/main/java/com/android/tools/r8/Diagnostic.java b/src/main/java/com/android/tools/r8/Diagnostic.java
index 6be2748..3991c4f 100644
--- a/src/main/java/com/android/tools/r8/Diagnostic.java
+++ b/src/main/java/com/android/tools/r8/Diagnostic.java
@@ -7,5 +7,5 @@
  * Interface for all diagnostic message produced by D8 and R8.
  */
 public interface Diagnostic {
-  String toString();
+  String getDiagnosticMessage();
 }
diff --git a/src/main/java/com/android/tools/r8/DiagnosticsHandler.java b/src/main/java/com/android/tools/r8/DiagnosticsHandler.java
index 4a89c6f..3548644 100644
--- a/src/main/java/com/android/tools/r8/DiagnosticsHandler.java
+++ b/src/main/java/com/android/tools/r8/DiagnosticsHandler.java
@@ -6,29 +6,17 @@
 /**
  * A DiagnosticsHandler can be provided to customize handling of diagnostics information.
  *
- * <p>During compilation the error, warning and info methods will be called.
+ * <p>During compilation the warning and info methods will be called.
  */
 public interface DiagnosticsHandler {
 
   /**
-   * Handle error diagnostics.
-   *
-   * <p>By default this throws the exception.
-   *
-   * @param error CompilationException containing error information.
-   * @throws CompilationException
-   */
-  default void error(CompilationException error) throws CompilationException {
-    throw error;
-  }
-
-  /**
    * Handle warning diagnostics.
    *
    * @param warning Diagnostic containing warning information.
    */
   default void warning(Diagnostic warning) {
-    System.err.println(warning.toString());
+    System.err.println(warning.getDiagnosticMessage());
   }
 
   /**
@@ -37,6 +25,6 @@
    * @param info Diagnostic containing the information.
    */
   default void info(Diagnostic info) {
-    System.out.println(info.toString());
+    System.out.println(info.getDiagnosticMessage());
   }
 }
diff --git a/src/main/java/com/android/tools/r8/GenerateMainDexList.java b/src/main/java/com/android/tools/r8/GenerateMainDexList.java
index 6190cbd..296507f 100644
--- a/src/main/java/com/android/tools/r8/GenerateMainDexList.java
+++ b/src/main/java/com/android/tools/r8/GenerateMainDexList.java
@@ -41,7 +41,7 @@
         new ApplicationReader(app, options, timing).read(executor).toDirect();
     AppInfoWithSubtyping appInfo = new AppInfoWithSubtyping(application);
     RootSet mainDexRootSet =
-        new RootSetBuilder(application, appInfo, options.mainDexKeepRules).run(executor);
+        new RootSetBuilder(application, appInfo, options.mainDexKeepRules, options).run(executor);
     Set<DexType> mainDexBaseClasses = new Enqueuer(appInfo).traceMainDex(mainDexRootSet, timing);
     Set<DexType> mainDexClasses = new MainDexListBuilder(mainDexBaseClasses, application).run();
 
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 899a194..5b28e78 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -216,8 +216,10 @@
                 "Shrinking can't be performed because some library classes are missing.");
           }
         }
-        rootSet = new RootSetBuilder(application, appInfo, options.proguardConfiguration.getRules())
-            .run(executorService);
+        rootSet =
+            new RootSetBuilder(
+                    application, appInfo, options.proguardConfiguration.getRules(), options)
+                .run(executorService);
         Enqueuer enqueuer = new Enqueuer(appInfo);
         enqueuer.addExtension(new ProtoLiteExtension(appInfo));
         appInfo = enqueuer.traceApplication(rootSet, timing);
@@ -282,7 +284,8 @@
         Enqueuer enqueuer = new Enqueuer(appInfo);
         // Lets find classes which may have code executed before secondary dex files installation.
         RootSet mainDexRootSet =
-            new RootSetBuilder(application, appInfo, options.mainDexKeepRules).run(executorService);
+            new RootSetBuilder(application, appInfo, options.mainDexKeepRules, options)
+                .run(executorService);
         Set<DexType> mainDexBaseClasses = enqueuer.traceMainDex(mainDexRootSet, timing);
 
         // Calculate the automatic main dex list according to legacy multidex constraints.
@@ -316,7 +319,7 @@
       // Only perform discard-checking if tree-shaking is turned on.
       if (options.useTreeShaking && !rootSet.checkDiscarded.isEmpty()
           && options.useDiscardedChecker) {
-        new DiscardedChecker(rootSet, application).run();
+        new DiscardedChecker(rootSet, application, options).run();
       }
 
       timing.begin("Minification");
@@ -395,9 +398,6 @@
    * <p>The R8 API is intentionally limited and should "do the right thing" given a command. If this
    * API does not suffice please contact the R8 team.
    *
-   * <p>If the R8Command contains a DiagnosticsHandler that does not throw a CompilationException
-   * on error this method returns null if the run fails.
-   *
    * @param command R8 command.
    * @return the compilation result.
    */
@@ -478,9 +478,6 @@
    * <p>The R8 API is intentionally limited and should "do the right thing" given a command. If this
    * API does not suffice please contact the R8 team.
    *
-   * <p>If the R8Command contains a DiagnosticsHandler that does not throw a CompilationException
-   * on error this method returns null if the run fails.
-   *
    * @param command R8 command.
    * @param executor executor service from which to get threads for multi-threaded processing.
    * @return the compilation result.
@@ -488,15 +485,10 @@
   public static AndroidApp run(R8Command command, ExecutorService executor)
       throws IOException, CompilationException {
     InternalOptions options = command.getInternalOptions();
-    try {
-      AndroidApp outputApp =
-          runForTesting(command.getInputApp(), options, executor).androidApp;
-      writeOutputs(command, options, outputApp);
-      return outputApp;
-    } catch (CompilationException e) {
-      options.diagnosticsHandler.error(e);
-      return null;
-    }
+    AndroidApp outputApp =
+        runForTesting(command.getInputApp(), options, executor).androidApp;
+    writeOutputs(command, options, outputApp);
+    return outputApp;
   }
 
   private static void run(String[] args)
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 4405ef4..cfc1495 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
@@ -38,6 +38,7 @@
 import com.android.tools.r8.utils.CfgPrinter;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.StringDiagnostic;
 import com.android.tools.r8.utils.ThreadUtils;
 import com.android.tools.r8.utils.Timing;
 import com.google.common.collect.ArrayListMultimap;
@@ -494,7 +495,8 @@
       BiConsumer<IRCode, DexEncodedMethod> outlineHandler)
       throws ApiLevelException {
     if (options.verbose) {
-      System.out.println("Processing: " + method.toSourceString());
+      options.diagnosticsHandler.info(
+          new StringDiagnostic("Processing: " + method.toSourceString()));
     }
     if (Log.ENABLED) {
       Log.debug(getClass(), "Original code for %s:\n%s",
diff --git a/src/main/java/com/android/tools/r8/shaking/DiscardedChecker.java b/src/main/java/com/android/tools/r8/shaking/DiscardedChecker.java
index e675525..8a5c183 100644
--- a/src/main/java/com/android/tools/r8/shaking/DiscardedChecker.java
+++ b/src/main/java/com/android/tools/r8/shaking/DiscardedChecker.java
@@ -8,6 +8,8 @@
 import com.android.tools.r8.graph.DexItem;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.shaking.RootSetBuilder.RootSet;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.StringDiagnostic;
 import java.util.Set;
 
 public class DiscardedChecker {
@@ -15,10 +17,12 @@
   private final Set<DexItem> checkDiscarded;
   private final DexApplication application;
   private boolean fail = false;
+  private InternalOptions options;
 
-  public DiscardedChecker(RootSet rootSet, DexApplication application) {
+  public DiscardedChecker(RootSet rootSet, DexApplication application, InternalOptions options) {
     this.checkDiscarded = rootSet.checkDiscarded;
     this.application = application;
+    this.options = options;
   }
 
   public void run() {
@@ -34,7 +38,8 @@
 
   private void checkItem(DexItem item) {
     if (checkDiscarded.contains(item)) {
-      System.err.println("Item " + item.toSourceString() + " was not discarded.");
+      options.diagnosticsHandler.info(
+          new StringDiagnostic("Item " + item.toSourceString() + " was not discarded."));
       fail = true;
     }
   }
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
index d4ff512..6ab4a0aa 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
@@ -19,7 +19,9 @@
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.logging.Log;
+import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.MethodSignatureEquivalence;
+import com.android.tools.r8.utils.StringDiagnostic;
 import com.android.tools.r8.utils.ThreadUtils;
 import com.google.common.base.Equivalence.Wrapper;
 import com.google.common.collect.Sets;
@@ -56,12 +58,14 @@
       new IdentityHashMap<>();
   private final Map<DexItem, ProguardMemberRule> noSideEffects = new IdentityHashMap<>();
   private final Map<DexItem, ProguardMemberRule> assumedValues = new IdentityHashMap<>();
+  private final InternalOptions options;
 
   public RootSetBuilder(DexApplication application, AppInfo appInfo,
-      List<ProguardConfigurationRule> rules) {
+      List<ProguardConfigurationRule> rules, InternalOptions options) {
     this.application = application.asDirect();
     this.appInfo = appInfo;
     this.rules = rules;
+    this.options = options;
   }
 
   private boolean anySuperTypeMatches(DexType type, ProguardTypeMatcher name,
@@ -141,13 +145,15 @@
       // Warn if users got it wrong, but only warn once.
       if (extendsExpected && !rule.getInheritanceIsExtends()) {
         if (rulesThatUseExtendsOrImplementsWrong.add(rule)) {
-          System.err.println(
-              "The rule `" + rule + "` uses implements but actually matches extends.");
+          options.diagnosticsHandler.warning(
+              new StringDiagnostic(
+                  "The rule `" + rule + "` uses implements but actually matches extends."));
         }
       } else if (implementsExpected && rule.getInheritanceIsExtends()) {
         if (rulesThatUseExtendsOrImplementsWrong.add(rule)) {
-          System.err.println(
-              "The rule `" + rule + "` uses extends but actually matches implements.");
+          options.diagnosticsHandler.warning(
+              new StringDiagnostic(
+                  "The rule `" + rule + "` uses extends but actually matches implements."));
         }
       }
     }
diff --git a/src/main/java/com/android/tools/r8/shaking/TreePruner.java b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
index f3b712f..947abe3 100644
--- a/src/main/java/com/android/tools/r8/shaking/TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
@@ -14,6 +14,7 @@
 import com.android.tools.r8.logging.Log;
 import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
 import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.StringDiagnostic;
 import com.google.common.collect.Sets;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -41,10 +42,12 @@
   public DexApplication run() {
     application.timing.begin("Pruning application...");
     if (options.debugKeepRules && !options.skipMinification) {
-      System.out.println(
-          "NOTE: Debugging keep rules on a minified build might yield broken builds, as\n"
-              + "      minification also depends on the used keep rules. We recommend using\n"
-              + "      --skip-minification.");
+
+      options.diagnosticsHandler.info(
+          new StringDiagnostic(
+              "Debugging keep rules on a minified build might yield broken builds, as "
+                  + "minification also depends on the used keep rules. We recommend using "
+                  + "--skip-minification."));
     }
     DexApplication result;
     try {
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java b/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
index 47bd02e..9f40791 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
@@ -10,7 +10,8 @@
  */
 public enum AndroidApiLevel {
   LATEST(-1),
-  P(27),
+  P(28),
+  O_MR1(27),
   O(26),
   N_MR1(25),
   N(24),
@@ -133,6 +134,8 @@
       case 26:
         return O;
       case 27:
+        return O_MR1;
+      case 28:
         return P;
       default:
         return LATEST;
diff --git a/src/main/java/com/android/tools/r8/utils/DexVersion.java b/src/main/java/com/android/tools/r8/utils/DexVersion.java
index c9fa818..7406227 100644
--- a/src/main/java/com/android/tools/r8/utils/DexVersion.java
+++ b/src/main/java/com/android/tools/r8/utils/DexVersion.java
@@ -51,6 +51,7 @@
       case P:
         return DexVersion.V39;
       case LATEST:
+      case O_MR1:
       case O:
         return DexVersion.V38;
       case N_MR1:
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 a72d356..5c4909a 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -136,27 +136,31 @@
     boolean printed = false;
     boolean printOutdatedToolchain = false;
     if (warningInvalidParameterAnnotations != null) {
-      System.out.println("Warning: " + warningInvalidParameterAnnotations);
+      diagnosticsHandler.warning(
+          new StringDiagnostic(warningInvalidParameterAnnotations));
       printed = true;
     }
     if (warningInvalidDebugInfoCount > 0) {
-      System.out.println("Warning: stripped invalid locals information from "
+      diagnosticsHandler.warning(
+          new StringDiagnostic("Stripped invalid locals information from "
           + warningInvalidDebugInfoCount
-          + (warningInvalidDebugInfoCount == 1 ? " method." : " methods."));
+          + (warningInvalidDebugInfoCount == 1 ? " method." : " methods.")));
       printed = true;
       printOutdatedToolchain = true;
     }
     if (warningMissingEnclosingMember) {
-      System.out.println(
-          "Warning: InnerClass annotations are missing corresponding EnclosingMember annotations."
-              + " Such InnerClass annotations are ignored.");
+      diagnosticsHandler.warning(
+          new StringDiagnostic(
+              "InnerClass annotations are missing corresponding EnclosingMember annotations."
+                  + " Such InnerClass annotations are ignored."));
       printed = true;
       printOutdatedToolchain = true;
     }
     if (printOutdatedToolchain) {
-      System.out.println(
-          "Some warnings are typically a sign of using an outdated Java toolchain."
-              + " To fix, recompile the source with an updated toolchain.");
+      diagnosticsHandler.warning(
+          new StringDiagnostic(
+              "Some warnings are typically a sign of using an outdated Java toolchain."
+                  + " To fix, recompile the source with an updated toolchain."));
     }
     return printed;
   }
diff --git a/src/main/java/com/android/tools/r8/utils/StringDiagnostic.java b/src/main/java/com/android/tools/r8/utils/StringDiagnostic.java
index 0606be2..9c690ff 100644
--- a/src/main/java/com/android/tools/r8/utils/StringDiagnostic.java
+++ b/src/main/java/com/android/tools/r8/utils/StringDiagnostic.java
@@ -13,7 +13,7 @@
   }
 
   @Override
-  public String toString() {
+  public String getDiagnosticMessage() {
     return message;
   }
 }
diff --git a/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java b/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
index cf0b71e..1a8f68a 100644
--- a/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
@@ -7,6 +7,7 @@
 
 import com.android.tools.r8.ToolHelper.DexVm;
 import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.dex.Marker.Tool;
 import com.android.tools.r8.shaking.ProguardRuleParserException;
 import com.android.tools.r8.utils.StringUtils;
 import com.google.common.collect.ImmutableList;
@@ -151,28 +152,29 @@
     String generated = outputPath + "/classes.dex";
     String output = "";
 
-    if (dalvikVerificationError.containsKey(ToolHelper.getDexVm())
-        && dalvikVerificationError.get(ToolHelper.getDexVm()).contains(directoryName)) {
+    DexVm.Version dexVmVersion = ToolHelper.getDexVm().getVersion();
+    if (dalvikVerificationError.containsKey(dexVmVersion)
+        && dalvikVerificationError.get(dexVmVersion).contains(directoryName)) {
       try {
         ToolHelper.runArtNoVerificationErrors(generated, mainClass);
       } catch (AssertionError e) {
         assert e.toString().contains("VerifyError");
       }
       return;
-    } else if (originalFailingOnArtVersions.containsKey(ToolHelper.getDexVm())
-        && originalFailingOnArtVersions.get(ToolHelper.getDexVm()).contains(directoryName)) {
+    } else if (originalFailingOnArtVersions.containsKey(dexVmVersion)
+        && originalFailingOnArtVersions.get(dexVmVersion).contains(directoryName)) {
       // If the original smali code fails on the target VM, only run the code produced by R8.
       output = ToolHelper.runArtNoVerificationErrors(generated, mainClass);
-    } else if (customProcessedOutputExpectation.containsKey(ToolHelper.getDexVm())
-        && customProcessedOutputExpectation.get(ToolHelper.getDexVm()).containsKey(directoryName)) {
+    } else if (customProcessedOutputExpectation.containsKey(dexVmVersion)
+        && customProcessedOutputExpectation.get(dexVmVersion).containsKey(directoryName)) {
       // If the original and the processed code have different expected output, only run
       // the code produced by R8.
       expectedOutput =
-          customProcessedOutputExpectation.get(ToolHelper.getDexVm()).get(directoryName);
+          customProcessedOutputExpectation.get(dexVmVersion).get(directoryName);
       output = ToolHelper.runArtNoVerificationErrors(generated, mainClass);
     } else {
-      if (failingOnArtVersions.containsKey(ToolHelper.getDexVm())
-          && failingOnArtVersions.get(ToolHelper.getDexVm()).contains(directoryName)) {
+      if (failingOnArtVersions.containsKey(dexVmVersion)
+          && failingOnArtVersions.get(dexVmVersion).contains(directoryName)) {
         thrown.expect(Throwable.class);
       }
       output =
diff --git a/src/test/java/com/android/tools/r8/debug/DebugTestBase.java b/src/test/java/com/android/tools/r8/debug/DebugTestBase.java
index b260663..a9b945d 100644
--- a/src/test/java/com/android/tools/r8/debug/DebugTestBase.java
+++ b/src/test/java/com/android/tools/r8/debug/DebugTestBase.java
@@ -10,9 +10,7 @@
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.ArtCommandBuilder;
 import com.android.tools.r8.ToolHelper.DexVm;
-import com.android.tools.r8.ToolHelper.DexVm.Kind;
 import com.android.tools.r8.ToolHelper.DexVm.Version;
-import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.shaking.ProguardConfiguration;
 import com.android.tools.r8.shaking.ProguardRuleParserException;
 import com.android.tools.r8.utils.AndroidApiLevel;
@@ -39,6 +37,7 @@
 import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.stream.Collectors;
+import org.apache.harmony.jpda.tests.framework.TestErrorException;
 import org.apache.harmony.jpda.tests.framework.jdwp.CommandPacket;
 import org.apache.harmony.jpda.tests.framework.jdwp.Event;
 import org.apache.harmony.jpda.tests.framework.jdwp.EventBuilder;
@@ -514,7 +513,24 @@
             if (DEBUG_TESTS) {
               logWriter.println("Process command " + command.toString());
             }
-            command.perform(this);
+            try {
+              command.perform(this);
+            } catch (TestErrorException e) {
+              boolean ignoreException = false;
+              if (ToolHelper.getDexVm().getVersion() == Version.V4_4_4) {
+                // Dalvik has flaky synchronization issue on shutdown. The workaround is to ignore
+                // the exception if and only if we know that it's the final resume command.
+                if (debuggeeState == null && commandsQueue.isEmpty()) {
+                  // We should receive the VMDeath event and transition to the Exit state here.
+                  processEvents();
+                  assert state == State.Exit;
+                  ignoreException = true;
+                }
+              }
+              if (!ignoreException) {
+                throw e;
+              }
+            }
             break;
           }
           case WaitForEvent:
diff --git a/src/test/java/com/android/tools/r8/jdwp/RunJdwpTests.java b/src/test/java/com/android/tools/r8/jdwp/RunJdwpTests.java
index 8e12fc6..d7c40d4 100644
--- a/src/test/java/com/android/tools/r8/jdwp/RunJdwpTests.java
+++ b/src/test/java/com/android/tools/r8/jdwp/RunJdwpTests.java
@@ -57,6 +57,10 @@
     boolean test(DexVm dexVm, Tool tool);
   }
 
+  static boolean isAndroidLOrAbove(DexVm dexVm, Tool tool) {
+    return dexVm.getVersion().isNewerThan(Version.V4_4_4);
+  }
+
   static boolean isAndroidMOrAbove(DexVm dexVm, Tool tool) {
     return dexVm.getVersion().isNewerThan(Version.V5_1_1);
   }
@@ -69,6 +73,10 @@
     return dexVm.getVersion().isNewerThan(Version.V7_0_0);
   }
 
+  static boolean isNotAndroidL(DexVm dexVm, Tool tool) {
+    return dexVm.getVersion() != Version.V5_1_1;
+  }
+
   static boolean isLatestRuntime(DexVm dexVm, Tool tool) {
     return dexVm == DexVm.ART_DEFAULT;
   }
@@ -85,46 +93,123 @@
 
   static final Map<String, TestPredicate> FAILING_TESTS =
       ImmutableMap.<String, TestPredicate>builder()
+          .put("ArrayReference.GetValuesTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("ArrayReference.LengthTest", RunJdwpTests::isAndroidLOrAbove)
           .put("ArrayReference.SetValues003Test", RunJdwpTests::isAndroidNOrAbove)
+          .put("ClassObjectReference.ReflectedTypeTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("ClassObjectReference.ReflectedType002Test", RunJdwpTests::isAndroidLOrAbove)
+          .put("ClassType.InvokeMethodTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("ClassType.InvokeMethod002Test", RunJdwpTests::isAndroidLOrAbove)
           .put("ClassType.InvokeMethodAfterMultipleThreadSuspensionTest",
               RunJdwpTests::isAndroidNOrAbove)
           .put("ClassType.InvokeMethodWithSuspensionTest", RunJdwpTests::isAndroidMOrAbove)
+          .put("ClassType.NewInstanceTest", RunJdwpTests::isAndroidLOrAbove)
           .put("ClassType.NewInstanceAfterMultipleThreadSuspensionTest",
               RunJdwpTests::isAndroidNOrAbove)
           .put("ClassType.NewInstanceStringTest", RunJdwpTests::isAndroidOOrAbove)
           .put("ClassType.NewInstanceTagTest", RunJdwpTests::isAndroidNOrAbove)
           .put("ClassType.NewInstanceWithSuspensionTest", RunJdwpTests::isAndroidMOrAbove)
+          .put("ClassType.SetValues002Test", RunJdwpTests::isAndroidLOrAbove)
+          .put("ClassType.SuperClassTest", RunJdwpTests::isAndroidLOrAbove)
           .put("Events.BreakpointTest", RunJdwpTests::isAndroidMOrAbove)
           .put("Events.Breakpoint002Test", RunJdwpTests::isAndroidMOrAbove)
           .put("Events.BreakpointOnCatchTest", RunJdwpTests::isAndroidMOrAbove)
+          .put("Events.ClassPrepareTest", RunJdwpTests::isAndroidLOrAbove)
           .put("Events.ClassPrepare002Test", RunJdwpTests::isAndroidOOrAbove)
+          .put("Events.CombinedEvents002Test", RunJdwpTests::isAndroidLOrAbove)
           .put("Events.CombinedExceptionEventsTest", RunJdwpTests::isAndroidMOrAbove)
           .put("Events.ExceptionCaughtTest", RunJdwpTests::isAndroidMOrAbove)
-          .put("Events.ExceptionUncaughtTest", RunJdwpTests::isAndroidMOrAbove)
+          .put("Events.ExceptionUncaughtTest", RunJdwpTests::isNotAndroidL)
+          .put("Events.ExceptionWithLocationTest", RunJdwpTests::isAndroidLOrAbove)
           .put("Events.EventWithExceptionTest", RunJdwpTests::isAndroidNOrAbove)
           .put("Events.FieldAccessTest", RunJdwpTests::isAndroidMOrAbove)
           .put("Events.FieldModificationTest", RunJdwpTests::isAndroidMOrAbove)
+          .put("Events.FieldModification002Test", RunJdwpTests::isAndroidLOrAbove)
+          .put("Events.FieldWithLocationTest", RunJdwpTests::isAndroidLOrAbove)
           .put("Events.MethodEntryTest", RunJdwpTests::isAndroidMOrAbove)
           .put("Events.MethodExitTest", RunJdwpTests::isAndroidMOrAbove)
           .put("Events.MethodExitWithReturnValueTest", RunJdwpTests::isAndroidMOrAbove)
-          .put("Events.SingleStepTest", RunJdwpTests::isAndroidMOrAbove)
+          .put("Events.SingleStepTest", RunJdwpTests::isNotAndroidL)
           .put("Events.SingleStepWithPendingExceptionTest", RunJdwpTests::isAndroidNOrAbove)
+          .put("EventModifiers.CountModifierTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("EventModifiers.ThreadOnlyModifierTest", RunJdwpTests::isAndroidLOrAbove)
           .put("InterfaceType.InvokeMethodTest", RunJdwpTests::isAndroidNOrAbove)
+          .put("Method.BytecodesTest", RunJdwpTests::isAndroidLOrAbove)
           .put("Method.IsObsoleteTest", RunJdwpTests::isAndroidNOrAbove)
           .put("Method.VariableTableWithGenericTest", RunJdwpTests::isAndroidOOrAbove)
+          .put("MultiSession.AttachConnectorTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("MultiSession.BreakpointTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("MultiSession.ClassObjectIDTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("MultiSession.ClassPrepareTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("MultiSession.EnableCollectionTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("MultiSession.ExceptionTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("MultiSession.FieldAccessTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("MultiSession.FieldModificationTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("MultiSession.MethodEntryExitTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("MultiSession.RefTypeIDTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("MultiSession.ResumeTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("MultiSession.SingleStepTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("MultiSession.VMDeathTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("ObjectReference.DisableCollectionTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("ObjectReference.EnableCollectionTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("ObjectReference.GetValues002Test", RunJdwpTests::isAndroidLOrAbove)
           .put("ObjectReference.InvokeMethodDefaultTest", RunJdwpTests::isAndroidNOrAbove)
           .put("ObjectReference.InvokeMethodDefault002Test", RunJdwpTests::isAndroidNOrAbove)
           .put("ObjectReference.InvokeMethodAfterMultipleThreadSuspensionTest",
               RunJdwpTests::isAndroidNOrAbove)
           .put("ObjectReference.InvokeMethodWithSuspensionTest", RunJdwpTests::isAndroidMOrAbove)
-          .put("ReferenceType.GetValues006Test", RunJdwpTests::isAndroidOOrAbove)
+          .put("ObjectReference.IsCollectedTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("ObjectReference.MonitorInfoTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("ObjectReference.SetValuesTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("ObjectReference.SetValues002Test", RunJdwpTests::isAndroidLOrAbove)
+          .put("ObjectReference.SetValues003Test", RunJdwpTests::isAndroidLOrAbove)
           .put("ReferenceType.ClassLoaderTest", RunJdwpTests::isAndroidNOrAbove)
+          .put("ReferenceType.FieldsTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("ReferenceType.GetValues002Test", RunJdwpTests::isAndroidLOrAbove)
+          .put("ReferenceType.GetValues004Test", RunJdwpTests::isAndroidLOrAbove)
+          .put("ReferenceType.GetValues006Test", RunJdwpTests::isAndroidOOrAbove)
+          .put("ReferenceType.MethodsTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("ReferenceType.ModifiersTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("ReferenceType.Signature002Test", RunJdwpTests::isAndroidLOrAbove)
+          .put("ReferenceType.SourceDebugExtensionTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("ReferenceType.SyntheticFieldsTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("ReferenceType.SyntheticMethodsTest", RunJdwpTests::isAndroidLOrAbove)
           .put("StackFrame.GetValuesTest", RunJdwpTests::isAndroidMOrAbove)
+          .put("StackFrame.ProxyThisObjectTest", RunJdwpTests::isAndroidLOrAbove)
           .put("StackFrame.SetValuesTest", RunJdwpTests::isAndroidMOrAbove)
           .put("StackFrame.SetValues002Test", RunJdwpTests::isAndroidMOrAbove)
+          .put("StackFrame.ThisObjectTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("StringReference.ValueTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("ThreadGroupReference.ChildrenTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("ThreadGroupReference.NameTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("ThreadGroupReference.ParentTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("ThreadReference.CurrentContendedMonitorTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("ThreadReference.FrameCountTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("ThreadReference.FramesTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("ThreadReference.InterruptTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("ThreadReference.OwnedMonitorsStackDepthInfoTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("ThreadReference.OwnedMonitorsTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("ThreadReference.ResumeTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("ThreadReference.Status002Test", RunJdwpTests::isAndroidLOrAbove)
+          .put("ThreadReference.Status003Test", RunJdwpTests::isAndroidLOrAbove)
+          .put("ThreadReference.Status004Test", RunJdwpTests::isAndroidLOrAbove)
+          .put("ThreadReference.Status005Test", RunJdwpTests::isAndroidLOrAbove)
+          .put("ThreadReference.Status006Test", RunJdwpTests::isAndroidLOrAbove)
+          .put("ThreadReference.StatusTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("ThreadReference.SuspendCountTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("ThreadReference.SuspendTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("ThreadReference.ThreadGroup002Test", RunJdwpTests::isAndroidLOrAbove)
+          .put("ThreadReference.ThreadGroupTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("VirtualMachine.AllClassesTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("VirtualMachine.AllThreadsTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("VirtualMachine.CapabilitiesTest", RunJdwpTests::isAndroidLOrAbove)
           .put("VirtualMachine.CapabilitiesNewTest", RunJdwpTests::isLatestRuntime)
           .put("VirtualMachine.ClassPathsTest", RunJdwpTests::isAndroidMOrAbove)
+          .put("VirtualMachine.DisposeTest", RunJdwpTests::isAndroidLOrAbove)
           .put("VirtualMachine.DisposeDuringInvokeTest", RunJdwpTests::isAndroidMOrAbove)
+          .put("VirtualMachine.DisposeObjectsTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("VirtualMachine.ExitTest", RunJdwpTests::isAndroidLOrAbove)
+          .put("VirtualMachine.ResumeTest", RunJdwpTests::isAndroidLOrAbove)
           .build();
 
   // The smoke tests are the set of tests that fail if there is no debugging info in the dex files.
diff --git a/src/test/java/com/android/tools/r8/naming/NamingTestBase.java b/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
index 8818bbb..f049102 100644
--- a/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
+++ b/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
@@ -70,7 +70,7 @@
       ClassAndMemberPublicizer.run(program);
     }
 
-    RootSet rootSet = new RootSetBuilder(program, appInfo, configuration.getRules())
+    RootSet rootSet = new RootSetBuilder(program, appInfo, configuration.getRules(), options)
         .run(ThreadUtils.getExecutorService(options));
     Enqueuer enqueuer = new Enqueuer(appInfo);
     appInfo = enqueuer.traceApplication(rootSet, timing);
diff --git a/third_party/jdwp-tests.tar.gz.sha1 b/third_party/jdwp-tests.tar.gz.sha1
index dd998eb..d3eeb60 100644
--- a/third_party/jdwp-tests.tar.gz.sha1
+++ b/third_party/jdwp-tests.tar.gz.sha1
@@ -1 +1 @@
-c1f8da93dfe1b811904ee19a670fb5ed1a35766f
\ No newline at end of file
+db49b6093abaa165e422734a755cdcecf36c03db
\ No newline at end of file
diff --git a/tools/run-jdwp-tests.py b/tools/run-jdwp-tests.py
index ff61dcc..15b69c8 100755
--- a/tools/run-jdwp-tests.py
+++ b/tools/run-jdwp-tests.py
@@ -18,12 +18,7 @@
   '7.0.0',
   '6.0.1',
   '5.1.1',
-]
-
-BOOT_LIBS = [
-  'core-libart-hostdex.jar',
-  'core-oj-hostdex.jar',
-  'apache-xml-hostdex.jar',
+  '4.4.4'
 ]
 
 JUNIT_HOSTDEX = os.path.join(
@@ -53,7 +48,10 @@
 ]
 
 def get_art_dir(version):
-  art_dir = version == 'default' and 'art' or 'art-%s' % version
+  if version == '4.4.4':
+    art_dir = 'dalvik'
+  else:
+    art_dir = version == 'default' and 'art' or 'art-%s' % version
   return os.path.join(utils.REPO_ROOT, 'tools', 'linux', art_dir)
 
 def get_lib_dir(version):
@@ -63,7 +61,7 @@
   return os.path.join(get_art_dir(version), 'framework')
 
 def get_vm(version):
-  return os.path.join(get_art_dir(version), 'bin', 'dalvikvm64')
+  return os.path.join(get_art_dir(version), 'bin', 'dalvikvm')
 
 def setup_environment(version):
   art_dir = get_art_dir(version)
@@ -71,6 +69,11 @@
   android_data = os.path.join(utils.REPO_ROOT, 'build', 'tmp', version)
   if not os.path.isdir(android_data):
     os.mkdir(android_data)
+  if version == '4.4.4':
+    # Dalvik expects that the dalvik-cache dir already exists.
+    dalvik_cache_dir = os.path.join(android_data, 'dalvik-cache')
+    if not os.path.isdir(dalvik_cache_dir):
+      os.mkdir(dalvik_cache_dir)
   os.environ['ANDROID_DATA'] = android_data
   os.environ['ANDROID_ROOT'] = art_dir
   os.environ['LD_LIBRARY_PATH'] = lib_dir
@@ -78,12 +81,25 @@
   os.environ['LD_USE_LOAD_BIAS'] = '1'
 
 def get_boot_libs(version):
-  return [os.path.join(get_fw_dir(version), lib) for lib in BOOT_LIBS]
+  boot_libs = []
+  if version == '4.4.4':
+    # Dalvik
+    boot_libs.extend(['core-hostdex.jar'])
+  else:
+    # ART
+    boot_libs.extend(['core-libart-hostdex.jar'])
+    if version != '5.1.1' and version != '6.0.1':
+      boot_libs.extend(['core-oj-hostdex.jar'])
+  boot_libs.extend(['apache-xml-hostdex.jar'])
+  return [os.path.join(get_fw_dir(version), lib) for lib in boot_libs]
 
 def get_common_flags(version):
-  flags = ['-Ximage:%s' % IMAGE]
-  if version != '5.1.1':
-    flags.extend(['-Xcompiler-option', '--debuggable'])
+  flags = []
+  flags.extend(['-Xbootclasspath:%s' % ':'.join(get_boot_libs(version))])
+  if version != '4.4.4':
+    flags.extend(['-Ximage:%s' % IMAGE])
+    if version != '5.1.1':
+      flags.extend(['-Xcompiler-option', '--debuggable'])
   return flags
 
 def get_debuggee_flags(version):
@@ -97,7 +113,6 @@
   lib_dir = get_lib_dir(version)
   fw_dir = get_fw_dir(version)
   cmd = [get_vm(version)]
-  cmd.append('-Xbootclasspath:%s' % ':'.join(get_boot_libs(version)))
   cmd.extend(get_debuggee_flags(version))
   cmd.extend(args)
   setup_environment(version)
@@ -108,10 +123,9 @@
   art_dir = get_art_dir(version)
   lib_dir = get_lib_dir(version)
   fw_dir = get_fw_dir(version)
-  dalvikvm = os.path.join(art_dir, 'bin', 'dalvikvm64')
+  dalvikvm = os.path.join(art_dir, 'bin', 'dalvikvm')
   cmd = [dalvikvm]
   cmd.extend(['-classpath', '%s:%s' % (classpath, JUNIT_HOSTDEX)])
-  cmd.append('-Xbootclasspath:%s' % ':'.join(get_boot_libs(version)))
   cmd.extend(get_debugger_flags(version))
   cmd.append('-Djpda.settings.debuggeeJavaPath=%s %s' %\
              (dalvikvm, ' '.join(get_debuggee_flags(version))))