Merge "ART: Export ASAN_OPTIONS in build testrunner"
diff --git a/build/Android.common_path.mk b/build/Android.common_path.mk
index 4466118..f4f8d49 100644
--- a/build/Android.common_path.mk
+++ b/build/Android.common_path.mk
@@ -74,9 +74,6 @@
 TARGET_CORE_IMG_LOCATION := $(ART_TARGET_TEST_OUT)/core.art
 
 # Jar files for core.art.
-TARGET_CORE_JARS := core-oj core-libart conscrypt okhttp bouncycastle apache-xml
-HOST_CORE_JARS := $(addsuffix -hostdex,$(TARGET_CORE_JARS))
-
 HOST_CORE_DEX_LOCATIONS   := $(foreach jar,$(HOST_CORE_JARS),  $(HOST_OUT_JAVA_LIBRARIES)/$(jar).jar)
 ifeq ($(ART_TEST_ANDROID_ROOT),)
 TARGET_CORE_DEX_LOCATIONS := $(foreach jar,$(TARGET_CORE_JARS),/$(DEXPREOPT_BOOT_JAR_DIR)/$(jar).jar)
diff --git a/test/044-proxy/check b/test/044-proxy/check
new file mode 100755
index 0000000..0cb2c32
--- /dev/null
+++ b/test/044-proxy/check
@@ -0,0 +1,33 @@
+#!/bin/bash
+#
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+expected="$1"
+output="$2"
+
+# Jack inserts a synthetic default method for interface methods with covariant return types.
+# Javac does not do this, so we must fiddle with the expected.txt to get the different behavior.
+
+expected_jack_line='Invocation of public default java[.]lang[.]Object NarrowingTest\$I2[.]foo[(][)]'
+replaced_javac_line='Invocation of public abstract java.lang.Object NarrowingTest\$I1.foo()'
+
+expected_replaced="$expected"
+
+if [[ $USE_JACK == false ]]; then
+  expected_replaced="$output.tmp"
+  sed "s:$expected_jack_line:$replaced_javac_line:g" "$expected" > "$expected_replaced"
+fi
+
+diff --strip-trailing-cr -q "$expected_replaced" "$output" >/dev/null
diff --git a/test/551-checker-shifter-operand/build b/test/551-checker-shifter-operand/build
deleted file mode 100644
index 027a0ea..0000000
--- a/test/551-checker-shifter-operand/build
+++ /dev/null
@@ -1,212 +0,0 @@
-#!/bin/bash
-#
-# Copyright (C) 2008 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-# This is an almost exact copy of `art/test/etc/default-build`. Only the parsing
-# of `dx` option has been overriden.
-
-# Stop if something fails.
-set -e
-
-# Set default values for directories.
-if [ -d smali ]; then
-  HAS_SMALI=true
-else
-  HAS_SMALI=false
-fi
-
-if [ -d src ]; then
-  HAS_SRC=true
-else
-  HAS_SRC=false
-fi
-
-if [ -d src2 ]; then
-  HAS_SRC2=true
-else
-  HAS_SRC2=false
-fi
-
-if [ -d src-multidex ]; then
-  HAS_SRC_MULTIDEX=true
-else
-  HAS_SRC_MULTIDEX=false
-fi
-
-if [ -d src-ex ]; then
-  HAS_SRC_EX=true
-else
-  HAS_SRC_EX=false
-fi
-
-DX_FLAGS=""
-SKIP_DX_MERGER="false"
-EXPERIMENTAL=""
-
-# Setup experimental flag mappings in a bash associative array.
-declare -A JACK_EXPERIMENTAL_ARGS
-JACK_EXPERIMENTAL_ARGS["default-methods"]="-D jack.java.source.version=1.8 -D jack.android.min-api-level=24"
-JACK_EXPERIMENTAL_ARGS["lambdas"]="-D jack.java.source.version=1.8 -D jack.android.min-api-level=24"
-
-while true; do
-  if [ "x$1" = "x--dx-option" ]; then
-    shift
-    option="$1"
-    # Make sure we run this test *with* `dx` optimizations.
-    if [ "x$option" != "x--no-optimize" ]; then
-      DX_FLAGS="${DX_FLAGS} $option"
-    fi
-    shift
-  elif [ "x$1" = "x--jvm" ]; then
-    shift
-  elif [ "x$1" = "x--no-src" ]; then
-    HAS_SRC=false
-    shift
-  elif [ "x$1" = "x--no-src2" ]; then
-    HAS_SRC2=false
-    shift
-  elif [ "x$1" = "x--no-src-multidex" ]; then
-    HAS_SRC_MULTIDEX=false
-    shift
-  elif [ "x$1" = "x--no-src-ex" ]; then
-    HAS_SRC_EX=false
-    shift
-  elif [ "x$1" = "x--no-smali" ]; then
-    HAS_SMALI=false
-    shift
-  elif [ "x$1" = "x--experimental" ]; then
-    shift
-    EXPERIMENTAL="${EXPERIMENTAL} $1"
-    shift
-  elif expr "x$1" : "x--" >/dev/null 2>&1; then
-    echo "unknown $0 option: $1" 1>&2
-    exit 1
-  else
-    break
-  fi
-done
-
-# Add args from the experimental mappings.
-for experiment in ${EXPERIMENTAL}; do
-  JACK_ARGS="${JACK_ARGS} ${JACK_EXPERIMENTAL_ARGS[${experiment}]}"
-done
-
-if [ -e classes.dex ]; then
-  zip $TEST_NAME.jar classes.dex
-  exit 0
-fi
-
-if ! [ "${HAS_SRC}" = "true" ] && ! [ "${HAS_SRC2}" = "true" ]; then
-  # No src directory? Then forget about trying to run dx.
-  SKIP_DX_MERGER="true"
-fi
-
-if [ "${HAS_SRC_MULTIDEX}" = "true" ]; then
-  # Jack does not support this configuration unless we specify how to partition the DEX file
-  # with a .jpp file.
-  USE_JACK="false"
-fi
-
-if [ ${USE_JACK} = "true" ]; then
-  # Jack toolchain
-  if [ "${HAS_SRC}" = "true" ]; then
-    ${JACK} ${JACK_ARGS} --output-jack src.jack src
-    imported_jack_files="--import src.jack"
-  fi
-
-  if [ "${HAS_SRC2}" = "true" ]; then
-    ${JACK} ${JACK_ARGS} --output-jack src2.jack src2
-    imported_jack_files="--import src2.jack ${imported_jack_files}"
-  fi
-
-  # Compile jack files into a DEX file. We set jack.import.type.policy=keep-first to consider
-  # class definitions from src2 first.
-  if [ "${HAS_SRC}" = "true" ] || [ "${HAS_SRC2}" = "true" ]; then
-    ${JACK} ${JACK_ARGS} ${imported_jack_files} -D jack.import.type.policy=keep-first --output-dex .
-  fi
-else
-  # Legacy toolchain with javac+dx
-  if [ "${HAS_SRC}" = "true" ]; then
-    mkdir classes
-    ${JAVAC} ${JAVAC_ARGS} -implicit:none -classpath src-multidex -d classes `find src -name '*.java'`
-  fi
-
-  if [ "${HAS_SRC_MULTIDEX}" = "true" ]; then
-    mkdir classes2
-    ${JAVAC} -implicit:none -classpath src -d classes2 `find src-multidex -name '*.java'`
-    if [ ${NEED_DEX} = "true" ]; then
-      ${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex \
-        --dump-width=1000 ${DX_FLAGS} classes2
-    fi
-  fi
-
-  if [ "${HAS_SRC2}" = "true" ]; then
-    mkdir -p classes
-    ${JAVAC} ${JAVAC_ARGS} -d classes `find src2 -name '*.java'`
-  fi
-
-  if [ "${HAS_SRC}" = "true" ] || [ "${HAS_SRC2}" = "true" ]; then
-    if [ ${NEED_DEX} = "true" -a ${SKIP_DX_MERGER} = "false" ]; then
-      ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex \
-        --dump-width=1000 ${DX_FLAGS} classes
-    fi
-  fi
-fi
-
-if [ "${HAS_SMALI}" = "true" ]; then
-  # Compile Smali classes
-  ${SMALI} -JXmx512m assemble ${SMALI_ARGS} --output smali_classes.dex `find smali -name '*.smali'`
-
-  # Don't bother with dexmerger if we provide our own main function in a smali file.
-  if [ ${SKIP_DX_MERGER} = "false" ]; then
-    ${DXMERGER} classes.dex classes.dex smali_classes.dex
-  else
-    mv smali_classes.dex classes.dex
-  fi
-fi
-
-if [ ${HAS_SRC_EX} = "true" ]; then
-  if [ ${USE_JACK} = "true" ]; then
-      # Rename previous "classes.dex" so it is not overwritten.
-      mv classes.dex classes-1.dex
-      #TODO find another way to append src.jack to the jack classpath
-      ${JACK}:src.jack ${JACK_ARGS} --output-dex . src-ex
-      zip $TEST_NAME-ex.jar classes.dex
-      # Restore previous "classes.dex" so it can be zipped.
-      mv classes-1.dex classes.dex
-  else
-    mkdir classes-ex
-    ${JAVAC} ${JAVAC_ARGS} -d classes-ex -cp classes `find src-ex -name '*.java'`
-    if [ ${NEED_DEX} = "true" ]; then
-      ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes-ex.dex \
-        --dump-width=1000 ${DX_FLAGS} classes-ex
-
-      # quick shuffle so that the stored name is "classes.dex"
-      mv classes.dex classes-1.dex
-      mv classes-ex.dex classes.dex
-      zip $TEST_NAME-ex.jar classes.dex
-      mv classes.dex classes-ex.dex
-      mv classes-1.dex classes.dex
-    fi
-  fi
-fi
-
-# Create a single jar with two dex files for multidex.
-if [ ${HAS_SRC_MULTIDEX} = "true" ]; then
-  zip $TEST_NAME.jar classes.dex classes2.dex
-elif [ ${NEED_DEX} = "true" ]; then
-  zip $TEST_NAME.jar classes.dex
-fi
diff --git a/test/636-arm64-veneer-pool/build b/test/636-arm64-veneer-pool/build
index 27cc4d6..eba22fc 100755
--- a/test/636-arm64-veneer-pool/build
+++ b/test/636-arm64-veneer-pool/build
@@ -19,4 +19,9 @@
 
 # Use javac+dx instead of jack.
 export USE_JACK=false
-./default-build "$@"
+
+# Don't use desugar because the bootclasspath jars will be missing
+# on a platform build compiled with ANDROID_COMPILE_WITH_JACK=true.
+export USE_DESUGAR=false
+
+./default-build
diff --git a/test/641-checker-arraycopy/build b/test/641-checker-arraycopy/build
index 9abc618..12e4423 100644
--- a/test/641-checker-arraycopy/build
+++ b/test/641-checker-arraycopy/build
@@ -21,4 +21,8 @@
 # the typed System.arraycopy versions directly.
 export USE_JACK=false
 
-./default-build
+# Don't use desugar because the bootclasspath jars will be missing
+# on a platform build compiled with ANDROID_COMPILE_WITH_JACK=true.
+export USE_DESUGAR=false
+
+./default-build "$@"
diff --git a/test/etc/default-build b/test/etc/default-build
index 0508b85..9e2a6e2 100755
--- a/test/etc/default-build
+++ b/test/etc/default-build
@@ -70,6 +70,9 @@
 SKIP_DX_MERGER="false"
 EXPERIMENTAL=""
 
+BUILD_MODE="target"
+DEV_MODE="no"
+
 # The key for default arguments if no experimental things are enabled.
 DEFAULT_EXPERIMENT="no-experiment"
 
@@ -137,6 +140,15 @@
     WITH_ZIP_ALIGN=true
     ZIP_ALIGN_BYTES="$1"
     shift
+  elif [ "x$1" = "x--host" ]; then
+    BUILD_MODE="host"
+    shift
+  elif [ "x$1" = "x--target" ]; then
+    BUILD_MODE="target"
+    shift
+  elif [ "x$1" = "x--dev" ]; then
+    DEV_MODE="yes"
+    shift
   elif expr "x$1" : "x--" >/dev/null 2>&1; then
     echo "unknown $0 option: $1" 1>&2
     exit 1
@@ -185,6 +197,41 @@
   fi
 }
 
