Merge "Fix divergence between interpreter and compiler."
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index c09116f..424aa7a 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -65,15 +65,18 @@
 	$(call dexpreopt-remove-classes.dex,$@)
 
 # Dex file dependencies for each gtest.
+ART_GTEST_dex2oat_environment_tests_DEX_DEPS := Main MainStripped MultiDex MultiDexModifiedSecondary Nested
+
 ART_GTEST_class_linker_test_DEX_DEPS := Interfaces MultiDex MyClass Nested Statics StaticsFromCode
 ART_GTEST_compiler_driver_test_DEX_DEPS := AbstractMethod StaticLeafMethods ProfileTestMultiDex
 ART_GTEST_dex_cache_test_DEX_DEPS := Main
 ART_GTEST_dex_file_test_DEX_DEPS := GetMethodSignature Main Nested
+ART_GTEST_dex2oat_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS)
 ART_GTEST_exception_test_DEX_DEPS := ExceptionHandle
 ART_GTEST_instrumentation_test_DEX_DEPS := Instrumentation
 ART_GTEST_jni_compiler_test_DEX_DEPS := MyClassNatives
 ART_GTEST_jni_internal_test_DEX_DEPS := AllFields StaticLeafMethods
-ART_GTEST_oat_file_assistant_test_DEX_DEPS := Main MainStripped MultiDex MultiDexModifiedSecondary Nested
+ART_GTEST_oat_file_assistant_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS)
 ART_GTEST_oat_file_test_DEX_DEPS := Main MultiDex
 ART_GTEST_oat_test_DEX_DEPS := Main
 ART_GTEST_object_test_DEX_DEPS := ProtoCompare ProtoCompare2 StaticsFromCode XandY
@@ -89,14 +92,25 @@
 ART_GTEST_elf_writer_test_HOST_DEPS := $(HOST_CORE_IMAGE_default_no-pic_64) $(HOST_CORE_IMAGE_default_no-pic_32)
 ART_GTEST_elf_writer_test_TARGET_DEPS := $(TARGET_CORE_IMAGE_default_no-pic_64) $(TARGET_CORE_IMAGE_default_no-pic_32)
 
-ART_GTEST_oat_file_assistant_test_HOST_DEPS := \
+ART_GTEST_dex2oat_environment_tests_HOST_DEPS := \
   $(HOST_CORE_IMAGE_default_no-pic_64) \
-  $(HOST_CORE_IMAGE_default_no-pic_32) \
-  $(HOST_OUT_EXECUTABLES)/patchoatd
-ART_GTEST_oat_file_assistant_test_TARGET_DEPS := \
+  $(HOST_CORE_IMAGE_default_no-pic_32)
+ART_GTEST_dex2oat_environment_tests_TARGET_DEPS := \
   $(TARGET_CORE_IMAGE_default_no-pic_64) \
-  $(TARGET_CORE_IMAGE_default_no-pic_32) \
-  $(TARGET_OUT_EXECUTABLES)/patchoatd
+  $(TARGET_CORE_IMAGE_default_no-pic_32)
+
+ART_GTEST_oat_file_assistant_test_HOST_DEPS := \
+   $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS) \
+   $(HOST_OUT_EXECUTABLES)/patchoatd
+ART_GTEST_oat_file_assistant_test_TARGET_DEPS := \
+   $(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS) \
+   $(TARGET_OUT_EXECUTABLES)/patchoatd
+
+
+ART_GTEST_dex2oat_test_HOST_DEPS := \
+  $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS)
+ART_GTEST_dex2oat_test_TARGET_DEPS := \
+  $(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS)
 
 # TODO: document why this is needed.
 ART_GTEST_proxy_test_HOST_DEPS := $(HOST_CORE_IMAGE_default_no-pic_64) $(HOST_CORE_IMAGE_default_no-pic_32)
@@ -157,6 +171,7 @@
   cmdline/cmdline_parser_test.cc \
   dexdump/dexdump_test.cc \
   dexlist/dexlist_test.cc \
+  dex2oat/dex2oat_test.cc \
   imgdiag/imgdiag_test.cc \
   oatdump/oatdump_test.cc \
   profman/profile_assistant_test.cc \
@@ -808,11 +823,15 @@
 ART_GTEST_oat_file_assistant_test_DEX_DEPS :=
 ART_GTEST_oat_file_assistant_test_HOST_DEPS :=
 ART_GTEST_oat_file_assistant_test_TARGET_DEPS :=
+ART_GTEST_dex2oat_test_DEX_DEPS :=
+ART_GTEST_dex2oat_test_HOST_DEPS :=
+ART_GTEST_dex2oat_test_TARGET_DEPS :=
 ART_GTEST_object_test_DEX_DEPS :=
 ART_GTEST_proxy_test_DEX_DEPS :=
 ART_GTEST_reflection_test_DEX_DEPS :=
 ART_GTEST_stub_test_DEX_DEPS :=
 ART_GTEST_transaction_test_DEX_DEPS :=
+ART_GTEST_dex2oat_environment_tests_DEX_DEPS :=
 ART_VALGRIND_DEPENDENCIES :=
 ART_VALGRIND_TARGET_DEPENDENCIES :=
 $(foreach dir,$(GTEST_DEX_DIRECTORIES), $(eval ART_TEST_TARGET_GTEST_$(dir)_DEX :=))
diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc
index 19629b1..f43f8ed 100644
--- a/compiler/optimizing/intrinsics_arm.cc
+++ b/compiler/optimizing/intrinsics_arm.cc
@@ -1976,50 +1976,6 @@
   __ revsh(out, in);
 }
 
