Version 0.1.4

This merge fixes testing issues. There are no functional changes to D8.

Merge "test.py: add aosp_jar test"
CL: https://r8-review.googlesource.com/c/r8/+/4640

Merge "Update jctf test specs after an ART update"
CL: https://r8-review.googlesource.com/c/r8/+/4560

Change-Id: I729db6af65c01ef71507cd3610678e08ccf5ac85
diff --git a/build.gradle b/build.gradle
index fa1e717..63513ce 100644
--- a/build.gradle
+++ b/build.gradle
@@ -918,13 +918,21 @@
     }
 }
 
+task AospJarTest(type: Exec) {
+    dependsOn CompatDx, downloadDeps
+    def script = "tools/test_aosp_jar.py"
+    inputs.file script
+    commandLine "python", script, "--no-build"
+    workingDir = projectDir
+}
+
 test {
     dependsOn supportLibList
     testLogging.exceptionFormat = 'full'
     if (project.hasProperty('print_test_stdout')) {
         testLogging.showStandardStreams = true
     }
-    if (project.hasProperty('dex_vm')) {
+    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') {
@@ -934,6 +942,7 @@
             exclude "com/android/tools/r8/art/jack/**"
         }
     }
+
     if (project.hasProperty('one_line_per_test')) {
         beforeTest { desc ->
             println "Start executing test ${desc.name} [${desc.className}]"
@@ -976,6 +985,9 @@
     if (project.hasProperty('test_dir')) {
         systemProperty 'test_dir', project.property('test_dir')
     }
+    if (project.hasProperty('aosp_jar')) {
+        dependsOn AospJarTest
+    }
 
     if (OperatingSystem.current().isLinux()
             || OperatingSystem.current().isMacOsX()
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index d452bc9..a2b0fd9 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -55,7 +55,7 @@
  */
 public final class D8 {
 
-  private static final String VERSION = "v0.1.3";
+  private static final String VERSION = "v0.1.4";
   private static final int STATUS_ERROR = 1;
 
   private D8() {}
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index c54936a..c05750a 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -71,7 +71,7 @@
 
 public class R8 {
 
-  private static final String VERSION = "v0.1.3";
+  private static final String VERSION = "v0.1.4";
   private final Timing timing = new Timing("R8");
   private final InternalOptions options;
 
diff --git a/src/test/java/com/android/tools/r8/JctfTestSpecifications.java b/src/test/java/com/android/tools/r8/JctfTestSpecifications.java
index beba10e..8b6926e 100644
--- a/src/test/java/com/android/tools/r8/JctfTestSpecifications.java
+++ b/src/test/java/com/android/tools/r8/JctfTestSpecifications.java
@@ -2675,7 +2675,8 @@
           // 1) t02
           // java.lang.AssertionError: Failed to load serialization resource file: serialization/com/google/jctf/test/lib/java/lang/String/CASE_INSENSITIVE_ORDER/serialization/String_serialization_A01.golden.0.ser
 
-          .put("lang.String.getBytesLjava_lang_String.String_getBytes_A14", any())
+          .put("lang.String.getBytesLjava_lang_String.String_getBytes_A14",
+              match(runtimes(DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
           // 1) t07
           // arrays first differed at element [0]; expected:<-2> but was:<-1>
           // Caused by: java.lang.AssertionError: expected:<-2> but was:<-1>
@@ -2735,7 +2736,8 @@
           // 1) t09
           // org.junit.ComparisonFailure: Incorrect double string returned expected:<0.001[0]> but was:<0.001[]>
 
-          .put("lang.String.getBytesLjava_nio_charset_Charset.String_getBytes_A14", any())
+          .put("lang.String.getBytesLjava_nio_charset_Charset.String_getBytes_A14",
+              match(runtimes(DexVm.ART_7_0_0, DexVm.ART_6_0_1, DexVm.ART_5_1_1)))
           // 1) t07
           // arrays first differed at element [0]; expected:<-2> but was:<-1>
           // Caused by: java.lang.AssertionError: expected:<-2> but was:<-1>
diff --git a/tools/compatdx.py b/tools/compatdx.py
index 51e3104..75910b1 100755
--- a/tools/compatdx.py
+++ b/tools/compatdx.py
@@ -9,8 +9,6 @@
 import sys
 import utils
 
-COMPATDX_JAR = os.path.join(utils.REPO_ROOT, 'build', 'libs', 'compatdx.jar')
-
 def run(args, build = True, debug = True, profile = False, track_memory_file=None):
   if build:
     gradle.RunGradle(['CompatDX'])
@@ -22,7 +20,7 @@
     cmd.append('-ea')
   if profile:
     cmd.append('-agentlib:hprof=cpu=samples,interval=1,depth=8')
-  cmd.extend(['-jar', COMPATDX_JAR])
+  cmd.extend(['-jar', utils.COMPATDX_JAR])
   cmd.extend(args)
   subprocess.check_call(cmd)
 
diff --git a/tools/run_proguard_dx_on_app.py b/tools/run_proguard_dx_on_app.py
index 92a75ba..a953229 100755
--- a/tools/run_proguard_dx_on_app.py
+++ b/tools/run_proguard_dx_on_app.py
@@ -26,7 +26,6 @@
 
 APPS = ['gmscore', 'youtube']
 DX_JAR = join(utils.REPO_ROOT, 'tools', 'linux', 'dx', 'framework', 'dx.jar')
-COMPATDX_JAR = join(utils.REPO_ROOT, 'build', 'libs', 'compatdx.jar')
 
 def parse_arguments(argv):
   parser = argparse.ArgumentParser(
@@ -122,7 +121,7 @@
 
   # run dex on the result
   if options.compatdx:
-    jar = COMPATDX_JAR
+    jar = utils.COMPATDX_JAR
   else:
     jar = DX_JAR
 
diff --git a/tools/test.py b/tools/test.py
index 1da077b..b0255cb 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -56,6 +56,9 @@
   result.add_option('--jctf_compile_only',
       help="Don't run, only compile JCTF tests.",
       default=False, action='store_true')
+  result.add_option('--aosp_jar',
+      help='Run aosp_jar test.',
+      default=False, action='store_true')
   result.add_option('--disable_assertions',
       help='Disable assertions when running tests.',
       default=False, action='store_true')
@@ -104,6 +107,8 @@
     gradle_args.append('-Ponly_jctf')
   if options.jctf_compile_only:
     gradle_args.append('-Pjctf_compile_only')
+  if options.aosp_jar:
+    gradle_args.append('-Paosp_jar')
   if options.disable_assertions:
     gradle_args.append('-Pdisable_assertions')
   if options.with_code_coverage:
diff --git a/tools/test_android_cts.py b/tools/test_android_cts.py
index 4ef8039..3f66302 100755
--- a/tools/test_android_cts.py
+++ b/tools/test_android_cts.py
@@ -40,7 +40,6 @@
 AOSP_HELPER_SH = join(utils.REPO_ROOT, 'scripts', 'aosp_helper.sh')
 
 D8_JAR = join(utils.REPO_ROOT, 'build/libs/d8.jar')
-COMPATDX_JAR = join(utils.REPO_ROOT, 'build/libs/compatdx.jar')
 D8LOGGER_JAR = join(utils.REPO_ROOT, 'build/libs/d8logger.jar')
 
 AOSP_ROOT = join(utils.REPO_ROOT, 'build/aosp')
@@ -175,7 +174,7 @@
       alt_jar_option += D8LOGGER_JAR
       os.environ['D8LOGGER_OUTPUT'] = args.d8log
     else:
-      alt_jar_option += COMPATDX_JAR
+      alt_jar_option += utils.COMPATDX_JAR
 
   gradle.RunGradle(['d8','d8logger', 'compatdx'])
 
diff --git a/tools/test_aosp_jar.py b/tools/test_aosp_jar.py
new file mode 100755
index 0000000..79a584a
--- /dev/null
+++ b/tools/test_aosp_jar.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+# 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.
+
+# Test prebuilt AOSP jar files: compile with D8 and run dex2out to validate
+
+from __future__ import print_function
+from glob import glob
+from itertools import chain
+from os.path import join
+import argparse
+import os
+import subprocess
+import sys
+
+import gradle
+
+import utils
+
+REPLAY_SCRIPT_DIR = join(utils.REPO_ROOT, 'third_party',
+    'android_cts_baseline', 'dx_replay')
+REPLAY_SCRIPT = join(REPLAY_SCRIPT_DIR, 'replay_script.py')
+OUT_DIR = join(REPLAY_SCRIPT_DIR, 'out')
+
+def parse_arguments():
+  parser = argparse.ArgumentParser(
+      description = 'Run D8 (CompatDX) and dex2oat on prebuilt AOSP jars.')
+  parser.add_argument('--no-build', default = False, action = 'store_true')
+  return parser.parse_args()
+
+def Main():
+
+  utils.check_java_version()
+  args = parse_arguments()
+
+  if not args.no_build:
+    gradle.RunGradle(['CompatDx'])
+
+  cmd = [REPLAY_SCRIPT, 'java', '-jar', utils.COMPATDX_JAR]
+  utils.PrintCmd(cmd)
+  subprocess.check_call(cmd)
+
+  # collect dex files below OUT_DIR
+  dex_files = (chain.from_iterable(glob(join(x[0], '*.dex'))
+      for x in os.walk(OUT_DIR)))
+
+  for dex_file in dex_files:
+      utils.verify_with_dex2oat(dex_file)
+
+
+if __name__ == '__main__':
+  sys.exit(Main())
+
diff --git a/tools/utils.py b/tools/utils.py
index dab1dd1..e281ccd 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -18,6 +18,7 @@
 DEX_SEGMENTS_JAR = os.path.join(REPO_ROOT, 'build', 'libs',
     'dexsegments.jar')
 DEX_SEGMENTS_RESULT_PATTERN = re.compile('- ([^:]+): ([0-9]+)')
+COMPATDX_JAR = os.path.join(REPO_ROOT, 'build', 'libs', 'compatdx.jar')
 
 def PrintCmd(s):
   if type(s) is list:
@@ -185,3 +186,34 @@
   if m is None:
     raise Exception("Incorrect java version, expected: '1.8.*-internal',"
         " actual: {}".format(version))
+
+def verify_with_dex2oat(dex_file):
+
+  # dex2oat accepts non-existent dex files, check here instead
+  if not os.path.exists(dex_file):
+    raise Exception('Dex file not found: "{}"'.format(dex_file))
+
+  android_root_dir = os.path.join(TOOLS_DIR, 'linux', 'art', 'product',
+    'angler')
+  boot_art = os.path.join(android_root_dir, 'system', 'framework', 'boot.art')
+  dex2oat = os.path.join(TOOLS_DIR, 'linux', 'art', 'bin', 'dex2oat')
+
+  with TempDir() as temp:
+    oat_file = os.path.join(temp, 'all.oat')
+
+    cmd = [
+        dex2oat,
+        '--android-root=' + android_root_dir,
+        '--runtime-arg', '-Xnorelocate',
+        '--boot-image=' + boot_art,
+        '--dex-file=' + dex_file,
+        '--oat-file=' + oat_file,
+        '--instruction-set=arm64',
+        '--compiler-filter=interpret-only'
+    ]
+
+    PrintCmd(cmd)
+    subprocess.check_call(cmd,
+      env = {"LD_LIBRARY_PATH":
+        os.path.join(TOOLS_DIR, 'linux', 'art', 'lib')}
+    )