+function desugar() {
+  local desugar_args=--mode=host
+  if [[ $BUILD_MODE == target ]]; then
+    desugar_args=--mode=target
+  fi
+
+  if [[ $DEV_MODE == yes ]]; then
+    desugar_args="$desugar_args --show-commands"
+  fi
+
+  "${ANDROID_BUILD_TOP}/art/tools/desugar.sh" --core-only $desugar_args "$@"
+}
+
+# Make a "dex" file given a directory of classes in $1.
+# Also calls desugar on the classes first to convert lambdas.
+function make_dex() {
+  local name="$1"
+
+  local dx_input
+  if [[ "$USE_DESUGAR" == "true" ]]; then
+    # Make a jar first so desugar doesn't need every .class file individually.
+    jar cf "$name.before-desugar.jar" -C "$name" .
+
+    dx_input="${name}.desugar.jar"
+
+    # Make desugared JAR.
+    desugar --input "$name.before-desugar.jar" --output "$dx_input"
+  else
+    dx_input="${name}"
+  fi
+
+  # Make dex file from desugared JAR.
+  ${DX} -JXmx256m --debug --dex --dump-to=${name}.lst --output=${name}.dex --dump-width=1000 ${DX_FLAGS} "${dx_input}"
+}
+
 if [ -e classes.dex ]; then
   zip $TEST_NAME.jar classes.dex
   exit 0