-static void GenBitCount(HInvoke* instr, bool is64bit, ArmAssembler* assembler) {
-  DCHECK(instr->GetType() == Primitive::kPrimInt);
-  DCHECK((is64bit && instr->InputAt(0)->GetType() == Primitive::kPrimLong) ||
-         (!is64bit && instr->InputAt(0)->GetType() == Primitive::kPrimInt));
-
-  LocationSummary* locations = instr->GetLocations();
-  Location     in = locations->InAt(0);
-  Register  src_0 = is64bit ? in.AsRegisterPairLow<Register>() : in.AsRegister<Register>();
-  Register  src_1 = is64bit ? in.AsRegisterPairHigh<Register>() : src_0;
-  SRegister tmp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
-  DRegister tmp_d = FromLowSToD(tmp_s);
-  Register  out_r = locations->Out().AsRegister<Register>();
-
-  // Move data from core register(s) to temp D-reg for bit count calculation, then move back.
-  // According to Cortex A57 and A72 optimization guides, compared to transferring to full D-reg,
-  // transferring data from core reg to upper or lower half of vfp D-reg requires extra latency,
-  // That's why for integer bit count, we use 'vmov d0, r0, r0' instead of 'vmov d0[0], r0'.
-  __ vmovdrr(tmp_d, src_1, src_0);                         // Temp DReg |--src_1|--src_0|
-  __ vcntd(tmp_d, tmp_d);                                  // Temp DReg |c|c|c|c|c|c|c|c|
-  __ vpaddld(tmp_d, tmp_d, 8, /* is_unsigned */ true);     // Temp DReg |--c|--c|--c|--c|
-  __ vpaddld(tmp_d, tmp_d, 16, /* is_unsigned */ true);    // Temp DReg |------c|------c|
-  if (is64bit) {
-    __ vpaddld(tmp_d, tmp_d, 32, /* is_unsigned */ true);  // Temp DReg |--------------c|
-  }
-  __ vmovrs(out_r, tmp_s);
-}
-
-void IntrinsicLocationsBuilderARM::VisitIntegerBitCount(HInvoke* invoke) {
-  CreateIntToIntLocations(arena_, invoke);
-  invoke->GetLocations()->AddTemp(Location::RequiresFpuRegister());
-}
-
-void IntrinsicCodeGeneratorARM::VisitIntegerBitCount(HInvoke* invoke) {
-  GenBitCount(invoke, /* is64bit */ false, GetAssembler());
-}
-
-void IntrinsicLocationsBuilderARM::VisitLongBitCount(HInvoke* invoke) {
-  VisitIntegerBitCount(invoke);
-}
-
-void IntrinsicCodeGeneratorARM::VisitLongBitCount(HInvoke* invoke) {
-  GenBitCount(invoke, /* is64bit */ true, GetAssembler());
-}
-
 void IntrinsicLocationsBuilderARM::VisitStringGetCharsNoCheck(HInvoke* invoke) {
   LocationSummary* locations = new (arena_) LocationSummary(invoke,
                                                             LocationSummary::kNoCall,
@@ -2160,6 +2116,8 @@
   __ Lsr(out, out, 5);
 }
 
+UNIMPLEMENTED_INTRINSIC(ARM, IntegerBitCount)
+UNIMPLEMENTED_INTRINSIC(ARM, LongBitCount)
 UNIMPLEMENTED_INTRINSIC(ARM, MathMinDoubleDouble)
 UNIMPLEMENTED_INTRINSIC(ARM, MathMinFloatFloat)
 UNIMPLEMENTED_INTRINSIC(ARM, MathMaxDoubleDouble)
diff --git a/compiler/utils/assembler_test.h b/compiler/utils/assembler_test.h
index afe0576..92b4c8e 100644
--- a/compiler/utils/assembler_test.h
+++ b/compiler/utils/assembler_test.h
@@ -344,6 +344,17 @@
   }
 
   template <typename ImmType>
+  std::string RepeatFFIb(void (Ass::*f)(FPReg, FPReg, ImmType), int imm_bits, std::string fmt) {
+    return RepeatTemplatedRegistersImmBits<FPReg, FPReg, ImmType>(f,
+                                                                  imm_bits,
+                                                                  GetFPRegisters(),
+                                                                  GetFPRegisters(),
+                                                                  &AssemblerTest::GetFPRegName,
+                                                                  &AssemblerTest::GetFPRegName,
+                                                                  fmt);
+  }
+
+  template <typename ImmType>
   std::string RepeatIbFF(void (Ass::*f)(ImmType, FPReg, FPReg), int imm_bits, std::string fmt) {
     return RepeatTemplatedImmBitsRegisters<ImmType, FPReg, FPReg>(f,
                                                                   GetFPRegisters(),
diff --git a/compiler/utils/mips/assembler_mips_test.cc b/compiler/utils/mips/assembler_mips_test.cc
index c722d0c..a1d6ad6 100644
--- a/compiler/utils/mips/assembler_mips_test.cc
+++ b/compiler/utils/mips/assembler_mips_test.cc
@@ -647,6 +647,26 @@
   DriverStr(RepeatRRIb(&mips::MipsAssembler::Movt, 3, "movt ${reg1}, ${reg2}, $fcc{imm}"), "Movt");
 }
 
+TEST_F(AssemblerMIPSTest, MovfS) {
+  DriverStr(RepeatFFIb(&mips::MipsAssembler::MovfS, 3, "movf.s ${reg1}, ${reg2}, $fcc{imm}"),
+            "MovfS");
+}
+
+TEST_F(AssemblerMIPSTest, MovfD) {
+  DriverStr(RepeatFFIb(&mips::MipsAssembler::MovfD, 3, "movf.d ${reg1}, ${reg2}, $fcc{imm}"),
+            "MovfD");
+}
+
+TEST_F(AssemblerMIPSTest, MovtS) {
+  DriverStr(RepeatFFIb(&mips::MipsAssembler::MovtS, 3, "movt.s ${reg1}, ${reg2}, $fcc{imm}"),
+            "MovtS");
+}
+
+TEST_F(AssemblerMIPSTest, MovtD) {
+  DriverStr(RepeatFFIb(&mips::MipsAssembler::MovtD, 3, "movt.d ${reg1}, ${reg2}, $fcc{imm}"),
+            "MovtD");
+}
+
 TEST_F(AssemblerMIPSTest, CvtSW) {
   DriverStr(RepeatFF(&mips::MipsAssembler::Cvtsw, "cvt.s.w ${reg1}, ${reg2}"), "CvtSW");
 }
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 24a4d58..c133980 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -22,6 +22,7 @@
 
 #include <fstream>
 #include <iostream>
+#include <limits>
 #include <sstream>
 #include <string>
 #include <unordered_set>
@@ -81,6 +82,9 @@
 
 namespace art {
 
+static constexpr size_t kDefaultMinDexFilesForSwap = 2;
+static constexpr size_t kDefaultMinDexFileCumulativeSizeForSwap = 20 * MB;
+
 static int original_argc;
 static char** original_argv;
 
@@ -351,6 +355,20 @@
   UsageError("  --swap-fd=<file-descriptor>:  specifies a file to use for swap (by descriptor).");
   UsageError("      Example: --swap-fd=10");
   UsageError("");
+  UsageError("  --swap-dex-size-threshold=<size>:  specifies the minimum total dex file size in");
+  UsageError("      bytes to allow the use of swap.");
+  UsageError("      Example: --swap-dex-size-threshold=1000000");
+  UsageError("      Default: %zu", kDefaultMinDexFileCumulativeSizeForSwap);
+  UsageError("");
+  UsageError("  --swap-dex-count-threshold=<count>:  specifies the minimum number of dex files to");
+  UsageError("      allow the use of swap.");
+  UsageError("      Example: --swap-dex-count-threshold=10");
+  UsageError("      Default: %zu", kDefaultMinDexFilesForSwap);
+  UsageError("");
+  UsageError("  --very-large-app-threshold=<size>:  specifies the minimum total dex file size in");
+  UsageError("      bytes to consider the input \"very large\" and punt on the compilation.");
+  UsageError("      Example: --very-large-app-threshold=100000000");
+  UsageError("");
   UsageError("  --app-image-fd=<file-descriptor>: specify output file descriptor for app image.");
   UsageError("      Example: --app-image-fd=10");
   UsageError("");
@@ -473,25 +491,6 @@
   pthread_t pthread_;
 };
 
-static constexpr size_t kMinDexFilesForSwap = 2;
-static constexpr size_t kMinDexFileCumulativeSizeForSwap = 20 * MB;
-
-static bool UseSwap(bool is_image, std::vector<const DexFile*>& dex_files) {
-  if (is_image) {
-    // Don't use swap, we know generation should succeed, and we don't want to slow it down.
-    return false;
-  }
-  if (dex_files.size() < kMinDexFilesForSwap) {
-    // If there are less dex files than the threshold, assume it's gonna be fine.
-    return false;
-  }
-  size_t dex_files_size = 0;
-  for (const auto* dex_file : dex_files) {
-    dex_files_size += dex_file->GetHeader().file_size_;
-  }
-  return dex_files_size >= kMinDexFileCumulativeSizeForSwap;
-}
-
 class Dex2Oat FINAL {
  public:
   explicit Dex2Oat(TimingLogger* timings) :
@@ -1132,6 +1131,21 @@
         swap_file_name_ = option.substr(strlen("--swap-file=")).data();
       } else if (option.starts_with("--swap-fd=")) {
         ParseUintOption(option, "--swap-fd", &swap_fd_, Usage);
+      } else if (option.starts_with("--swap-dex-size-threshold=")) {
+        ParseUintOption(option,
+                        "--swap-dex-size-threshold",
+                        &min_dex_file_cumulative_size_for_swap_,
+                        Usage);
+      } else if (option.starts_with("--swap-dex-count-threshold=")) {
+        ParseUintOption(option,
+                        "--swap-dex-count-threshold",
+                        &min_dex_files_for_swap_,
+                        Usage);
+      } else if (option.starts_with("--very-large-app-threshold=")) {
+        ParseUintOption(option,
+                        "--very-large-app-threshold",
+                        &very_large_threshold_,
+                        Usage);
       } else if (option.starts_with("--app-image-file=")) {
         app_image_file_name_ = option.substr(strlen("--app-image-file=")).data();
       } else if (option.starts_with("--app-image-fd=")) {
@@ -1414,6 +1428,19 @@
     }
     // Note that dex2oat won't close the swap_fd_. The compiler driver's swap space will do that.
 
+    // If we need to downgrade the compiler-filter for size reasons, do that check now.
+    if (!IsBootImage() && IsVeryLarge(dex_files_)) {
+      if (!CompilerFilter::IsAsGoodAs(CompilerFilter::kVerifyAtRuntime,
+                                      compiler_options_->GetCompilerFilter())) {
+        LOG(INFO) << "Very large app, downgrading to verify-at-runtime.";
+        // Note: this change won't be reflected in the key-value store, as that had to be
+        //       finalized before loading the dex files. This setup is currently required
+        //       to get the size from the DexFile objects.
+        // TODO: refactor. b/29790079
+        compiler_options_->SetCompilerFilter(CompilerFilter::kVerifyAtRuntime);
+      }
+    }
+
     if (IsBootImage()) {
       // For boot image, pass opened dex files to the Runtime::Create().
       // Note: Runtime acquires ownership of these dex files.
@@ -1842,10 +1869,6 @@
     }
   }
 
