Use instruction specific dalvik cache dirs.

- All oat & art files are now placed under /data/dalvik-cache/<isa>/.
- GetDalvikCacheOrDie now requires a mandatory subdirectory argument,
  and is implicitly rooted under /data/.
- Added helper methods to convert InstructionSet enums into strings
  and vice versa.

(cherry picked from commit 2974bc3d8a5d161d449dd66826d668d87bdc3cbe)

Change-Id: Ic7986938e6a7091a2af675ebafec768f7b5fb8cd
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index f25217f..429c523 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -49,6 +49,7 @@
 	runtime/gtest_test.cc \
 	runtime/indenter_test.cc \
 	runtime/indirect_reference_table_test.cc \
+	runtime/instruction_set_test.cc \
 	runtime/intern_table_test.cc \
 	runtime/leb128_test.cc \
 	runtime/mem_map_test.cc \
diff --git a/compiler/llvm/llvm_compilation_unit.cc b/compiler/llvm/llvm_compilation_unit.cc
index fe60959..78bdb4d 100644
--- a/compiler/llvm/llvm_compilation_unit.cc
+++ b/compiler/llvm/llvm_compilation_unit.cc
@@ -143,7 +143,7 @@
 
 static std::string DumpDirectory() {
   if (kIsTargetBuild) {
-    return GetDalvikCacheOrDie(GetAndroidData());
+    return GetDalvikCacheOrDie("llvm-dump");
   }
   return "/tmp";
 }
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index d3e56da..823b818 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1101,6 +1101,9 @@
   DexFileToMethodInlinerMap method_inliner_map;
   CompilerCallbacksImpl callbacks(&verification_results, &method_inliner_map);
   runtime_options.push_back(std::make_pair("compilercallbacks", &callbacks));