@@ -209,9 +256,9 @@
     ${JACK} --import classes.jill.jar --output-dex .
   else
     if [ ${NEED_DEX} = "true" ]; then
-      ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 ${DX_FLAGS} classes-ex
+      make_dex classes-ex
       zip ${TEST_NAME}-ex.jar classes.dex
-      ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 ${DX_FLAGS} classes
+      make_dex classes
     fi
   fi
 else
@@ -254,8 +301,7 @@
       mkdir classes2
       ${JAVAC} -implicit:none -classpath src -d classes2 `find src-multidex -name '*.java'`
       if [ ${NEED_DEX} = "true" ]; then
-        ${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex \
-          --dump-width=1000 ${DX_FLAGS} classes2
+        make_dex classes2
       fi
     fi
 
@@ -266,8 +312,7 @@
 
     if [ "${HAS_SRC}" = "true" ] || [ "${HAS_SRC2}" = "true" ]; then
       if [ ${NEED_DEX} = "true" -a ${SKIP_DX_MERGER} = "false" ]; then
-        ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex \
-          --dump-width=1000 ${DX_FLAGS} classes
+        make_dex classes
       fi
     fi
   fi
@@ -311,8 +356,7 @@
     mkdir classes-ex
     ${JAVAC} ${JAVAC_ARGS} -d classes-ex -cp classes `find src-ex -name '*.java'`
     if [ ${NEED_DEX} = "true" ]; then
-      ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes-ex.dex \
-        --dump-width=1000 ${DX_FLAGS} classes-ex
+      make_dex classes-ex
 
       # quick shuffle so that the stored name is "classes.dex"
       mv classes.dex classes-1.dex
diff --git a/test/knownfailures.json b/test/knownfailures.json
index 8843dc8..9a8f3be 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -601,38 +601,28 @@
             "004-ReferenceMap",
             "004-StackWalk",
             "048-reflect-v8",
+            "065-mismatched-implements",
             "089-many-methods",
             "138-duplicate-classes-check",
             "146-bad-interface",
             "157-void-class",
+            "529-checker-unresolved",
             "563-checker-invoke-super",
             "580-checker-string-fact-intrinsics",
             "596-monitor-inflation",
             "604-hot-static-interface",
+            "608-checker-unresolved-lse",
             "612-jit-dex-cache",
             "613-inlining-dex-cache",
             "616-cha-interface-default",
             "636-wrong-static-access",
+            "648-inline-caches-unresolved",
             "909-attach-agent",
             "910-methods",
             "911-get-stack-trace",
             "912-classes",
             "913-heaps",
-            "914-hello-obsolescence",
-            "915-obsolete-2",
-            "916-obsolete-jit",
-            "919-obsolete-fields",
-            "921-hello-failure",
-            "926-multi-obsolescence",
-            "940-recursive-obsolete",
-            "941-recurive-obsolete-jit",
-            "942-private-recursive",
-            "943-private-recursive-jit",
-            "945-obsolete-native",
-            "946-obsolete-throw",
             "948-change-annotations",
-            "950-redefine-intrinsic",
-            "951-threaded-obsolete",
             "952-invoke-custom",
             "953-invoke-polymorphic-compiler",
             "956-methodhandles",
@@ -648,9 +638,7 @@
             "966-default-conflict",
             "967-default-ame",
             "969-iface-super",
-            "981-dedup-original-dex",
-            "984-obsolete-invoke",
-            "985-re-obsolete"
+            "981-dedup-original-dex"
         ],
         "description": "The tests above fail with --build-with-javac-dx.",
         "env_vars": {"ANDROID_COMPILE_WITH_JACK": "false"},