-  CompilerOptions* GetCompilerOptions() const {
-    return compiler_options_.get();
-  }
-
   bool IsImage() const {
     return IsAppImage() || IsBootImage();
   }
@@ -1897,6 +1920,30 @@
   }
 
  private:
+  bool UseSwap(bool is_image, const std::vector<const DexFile*>& dex_files) {
+    if (is_image) {
+      // Don't use swap, we know generation should succeed, and we don't want to slow it down.
+      return false;
+    }
+    if (dex_files.size() < min_dex_files_for_swap_) {
+      // If there are less dex files than the threshold, assume it's gonna be fine.
+      return false;
+    }
+    size_t dex_files_size = 0;
+    for (const auto* dex_file : dex_files) {
+      dex_files_size += dex_file->GetHeader().file_size_;
+    }
+    return dex_files_size >= min_dex_file_cumulative_size_for_swap_;
+  }
+
+  bool IsVeryLarge(std::vector<const DexFile*>& dex_files) {
+    size_t dex_files_size = 0;
+    for (const auto* dex_file : dex_files) {
+      dex_files_size += dex_file->GetHeader().file_size_;
+    }
+    return dex_files_size >= very_large_threshold_;
+  }
+
   template <typename T>
   static std::vector<T*> MakeNonOwningPointerVector(const std::vector<std::unique_ptr<T>>& src) {
     std::vector<T*> result;
@@ -2486,6 +2533,9 @@
   bool dump_slow_timing_;
   std::string swap_file_name_;
   int swap_fd_;
+  size_t min_dex_files_for_swap_ = kDefaultMinDexFilesForSwap;
+  size_t min_dex_file_cumulative_size_for_swap_ = kDefaultMinDexFileCumulativeSizeForSwap;
+  size_t very_large_threshold_ = std::numeric_limits<size_t>::max();
   std::string app_image_file_name_;
   int app_image_fd_;
   std::string profile_file_;
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
new file mode 100644
index 0000000..6188883
--- /dev/null
+++ b/dex2oat/dex2oat_test.cc
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <string>
+#include <vector>
+#include <sstream>
+
+#include "common_runtime_test.h"
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/stringprintf.h"
+#include "dex2oat_environment_test.h"
+#include "oat.h"
+#include "oat_file.h"
+#include "utils.h"
+
+#include <sys/wait.h>
+#include <unistd.h>
+
+namespace art {
+
+class Dex2oatTest : public Dex2oatEnvironmentTest {
+ public:
+  virtual void TearDown() OVERRIDE {
+    Dex2oatEnvironmentTest::TearDown();
+
+    output_ = "";
+    error_msg_ = "";
+    success_ = false;
+  }
+
+ protected:
+  void GenerateOdexForTest(const std::string& dex_location,
+                           const std::string& odex_location,
+                           CompilerFilter::Filter filter,
+                           const std::vector<std::string>& extra_args = {},
+                           bool expect_success = true) {
+    std::vector<std::string> args;
+    args.push_back("--dex-file=" + dex_location);
+    args.push_back("--oat-file=" + odex_location);
+    args.push_back("--compiler-filter=" + CompilerFilter::NameOfFilter(filter));
+    args.push_back("--runtime-arg");
+    args.push_back("-Xnorelocate");
+
+    args.insert(args.end(), extra_args.begin(), extra_args.end());
+
+    std::string error_msg;
+    bool success = Dex2Oat(args, &error_msg);
+
+    if (expect_success) {
+      ASSERT_TRUE(success) << error_msg;
+
+      // Verify the odex file was generated as expected.
+      std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
+                                                       odex_location.c_str(),
+                                                       nullptr,
+                                                       nullptr,
+                                                       false,
+                                                       /*low_4gb*/false,
+                                                       dex_location.c_str(),
+                                                       &error_msg));
+      ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
+
+      CheckFilter(filter, odex_file->GetCompilerFilter());
+    } else {
+      ASSERT_FALSE(success) << output_;
+
+      error_msg_ = error_msg;
+
+      // Verify there's no loadable odex file.
+      std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
+                                                       odex_location.c_str(),
+                                                       nullptr,
+                                                       nullptr,
+                                                       false,
+                                                       /*low_4gb*/false,
+                                                       dex_location.c_str(),
+                                                       &error_msg));
+      ASSERT_TRUE(odex_file.get() == nullptr);
+    }
+  }
+
+  // Check the input compiler filter against the generated oat file's filter. Mayb be overridden
+  // in subclasses when equality is not expected.
+  virtual void CheckFilter(CompilerFilter::Filter expected, CompilerFilter::Filter actual) {
+    EXPECT_EQ(expected, actual);
+  }
+
+  bool Dex2Oat(const std::vector<std::string>& dex2oat_args, std::string* error_msg) {
+    Runtime* runtime = Runtime::Current();
+
+    const std::vector<gc::space::ImageSpace*>& image_spaces =
+        runtime->GetHeap()->GetBootImageSpaces();
+    if (image_spaces.empty()) {
+      *error_msg = "No image location found for Dex2Oat.";
+      return false;
+    }
+    std::string image_location = image_spaces[0]->GetImageLocation();
+
+    std::vector<std::string> argv;
+    argv.push_back(runtime->GetCompilerExecutable());
+    argv.push_back("--runtime-arg");
+    argv.push_back("-classpath");
+    argv.push_back("--runtime-arg");
+    std::string class_path = runtime->GetClassPathString();
+    if (class_path == "") {
+      class_path = OatFile::kSpecialSharedLibrary;
+    }
+    argv.push_back(class_path);
+    if (runtime->IsDebuggable()) {
+      argv.push_back("--debuggable");
+    }
+    runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv);
+
+    if (!runtime->IsVerificationEnabled()) {
+      argv.push_back("--compiler-filter=verify-none");
+    }
+
+    if (runtime->MustRelocateIfPossible()) {
+      argv.push_back("--runtime-arg");
+      argv.push_back("-Xrelocate");
+    } else {
+      argv.push_back("--runtime-arg");
+      argv.push_back("-Xnorelocate");
+    }
+
+    if (!kIsTargetBuild) {
+      argv.push_back("--host");
+    }
+
+    argv.push_back("--boot-image=" + image_location);
+
+    std::vector<std::string> compiler_options = runtime->GetCompilerOptions();
+    argv.insert(argv.end(), compiler_options.begin(), compiler_options.end());
+
+    argv.insert(argv.end(), dex2oat_args.begin(), dex2oat_args.end());
+
+    // We must set --android-root.
+    const char* android_root = getenv("ANDROID_ROOT");
+    CHECK(android_root != nullptr);
+    argv.push_back("--android-root=" + std::string(android_root));
+
+    std::string command_line(Join(argv, ' '));
+
+    // We need to fix up the '&' being used for "do not check classpath."
+    size_t ampersand = command_line.find(" &");
+    CHECK_NE(ampersand, std::string::npos);
+    command_line = command_line.replace(ampersand, 2, " \\&");
+
+    command_line += " 2>&1";
+
+    // We need dex2oat to actually log things.
+    setenv("ANDROID_LOG_TAGS", "*:d", 1);
+
+    FILE* pipe = popen(command_line.c_str(), "r");
+
+    setenv("ANDROID_LOG_TAGS", "*:e", 1);
+
+    if (pipe == nullptr) {
+      success_ = false;
+    } else {
+      char buffer[128];
+
+      while (fgets(buffer, 128, pipe) != nullptr) {
+        output_ += buffer;
+      }
+
+      int result = pclose(pipe);
+      success_ = result == 0;
+    }
+    return success_;
+  }
+
+  std::string output_ = "";
+  std::string error_msg_ = "";
+  bool success_ = false;
+};
+
+class Dex2oatSwapTest : public Dex2oatTest {
+ protected:
+  void RunTest(bool use_fd, bool expect_use, const std::vector<std::string>& extra_args = {}) {
+    std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar";
+    std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex";
+
+    Copy(GetDexSrc1(), dex_location);
+
+    std::vector<std::string> copy(extra_args);
+
+    std::unique_ptr<ScratchFile> sf;
+    if (use_fd) {
+      sf.reset(new ScratchFile());
+      copy.push_back(StringPrintf("--swap-fd=%d", sf->GetFd()));
+    } else {
+      std::string swap_location = GetOdexDir() + "/Dex2OatSwapTest.odex.swap";
+      copy.push_back("--swap-file=" + swap_location);
+    }
+    GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, copy);
+
+    CheckValidity();
+    ASSERT_TRUE(success_);
+    CheckResult(expect_use);
+  }
+
+  void CheckResult(bool expect_use) {
+    if (kIsTargetBuild) {
+      CheckTargetResult(expect_use);
+    } else {
+      CheckHostResult(expect_use);
+    }
+  }
+
+  void CheckTargetResult(bool expect_use ATTRIBUTE_UNUSED) {
+    // TODO: Ignore for now, as we won't capture any output (it goes to the logcat). We may do
+    //       something for variants with file descriptor where we can control the lifetime of
+    //       the swap file and thus take a look at it.
+  }
+
+  void CheckHostResult(bool expect_use) {
+    if (!kIsTargetBuild) {
+      if (expect_use) {
+        EXPECT_NE(output_.find("Large app, accepted running with swap."), std::string::npos)
+            << output_;
+      } else {
+        EXPECT_EQ(output_.find("Large app, accepted running with swap."), std::string::npos)
+            << output_;
+      }
+    }
+  }
+
+  // Check whether the dex2oat run was really successful.
+  void CheckValidity() {
+    if (kIsTargetBuild) {
+      CheckTargetValidity();
+    } else {
+      CheckHostValidity();
+    }
+  }
+
+  void CheckTargetValidity() {
+    // TODO: Ignore for now, as we won't capture any output (it goes to the logcat). We may do
+    //       something for variants with file descriptor where we can control the lifetime of
+    //       the swap file and thus take a look at it.
+  }
+
+  // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
+  void CheckHostValidity() {
+    EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
+  }
+};
+
+TEST_F(Dex2oatSwapTest, DoNotUseSwapDefaultSingleSmall) {
+  RunTest(false /* use_fd */, false /* expect_use */);
+  RunTest(true /* use_fd */, false /* expect_use */);
+}
+
+TEST_F(Dex2oatSwapTest, DoNotUseSwapSingle) {
+  RunTest(false /* use_fd */, false /* expect_use */, { "--swap-dex-size-threshold=0" });
+  RunTest(true /* use_fd */, false /* expect_use */, { "--swap-dex-size-threshold=0" });
+}
+
+TEST_F(Dex2oatSwapTest, DoNotUseSwapSmall) {
+  RunTest(false /* use_fd */, false /* expect_use */, { "--swap-dex-count-threshold=0" });
+  RunTest(true /* use_fd */, false /* expect_use */, { "--swap-dex-count-threshold=0" });
+}
+
+TEST_F(Dex2oatSwapTest, DoUseSwapSingleSmall) {
+  RunTest(false /* use_fd */,
+          true /* expect_use */,
+          { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" });
+  RunTest(true /* use_fd */,
+          true /* expect_use */,
+          { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" });
+}
+
+class Dex2oatVeryLargeTest : public Dex2oatTest {
+ protected:
+  void CheckFilter(CompilerFilter::Filter input ATTRIBUTE_UNUSED,
+                   CompilerFilter::Filter result ATTRIBUTE_UNUSED) OVERRIDE {
+    // Ignore, we'll do our own checks.
+  }
+
+  void RunTest(CompilerFilter::Filter filter,
+               bool expect_large,
+               const std::vector<std::string>& extra_args = {}) {
+    std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
+    std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
+
+    Copy(GetDexSrc1(), dex_location);
+
+    std::vector<std::string> copy(extra_args);
+
+    GenerateOdexForTest(dex_location, odex_location, filter, copy);
+
+    CheckValidity();
+    ASSERT_TRUE(success_);
+    CheckResult(dex_location, odex_location, filter, expect_large);
+  }
+
+  void CheckResult(const std::string& dex_location,
+                   const std::string& odex_location,
+                   CompilerFilter::Filter filter,
+                   bool expect_large) {
+    // Host/target independent checks.
+    std::string error_msg;
+    std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
+                                                     odex_location.c_str(),
+                                                     nullptr,
+                                                     nullptr,
+                                                     false,
+                                                     /*low_4gb*/false,
+                                                     dex_location.c_str(),
+                                                     &error_msg));
+    ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
+    if (expect_large) {
+      // Note: we cannot check the following:
+      //   EXPECT_TRUE(CompilerFilter::IsAsGoodAs(CompilerFilter::kVerifyAtRuntime,
+      //                                          odex_file->GetCompilerFilter()));
+      // The reason is that the filter override currently happens when the dex files are
+      // loaded in dex2oat, which is after the oat file has been started. Thus, the header
+      // store cannot be changed, and the original filter is set in stone.
+
+      for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) {
+        std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error_msg);
+        ASSERT_TRUE(dex_file != nullptr);
+        uint32_t class_def_count = dex_file->NumClassDefs();
+        ASSERT_LT(class_def_count, std::numeric_limits<uint16_t>::max());
+        for (uint16_t class_def_index = 0; class_def_index < class_def_count; ++class_def_index) {
+          OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
+          EXPECT_EQ(oat_class.GetType(), OatClassType::kOatClassNoneCompiled);
+        }
+      }
+
+      // If the input filter was "below," it should have been used.
+      if (!CompilerFilter::IsAsGoodAs(CompilerFilter::kVerifyAtRuntime, filter)) {
+        EXPECT_EQ(odex_file->GetCompilerFilter(), filter);
+      }
+    } else {
+      EXPECT_EQ(odex_file->GetCompilerFilter(), filter);
+    }
+
+    // Host/target dependent checks.
+    if (kIsTargetBuild) {
+      CheckTargetResult(expect_large);
+    } else {
+      CheckHostResult(expect_large);
+    }
+  }
+
+  void CheckTargetResult(bool expect_large ATTRIBUTE_UNUSED) {
+    // TODO: Ignore for now. May do something for fd things.
+  }
+
+  void CheckHostResult(bool expect_large) {
+    if (!kIsTargetBuild) {
+      if (expect_large) {
+        EXPECT_NE(output_.find("Very large app, downgrading to verify-at-runtime."),
+                  std::string::npos)
+            << output_;
+      } else {
+        EXPECT_EQ(output_.find("Very large app, downgrading to verify-at-runtime."),
+                  std::string::npos)
+            << output_;
+      }
+    }
+  }
+
+  // Check whether the dex2oat run was really successful.
+  void CheckValidity() {
+    if (kIsTargetBuild) {
+      CheckTargetValidity();
+    } else {
+      CheckHostValidity();
+    }
+  }
+
+  void CheckTargetValidity() {
+    // TODO: Ignore for now.
+  }
+
+  // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
+  void CheckHostValidity() {
+    EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
+  }
+};
+
+TEST_F(Dex2oatVeryLargeTest, DontUseVeryLarge) {
+  RunTest(CompilerFilter::kVerifyNone, false);
+  RunTest(CompilerFilter::kVerifyAtRuntime, false);
+  RunTest(CompilerFilter::kInterpretOnly, false);
+  RunTest(CompilerFilter::kSpeed, false);
+
+  RunTest(CompilerFilter::kVerifyNone, false, { "--very-large-app-threshold=1000000" });
+  RunTest(CompilerFilter::kVerifyAtRuntime, false, { "--very-large-app-threshold=1000000" });
+  RunTest(CompilerFilter::kInterpretOnly, false, { "--very-large-app-threshold=1000000" });
+  RunTest(CompilerFilter::kSpeed, false, { "--very-large-app-threshold=1000000" });
+}
+
+TEST_F(Dex2oatVeryLargeTest, UseVeryLarge) {
+  RunTest(CompilerFilter::kVerifyNone, false, { "--very-large-app-threshold=100" });
+  RunTest(CompilerFilter::kVerifyAtRuntime, false, { "--very-large-app-threshold=100" });
+  RunTest(CompilerFilter::kInterpretOnly, true, { "--very-large-app-threshold=100" });
+  RunTest(CompilerFilter::kSpeed, true, { "--very-large-app-threshold=100" });
+}
+
+}  // namespace art
diff --git a/disassembler/disassembler_mips.cc b/disassembler/disassembler_mips.cc
index a95ea64..1f51311 100644
--- a/disassembler/disassembler_mips.cc
+++ b/disassembler/disassembler_mips.cc
@@ -384,6 +384,8 @@
   { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 13, "trunc.w", "fad" },
   { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 14, "ceil.w", "fad" },
   { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 15, "floor.w", "fad" },
