Merge "Invoke dex2oat explictly before dalvikvm"
diff --git a/tools/art b/tools/art
index 933ad7a..b9c986c 100644
--- a/tools/art
+++ b/tools/art
@@ -17,8 +17,8 @@
 # Android (e.g. mksh).
 
 # Globals
-ARCHS={arm,arm64,mips,mips64,x86,x86_64}
 ART_BINARY=dalvikvm
+DEX2OAT_BINARY=dex2oat
 DELETE_ANDROID_DATA="no"
 LAUNCH_WRAPPER=
 LIBART=libart.so
@@ -46,29 +46,6 @@
   fi
 }
 
-function replace_compiler_filter_with_interepret_only() {
-  ARGS_WITH_INTERPRET_ONLY=("$@")
-
-  found="false"
-  ((index=0))
-  while ((index <= $#)); do
-    what="${ARGS_WITH_INTERPRET_ONLY[$index]}"
-
-    case "$what" in
-      --compiler-filter=*)
-        ARGS_WITH_INTERPRET_ONLY[$index]="--compiler-filter=interpret-only"
-        found="true"
-        ;;
-    esac
-
-    ((index++))
-    shift
-  done
-  if [ "$found" != "true" ]; then
-    ARGS_WITH_INTERPRET_ONLY=(-Xcompiler-option --compiler-filter=interpret-only "${ARGS_WITH_INTERPRET_ONLY[@]}")
-  fi
-}
-
 function usage() {
   cat 1>&2 <<EOF
 Usage: art [OPTIONS] [--] [ART_OPTIONS] CLASS
@@ -89,6 +66,8 @@
   --verbose                Run script verbosely.
 
 The ART_OPTIONS are passed directly to the Android Runtime.
+Before calling ART, the script will invoke dex2oat on each element of the
+classpath. '-Xcompiler-option' and '-Ximage' will be forwarded to dex2oat.
 
 Example:
   art --32 -cp my_classes.dex MainClass
@@ -123,10 +102,71 @@
               $LAUNCH_WRAPPER $ART_BINARY_PATH $lib    \
               -XXlib:$LIBART                           \
               -Xnorelocate                             \
-              -Ximage:$ANDROID_ROOT/framework/core.art \
+              -Ximage:$DEFAULT_IMAGE                   \
               "$@"
 }
 
+function run_dex2oat() {
+  for dex_file in "${DEX2OAT_CLASSPATH[@]}"
+  do
+    while [ -h "$dex_file" ]; do
+      # On Mac OS, readlink -f doesn't work.
+      dex_file="$(readlink "$dex_file")"
+    done
+    local dalvik_cache=$ANDROID_DATA/dalvik-cache/$ISA
+    # The oat file name if the absolute path of the dex file where '/' is
+    # replaced by '@'. The first '/' in the path is ignored and must be removed.
+    local oat_file=${dex_file//\//@}
+    local oat_file=${oat_file:1}
+    # When running dex2oat use the exact same context as when running dalvikvm.
+    # (see run_art function)
+    verbose_run ANDROID_DATA=$ANDROID_DATA        \
+          ANDROID_ROOT=$ANDROID_ROOT              \
+          LD_LIBRARY_PATH=$LD_LIBRARY_PATH        \
+          PATH=$ANDROID_ROOT/bin:$PATH            \
+          LD_USE_LOAD_BIAS=1                      \
+          $DEX2OAT_BINARY_PATH                    \
+          --runtime-arg -Xnorelocate              \
+          --boot-image=$DEX2OAT_BOOTIMAGE         \
+          --instruction-set=$ISA                  \
+          "${DEX2OAT_FLAGS[@]}"                   \
+          --dex-file="$dex_file"                  \
+          --oat-file="$dalvik_cache/$oat_file"
+  done
+}
+
+# Extract the dex2oat flags from the list of arguments.
+# -Xcompiler-options arguments are stored in DEX2OAT_FLAGS array
+# -cp argument is split by ':' and stored in DEX2OAT_CLASSPATH
+# -Ximage argument is stored in DEX2OAT_BOOTIMAGE
+function extract_dex2oat_flags() {
+  while [ $# -gt 0 ]; do
+    case $1 in
+      -Xcompiler-option)
+        DEX2OAT_FLAGS+=("$2")
+        shift
+        ;;
+      -Ximage:*)
+        DEX2OAT_BOOTIMAGE=$1
+        # Remove '-Ximage:' from the argument.
+        DEX2OAT_BOOTIMAGE=${DEX2OAT_BOOTIMAGE##-Ximage:}
+        ;;
+      -cp)
+        # TODO: support -classpath and CLASSPATH
+        local oifs=$IFS
+        IFS=':'
+        for classpath_elem in $2
+        do
+          DEX2OAT_CLASSPATH+=("$classpath_elem")
+        done
+        shift
+        IFS=$oifs
+        ;;
+    esac
+    shift
+  done
+}
+
 while [[ "$1" = "-"* ]]; do
   case $1 in
   --)
@@ -147,9 +187,11 @@
     ;& # Fallthrough
   --debug)
     LIBART="libartd.so"
+    DEX2OAT_BINARY="dex2oatd"
     ;;
   --gdb)
     LIBART="libartd.so"
+    DEX2OAT_BINARY="dex2oatd"
     LAUNCH_WRAPPER="gdb --args"
     ;;
   --help)
@@ -192,6 +234,15 @@
 PROG_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
 ANDROID_ROOT=$PROG_DIR/..
 ART_BINARY_PATH=$ANDROID_ROOT/bin/$ART_BINARY