diff --git a/test/run-test b/test/run-test
index 41a0dc2..ba1f992 100755
--- a/test/run-test
+++ b/test/run-test
@@ -46,6 +46,7 @@
 export DEX_LOCATION=/data/run-test/${test_dir}
 export NEED_DEX="true"
 export USE_JACK="true"
+export USE_DESUGAR="true"
 export SMALI_ARGS=""
 
 # If dx was not set by the environment variable, assume it is in the path.
@@ -771,6 +772,16 @@
   err_echo "ulimit file size setting failed"
 fi
 
+if [[ "$target_mode" == "yes" ]]; then
+  build_args="$build_args --target"
+else
+  build_args="$build_args --host"
+fi
+
+if [[ "$dev_mode" == "yes" ]]; then
+  build_args="$build_args --dev"
+fi
+
 good="no"
 good_build="yes"
 good_run="yes"
diff --git a/test/ti-stress/stress.cc b/test/ti-stress/stress.cc
index 497db1c..515a391 100644
--- a/test/ti-stress/stress.cc
+++ b/test/ti-stress/stress.cc
@@ -18,6 +18,7 @@
 #include <stdio.h>
 #include <iostream>
 #include <fstream>
+#include <memory>
 #include <stdio.h>
 #include <sstream>
 #include <strstream>