+  runtime_options.push_back(
+      std::make_pair("imageinstructionset",
+                     reinterpret_cast<const void*>(GetInstructionSetString(instruction_set))));
 
   Dex2Oat* p_dex2oat;
   if (!Dex2Oat::Create(&p_dex2oat,
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 583e5e5..c9e3c11 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -919,7 +919,9 @@
   }
 
   std::string cache_error_msg;
-  std::string cache_location(GetDalvikCacheFilenameOrDie(dex_location));
+  const std::string dalvik_cache(GetDalvikCacheOrDie(GetInstructionSetString(kRuntimeISA)));
+  std::string cache_location(GetDalvikCacheFilenameOrDie(dex_location,
+                                                         dalvik_cache.c_str()));
   dex_file = VerifyAndOpenDexFileFromOatFile(cache_location, dex_location, &cache_error_msg,
                                              &open_failed);
   if (dex_file != nullptr) {
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 4d074f1..50ef7a6 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -89,7 +89,7 @@
 
 Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max_free,
            double target_utilization, double foreground_heap_growth_multiplier, size_t capacity,
-           const std::string& image_file_name,
+           const std::string& image_file_name, const InstructionSet image_instruction_set,
            CollectorType foreground_collector_type, CollectorType background_collector_type,
            size_t parallel_gc_threads, size_t conc_gc_threads, bool low_memory_mode,
            size_t long_pause_log_threshold, size_t long_gc_log_threshold,
@@ -186,7 +186,8 @@
   // Requested begin for the alloc space, to follow the mapped image and oat files
   byte* requested_alloc_space_begin = nullptr;
   if (!image_file_name.empty()) {
-    space::ImageSpace* image_space = space::ImageSpace::Create(image_file_name.c_str());
+    space::ImageSpace* image_space = space::ImageSpace::Create(image_file_name.c_str(),
+                                                               image_instruction_set);
     CHECK(image_space != nullptr) << "Failed to create space for " << image_file_name;
     AddSpace(image_space);
     // Oat files referenced by image files immediately follow them in memory, ensure alloc space
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index c631372..5533f3d 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -31,6 +31,7 @@
 #include "gc/collector_type.h"
 #include "globals.h"
 #include "gtest/gtest.h"
+#include "instruction_set.h"
 #include "jni.h"
 #include "object_callbacks.h"
 #include "offsets.h"
@@ -140,6 +141,7 @@
                 size_t max_free, double target_utilization,
                 double foreground_heap_growth_multiplier, size_t capacity,
                 const std::string& original_image_file_name,
+                const InstructionSet image_instruction_set,
                 CollectorType foreground_collector_type, CollectorType background_collector_type,
                 size_t parallel_gc_threads, size_t conc_gc_threads, bool low_memory_mode,
                 size_t long_pause_threshold, size_t long_gc_threshold,
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 91d8820..3de1ba4 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -24,7 +24,6 @@
 #include "mirror/object-inl.h"
 #include "oat_file.h"
 #include "os.h"
-#include "runtime.h"
 #include "space-inl.h"
 #include "utils.h"
 
@@ -99,7 +98,8 @@
   return Exec(arg_vector, error_msg);
 }
 
-ImageSpace* ImageSpace::Create(const char* original_image_file_name) {
+ImageSpace* ImageSpace::Create(const char* original_image_file_name,
+                               const InstructionSet image_isa) {
   if (OS::FileExists(original_image_file_name)) {
     // If the /system file exists, it should be up-to-date, don't try to generate
     std::string error_msg;
@@ -112,7 +112,9 @@
   // If the /system file didn't exist, we need to use one from the dalvik-cache.
   // If the cache file exists, try to open, but if it fails, regenerate.
   // If it does not exist, generate.
-  std::string image_file_name(GetDalvikCacheFilenameOrDie(original_image_file_name));
+  const std::string dalvik_cache = GetDalvikCacheOrDie(GetInstructionSetString(image_isa));
+  std::string image_file_name(GetDalvikCacheFilenameOrDie(original_image_file_name,
+                                                          dalvik_cache.c_str()));
   std::string error_msg;
   if (OS::FileExists(image_file_name.c_str())) {
     space::ImageSpace* image_space = ImageSpace::Init(image_file_name.c_str(), true, &error_msg);
diff --git a/runtime/gc/space/image_space.h b/runtime/gc/space/image_space.h
index f6daf89..1652ec9 100644
--- a/runtime/gc/space/image_space.h
+++ b/runtime/gc/space/image_space.h
@@ -18,6 +18,7 @@
 #define ART_RUNTIME_GC_SPACE_IMAGE_SPACE_H_
 
 #include "gc/accounting/space_bitmap.h"
+#include "runtime.h"
 #include "space.h"
 
 namespace art {
@@ -34,15 +35,16 @@
     return kSpaceTypeImageSpace;
   }
 
-  // Create a Space from an image file. Cannot be used for future
-  // allocation or collected.
+  // Create a Space from an image file for a specified instruction
+  // set. Cannot be used for future allocation or collected.
   //
   // Create also opens the OatFile associated with the image file so
   // that it be contiguously allocated with the image before the
   // creation of the alloc space. The ReleaseOatFile will later be
   // used to transfer ownership of the OatFile to the ClassLinker when
   // it is initialized.
-  static ImageSpace* Create(const char* image) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static ImageSpace* Create(const char* image, const InstructionSet image_isa)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Releases the OatFile from the ImageSpace so it can be transfer to
   // the caller, presumably the ClassLinker.
diff --git a/runtime/instruction_set.cc b/runtime/instruction_set.cc
index 73d4279..cbcd2e0 100644
--- a/runtime/instruction_set.cc
+++ b/runtime/instruction_set.cc
@@ -21,6 +21,48 @@
 
 namespace art {
 
+const char* GetInstructionSetString(const InstructionSet isa) {
+  switch (isa) {
+    case kArm:
+    case kThumb2:
+      return "arm";
+    case kArm64:
+      return "arm64";
+    case kX86:
+      return "x86";
+    case kX86_64:
+      return "x86_64";
+    case kMips:
+      return "mips";
+    case kNone:
+      return "none";
+    default:
+      LOG(FATAL) << "Unknown ISA " << isa;
+      return nullptr;
+  }
+}
+
+InstructionSet GetInstructionSetFromString(const char* isa_str) {
+  CHECK(isa_str != nullptr);
+
+  if (!strcmp("arm", isa_str)) {
+    return kArm;
+  } else if (!strcmp("arm64", isa_str)) {
+    return kArm64;
+  } else if (!strcmp("x86", isa_str)) {
+    return kX86;
+  } else if (!strcmp("x86_64", isa_str)) {
+    return kX86_64;
+  } else if (!strcmp("mips", isa_str)) {
+    return kMips;
+  } else if (!strcmp("none", isa_str)) {
+    return kNone;
+  }
+
+  LOG(FATAL) << "Unknown ISA " << isa_str;
+  return kNone;
+}
+
 size_t GetInstructionSetPointerSize(InstructionSet isa) {
   switch (isa) {
     case kArm:
diff --git a/runtime/instruction_set.h b/runtime/instruction_set.h
index c746e06..4bc35a7 100644
--- a/runtime/instruction_set.h
+++ b/runtime/instruction_set.h
@@ -35,6 +35,9 @@
 };
 std::ostream& operator<<(std::ostream& os, const InstructionSet& rhs);
 
+const char* GetInstructionSetString(const InstructionSet isa);
+InstructionSet GetInstructionSetFromString(const char* instruction_set);
+
 size_t GetInstructionSetPointerSize(InstructionSet isa);
 size_t GetInstructionSetAlignment(InstructionSet isa);
 bool Is64BitInstructionSet(InstructionSet isa);
diff --git a/runtime/instruction_set_test.cc b/runtime/instruction_set_test.cc
new file mode 100644
index 0000000..cd6337c
--- /dev/null
+++ b/runtime/instruction_set_test.cc
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#include "instruction_set.h"
+
+#include "common_runtime_test.h"
+
+namespace art {
+
+class InstructionSetTest : public CommonRuntimeTest {};
+
+TEST_F(InstructionSetTest, GetInstructionSetFromString) {
+  EXPECT_EQ(kArm, GetInstructionSetFromString("arm"));
+  EXPECT_EQ(kArm64, GetInstructionSetFromString("arm64"));
+  EXPECT_EQ(kX86, GetInstructionSetFromString("x86"));
+  EXPECT_EQ(kX86_64, GetInstructionSetFromString("x86_64"));
+  EXPECT_EQ(kMips, GetInstructionSetFromString("mips"));
+  EXPECT_EQ(kNone, GetInstructionSetFromString("none"));
+}
+
+TEST_F(InstructionSetTest, GetInstructionSetString) {
+  EXPECT_STREQ("arm", GetInstructionSetString(kArm));
+  EXPECT_STREQ("arm", GetInstructionSetString(kThumb2));
+  EXPECT_STREQ("arm64", GetInstructionSetString(kArm64));
+  EXPECT_STREQ("x86", GetInstructionSetString(kX86));
+  EXPECT_STREQ("x86_64", GetInstructionSetString(kX86_64));
+  EXPECT_STREQ("mips", GetInstructionSetString(kMips));
+  EXPECT_STREQ("none", GetInstructionSetString(kNone));
+}
+
+TEST_F(InstructionSetTest, TestRoundTrip) {
+  EXPECT_EQ(kRuntimeISA, GetInstructionSetFromString(GetInstructionSetString(kRuntimeISA)));
+}
+
+}  // namespace art
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index 953d3a6..d9c1309 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -260,16 +260,15 @@
 #endif
 }
 
-static jboolean DexFile_isDexOptNeededInternal(JNIEnv* env, jclass, jstring javaFilename,
-    jstring javaPkgname, jboolean defer) {
+static jboolean IsDexOptNeededInternal(JNIEnv* env, const char* filename,
+    const char* pkgname, const char* instruction_set, const jboolean defer) {
   const bool kVerboseLogging = false;  // Spammy logging.
   const bool kReasonLogging = true;  // Logging of reason for returning JNI_TRUE.
 
-  ScopedUtfChars filename(env, javaFilename);
-  if ((filename.c_str() == nullptr) || !OS::FileExists(filename.c_str())) {
-    LOG(ERROR) << "DexFile_isDexOptNeeded file '" << filename.c_str() << "' does not exist";
+  if ((filename == nullptr) || !OS::FileExists(filename)) {
+    LOG(ERROR) << "DexFile_isDexOptNeeded file '" << filename << "' does not exist";
     ScopedLocalRef<jclass> fnfe(env, env->FindClass("java/io/FileNotFoundException"));
-    const char* message = (filename.c_str() == nullptr) ? "<empty file name>" : filename.c_str();
+    const char* message = (filename == nullptr) ? "<empty file name>" : filename;
     env->ThrowNew(fnfe.get(), message);
     return JNI_FALSE;
   }
@@ -278,11 +277,14 @@
   // fact that code is running at all means that this should be true.
   Runtime* runtime = Runtime::Current();
   ClassLinker* class_linker = runtime->GetClassLinker();
+  // TODO: We're assuming that the 64 and 32 bit runtimes have identical
+  // class paths. isDexOptNeeded will not necessarily be called on a runtime
+  // that has the same instruction set as the file being dexopted.
   const std::vector<const DexFile*>& boot_class_path = class_linker->GetBootClassPath();
   for (size_t i = 0; i < boot_class_path.size(); i++) {
-    if (boot_class_path[i]->GetLocation() == filename.c_str()) {
+    if (boot_class_path[i]->GetLocation() == filename) {
       if (kVerboseLogging) {
-        LOG(INFO) << "DexFile_isDexOptNeeded ignoring boot class path file: " << filename.c_str();
+        LOG(INFO) << "DexFile_isDexOptNeeded ignoring boot class path file: " << filename;
       }
       return JNI_FALSE;
     }
@@ -293,12 +295,11 @@
   // If the 'defer' argument is true then this will be retried later.  In this case we
   // need to make sure that the profile file copy is not made so that we will get the
   // same result second time.
-  if (javaPkgname != NULL) {
-    ScopedUtfChars pkgname(env, javaPkgname);
-    std::string profile_file = GetDalvikCacheOrDie(GetAndroidData()) + std::string("/profiles/") +
-    pkgname.c_str();
-
-    std::string profile_cache_dir = GetDalvikCacheOrDie(GetAndroidData()) + "/profile-cache";
+  if (pkgname != nullptr) {
+    const std::string profile_file = GetDalvikCacheOrDie("profiles", false /* create_if_absent */)
+        + std::string("/") + pkgname;
+    const std::string profile_cache_dir = GetDalvikCacheOrDie("profile-cache",
+                                                              false /* create_if_absent */);
 
     // Make the profile cache if it doesn't exist.
     mkdir(profile_cache_dir.c_str(), 0700);
@@ -306,7 +307,7 @@
     // The previous profile file (a copy of the profile the last time this was run) is
     // in the dalvik-cache directory because this is owned by system.  The profiles
     // directory is owned by install so system cannot write files in there.
-    std::string prev_profile_file = profile_cache_dir + std::string("/") + pkgname.c_str();
+    std::string prev_profile_file = profile_cache_dir + std::string("/") + pkgname;
 
     struct stat profstat, prevstat;
     int e1 = stat(profile_file.c_str(), &profstat);
@@ -377,41 +378,41 @@
   }
 
   // Check if we have an odex file next to the dex file.
-  std::string odex_filename(OatFile::DexFilenameToOdexFilename(filename.c_str()));
+  std::string odex_filename(OatFile::DexFilenameToOdexFilename(filename));
   std::string error_msg;
   UniquePtr<const OatFile> oat_file(OatFile::Open(odex_filename, odex_filename, NULL, false,
                                                   &error_msg));
   if (oat_file.get() == nullptr) {
     if (kVerboseLogging) {
-      LOG(INFO) << "DexFile_isDexOptNeeded failed to open oat file '" << filename.c_str()
+      LOG(INFO) << "DexFile_isDexOptNeeded failed to open oat file '" << filename
           << "': " << error_msg;
     }
     error_msg.clear();
   } else {
-    const art::OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(filename.c_str(), NULL,
+    const art::OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(filename, NULL,
                                                                            kReasonLogging);
     if (oat_dex_file != nullptr) {
       uint32_t location_checksum;
       // If its not possible to read the classes.dex assume up-to-date as we won't be able to
       // compile it anyway.
-      if (!DexFile::GetChecksum(filename.c_str(), &location_checksum, &error_msg)) {
+      if (!DexFile::GetChecksum(filename, &location_checksum, &error_msg)) {
         if (kVerboseLogging) {
           LOG(INFO) << "DexFile_isDexOptNeeded ignoring precompiled stripped file: "
-              << filename.c_str() << ": " << error_msg;
+              << filename << ": " << error_msg;
         }
         return JNI_FALSE;
       }
-      if (ClassLinker::VerifyOatFileChecksums(oat_file.get(), filename.c_str(), location_checksum,
+      if (ClassLinker::VerifyOatFileChecksums(oat_file.get(), filename, location_checksum,
                                               &error_msg)) {
         if (kVerboseLogging) {
           LOG(INFO) << "DexFile_isDexOptNeeded precompiled file " << odex_filename
-              << " has an up-to-date checksum compared to " << filename.c_str();
+              << " has an up-to-date checksum compared to " << filename;
         }
         return JNI_FALSE;
       } else {
         if (kVerboseLogging) {
           LOG(INFO) << "DexFile_isDexOptNeeded found precompiled file " << odex_filename
-              << " with an out-of-date checksum compared to " << filename.c_str()
+              << " with an out-of-date checksum compared to " << filename
               << ": " << error_msg;
         }
         error_msg.clear();
@@ -420,12 +421,14 @@
   }
 
   // Check if we have an oat file in the cache
-  std::string cache_location(GetDalvikCacheFilenameOrDie(filename.c_str()));
-  oat_file.reset(OatFile::Open(cache_location, filename.c_str(), NULL, false, &error_msg));
+  const std::string cache_dir(GetDalvikCacheOrDie(instruction_set));
+  const std::string cache_location(
+      GetDalvikCacheFilenameOrDie(filename, cache_dir.c_str()));
+  oat_file.reset(OatFile::Open(cache_location, filename, NULL, false, &error_msg));
   if (oat_file.get() == nullptr) {
     if (kReasonLogging) {
       LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
-          << " does not exist for " << filename.c_str() << ": " << error_msg;
+          << " does not exist for " << filename << ": " << error_msg;
     }
     return JNI_TRUE;
   }
@@ -458,19 +461,19 @@
   }
 
   uint32_t location_checksum;
-  if (!DexFile::GetChecksum(filename.c_str(), &location_checksum, &error_msg)) {
+  if (!DexFile::GetChecksum(filename, &location_checksum, &error_msg)) {
     if (kReasonLogging) {
-      LOG(ERROR) << "DexFile_isDexOptNeeded failed to compute checksum of " << filename.c_str()
+      LOG(ERROR) << "DexFile_isDexOptNeeded failed to compute checksum of " << filename
             << " (error " << error_msg << ")";
     }
     return JNI_TRUE;
   }
 
-  if (!ClassLinker::VerifyOatFileChecksums(oat_file.get(), filename.c_str(), location_checksum,
+  if (!ClassLinker::VerifyOatFileChecksums(oat_file.get(), filename, location_checksum,
                                            &error_msg)) {
     if (kReasonLogging) {
       LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
-          << " has out-of-date checksum compared to " << filename.c_str()
+          << " has out-of-date checksum compared to " << filename
           << " (error " << error_msg << ")";
     }
     return JNI_TRUE;
@@ -478,15 +481,28 @@
 
   if (kVerboseLogging) {
     LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
-              << " is up-to-date for " << filename.c_str();
+              << " is up-to-date for " << filename;
   }
   CHECK(error_msg.empty()) << error_msg;
   return JNI_FALSE;
 }
 
+static jboolean DexFile_isDexOptNeededInternal(JNIEnv* env, jclass, jstring javaFilename,
+    jstring javaPkgname, jstring javaInstructionSet, jboolean defer) {
+  ScopedUtfChars filename(env, javaFilename);
+  NullableScopedUtfChars pkgname(env, javaPkgname);
+  ScopedUtfChars instruction_set(env, javaInstructionSet);
+
+  return IsDexOptNeededInternal(env, filename.c_str(), pkgname.c_str(),
+                                instruction_set.c_str(), defer);
+}
+
 // public API, NULL pkgname
-static jboolean DexFile_isDexOptNeeded(JNIEnv* env, jclass c, jstring javaFilename) {
-  return DexFile_isDexOptNeededInternal(env, c, javaFilename, NULL, false);
+static jboolean DexFile_isDexOptNeeded(JNIEnv* env, jclass, jstring javaFilename) {
+  const char* instruction_set = GetInstructionSetString(kRuntimeISA);
+  ScopedUtfChars filename(env, javaFilename);
+  return IsDexOptNeededInternal(env, filename.c_str(), nullptr /* pkgname */,
+                                instruction_set, false /* defer */);
 }
 
 
@@ -495,7 +511,7 @@
   NATIVE_METHOD(DexFile, defineClassNative, "(Ljava/lang/String;Ljava/lang/ClassLoader;J)Ljava/lang/Class;"),
   NATIVE_METHOD(DexFile, getClassNameList, "(J)[Ljava/lang/String;"),
   NATIVE_METHOD(DexFile, isDexOptNeeded, "(Ljava/lang/String;)Z"),
-  NATIVE_METHOD(DexFile, isDexOptNeededInternal, "(Ljava/lang/String;Ljava/lang/String;Z)Z"),
+  NATIVE_METHOD(DexFile, isDexOptNeededInternal, "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)Z"),
   NATIVE_METHOD(DexFile, openDexFileNative, "(Ljava/lang/String;Ljava/lang/String;I)J"),
 };
 
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index c0dc94b..9cf8785 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -246,6 +246,7 @@
   profile_clock_source_ = kDefaultProfilerClockSource;
 
   verify_ = true;
+  image_isa_ = kRuntimeISA;
 
   // Default to explicit checks.  Switch off with -implicit-checks:.
   // or setprop dalvik.vm.implicit_checks check1,check2,...
@@ -412,6 +413,9 @@
     } else if (option == "compilercallbacks") {
       compiler_callbacks_ =
           reinterpret_cast<CompilerCallbacks*>(const_cast<void*>(options[i].second));
+    } else if (option == "imageinstructionset") {
+      image_isa_ = GetInstructionSetFromString(
+          reinterpret_cast<const char*>(options[i].second));
     } else if (option == "-Xzygote") {
       is_zygote_ = true;
     } else if (option == "-Xint") {
@@ -673,7 +677,7 @@
     background_collector_type_ = collector_type_;
   }
   return true;
-}
+}  // NOLINT(readability/fn_size)
 
 void ParsedOptions::Exit(int status) {
   hook_exit_(status);
diff --git a/runtime/parsed_options.h b/runtime/parsed_options.h
index c02eb1d..e0b0fb5 100644
--- a/runtime/parsed_options.h
+++ b/runtime/parsed_options.h
@@ -85,6 +85,7 @@
   bool profile_start_immediately_;
   ProfilerClockSource profile_clock_source_;
   bool verify_;
+  InstructionSet image_isa_;
 
   static constexpr uint32_t kExplicitNullCheck = 1;
   static constexpr uint32_t kExplicitSuspendCheck = 2;
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 6bbfcee..20df78e 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -567,6 +567,7 @@
                        options->foreground_heap_growth_multiplier_,
                        options->heap_maximum_size_,
                        options->image_,
+                       options->image_isa_,
                        options->collector_type_,
                        options->background_collector_type_,
                        options->parallel_gc_threads_,
diff --git a/runtime/utils.cc b/runtime/utils.cc
index c4d1a78..a0ecb41 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -1167,14 +1167,20 @@
   return android_data;
 }
 
-std::string GetDalvikCacheOrDie(const char* android_data) {
-  std::string dalvik_cache(StringPrintf("%s/dalvik-cache", android_data));
-
-  if (!OS::DirectoryExists(dalvik_cache.c_str())) {
-    if (StartsWith(dalvik_cache, "/tmp/")) {
-      int result = mkdir(dalvik_cache.c_str(), 0700);
+std::string GetDalvikCacheOrDie(const char* subdir, const bool create_if_absent) {
+  CHECK(subdir != nullptr);
+  const std::string dalvik_cache_root(StringPrintf("%s/dalvik-cache/", GetAndroidData()));
+  const std::string dalvik_cache = dalvik_cache_root + subdir;
+  if (create_if_absent && !OS::DirectoryExists(dalvik_cache.c_str())) {
+    if (StartsWith(dalvik_cache_root, "/tmp/")) {
+      int result = mkdir(dalvik_cache_root.c_str(), 0700);
       if (result != 0) {
-        LOG(FATAL) << "Failed to create dalvik-cache directory " << dalvik_cache;
+        PLOG(FATAL) << "Failed to create dalvik-cache directory " << dalvik_cache_root;
+        return "";
+      }
+      result = mkdir(dalvik_cache.c_str(), 0700);
+      if (result != 0) {
+        PLOG(FATAL) << "Failed to create dalvik-cache directory " << dalvik_cache;
         return "";
       }
     } else {
@@ -1185,8 +1191,7 @@
   return dalvik_cache;
 }
 
-std::string GetDalvikCacheFilenameOrDie(const char* location) {
-  std::string dalvik_cache(GetDalvikCacheOrDie(GetAndroidData()));
+std::string GetDalvikCacheFilenameOrDie(const char* location, const char* cache_location) {
   if (location[0] != '/') {
     LOG(FATAL) << "Expected path in location to be absolute: "<< location;
   }
@@ -1196,7 +1201,7 @@
     cache_file += DexFile::kClassesDex;
   }
   std::replace(cache_file.begin(), cache_file.end(), '/', '@');
-  return dalvik_cache + "/" + cache_file;
+  return StringPrintf("%s/%s", cache_location, cache_file.c_str());
 }
 
 bool IsZipMagic(uint32_t magic) {
diff --git a/runtime/utils.h b/runtime/utils.h
index 6ab1013..4b2f230 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -394,11 +394,14 @@
 // Find $ANDROID_DATA, /data, or abort.
 const char* GetAndroidData();
 
-// Returns the dalvik-cache location, or dies trying.
-std::string GetDalvikCacheOrDie(const char* android_data);
+// Returns the dalvik-cache location, or dies trying. subdir will be
+// appended to the cache location.
+std::string GetDalvikCacheOrDie(const char* subdir, bool create_if_absent = true);
 
-// Returns the dalvik-cache location for a DexFile or OatFile, or dies trying.
-std::string GetDalvikCacheFilenameOrDie(const char* location);
+// Returns the absolute dalvik-cache path for a DexFile or OatFile, or
+// dies trying. The path returned will be rooted at cache_location.
+std::string GetDalvikCacheFilenameOrDie(const char* file_location,
+                                        const char* cache_location);
 
 // Check whether the given magic matches a known file type.
 bool IsZipMagic(uint32_t magic);
diff --git a/runtime/utils_test.cc b/runtime/utils_test.cc
index 2c1aae8..d425620 100644
--- a/runtime/utils_test.cc
+++ b/runtime/utils_test.cc
@@ -338,18 +338,16 @@
   EXPECT_FALSE(EndsWith("oo", "foo"));
 }
 
-void CheckGetDalvikCacheFilenameOrDie(const char* in, const char* out) {
-  std::string expected(getenv("ANDROID_DATA"));
-  expected += "/dalvik-cache/";
-  expected += out;
-  EXPECT_STREQ(expected.c_str(), GetDalvikCacheFilenameOrDie(in).c_str());
-}
-
 TEST_F(UtilsTest, GetDalvikCacheFilenameOrDie) {
-  CheckGetDalvikCacheFilenameOrDie("/system/app/Foo.apk", "system@app@Foo.apk@classes.dex");
-  CheckGetDalvikCacheFilenameOrDie("/data/app/foo-1.apk", "data@app@foo-1.apk@classes.dex");
-  CheckGetDalvikCacheFilenameOrDie("/system/framework/core.jar", "system@framework@core.jar@classes.dex");
-  CheckGetDalvikCacheFilenameOrDie("/system/framework/boot.art", "system@framework@boot.art");
+  EXPECT_STREQ("/foo/system@app@Foo.apk@classes.dex",
+               GetDalvikCacheFilenameOrDie("/system/app/Foo.apk", "/foo").c_str());
+
+  EXPECT_STREQ("/foo/data@app@foo-1.apk@classes.dex",
+               GetDalvikCacheFilenameOrDie("/data/app/foo-1.apk", "/foo").c_str());
+  EXPECT_STREQ("/foo/system@framework@core.jar@classes.dex",
+               GetDalvikCacheFilenameOrDie("/system/framework/core.jar", "/foo").c_str());
+  EXPECT_STREQ("/foo/system@framework@boot.art",
+               GetDalvikCacheFilenameOrDie("/system/framework/boot.art", "/foo").c_str());
 }
 
 TEST_F(UtilsTest, ExecSuccess) {