+DEX2OAT_BINARY_PATH=$ANDROID_ROOT/bin/$DEX2OAT_BINARY
+
+if [ ! -x "$DEX2OAT_BINARY_PATH" ]; then
+  cat 1>&2 <<EOF
+Android Runtime not found: $DEX2OAT_BINARY_PATH
+This script should be in the same directory as the Android Runtime ($DEX2OAT_BINARY).
+EOF
+  exit 1
+fi
 
 if [ ! -x "$ART_BINARY_PATH" ]; then
   cat 1>&2 <<EOF
@@ -205,11 +256,23 @@
 LD_LIBRARY_PATH=$ANDROID_ROOT/$LIBDIR
 EXTRA_OPTIONS=""
 
+DEFAULT_IMAGE=$ANDROID_ROOT/framework/core.art
+DEX2OAT_FLAGS=()
+DEX2OAT_CLASSPATH=()
+DEX2OAT_BOOTIMAGE=$DEFAULT_IMAGE
+ISA=$($ART_BINARY_PATH -showversion | (read art version number isa && echo $isa))
+
+# Extract the dex2oat flags from the list of arguments.
+# -Xcompiler-options arguments are stored in DEX2OAT_FLAGS array
+# -cp argument is split by ':' and stored in DEX2OAT_CLASSPATH
+# -Ximage argument is stored in DEX2OAT_BOOTIMAGE
+extract_dex2oat_flags "$@"
+
 # If ANDROID_DATA is the system ANDROID_DATA or is not set, use our own,
 # and ensure we delete it at the end.
 if [ "$ANDROID_DATA" = "/data" ] || [ "$ANDROID_DATA" = "" ]; then
   ANDROID_DATA=$PWD/android-data$$
-  mkdir -p $ANDROID_DATA/dalvik-cache/$ARCHS
+  mkdir -p "$ANDROID_DATA/dalvik-cache/$ISA"
   DELETE_ANDROID_DATA="yes"
 fi
 
@@ -218,40 +281,6 @@
   EXTRA_OPTIONS="-Xcompiler-option --generate-debug-info"
 fi
 
-if [ "$JIT_PROFILE" = "yes" ]; then
-  # Create the profile. The runtime expects profiles to be created before
-  # execution.
-  PROFILE_PATH="$ANDROID_DATA/primary.prof"
-  touch $PROFILE_PATH
-
-  # Replace the compiler filter with interpret-only so that we
-  # can capture the profile.
-  ARGS_WITH_INTERPRET_ONLY=
-  replace_compiler_filter_with_interepret_only "$@"
-
-  run_art -Xjitsaveprofilinginfo               \
-          -Xps-min-methods-to-save:1           \
-          -Xps-min-classes-to-save:1           \
-          -Xps-min-notification-before-wake:10 \
-          -Xps-profile-path:$PROFILE_PATH      \
-          -Xusejit:true                        \
-          "${ARGS_WITH_INTERPRET_ONLY[@]}"     \
-          "&>" "$ANDROID_DATA/profile_gen.log"
-  EXIT_STATUS=$?
-
-  if [ $EXIT_STATUS != 0 ]; then
-    cat "$ANDROID_DATA/profile_gen.log"
-    clean_android_data
-    exit $EXIT_STATUS
-  fi
-
-  # Wipe dalvik-cache to prepare it for the next invocation.
-  rm -rf $ANDROID_DATA/dalvik-cache/$ARCHS/*
-
-  # Append arguments so next invocation of run_art uses the profile.
-  EXTRA_OPTIONS="$EXTRA_OPTIONS -Xcompiler-option --profile-file=$PROFILE_PATH"
-fi
-
 # Protect additional arguments in quotes to preserve whitespaces when evaluated.
 # This is for run-jdwp-test.sh which uses this script and has arguments with
 # whitespaces when running on device.
@@ -260,6 +289,43 @@
   shift
 done
 
+if [ "$JIT_PROFILE" = "yes" ]; then
+  # Create the profile. The runtime expects profiles to be created before
+  # execution.
+  PROFILE_PATH="$ANDROID_DATA/primary.prof"
+  touch $PROFILE_PATH
+
+  run_art -Xjitsaveprofilinginfo               \
+          -Xps-min-methods-to-save:1           \
+          -Xps-min-classes-to-save:1           \
+          -Xps-min-notification-before-wake:10 \
+          -Xps-profile-path:$PROFILE_PATH      \
+          -Xusejit:true                        \
+          $EXTRA_OPTIONS                       \
+          "&>" "$ANDROID_DATA/profile_gen.log"
+
+  DEX2OAT_FLAGS+=("--profile-file=$PROFILE_PATH")
+
+  EXIT_STATUS=$?
+
+  if [ $EXIT_STATUS != 0 ]; then
+    cat "$ANDROID_DATA/profile_gen.log"
+    clean_android_data
+    exit $EXIT_STATUS
+  fi
+fi
+
+# Run dex2oat before launching ART to generate the oat files for the classpath.
+run_dex2oat
+
+# Do not continue if the dex2oat failed.
+EXIT_STATUS=$?
+if [ $EXIT_STATUS != 0 ]; then
+  echo "Failed dex2oat invocation" >&2
+  exit $EXIT_STATUS
+fi
+
+# Launch ART using the additional arguments stored in EXTRA_OPTIONS.
 run_art $EXTRA_OPTIONS
 EXIT_STATUS=$?