@@ -87,6 +88,142 @@
   return ReadIntoBuffer(data->out_temp_dex, dex);
 }
 
+class ScopedThreadInfo {
+ public:
+  ScopedThreadInfo(jvmtiEnv* jvmtienv, JNIEnv* env, jthread thread)
+      : jvmtienv_(jvmtienv), env_(env), free_name_(false) {
+    memset(&info_, 0, sizeof(info_));
+    if (thread == nullptr) {
+      info_.name = const_cast<char*>("<NULLPTR>");
+    } else if (jvmtienv->GetThreadInfo(thread, &info_) != JVMTI_ERROR_NONE) {
+      info_.name = const_cast<char*>("<UNKNOWN THREAD>");
+    } else {
+      free_name_ = true;
+    }
+  }
+
+  ~ScopedThreadInfo() {
+    if (free_name_) {
+      jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(info_.name));
+    }
+    env_->DeleteLocalRef(info_.thread_group);
+    env_->DeleteLocalRef(info_.context_class_loader);
+  }
+
+  const char* GetName() const {
+    return info_.name;
+  }
+
+ private:
+  jvmtiEnv* jvmtienv_;
+  JNIEnv* env_;
+  bool free_name_;
+  jvmtiThreadInfo info_;
+};
+
+class ScopedClassInfo {
+ public:
+  ScopedClassInfo(jvmtiEnv* jvmtienv, jclass c)
+      : jvmtienv_(jvmtienv),
+        class_(c),
+        name_(nullptr),
+        generic_(nullptr) {}
+
+  ~ScopedClassInfo() {
+    jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(name_));
+    jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(generic_));
+  }
+
+  bool Init() {
+    return jvmtienv_->GetClassSignature(class_, &name_, &generic_) == JVMTI_ERROR_NONE;
+  }
+
+  jclass GetClass() const {
+    return class_;
+  }
+  const char* GetName() const {
+    return name_;
+  }
+  const char* GetGeneric() const {
+    return generic_;
+  }
+
+ private:
+  jvmtiEnv* jvmtienv_;
+  jclass class_;
+  char* name_;
+  char* generic_;
+};
+
+class ScopedMethodInfo {
+ public:
+  ScopedMethodInfo(jvmtiEnv* jvmtienv, JNIEnv* env, jmethodID m)
+      : jvmtienv_(jvmtienv),
+        env_(env),
+        method_(m),
+        declaring_class_(nullptr),
+        class_info_(nullptr),
+        name_(nullptr),
+        signature_(nullptr),
+        generic_(nullptr) {}
+
+  ~ScopedMethodInfo() {
+    env_->DeleteLocalRef(declaring_class_);
+    jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(name_));
+    jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(signature_));
+    jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(generic_));
+  }
+
+  bool Init() {
+    if (jvmtienv_->GetMethodDeclaringClass(method_, &declaring_class_) != JVMTI_ERROR_NONE) {
+      return false;
+    }
+    class_info_.reset(new ScopedClassInfo(jvmtienv_, declaring_class_));
+    return class_info_->Init() &&
+        (jvmtienv_->GetMethodName(method_, &name_, &signature_, &generic_) == JVMTI_ERROR_NONE);
+  }
+
+  const ScopedClassInfo& GetDeclaringClassInfo() const {
+    return *class_info_;
+  }
+
+  jclass GetDeclaringClass() const {
+    return declaring_class_;
+  }
+
+  const char* GetName() const {
+    return name_;
+  }
+
+  const char* GetSignature() const {
+    return signature_;
+  }
+
+  const char* GetGeneric() const {
+    return generic_;
+  }
+
+ private:
+  jvmtiEnv* jvmtienv_;
+  JNIEnv* env_;
+  jmethodID method_;
+  jclass declaring_class_;
+  std::unique_ptr<ScopedClassInfo> class_info_;
+  char* name_;
+  char* signature_;
+  char* generic_;
+
+  friend std::ostream& operator<<(std::ostream &os, ScopedMethodInfo const& m);
+};
+
+std::ostream& operator<<(std::ostream &os, const ScopedMethodInfo* m) {
+  return os << *m;
+}
+
+std::ostream& operator<<(std::ostream &os, ScopedMethodInfo const& m) {
+  return os << m.GetDeclaringClassInfo().GetName() << "->" << m.GetName() << m.GetSignature();
+}
+
 static void doJvmtiMethodBind(jvmtiEnv* jvmtienv,
                               JNIEnv* env,
                               jthread thread,
@@ -94,38 +231,14 @@
                               void* address,
                               /*out*/void** out_address) {
   *out_address = address;
-  jvmtiThreadInfo info;
-  if (thread == nullptr) {
-    info.name = const_cast<char*>("<NULLPTR>");
-  } else if (jvmtienv->GetThreadInfo(thread, &info) != JVMTI_ERROR_NONE) {
-    info.name = const_cast<char*>("<UNKNOWN THREAD>");
-  }
-  char *fname, *fsig, *fgen;
-  char *cname, *cgen;
-  jclass klass = nullptr;
-  if (jvmtienv->GetMethodDeclaringClass(m, &klass) != JVMTI_ERROR_NONE) {
-    LOG(ERROR) << "Unable to get method declaring class!";
+  ScopedThreadInfo thread_info(jvmtienv, env, thread);
+  ScopedMethodInfo method_info(jvmtienv, env, m);
+  if (!method_info.Init()) {
+    LOG(ERROR) << "Unable to get method info!";
     return;
   }
-  if (jvmtienv->GetMethodName(m, &fname, &fsig, &fgen) != JVMTI_ERROR_NONE) {
-    LOG(ERROR) << "Unable to get method name!";
-    env->DeleteLocalRef(klass);
-    return;
-  }
-  if (jvmtienv->GetClassSignature(klass, &cname, &cgen) != JVMTI_ERROR_NONE) {
-    LOG(ERROR) << "Unable to get class name!";
-    env->DeleteLocalRef(klass);
-    return;
-  }
-  LOG(INFO) << "Loading native method \"" << cname << "->" << fname << fsig << "\". Thread is \""
-            << info.name << "\"";
-  jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(cname));
-  jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(cgen));
-  jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(fname));
-  jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(fsig));
-  jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(fgen));
-  env->DeleteLocalRef(klass);
-  return;
+  LOG(INFO) << "Loading native method \"" << method_info << "\". Thread is "
+            << thread_info.GetName();
 }
 
 static std::string GetName(jvmtiEnv* jvmtienv, JNIEnv* jnienv, jobject obj) {
@@ -197,80 +310,32 @@
                             jmethodID m,
                             jboolean was_popped_by_exception,
                             jvalue val) {
-  jvmtiThreadInfo info;
-  if (thread == nullptr) {
-    info.name = const_cast<char*>("<NULLPTR>");
-  } else if (jvmtienv->GetThreadInfo(thread, &info) != JVMTI_ERROR_NONE) {
-    // LOG(WARNING) << "Unable to get thread info!";
-    info.name = const_cast<char*>("<UNKNOWN THREAD>");
-  }
-  char *fname, *fsig, *fgen;
-  char *cname, *cgen;
-  jclass klass = nullptr;
-  if (jvmtienv->GetMethodDeclaringClass(m, &klass) != JVMTI_ERROR_NONE) {
-    LOG(ERROR) << "Unable to get method declaring class!";
+  ScopedThreadInfo info(jvmtienv, env, thread);
+  ScopedMethodInfo method_info(jvmtienv, env, m);
+  if (!method_info.Init()) {
+    LOG(ERROR) << "Unable to get method info!";
     return;
   }
-  if (jvmtienv->GetMethodName(m, &fname, &fsig, &fgen) != JVMTI_ERROR_NONE) {
-    LOG(ERROR) << "Unable to get method name!";
-    env->DeleteLocalRef(klass);
-    return;
-  }
-  if (jvmtienv->GetClassSignature(klass, &cname, &cgen) != JVMTI_ERROR_NONE) {
-    LOG(ERROR) << "Unable to get class name!";
-    env->DeleteLocalRef(klass);
-    return;
-  }
-  std::string type(fsig);
+  std::string type(method_info.GetSignature());
   type = type.substr(type.find(")") + 1);
   std::string out_val(was_popped_by_exception ? "" : GetValOf(jvmtienv, env, type, val));
-  LOG(INFO) << "Leaving method \"" << cname << "->" << fname << fsig << "\". Thread is \""
-            << info.name << "\"." << std::endl
+  LOG(INFO) << "Leaving method \"" << method_info << "\". Thread is \"" << info.GetName() << "\"."
+            << std::endl
             << "    Cause: " << (was_popped_by_exception ? "exception" : "return ")
             << out_val << ".";
-  jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(cname));
-  jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(cgen));
-  jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(fname));
-  jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(fsig));
-  jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(fgen));
-  env->DeleteLocalRef(klass);
 }
 
 void JNICALL MethodEntryHook(jvmtiEnv* jvmtienv,
                              JNIEnv* env,
                              jthread thread,
                              jmethodID m) {
-  jvmtiThreadInfo info;
-  if (thread == nullptr) {
-    info.name = const_cast<char*>("<NULLPTR>");
-  } else if (jvmtienv->GetThreadInfo(thread, &info) != JVMTI_ERROR_NONE) {
-    info.name = const_cast<char*>("<UNKNOWN THREAD>");
-  }
-  char *fname, *fsig, *fgen;
-  char *cname, *cgen;
-  jclass klass = nullptr;
-  if (jvmtienv->GetMethodDeclaringClass(m, &klass) != JVMTI_ERROR_NONE) {
-    LOG(ERROR) << "Unable to get method declaring class!";
+  ScopedThreadInfo info(jvmtienv, env, thread);
+  ScopedMethodInfo method_info(jvmtienv, env, m);
+  if (!method_info.Init()) {
+    LOG(ERROR) << "Unable to get method info!";
     return;
   }
-  if (jvmtienv->GetMethodName(m, &fname, &fsig, &fgen) != JVMTI_ERROR_NONE) {
-    LOG(ERROR) << "Unable to get method name!";
-    env->DeleteLocalRef(klass);
-    return;
-  }
-  if (jvmtienv->GetClassSignature(klass, &cname, &cgen) != JVMTI_ERROR_NONE) {
-    LOG(ERROR) << "Unable to get class name!";
-    env->DeleteLocalRef(klass);
-    return;
-  }
-  LOG(INFO) << "Entering method \"" << cname << "->" << fname << fsig << "\". Thread is \""
-            << info.name << "\"";
-  jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(cname));
-  jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(cgen));
-  jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(fname));
-  jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(fsig));
-  jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(fgen));
-  env->DeleteLocalRef(klass);
+  LOG(INFO) << "Entering method \"" << method_info << "\". Thread is \"" << info.GetName() << "\"";
 }
 
 // The hook we are using.