+  { kFpMask | (0x201 << 16), kCop1 | (0x200 << 16) | 17, "movf", "fadc" },
+  { kFpMask | (0x201 << 16), kCop1 | (0x201 << 16) | 17, "movt", "fadc" },
   { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 26, "rint", "fad" },
   { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 27, "class", "fad" },
   { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 32, "cvt.s", "fad" },
diff --git a/runtime/base/mutex-inl.h b/runtime/base/mutex-inl.h
index bd8de87..1c32024 100644
--- a/runtime/base/mutex-inl.h
+++ b/runtime/base/mutex-inl.h
@@ -73,6 +73,11 @@
           level == kThreadListLock ||
           // Ignore logging which may or may not have set up thread data structures.
           level == kLoggingLock ||
+          // When transitioning from suspended to runnable, a daemon thread might be in
+          // a situation where the runtime is shutting down. To not crash our debug locking
+          // mechanism we just pass null Thread* to the MutexLock during that transition
+          // (see Thread::TransitionFromSuspendedToRunnable).
+          level == kThreadSuspendCountLock ||
           // Avoid recursive death.
           level == kAbortLock) << level;
   }
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index 3509d9a..741b682 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -463,7 +463,7 @@
 #define ART_TARGET_NATIVETEST_DIR_STRING ""
 #endif
 