diff --git a/tools/bootjars.sh b/tools/bootjars.sh
new file mode 100755
index 0000000..bb47e55
--- /dev/null
+++ b/tools/bootjars.sh
@@ -0,0 +1,87 @@
+#!/bin/bash
+#
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# This script lists the boot jars that an ART bootclasspath would need.
+#
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+TOP="$DIR/../.."
+
+source "${TOP}/build/envsetup.sh" >&/dev/null # import get_build_var
+
+selected_env_var=
+core_jars_only=n
+print_file_path=n
+mode=target
+while true; do
+  case $1 in
+    --help)
+      echo "Usage: $0 [--core] [--path] [--host|--target] [--help]"
+      exit 0
+      ;;
+    --core)
+      core_jars_only=y
+      ;;
+    --path)
+      print_file_path=y
+      ;;
+    --host)
+      mode=host
+      ;;
+    --target)
+      mode=target
+      ;;
+    *)
+      break
+      ;;
+  esac
+  shift
+done
+
+if [[ $mode == target ]]; then
+  if [[ $core_jars_only == y ]]; then
+    selected_env_var=TARGET_CORE_JARS
+  else
+    selected_env_var=PRODUCT_BOOT_JARS
+  fi
+  intermediates_env_var=TARGET_OUT_COMMON_INTERMEDIATES
+elif [[ $mode == host ]]; then
+  if [[ $core_jars_only == n ]]; then
+    echo "Error: --host does not have non-core boot jars, --core required" >&2
+    exit 1
+  fi
+  selected_env_var=HOST_CORE_JARS
+  intermediates_env_var=HOST_OUT_COMMON_INTERMEDIATES
+fi
+
+boot_jars_list=$(get_build_var "$selected_env_var")
+
+# Print only the list of boot jars.
+if [[ $print_file_path == n ]]; then
+  echo $boot_jars_list
+  exit 0
+fi
+
+# Print the file path (relative to $TOP) to the classes.jar of each boot jar in the intermediates directory.
+intermediates_dir=$(get_build_var "$intermediates_env_var")
+
+# turn the file path into an absolute path
+intermediates_dir=$(readlink -f $TOP/$intermediates_dir)
+
+for jar in $boot_jars_list; do
+  echo "$intermediates_dir/JAVA_LIBRARIES/${jar}_intermediates/classes.jar"
+done
diff --git a/tools/desugar.sh b/tools/desugar.sh
new file mode 100755
index 0000000..43541aa
--- /dev/null
+++ b/tools/desugar.sh
@@ -0,0 +1,91 @@
+#!/bin/bash
+#
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Calls desugar.jar with the --bootclasspath_entry values passed in automatically.
+# (This avoids having to manually set a boot class path).
+#
+#
+# Script-specific args:
+#   --mode=[host|target]: Select between host or target bootclasspath (default target).
+#   --core-only:          Use only "core" bootclasspath (e.g. do not include framework).
+#   --show-commands:      Print the desugar command being executed.
+#   --help:               Print above list of args.
+#
+# All other args are forwarded to desugar.jar
+#
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+TOP=$DIR/../..
+
+pushd "$TOP" >/dev/null # back to android root.
+
+out=${OUT_DIR:-out}
+desugar_jar=$out/host/linux-x86/framework/desugar.jar
+
+if ! [[ -f $desugar_jar ]]; then
+  echo "Error: Missing $desugar_jar; did you do a build?" >&2
+  exit 1
+fi
+
+desugar_jar=$(readlink -f "$desugar_jar") # absolute path to desugar jar
+popd >/dev/null
+
+bootjars_args=
+mode=target
+showcommands=n
+while true; do
+  case $1 in
+    --help)
+      echo "Usage: $0 [--mode=host|target] [--core-only] [--show-commands] <desugar args>"
+      exit 0
+      ;;
+    --mode=host)
+      bootjars_args="$bootjars_args --host"
+      ;;
+    --mode=target)
+      bootjars_args="$bootjars_args --target"
+      ;;
+    --core-only)
+      bootjars_args="$bootjars_args --core"
+      ;;
+    --show-commands)
+      showcommands=y
+      ;;
+    *)
+      break
+      ;;
+  esac
+  shift
+done
+
+desugar_args=()
+boot_class_path_list=$($TOP/art/tools/bootjars.sh $bootjars_args --path)
+
+for path in $boot_class_path_list; do
+  desugar_args+=(--bootclasspath_entry="$path")
+done
+
+if [[ ${#desugar_args[@]} -eq 0 ]]; then
+  echo "FATAL: Missing bootjars.sh file path list" >&2
+  exit 1
+fi
+
+if [[ $showcommands == y ]]; then
+  echo java -jar "$desugar_jar" "${desugar_args[@]}" "$@"
+fi
+
+java -jar "$desugar_jar" "${desugar_args[@]}" "$@"