-std::string CommonRuntimeTestImpl::GetTestDexFileName(const char* name) {
+std::string CommonRuntimeTestImpl::GetTestDexFileName(const char* name) const {
   CHECK(name != nullptr);
   std::string filename;
   if (IsHost()) {
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index 0ce40e8..b68eb19 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -111,7 +111,7 @@
 
   std::string GetTestAndroidRoot();
 
-  std::string GetTestDexFileName(const char* name);
+  std::string GetTestDexFileName(const char* name) const;
 
   std::vector<std::unique_ptr<const DexFile>> OpenTestDexFiles(const char* name)
       SHARED_REQUIRES(Locks::mutator_lock_);
diff --git a/runtime/dex2oat_environment_test.h b/runtime/dex2oat_environment_test.h
new file mode 100644
index 0000000..743fbb9
--- /dev/null
+++ b/runtime/dex2oat_environment_test.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef ART_RUNTIME_DEX2OAT_ENVIRONMENT_TEST_H_
+#define ART_RUNTIME_DEX2OAT_ENVIRONMENT_TEST_H_
+
+#include <fstream>
+#include <string>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "common_runtime_test.h"
+#include "compiler_callbacks.h"
+#include "gc/heap.h"
+#include "gc/space/image_space.h"
+#include "oat_file_assistant.h"
+#include "os.h"
+#include "runtime.h"
+#include "utils.h"
+
+namespace art {
+
+// Test class that provides some helpers to set a test up for compilation using dex2oat.
+class Dex2oatEnvironmentTest : public CommonRuntimeTest {
+ public:
+  virtual void SetUp() OVERRIDE {
+    CommonRuntimeTest::SetUp();
+
+    // Create a scratch directory to work from.
+    scratch_dir_ = android_data_ + "/Dex2oatEnvironmentTest";
+    ASSERT_EQ(0, mkdir(scratch_dir_.c_str(), 0700));
+
+    // Create a subdirectory in scratch for odex files.
+    odex_oat_dir_ = scratch_dir_ + "/oat";
+    ASSERT_EQ(0, mkdir(odex_oat_dir_.c_str(), 0700));
+
+    odex_dir_ = odex_oat_dir_ + "/" + std::string(GetInstructionSetString(kRuntimeISA));
+    ASSERT_EQ(0, mkdir(odex_dir_.c_str(), 0700));
+
+    // Verify the environment is as we expect
+    uint32_t checksum;
+    std::string error_msg;
+    ASSERT_TRUE(OS::FileExists(GetSystemImageFile().c_str()))
+      << "Expected pre-compiled boot image to be at: " << GetSystemImageFile();
+    ASSERT_TRUE(OS::FileExists(GetDexSrc1().c_str()))
+      << "Expected dex file to be at: " << GetDexSrc1();
+    ASSERT_TRUE(OS::FileExists(GetStrippedDexSrc1().c_str()))
+      << "Expected stripped dex file to be at: " << GetStrippedDexSrc1();
+    ASSERT_FALSE(DexFile::GetChecksum(GetStrippedDexSrc1().c_str(), &checksum, &error_msg))
+      << "Expected stripped dex file to be stripped: " << GetStrippedDexSrc1();
+    ASSERT_TRUE(OS::FileExists(GetDexSrc2().c_str()))
+      << "Expected dex file to be at: " << GetDexSrc2();
+
+    // GetMultiDexSrc2 should have the same primary dex checksum as
+    // GetMultiDexSrc1, but a different secondary dex checksum.
+    static constexpr bool kVerifyChecksum = true;
+    std::vector<std::unique_ptr<const DexFile>> multi1;
+    ASSERT_TRUE(DexFile::Open(GetMultiDexSrc1().c_str(),
+          GetMultiDexSrc1().c_str(), kVerifyChecksum, &error_msg, &multi1)) << error_msg;
+    ASSERT_GT(multi1.size(), 1u);
+
+    std::vector<std::unique_ptr<const DexFile>> multi2;
+    ASSERT_TRUE(DexFile::Open(GetMultiDexSrc2().c_str(),
+          GetMultiDexSrc2().c_str(), kVerifyChecksum, &error_msg, &multi2)) << error_msg;
+    ASSERT_GT(multi2.size(), 1u);
+
+    ASSERT_EQ(multi1[0]->GetLocationChecksum(), multi2[0]->GetLocationChecksum());
+    ASSERT_NE(multi1[1]->GetLocationChecksum(), multi2[1]->GetLocationChecksum());
+  }
+
+  virtual void SetUpRuntimeOptions(RuntimeOptions* options) OVERRIDE {
+    // options->push_back(std::make_pair("-verbose:oat", nullptr));
+
+    // Set up the image location.
+    options->push_back(std::make_pair("-Ximage:" + GetImageLocation(),
+          nullptr));
+    // Make sure compilercallbacks are not set so that relocation will be
+    // enabled.
+    callbacks_.reset();
+  }
+
+  virtual void TearDown() OVERRIDE {
+    ClearDirectory(odex_dir_.c_str());
+    ASSERT_EQ(0, rmdir(odex_dir_.c_str()));
+
+    ClearDirectory(odex_oat_dir_.c_str());
+    ASSERT_EQ(0, rmdir(odex_oat_dir_.c_str()));
+
+    ClearDirectory(scratch_dir_.c_str());
+    ASSERT_EQ(0, rmdir(scratch_dir_.c_str()));
+
+    CommonRuntimeTest::TearDown();
+  }
+
+  static void Copy(const std::string& src, const std::string& dst) {
+    std::ifstream  src_stream(src, std::ios::binary);
+    std::ofstream  dst_stream(dst, std::ios::binary);
+
+    dst_stream << src_stream.rdbuf();
+  }
+
+  // Returns the directory where the pre-compiled core.art can be found.
+  // TODO: We should factor out this into common tests somewhere rather than
+  // re-hardcoding it here (This was copied originally from the elf writer
+  // test).
+  std::string GetImageDirectory() const {
+    if (IsHost()) {
+      const char* host_dir = getenv("ANDROID_HOST_OUT");
+      CHECK(host_dir != nullptr);
+      return std::string(host_dir) + "/framework";
+    } else {
+      return std::string("/data/art-test");
+    }
+  }
+
+  std::string GetImageLocation() const {
+    return GetImageDirectory() + "/core.art";
+  }
+
+  std::string GetSystemImageFile() const {
+    return GetImageDirectory() + "/" + GetInstructionSetString(kRuntimeISA)
+      + "/core.art";
+  }
+
+  bool GetCachedImageFile(/*out*/std::string* image, std::string* error_msg) const {
+    std::string cache = GetDalvikCache(GetInstructionSetString(kRuntimeISA), true);
+    return GetDalvikCacheFilename(GetImageLocation().c_str(), cache.c_str(), image, error_msg);
+  }
+
+  std::string GetDexSrc1() const {
+    return GetTestDexFileName("Main");
+  }
+
+  // Returns the path to a dex file equivalent to GetDexSrc1, but with the dex
+  // file stripped.
+  std::string GetStrippedDexSrc1() const {
+    return GetTestDexFileName("MainStripped");
+  }
+
+  std::string GetMultiDexSrc1() const {
+    return GetTestDexFileName("MultiDex");
+  }
+
+  // Returns the path to a multidex file equivalent to GetMultiDexSrc2, but
+  // with the contents of the secondary dex file changed.
+  std::string GetMultiDexSrc2() const {
+    return GetTestDexFileName("MultiDexModifiedSecondary");
+  }
+
+  std::string GetDexSrc2() const {
+    return GetTestDexFileName("Nested");
+  }
+
+  // Scratch directory, for dex and odex files (oat files will go in the
+  // dalvik cache).
+  const std::string& GetScratchDir() const {
+    return scratch_dir_;
+  }
+
+  // Odex directory is the subdirectory in the scratch directory where odex
+  // files should be located.
+  const std::string& GetOdexDir() const {
+    return odex_dir_;
+  }
+
+ private:
+  std::string scratch_dir_;
+  std::string odex_oat_dir_;
+  std::string odex_dir_;
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_DEX2OAT_ENVIRONMENT_TEST_H_
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index e3cc77f..a1d3ed9 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#include "oat_file_assistant.h"
-
 #include <algorithm>
 #include <fstream>
 #include <string>
@@ -29,8 +27,10 @@
 #include "class_linker-inl.h"
 #include "common_runtime_test.h"
 #include "compiler_callbacks.h"
+#include "dex2oat_environment_test.h"
 #include "gc/space/image_space.h"
 #include "mem_map.h"
+#include "oat_file_assistant.h"
 #include "oat_file_manager.h"
 #include "os.h"
 #include "scoped_thread_state_change.h"
@@ -39,52 +39,11 @@
 
 namespace art {
 
-class OatFileAssistantTest : public CommonRuntimeTest {
+class OatFileAssistantTest : public Dex2oatEnvironmentTest {
  public:
-  virtual void SetUp() {
+  virtual void SetUp() OVERRIDE {
     ReserveImageSpace();
-    CommonRuntimeTest::SetUp();
-
-    // Create a scratch directory to work from.
-    scratch_dir_ = android_data_ + "/OatFileAssistantTest";
-    ASSERT_EQ(0, mkdir(scratch_dir_.c_str(), 0700));
-
-    // Create a subdirectory in scratch for odex files.
-    odex_oat_dir_ = scratch_dir_ + "/oat";
-    ASSERT_EQ(0, mkdir(odex_oat_dir_.c_str(), 0700));
-
-    odex_dir_ = odex_oat_dir_ + "/" + std::string(GetInstructionSetString(kRuntimeISA));
-    ASSERT_EQ(0, mkdir(odex_dir_.c_str(), 0700));
-
-    // Verify the environment is as we expect
-    uint32_t checksum;
-    std::string error_msg;
-    ASSERT_TRUE(OS::FileExists(GetSystemImageFile().c_str()))
-      << "Expected pre-compiled boot image to be at: " << GetSystemImageFile();
-    ASSERT_TRUE(OS::FileExists(GetDexSrc1().c_str()))
-      << "Expected dex file to be at: " << GetDexSrc1();
-    ASSERT_TRUE(OS::FileExists(GetStrippedDexSrc1().c_str()))
-      << "Expected stripped dex file to be at: " << GetStrippedDexSrc1();
-    ASSERT_FALSE(DexFile::GetChecksum(GetStrippedDexSrc1().c_str(), &checksum, &error_msg))
-      << "Expected stripped dex file to be stripped: " << GetStrippedDexSrc1();
-    ASSERT_TRUE(OS::FileExists(GetDexSrc2().c_str()))
-      << "Expected dex file to be at: " << GetDexSrc2();
-
-    // GetMultiDexSrc2 should have the same primary dex checksum as
-    // GetMultiDexSrc1, but a different secondary dex checksum.
-    static constexpr bool kVerifyChecksum = true;
-    std::vector<std::unique_ptr<const DexFile>> multi1;
-    ASSERT_TRUE(DexFile::Open(GetMultiDexSrc1().c_str(),
-          GetMultiDexSrc1().c_str(), kVerifyChecksum, &error_msg, &multi1)) << error_msg;
-    ASSERT_GT(multi1.size(), 1u);
-
-    std::vector<std::unique_ptr<const DexFile>> multi2;
-    ASSERT_TRUE(DexFile::Open(GetMultiDexSrc2().c_str(),
-          GetMultiDexSrc2().c_str(), kVerifyChecksum, &error_msg, &multi2)) << error_msg;
-    ASSERT_GT(multi2.size(), 1u);
-
-    ASSERT_EQ(multi1[0]->GetLocationChecksum(), multi2[0]->GetLocationChecksum());
-    ASSERT_NE(multi1[1]->GetLocationChecksum(), multi2[1]->GetLocationChecksum());
+    Dex2oatEnvironmentTest::SetUp();
   }
 
   // Pre-Relocate the image to a known non-zero offset so we don't have to
@@ -108,17 +67,6 @@
     return Exec(argv, error_msg);
   }
 
-  virtual void SetUpRuntimeOptions(RuntimeOptions* options) {
-    // options->push_back(std::make_pair("-verbose:oat", nullptr));
-
-    // Set up the image location.
-    options->push_back(std::make_pair("-Ximage:" + GetImageLocation(),
-          nullptr));
-    // Make sure compilercallbacks are not set so that relocation will be
-    // enabled.
-    callbacks_.reset();
-  }
-
   virtual void PreRuntimeCreate() {
     std::string error_msg;
     ASSERT_TRUE(PreRelocateImage(&error_msg)) << error_msg;
@@ -126,94 +74,10 @@
     UnreserveImageSpace();
   }
 
-  virtual void PostRuntimeCreate() {
+  virtual void PostRuntimeCreate() OVERRIDE {
     ReserveImageSpace();
   }
 
-  virtual void TearDown() {
-    ClearDirectory(odex_dir_.c_str());
-    ASSERT_EQ(0, rmdir(odex_dir_.c_str()));
-
-    ClearDirectory(odex_oat_dir_.c_str());
-    ASSERT_EQ(0, rmdir(odex_oat_dir_.c_str()));
-
-    ClearDirectory(scratch_dir_.c_str());
-    ASSERT_EQ(0, rmdir(scratch_dir_.c_str()));
-
-    CommonRuntimeTest::TearDown();
-  }
-
-  void Copy(std::string src, std::string dst) {
-    std::ifstream  src_stream(src, std::ios::binary);
-    std::ofstream  dst_stream(dst, std::ios::binary);
-
-    dst_stream << src_stream.rdbuf();
-  }
-
-  // Returns the directory where the pre-compiled core.art can be found.
-  // TODO: We should factor out this into common tests somewhere rather than
-  // re-hardcoding it here (This was copied originally from the elf writer
-  // test).
-  std::string GetImageDirectory() {
-    if (IsHost()) {
-      const char* host_dir = getenv("ANDROID_HOST_OUT");
-      CHECK(host_dir != nullptr);
-      return std::string(host_dir) + "/framework";
-    } else {
-      return std::string("/data/art-test");
-    }
-  }
-
-  std::string GetImageLocation() {
-    return GetImageDirectory() + "/core.art";
-  }
-
-  std::string GetSystemImageFile() {
-    return GetImageDirectory() + "/" + GetInstructionSetString(kRuntimeISA)
-      + "/core.art";
-  }
-
-  bool GetCachedImageFile(/*out*/std::string* image, std::string* error_msg) {
-    std::string cache = GetDalvikCache(GetInstructionSetString(kRuntimeISA), true);
-    return GetDalvikCacheFilename(GetImageLocation().c_str(), cache.c_str(), image, error_msg);
-  }
-
-  std::string GetDexSrc1() {
-    return GetTestDexFileName("Main");
-  }
-
-  // Returns the path to a dex file equivalent to GetDexSrc1, but with the dex
-  // file stripped.
-  std::string GetStrippedDexSrc1() {
-    return GetTestDexFileName("MainStripped");
-  }
-
-  std::string GetMultiDexSrc1() {
-    return GetTestDexFileName("MultiDex");
-  }
-
-  // Returns the path to a multidex file equivalent to GetMultiDexSrc2, but
-  // with the contents of the secondary dex file changed.
-  std::string GetMultiDexSrc2() {
-    return GetTestDexFileName("MultiDexModifiedSecondary");
-  }
-
-  std::string GetDexSrc2() {
-    return GetTestDexFileName("Nested");
-  }
-
-  // Scratch directory, for dex and odex files (oat files will go in the
-  // dalvik cache).
-  std::string GetScratchDir() {
-    return scratch_dir_;
-  }
-
-  // Odex directory is the subdirectory in the scratch directory where odex
-  // files should be located.
-  std::string GetOdexDir() {
-    return odex_dir_;
-  }
-
   // Generate a non-PIC odex file for the purposes of test.
   // The generated odex file will be un-relocated.
   void GenerateOdexForTest(const std::string& dex_location,
@@ -334,9 +198,6 @@
     image_reservation_.clear();
   }
 
-  std::string scratch_dir_;
-  std::string odex_oat_dir_;
-  std::string odex_dir_;
   std::vector<std::unique_ptr<MemMap>> image_reservation_;
 };
 
diff --git a/runtime/thread-inl.h b/runtime/thread-inl.h
index d98f82a..3fd66a7 100644
--- a/runtime/thread-inl.h
+++ b/runtime/thread-inl.h
@@ -201,12 +201,22 @@
                  << " state=" << old_state_and_flags.as_struct.state;
     } else if ((old_state_and_flags.as_struct.flags & kSuspendRequest) != 0) {
       // Wait while our suspend count is non-zero.
-      MutexLock mu(this, *Locks::thread_suspend_count_lock_);
+
+      // We pass null to the MutexLock as we may be in a situation where the
+      // runtime is shutting down. Guarding ourselves from that situation
+      // requires to take the shutdown lock, which is undesirable here.
+      Thread* thread_to_pass = nullptr;
+      if (kIsDebugBuild && !IsDaemon()) {
+        // We know we can make our debug locking checks on non-daemon threads,
+        // so re-enable them on debug builds.
+        thread_to_pass = this;
+      }
+      MutexLock mu(thread_to_pass, *Locks::thread_suspend_count_lock_);
       old_state_and_flags.as_int = tls32_.state_and_flags.as_int;
       DCHECK_EQ(old_state_and_flags.as_struct.state, old_state);
       while ((old_state_and_flags.as_struct.flags & kSuspendRequest) != 0) {
         // Re-check when Thread::resume_cond_ is notified.
-        Thread::resume_cond_->Wait(this);
+        Thread::resume_cond_->Wait(thread_to_pass);
         old_state_and_flags.as_int = tls32_.state_and_flags.as_int;
         DCHECK_EQ(old_state_and_flags.as_struct.state, old_state);
       }