Merge "Delete pin table" into lmp-dev
diff --git a/compiler/elf_patcher.cc b/compiler/elf_patcher.cc
index 137110f..ea4517f 100644
--- a/compiler/elf_patcher.cc
+++ b/compiler/elf_patcher.cc
@@ -197,7 +197,8 @@
     mirror::ArtMethod* target = GetTargetMethod(patch);
     uintptr_t quick_code = reinterpret_cast<uintptr_t>(class_linker->GetQuickOatCodeFor(target));
     DCHECK_NE(quick_code, 0U) << PrettyMethod(target);
-    const OatFile* target_oat = class_linker->FindOpenedOatFileForDexFile(*patch->GetTargetDexFile());
+    const OatFile* target_oat =
+        class_linker->FindOpenedOatDexFileForDexFile(*patch->GetTargetDexFile())->GetOatFile();
     // Get where the data actually starts. if target is this oat_file_ it is oat_data_start_,
     // otherwise it is wherever target_oat is loaded.
     uintptr_t oat_data_addr = GetBaseAddressFor(target_oat);
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 26f32f9..ed5c843 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -676,18 +676,18 @@
   return *oat_file;
 }
 
-const OatFile* ClassLinker::FindOpenedOatFileForDexFile(const DexFile& dex_file) {
+const OatFile::OatDexFile* ClassLinker::FindOpenedOatDexFileForDexFile(const DexFile& dex_file) {
   const char* dex_location = dex_file.GetLocation().c_str();
   uint32_t dex_location_checksum = dex_file.GetLocationChecksum();
-  return FindOpenedOatFile(nullptr, dex_location, &dex_location_checksum);
+  return FindOpenedOatDexFile(nullptr, dex_location, &dex_location_checksum);
 }
 
-const OatFile* ClassLinker::FindOpenedOatFile(const char* oat_location, const char* dex_location,
-                                              const uint32_t* const dex_location_checksum) {
+const OatFile::OatDexFile* ClassLinker::FindOpenedOatDexFile(const char* oat_location,
+                                                             const char* dex_location,
+                                                             const uint32_t* dex_location_checksum) {
   ReaderMutexLock mu(Thread::Current(), dex_lock_);
-  for (size_t i = 0; i < oat_files_.size(); i++) {
-    const OatFile* oat_file = oat_files_[i];
-    DCHECK(oat_file != NULL);
+  for (const OatFile* oat_file : oat_files_) {
+    DCHECK(oat_file != nullptr);
 
     if (oat_location != nullptr) {
       if (oat_file->GetLocation() != oat_location) {
@@ -698,11 +698,11 @@
     const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location,
                                                                       dex_location_checksum,
                                                                       false);
-    if (oat_dex_file != NULL) {
-      return oat_file;
+    if (oat_dex_file != nullptr) {
+      return oat_dex_file;
     }
   }
-  return NULL;
+  return nullptr;
 }
 
 
@@ -824,8 +824,10 @@
 
   bool needs_registering = false;
 
-  std::unique_ptr<const OatFile> open_oat_file(FindOpenedOatFile(oat_location, dex_location,
-                                                                 dex_location_checksum_pointer));
+  const OatFile::OatDexFile* oat_dex_file = FindOpenedOatDexFile(oat_location, dex_location,
+                                                                 dex_location_checksum_pointer);
+  std::unique_ptr<const OatFile> open_oat_file(
+      oat_dex_file != nullptr ? oat_dex_file->GetOatFile() : nullptr);
 
   // 2) If we do not have an open one, maybe there's one on disk already.
 
@@ -946,7 +948,8 @@
   }
 
   // Try to load again, but stronger checks.
-  success = LoadMultiDexFilesFromOatFile(open_oat_file.get(), dex_location, dex_location_checksum_pointer,
+  success = LoadMultiDexFilesFromOatFile(open_oat_file.get(), dex_location,
+                                         dex_location_checksum_pointer,
                                          true, error_msgs, dex_files);
   if (success) {
     RegisterOatFile(open_oat_file.release());
@@ -1121,12 +1124,11 @@
   if (oat_dex_file == NULL) {
     *error_msg = StringPrintf("oat file '%s' does not contain contents for '%s' with checksum 0x%x",
                               oat_file->GetLocation().c_str(), dex_location, dex_location_checksum);
-    std::vector<const OatFile::OatDexFile*> oat_dex_files = oat_file->GetOatDexFiles();
-    for (size_t i = 0; i < oat_dex_files.size(); i++) {
-      const OatFile::OatDexFile* oat_dex_file = oat_dex_files[i];
-      *error_msg  += StringPrintf("\noat file '%s' contains contents for '%s'",
+    for (const OatFile::OatDexFile* oat_dex_file : oat_file->GetOatDexFiles()) {
+      *error_msg  += StringPrintf("\noat file '%s' contains contents for '%s' with checksum 0x%x",
                                   oat_file->GetLocation().c_str(),
-                                  oat_dex_file->GetDexFileLocation().c_str());
+                                  oat_dex_file->GetDexFileLocation().c_str(),
+                                  oat_dex_file->GetDexFileLocationChecksum());
     }
     return false;
   }
@@ -1174,7 +1176,7 @@
 
 const OatFile* ClassLinker::FindOatFileContainingDexFileFromDexLocation(
     const char* dex_location,
-    const uint32_t* const dex_location_checksum,
+    const uint32_t* dex_location_checksum,
     InstructionSet isa,
     std::vector<std::string>* error_msgs,
     bool* obsolete_file_cleanup_failed) {
@@ -2066,7 +2068,7 @@
       if (pair.second != nullptr) {
         mirror::Class* klass = LookupClass(descriptor, nullptr);
         if (klass != nullptr) {
-          return klass;
+          return EnsureResolved(self, descriptor, klass);
         }
         klass = DefineClass(descriptor, NullHandle<mirror::ClassLoader>(), *pair.first,
                             *pair.second);
@@ -2311,14 +2313,10 @@
                                OatFile::OatClass* oat_class) {
   DCHECK(oat_class != nullptr);
   DCHECK_NE(class_def_idx, DexFile::kDexNoIndex16);
-  const OatFile* oat_file = FindOpenedOatFileForDexFile(dex_file);
-  if (oat_file == nullptr) {
+  const OatFile::OatDexFile* oat_dex_file = FindOpenedOatDexFileForDexFile(dex_file);
+  if (oat_dex_file == nullptr) {
     return false;
   }
-  uint dex_location_checksum = dex_file.GetLocationChecksum();
-  const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation().c_str(),
-                                                                    &dex_location_checksum);
-  CHECK(oat_dex_file != NULL) << dex_file.GetLocation();
   *oat_class = oat_dex_file->GetOatClass(class_def_idx);
   return true;
 }
@@ -3413,8 +3411,11 @@
   ObjectLock<mirror::Class> lock(self, klass);
 
   // Don't attempt to re-verify if already sufficiently verified.
-  if (klass->IsVerified() ||
-      (klass->IsCompileTimeVerified() && Runtime::Current()->IsCompiler())) {
+  if (klass->IsVerified()) {
+    EnsurePreverifiedMethods(klass);
+    return;
+  }
+  if (klass->IsCompileTimeVerified() && Runtime::Current()->IsCompiler()) {
     return;
   }
 
@@ -3437,6 +3438,7 @@
   // Skip verification if disabled.
   if (!Runtime::Current()->IsVerificationEnabled()) {
     klass->SetStatus(mirror::Class::kStatusVerified, self);
+    EnsurePreverifiedMethods(klass);
     return;
   }
 
@@ -3522,6 +3524,9 @@
         klass->SetStatus(mirror::Class::kStatusRetryVerificationAtRuntime, self);
       } else {
         klass->SetStatus(mirror::Class::kStatusVerified, self);
+        // As this is a fake verified status, make sure the methods are _not_ marked preverified
+        // later.
+        klass->SetAccessFlags(klass->GetAccessFlags() | kAccPreverified);
       }
     }
   } else {
@@ -3539,7 +3544,14 @@
     // Note: we're going here during compilation and at runtime. When we set the
     // kAccPreverified flag when compiling image classes, the flag is recorded
     // in the image and is set when loading the image.
+    EnsurePreverifiedMethods(klass);
+  }
+}
+
+void ClassLinker::EnsurePreverifiedMethods(Handle<mirror::Class> klass) {
+  if ((klass->GetAccessFlags() & kAccPreverified) == 0) {
     klass->SetPreverifiedFlagOnAllMethods();
+    klass->SetAccessFlags(klass->GetAccessFlags() | kAccPreverified);
   }
 }
 
@@ -3562,17 +3574,13 @@
     }
   }
 
-  const OatFile* oat_file = FindOpenedOatFileForDexFile(dex_file);
+  const OatFile::OatDexFile* oat_dex_file = FindOpenedOatDexFileForDexFile(dex_file);
   // Make this work with gtests, which do not set up the image properly.
   // TODO: we should clean up gtests to set up the image path properly.
-  if (Runtime::Current()->IsCompiler() || (oat_file == NULL)) {
+  if (Runtime::Current()->IsCompiler() || (oat_dex_file == nullptr)) {
     return false;
   }
 
-  CHECK(oat_file != NULL) << dex_file.GetLocation() << " " << PrettyClass(klass);
-  uint dex_location_checksum = dex_file.GetLocationChecksum();
-  const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation().c_str(),
-                                                                    &dex_location_checksum);
   CHECK(oat_dex_file != NULL) << dex_file.GetLocation() << " " << PrettyClass(klass);
   uint16_t class_def_index = klass->GetDexClassDefIndex();
   oat_file_class_status = oat_dex_file->GetOatClass(class_def_index).GetStatus();
@@ -3677,7 +3685,8 @@
   }
   DCHECK(klass->GetClass() != NULL);
   klass->SetObjectSize(sizeof(mirror::Proxy));
-  klass->SetAccessFlags(kAccClassIsProxy | kAccPublic | kAccFinal);
+  // Set the class access flags incl. preverified, so we do not try to set the flag on the methods.
+  klass->SetAccessFlags(kAccClassIsProxy | kAccPublic | kAccFinal | kAccPreverified);
   klass->SetClassLoader(soa.Decode<mirror::ClassLoader*>(loader));
   DCHECK_EQ(klass->GetPrimitiveType(), Primitive::kPrimNot);
   klass->SetName(soa.Decode<mirror::String*>(name));
@@ -4238,6 +4247,7 @@
                                     bool can_init_parents) {
   DCHECK(c.Get() != nullptr);
   if (c->IsInitialized()) {
+    EnsurePreverifiedMethods(c);
     return true;
   }
   const bool success = InitializeClass(c, can_init_fields, can_init_parents);
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 79cbb02..f6b08f0 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -541,14 +541,15 @@
   }
   mirror::DexCache* GetDexCache(size_t idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, dex_lock_);
 
-  const OatFile* FindOpenedOatFileForDexFile(const DexFile& dex_file)
+  const OatFile::OatDexFile* FindOpenedOatDexFileForDexFile(const DexFile& dex_file)
       LOCKS_EXCLUDED(dex_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  // Find an opened oat file that contains dex_location. If oat_location is not nullptr, the file
-  // must have that location, else any oat location is accepted.
-  const OatFile* FindOpenedOatFile(const char* oat_location, const char* dex_location,
-                                   const uint32_t* const dex_location_checksum)
+  // Find an opened oat dex file that contains dex_location. If oat_location is not nullptr,
+  // the file must have that location, else any oat location is accepted.
+  const OatFile::OatDexFile* FindOpenedOatDexFile(const char* oat_location,
+                                                  const char* dex_location,
+                                                  const uint32_t* dex_location_checksum)
       LOCKS_EXCLUDED(dex_lock_);
 
   // Will open the oat file directly without relocating, even if we could/should do relocation.
@@ -598,8 +599,8 @@
   // Note 1: this will not check open oat files, which are assumed to be stale when this is run.
   // Note 2: Does not register the oat file. It is the caller's job to register if the file is to
   //         be kept.
-  const OatFile* FindOatFileContainingDexFileFromDexLocation(const char* location,
-                                                             const uint32_t* const location_checksum,
+  const OatFile* FindOatFileContainingDexFileFromDexLocation(const char* dex_location,
+                                                             const uint32_t* dex_location_checksum,
                                                              InstructionSet isa,
                                                              std::vector<std::string>* error_msgs,
                                                              bool* obsolete_file_cleanup_failed)
@@ -626,6 +627,11 @@
                                        Handle<mirror::ArtMethod> prototype)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  // Ensures that methods have the kAccPreverified bit set. We use the kAccPreverfied bit on the
+  // class access flags to determine whether this has been done before.
+  void EnsurePreverifiedMethods(Handle<mirror::Class> c)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   mirror::Class* LookupClassFromTableLocked(const char* descriptor,
                                             const mirror::ClassLoader* class_loader,
                                             size_t hash)
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 69c281e..883c6e2 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -1092,4 +1092,65 @@
   EXPECT_EQ(c->GetClassSize(), mirror::ArtMethod::ClassSize());
 }
 
+static void CheckMethod(mirror::ArtMethod* method, bool verified)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  if (!method->IsNative() && !method->IsAbstract()) {
+    EXPECT_EQ((method->GetAccessFlags() & kAccPreverified) != 0U, verified)
+        << PrettyMethod(method, true);
+  }
+}
+
+static void CheckPreverified(mirror::Class* c, bool preverified)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  EXPECT_EQ((c->GetAccessFlags() & kAccPreverified) != 0U, preverified)
+      << "Class " << PrettyClass(c) << " not as expected";
+  for (uint32_t i = 0; i < c->NumDirectMethods(); ++i) {
+    CheckMethod(c->GetDirectMethod(i), preverified);
+  }
+  for (uint32_t i = 0; i < c->NumVirtualMethods(); ++i) {
+    CheckMethod(c->GetVirtualMethod(i), preverified);
+  }
+}
+
+TEST_F(ClassLinkerTest, Preverified_InitializedBoot) {
+  ScopedObjectAccess soa(Thread::Current());
+
+  mirror::Class* JavaLangObject = class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;");
+  ASSERT_TRUE(JavaLangObject != NULL);
+  EXPECT_TRUE(JavaLangObject->IsInitialized()) << "Not testing already initialized class from the "
+                                                  "core";
+  CheckPreverified(JavaLangObject, true);
+}
+
+TEST_F(ClassLinkerTest, Preverified_UninitializedBoot) {
+  ScopedObjectAccess soa(Thread::Current());
+
+  StackHandleScope<1> hs(soa.Self());
+
+  Handle<mirror::Class> security_manager(hs.NewHandle(class_linker_->FindSystemClass(
+      soa.Self(), "Ljava/lang/SecurityManager;")));
+  EXPECT_FALSE(security_manager->IsInitialized()) << "Not testing uninitialized class from the "
+                                                     "core";
+
+  CheckPreverified(security_manager.Get(), false);
+
+  class_linker_->EnsureInitialized(security_manager, true, true);
+  CheckPreverified(security_manager.Get(), true);
+}
+
+TEST_F(ClassLinkerTest, Preverified_App) {
+  ScopedObjectAccess soa(Thread::Current());
+
+  StackHandleScope<2> hs(soa.Self());
+  Handle<mirror::ClassLoader> class_loader(
+      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Statics"))));
+  Handle<mirror::Class> statics(
+      hs.NewHandle(class_linker_->FindClass(soa.Self(), "LStatics;", class_loader)));
+
+  CheckPreverified(statics.Get(), false);
+
+  class_linker_->EnsureInitialized(statics, true, true);
+  CheckPreverified(statics.Get(), true);
+}
+
 }  // namespace art
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 80ce081..37cabea 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -1152,7 +1152,8 @@
   };
 
   ClassListCreator clc(classes);
-  Runtime::Current()->GetClassLinker()->VisitClasses(ClassListCreator::Visit, &clc);
+  Runtime::Current()->GetClassLinker()->VisitClassesWithoutClassesLock(ClassListCreator::Visit,
+                                                                       &clc);
 }
 
 JDWP::JdwpError Dbg::GetClassInfo(JDWP::RefTypeId class_id, JDWP::JdwpTypeTag* pTypeTag,
@@ -2082,66 +2083,51 @@
   return JDWP::ERR_NONE;
 }
 
+static bool IsInDesiredThreadGroup(ScopedObjectAccessUnchecked& soa,
+                                   mirror::Object* desired_thread_group, mirror::Object* peer)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  // Do we want threads from all thread groups?
+  if (desired_thread_group == nullptr) {
+    return true;
+  }
+  mirror::ArtField* thread_group_field = soa.DecodeField(WellKnownClasses::java_lang_Thread_group);
+  DCHECK(thread_group_field != nullptr);
+  mirror::Object* group = thread_group_field->GetObject(peer);
+  return (group == desired_thread_group);
+}
+
 void Dbg::GetThreads(JDWP::ObjectId thread_group_id, std::vector<JDWP::ObjectId>& thread_ids) {
-  class ThreadListVisitor {
-   public:
-    ThreadListVisitor(const ScopedObjectAccessUnchecked& soa, mirror::Object* desired_thread_group,
-                      std::vector<JDWP::ObjectId>& thread_ids)
-        SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-        : soa_(soa), desired_thread_group_(desired_thread_group), thread_ids_(thread_ids) {}
-
-    static void Visit(Thread* t, void* arg) {
-      reinterpret_cast<ThreadListVisitor*>(arg)->Visit(t);
-    }
-
-    // TODO: Enable annotalysis. We know lock is held in constructor, but abstraction confuses
-    // annotalysis.
-    void Visit(Thread* t) NO_THREAD_SAFETY_ANALYSIS {
-      if (t == Dbg::GetDebugThread()) {
-        // Skip the JDWP thread. Some debuggers get bent out of shape when they can't suspend and
-        // query all threads, so it's easier if we just don't tell them about this thread.
-        return;
-      }
-      if (t->IsStillStarting()) {
-        // This thread is being started (and has been registered in the thread list). However, it is
-        // not completely started yet so we must ignore it.
-        return;
-      }
-      mirror::Object* peer = t->GetPeer();
-      if (IsInDesiredThreadGroup(peer)) {
-        thread_ids_.push_back(gRegistry->Add(peer));
-      }
-    }
-
-   private:
-    bool IsInDesiredThreadGroup(mirror::Object* peer)
-        SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-      // peer might be NULL if the thread is still starting up.
-      if (peer == NULL) {
-        // We can't tell the debugger about this thread yet.
-        // TODO: if we identified threads to the debugger by their Thread*
-        // rather than their peer's mirror::Object*, we could fix this.
-        // Doing so might help us report ZOMBIE threads too.
-        return false;
-      }
-      // Do we want threads from all thread groups?
-      if (desired_thread_group_ == NULL) {
-        return true;
-      }
-      mirror::Object* group = soa_.DecodeField(WellKnownClasses::java_lang_Thread_group)->GetObject(peer);
-      return (group == desired_thread_group_);
-    }
-
-    const ScopedObjectAccessUnchecked& soa_;
-    mirror::Object* const desired_thread_group_;
-    std::vector<JDWP::ObjectId>& thread_ids_;
-  };
-
   ScopedObjectAccessUnchecked soa(Thread::Current());
   mirror::Object* thread_group = gRegistry->Get<mirror::Object*>(thread_group_id);
-  ThreadListVisitor tlv(soa, thread_group, thread_ids);
-  MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
-  Runtime::Current()->GetThreadList()->ForEach(ThreadListVisitor::Visit, &tlv);
+  std::list<Thread*> all_threads_list;
+  {
+    MutexLock mu(Thread::Current(), *Locks::thread_list_lock_);
+    all_threads_list = Runtime::Current()->GetThreadList()->GetList();
+  }
+  for (Thread* t : all_threads_list) {
+    if (t == Dbg::GetDebugThread()) {
+      // Skip the JDWP thread. Some debuggers get bent out of shape when they can't suspend and
+      // query all threads, so it's easier if we just don't tell them about this thread.
+      continue;
+    }
+    if (t->IsStillStarting()) {
+      // This thread is being started (and has been registered in the thread list). However, it is
+      // not completely started yet so we must ignore it.
+      continue;
+    }
+    mirror::Object* peer = t->GetPeer();
+    if (peer == nullptr) {
+      // peer might be NULL if the thread is still starting up. We can't tell the debugger about
+      // this thread yet.
+      // TODO: if we identified threads to the debugger by their Thread*
+      // rather than their peer's mirror::Object*, we could fix this.
+      // Doing so might help us report ZOMBIE threads too.
+      continue;
+    }
+    if (IsInDesiredThreadGroup(soa, thread_group, peer)) {
+      thread_ids.push_back(gRegistry->Add(peer));
+    }
+  }
 }
 
 void Dbg::GetChildThreadGroups(JDWP::ObjectId thread_group_id, std::vector<JDWP::ObjectId>& child_thread_group_ids) {
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index 38ea754..c783ee4 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -77,14 +77,13 @@
   // Strip ":...", which is the location
   const char* zip_entry_name = kClassesDex;
   const char* file_part = filename;
-  std::unique_ptr<const char> file_part_ptr;
+  std::string file_part_storage;
 
-
-  if (IsMultiDexLocation(filename)) {
-    std::pair<const char*, const char*> pair = SplitMultiDexLocation(filename);
-    file_part_ptr.reset(pair.first);
-    file_part = pair.first;
-    zip_entry_name = pair.second;
+  if (DexFile::IsMultiDexLocation(filename)) {
+    file_part_storage = GetBaseLocation(filename);
+    file_part = file_part_storage.c_str();
+    zip_entry_name = filename + file_part_storage.size() + 1;
+    DCHECK_EQ(zip_entry_name[-1], kMultiDexSeparator);
   }
 
   ScopedFd fd(OpenAndReadMagic(file_part, &magic, error_msg));
@@ -303,7 +302,7 @@
 
     while (i < 100) {
       std::string name = StringPrintf("classes%zu.dex", i);
-      std::string fake_location = location + ":" + name;
+      std::string fake_location = location + kMultiDexSeparator + name;
       std::unique_ptr<const DexFile> next_dex_file(Open(zip_archive, name.c_str(), fake_location,
                                                         error_msg, &error_code));
       if (next_dex_file.get() == nullptr) {
@@ -951,21 +950,6 @@
   return strrchr(location, kMultiDexSeparator) != nullptr;
 }
 
-std::pair<const char*, const char*> DexFile::SplitMultiDexLocation(
-    const char* location) {
-  const char* colon_ptr = strrchr(location, kMultiDexSeparator);
-
-  // Check it's synthetic.
-  CHECK_NE(colon_ptr, static_cast<const char*>(nullptr));
-
-  size_t colon_index = colon_ptr - location;
-  char* tmp = new char[colon_index + 1];
-  strncpy(tmp, location, colon_index);
-  tmp[colon_index] = 0;
-
-  return std::make_pair(tmp, colon_ptr + 1);
-}
-
 std::string DexFile::GetMultiDexClassesDexName(size_t number, const char* dex_location) {
   if (number == 0) {
     return dex_location;
@@ -976,26 +960,17 @@
 
 std::string DexFile::GetDexCanonicalLocation(const char* dex_location) {
   CHECK_NE(dex_location, static_cast<const char*>(nullptr));
-  char* path = nullptr;
-  if (!IsMultiDexLocation(dex_location)) {
-    path = realpath(dex_location, nullptr);
+  std::string base_location = GetBaseLocation(dex_location);
+  const char* suffix = dex_location + base_location.size();
+  DCHECK(suffix[0] == 0 || suffix[0] == kMultiDexSeparator);
+  UniqueCPtr<const char[]> path(realpath(base_location.c_str(), nullptr));
+  if (path != nullptr && path.get() != base_location) {
+    return std::string(path.get()) + suffix;
+  } else if (suffix[0] == 0) {
+    return base_location;
   } else {
-    std::pair<const char*, const char*> pair = DexFile::SplitMultiDexLocation(dex_location);
-    const char* dex_real_location(realpath(pair.first, nullptr));
-    delete pair.first;
-    if (dex_real_location != nullptr) {
-      int length = strlen(dex_real_location) + strlen(pair.second) + strlen(kMultiDexSeparatorString) + 1;
-      char* multidex_canonical_location = reinterpret_cast<char*>(malloc(sizeof(char) * length));
-      snprintf(multidex_canonical_location, length, "%s" kMultiDexSeparatorString "%s", dex_real_location, pair.second);
-      free(const_cast<char*>(dex_real_location));
-      path = multidex_canonical_location;
-    }
+    return dex_location;
   }
-
-  // If realpath fails then we just copy the argument.
-  std::string result(path == nullptr ? dex_location : path);
-  free(path);
-  return result;
 }
 
 std::ostream& operator<<(std::ostream& os, const DexFile& dex_file) {
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 1da1f81..50d7e54 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -389,14 +389,21 @@
   // For normal dex files, location and base location coincide. If a dex file is part of a multidex
   // archive, the base location is the name of the originating jar/apk, stripped of any internal
   // classes*.dex path.
-  const std::string GetBaseLocation() const {
-    if (IsMultiDexLocation(location_.c_str())) {
-      std::pair<const char*, const char*> pair = SplitMultiDexLocation(location_.c_str());
-      std::string res(pair.first);
-      delete[] pair.first;
-      return res;
+  static std::string GetBaseLocation(const char* location) {
+    const char* pos = strrchr(location, kMultiDexSeparator);
+    if (pos == nullptr) {
+      return location;
     } else {
+      return std::string(location, pos - location);
+    }
+  }
+
+  std::string GetBaseLocation() const {
+    size_t pos = location_.rfind(kMultiDexSeparator);
+    if (pos == std::string::npos) {
       return location_;
+    } else {
+      return location_.substr(0, pos);
     }
   }
 
@@ -918,13 +925,6 @@
   // whether the string contains the separator character.
   static bool IsMultiDexLocation(const char* location);
 
-  // Splits a multidex location at the last separator character. The second component is a pointer
-  // to the character after the separator. The first is a copy of the substring up to the separator.
-  //
-  // Note: It's the caller's job to free the first component of the returned pair.
-  // Bug 15313523: gcc/libc++ don't allow a unique_ptr for the first component
-  static std::pair<const char*, const char*> SplitMultiDexLocation(const char* location);
-
 
   // The base address of the memory mapping.
   const byte* const begin_;
diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc
index fa13290..d0c5603 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex_file_test.cc
@@ -355,9 +355,10 @@
 
 TEST_F(DexFileTest, GetDexCanonicalLocation) {
   ScratchFile file;
-  std::string dex_location = file.GetFilename();
+  UniqueCPtr<const char[]> dex_location_real(realpath(file.GetFilename().c_str(), nullptr));
+  std::string dex_location(dex_location_real.get());
 
-  ASSERT_EQ(file.GetFilename(), DexFile::GetDexCanonicalLocation(dex_location.c_str()));
+  ASSERT_EQ(dex_location, DexFile::GetDexCanonicalLocation(dex_location.c_str()));
   std::string multidex_location = DexFile::GetMultiDexClassesDexName(1, dex_location.c_str());
   ASSERT_EQ(multidex_location, DexFile::GetDexCanonicalLocation(multidex_location.c_str()));
 
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index 8aaa471..6ede6de 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -33,8 +33,10 @@
 
 namespace art {
 
-static inline mirror::Class* CheckFilledNewArrayAlloc(uint32_t type_idx, mirror::ArtMethod* referrer,
-                                                      int32_t component_count, Thread* self,
+static inline mirror::Class* CheckFilledNewArrayAlloc(uint32_t type_idx,
+                                                      mirror::ArtMethod* referrer,
+                                                      int32_t component_count,
+                                                      Thread* self,
                                                       bool access_check)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   if (UNLIKELY(component_count < 0)) {
@@ -56,9 +58,10 @@
     } else {
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
       DCHECK(throw_location.GetMethod() == referrer);
-      self->ThrowNewExceptionF(throw_location, "Ljava/lang/InternalError;",
-                               "Found type %s; filled-new-array not implemented for anything but 'int'",
-                               PrettyDescriptor(klass).c_str());
+      self->ThrowNewExceptionF(
+          throw_location, "Ljava/lang/InternalError;",
+          "Found type %s; filled-new-array not implemented for anything but 'int'",
+          PrettyDescriptor(klass).c_str());
     }
     return nullptr;  // Failure
   }
@@ -92,8 +95,10 @@
 }
 
 // Helper function to allocate array for FILLED_NEW_ARRAY.
-mirror::Array* CheckAndAllocArrayFromCodeInstrumented(uint32_t type_idx, mirror::ArtMethod* referrer,
-                                                      int32_t component_count, Thread* self,
+mirror::Array* CheckAndAllocArrayFromCodeInstrumented(uint32_t type_idx,
+                                                      mirror::ArtMethod* referrer,
+                                                      int32_t component_count,
+                                                      Thread* self,
                                                       bool access_check,
                                                       gc::AllocatorType /* allocator_type */) {
   mirror::Class* klass = CheckFilledNewArrayAlloc(type_idx, referrer, component_count, self,
@@ -144,24 +149,19 @@
     // TODO: Use String::FromModifiedUTF...?
     ScopedLocalRef<jstring> s(env, env->NewStringUTF(msg.c_str()));
     if (s.get() != nullptr) {
-      jfieldID detail_message_id = env->GetFieldID(WellKnownClasses::java_lang_Throwable,
-                                                   "detailMessage", "Ljava/lang/String;");
-      env->SetObjectField(exc.get(), detail_message_id, s.get());
+      env->SetObjectField(exc.get(), WellKnownClasses::java_lang_Throwable_detailMessage, s.get());
 
       // cause.
-      jfieldID cause_id = env->GetFieldID(WellKnownClasses::java_lang_Throwable,
-                                          "cause", "Ljava/lang/Throwable;");
-      env->SetObjectField(exc.get(), cause_id, exc.get());
+      env->SetObjectField(exc.get(), WellKnownClasses::java_lang_Throwable_cause, exc.get());
 
       // suppressedExceptions.
-      jfieldID emptylist_id = env->GetStaticFieldID(WellKnownClasses::java_util_Collections,
-                                                    "EMPTY_LIST", "Ljava/util/List;");
       ScopedLocalRef<jobject> emptylist(env, env->GetStaticObjectField(
-              WellKnownClasses::java_util_Collections, emptylist_id));
+          WellKnownClasses::java_util_Collections,
+          WellKnownClasses::java_util_Collections_EMPTY_LIST));
       CHECK(emptylist.get() != nullptr);
-      jfieldID suppressed_id = env->GetFieldID(WellKnownClasses::java_lang_Throwable,
-                                               "suppressedExceptions", "Ljava/util/List;");
-      env->SetObjectField(exc.get(), suppressed_id, emptylist.get());
+      env->SetObjectField(exc.get(),
+                          WellKnownClasses::java_lang_Throwable_suppressedExceptions,
+                          emptylist.get());
 
       // stackState is set as result of fillInStackTrace. fillInStackTrace calls
       // nativeFillInStackTrace.
@@ -171,19 +171,17 @@
         stack_state_val.reset(soa.Self()->CreateInternalStackTrace<false>(soa));
       }
       if (stack_state_val.get() != nullptr) {
-        jfieldID stackstateID = env->GetFieldID(WellKnownClasses::java_lang_Throwable,
-            "stackState", "Ljava/lang/Object;");
-        env->SetObjectField(exc.get(), stackstateID, stack_state_val.get());
+        env->SetObjectField(exc.get(),
+                            WellKnownClasses::java_lang_Throwable_stackState,
+                            stack_state_val.get());
 
         // stackTrace.
-        jfieldID stack_trace_elem_id = env->GetStaticFieldID(
-            WellKnownClasses::libcore_util_EmptyArray, "STACK_TRACE_ELEMENT",
-            "[Ljava/lang/StackTraceElement;");
         ScopedLocalRef<jobject> stack_trace_elem(env, env->GetStaticObjectField(
-                WellKnownClasses::libcore_util_EmptyArray, stack_trace_elem_id));
-        jfieldID stacktrace_id = env->GetFieldID(
-            WellKnownClasses::java_lang_Throwable, "stackTrace", "[Ljava/lang/StackTraceElement;");
-        env->SetObjectField(exc.get(), stacktrace_id, stack_trace_elem.get());
+            WellKnownClasses::libcore_util_EmptyArray,
+            WellKnownClasses::libcore_util_EmptyArray_STACK_TRACE_ELEMENT));
+        env->SetObjectField(exc.get(),
+                            WellKnownClasses::java_lang_Throwable_stackTrace,
+                            stack_trace_elem.get());
 
         // Throw the exception.
         ThrowLocation throw_location = self->GetCurrentLocationForThrow();
@@ -327,7 +325,8 @@
         }
       }
       CHECK_NE(throws_index, -1);
-      mirror::ObjectArray<mirror::Class>* declared_exceptions = proxy_class->GetThrows()->Get(throws_index);
+      mirror::ObjectArray<mirror::Class>* declared_exceptions =
+          proxy_class->GetThrows()->Get(throws_index);
       mirror::Class* exception_class = exception->GetClass();
       bool declares_exception = false;
       for (int i = 0; i < declared_exceptions->GetLength() && !declares_exception; i++) {
diff --git a/runtime/jdwp/object_registry.h b/runtime/jdwp/object_registry.h
index f0314a3..bc3530b 100644
--- a/runtime/jdwp/object_registry.h
+++ b/runtime/jdwp/object_registry.h
@@ -62,7 +62,8 @@
 
   JDWP::ObjectId Add(mirror::Object* o)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(Locks::thread_list_lock_);
-  JDWP::RefTypeId AddRefType(mirror::Class* c) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  JDWP::RefTypeId AddRefType(mirror::Class* c)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(Locks::thread_list_lock_);
 
   template<typename T> T Get(JDWP::ObjectId id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     if (id == 0) {
@@ -77,10 +78,14 @@
 
   void Clear() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void DisableCollection(JDWP::ObjectId id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void EnableCollection(JDWP::ObjectId id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void DisableCollection(JDWP::ObjectId id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(lock_);
 
-  bool IsCollected(JDWP::ObjectId id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void EnableCollection(JDWP::ObjectId id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(lock_);
+
+  bool IsCollected(JDWP::ObjectId id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(lock_);
 
   void DisposeObject(JDWP::ObjectId id, uint32_t reference_count)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -94,12 +99,24 @@
 
  private:
   JDWP::ObjectId InternalAdd(mirror::Object* o)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(Locks::thread_list_lock_);
-  mirror::Object* InternalGet(JDWP::ObjectId id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void Demote(ObjectRegistryEntry& entry) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, lock_);
-  void Promote(ObjectRegistryEntry& entry) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, lock_);
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      LOCKS_EXCLUDED(lock_, Locks::thread_list_lock_);
+
+  mirror::Object* InternalGet(JDWP::ObjectId id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      LOCKS_EXCLUDED(lock_);
+
+  void Demote(ObjectRegistryEntry& entry)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      EXCLUSIVE_LOCKS_REQUIRED(lock_);
+
+  void Promote(ObjectRegistryEntry& entry)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      EXCLUSIVE_LOCKS_REQUIRED(lock_);
+
   bool Contains(mirror::Object* o, ObjectRegistryEntry** out_entry)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(lock_);
+
   bool ContainsLocked(Thread* self, mirror::Object* o, int32_t identity_hash_code,
                       ObjectRegistryEntry** out_entry)
       EXCLUSIVE_LOCKS_REQUIRED(lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index b0ff7ea..8e44471 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -724,6 +724,15 @@
   klass->SetDexTypeIndex(DexFile::kDexNoIndex16);  // Default to no valid type index.
 }
 
+inline void Class::SetAccessFlags(uint32_t new_access_flags) {
+  // Called inside a transaction when setting pre-verified flag during boot image compilation.
+  if (Runtime::Current()->IsActiveTransaction()) {
+    SetField32<true>(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), new_access_flags);
+  } else {
+    SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), new_access_flags);
+  }
+}
+
 }  // namespace mirror
 }  // namespace art
 
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 13d0c80..43ac98d 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -217,10 +217,7 @@
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   uint32_t GetAccessFlags() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void SetAccessFlags(uint32_t new_access_flags) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    // Not called within a transaction.
-    SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), new_access_flags);
-  }
+  void SetAccessFlags(uint32_t new_access_flags) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Returns true if the class is an interface.
   bool IsInterface() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
diff --git a/runtime/modifiers.h b/runtime/modifiers.h
index e599b03..2814ed8 100644
--- a/runtime/modifiers.h
+++ b/runtime/modifiers.h
@@ -45,7 +45,7 @@
 static const uint32_t kAccConstructor = 0x00010000;  // method (dex only) <init> and <clinit>
 static const uint32_t kAccDeclaredSynchronized = 0x00020000;  // method (dex only)
 static const uint32_t kAccClassIsProxy = 0x00040000;  // class (dex only)
-static const uint32_t kAccPreverified = 0x00080000;  // method (dex only)
+static const uint32_t kAccPreverified = 0x00080000;  // class (runtime), method (dex only)
 static const uint32_t kAccFastNative = 0x0080000;  // method (dex only)
 static const uint32_t kAccPortableCompiled = 0x0100000;  // method (dex only)
 
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 2ebdebd..d5142a7 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -140,7 +140,7 @@
 }
 
 OatFile::~OatFile() {
-  STLDeleteValues(&oat_dex_files_);
+  STLDeleteElements(&oat_dex_files_storage_);
   if (dlopen_handle_ != NULL) {
     dlclose(dlopen_handle_);
   }
@@ -238,7 +238,9 @@
     return false;
   }
 
-  for (size_t i = 0; i < GetOatHeader().GetDexFileCount(); i++) {
+  uint32_t dex_file_count = GetOatHeader().GetDexFileCount();
+  oat_dex_files_storage_.reserve(dex_file_count);
+  for (size_t i = 0; i < dex_file_count; i++) {
     uint32_t dex_file_location_size = *reinterpret_cast<const uint32_t*>(oat);
     if (UNLIKELY(dex_file_location_size == 0U)) {
       *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd with empty location name",
@@ -315,14 +317,24 @@
       return false;
     }
 
-    // Create the OatDexFile and add it to the owning map indexed by the dex file location.
+    std::string canonical_location = DexFile::GetDexCanonicalLocation(dex_file_location.c_str());
+
+    // Create the OatDexFile and add it to the owning container.
     OatDexFile* oat_dex_file = new OatDexFile(this,
                                               dex_file_location,
+                                              canonical_location,
                                               dex_file_checksum,
                                               dex_file_pointer,
                                               methods_offsets_pointer);
+    oat_dex_files_storage_.push_back(oat_dex_file);
+
+    // Add the location and canonical location (if different) to the oat_dex_files_ table.
     StringPiece key(oat_dex_file->GetDexFileLocation());
     oat_dex_files_.Put(key, oat_dex_file);
+    if (canonical_location != dex_file_location) {
+      StringPiece canonical_key(oat_dex_file->GetCanonicalDexFileLocation());
+      oat_dex_files_.Put(canonical_key, oat_dex_file);
+    }
   }
   return true;
 }
@@ -370,20 +382,13 @@
       oat_dex_file = secondary_lb->second;  // May be nullptr.
     } else {
       // We haven't seen this dex_location before, we must check the canonical location.
-      if (UNLIKELY(oat_dex_files_by_canonical_location_.empty())) {
-        // Lazily fill in the oat_dex_files_by_canonical_location_.
-        for (const auto& entry : oat_dex_files_) {
-          const std::string& dex_location = entry.second->GetDexFileLocation();
-          string_cache_.emplace_back(DexFile::GetDexCanonicalLocation(dex_location.c_str()));
-          StringPiece canonical_location_key(string_cache_.back());
-          oat_dex_files_by_canonical_location_.Put(canonical_location_key, entry.second);
-        }
-      }
       std::string dex_canonical_location = DexFile::GetDexCanonicalLocation(dex_location);
-      StringPiece canonical_key(dex_canonical_location);
-      auto canonical_it = oat_dex_files_by_canonical_location_.find(canonical_key);
-      if (canonical_it != oat_dex_files_by_canonical_location_.end()) {
-        oat_dex_file = canonical_it->second;
+      if (dex_canonical_location != dex_location) {
+        StringPiece canonical_key(dex_canonical_location);
+        auto canonical_it = oat_dex_files_.find(canonical_key);
+        if (canonical_it != oat_dex_files_.end()) {
+          oat_dex_file = canonical_it->second;
+        }  // else keep nullptr.
       }  // else keep nullptr.
 
       // Copy the key to the string_cache_ and store the result in secondary map.
@@ -408,11 +413,11 @@
                  << " ( canonical path " << dex_canonical_location << ")"
                  << " with checksum " << checksum << " in OatFile " << GetLocation();
     if (kIsDebugBuild) {
-      for (Table::const_iterator it = oat_dex_files_.begin(); it != oat_dex_files_.end(); ++it) {
+      for (const OatDexFile* odf : oat_dex_files_storage_) {
         LOG(WARNING) << "OatFile " << GetLocation()
-                     << " contains OatDexFile " << it->second->GetDexFileLocation()
-                     << " (canonical path " << it->first << ")"
-                     << " with checksum 0x" << std::hex << it->second->GetDexFileLocationChecksum();
+                     << " contains OatDexFile " << odf->GetDexFileLocation()
+                     << " (canonical path " << odf->GetCanonicalDexFileLocation() << ")"
+                     << " with checksum 0x" << std::hex << odf->GetDexFileLocationChecksum();
       }
     }
   }
@@ -420,21 +425,15 @@
   return NULL;
 }
 
-std::vector<const OatFile::OatDexFile*> OatFile::GetOatDexFiles() const {
-  std::vector<const OatFile::OatDexFile*> result;
-  for (Table::const_iterator it = oat_dex_files_.begin(); it != oat_dex_files_.end(); ++it) {
-    result.push_back(it->second);
-  }
-  return result;
-}
-
 OatFile::OatDexFile::OatDexFile(const OatFile* oat_file,
                                 const std::string& dex_file_location,
+                                const std::string& canonical_dex_file_location,
                                 uint32_t dex_file_location_checksum,
                                 const byte* dex_file_pointer,
                                 const uint32_t* oat_class_offsets_pointer)
     : oat_file_(oat_file),
       dex_file_location_(dex_file_location),
+      canonical_dex_file_location_(canonical_dex_file_location),
       dex_file_location_checksum_(dex_file_location_checksum),
       dex_file_pointer_(dex_file_pointer),
       oat_class_offsets_pointer_(oat_class_offsets_pointer) {}
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 0bf2b7b..d8b48a9 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -204,6 +204,10 @@
     // Opens the DexFile referred to by this OatDexFile from within the containing OatFile.
     const DexFile* OpenDexFile(std::string* error_msg) const;
 
+    const OatFile* GetOatFile() const {
+      return oat_file_;
+    }
+
     // Returns the size of the DexFile refered to by this OatDexFile.
     size_t FileSize() const;
 
@@ -212,6 +216,11 @@
       return dex_file_location_;
     }
 
+    // Returns the canonical location of DexFile that was the source of this OatDexFile.
+    const std::string& GetCanonicalDexFileLocation() const {
+      return canonical_dex_file_location_;
+    }
+
     // Returns checksum of original DexFile that was the source of this OatDexFile;
     uint32_t GetDexFileLocationChecksum() const {
       return dex_file_location_checksum_;
@@ -225,12 +234,14 @@
    private:
     OatDexFile(const OatFile* oat_file,
                const std::string& dex_file_location,
+               const std::string& canonical_dex_file_location,
                uint32_t dex_file_checksum,
                const byte* dex_file_pointer,
                const uint32_t* oat_class_offsets_pointer);
 
     const OatFile* const oat_file_;
     const std::string dex_file_location_;
+    const std::string canonical_dex_file_location_;
     const uint32_t dex_file_location_checksum_;
     const byte* const dex_file_pointer_;
     const uint32_t* const oat_class_offsets_pointer_;
@@ -244,7 +255,9 @@
                                   bool exception_if_not_found = true) const
       LOCKS_EXCLUDED(secondary_lookup_lock_);
 
-  std::vector<const OatDexFile*> GetOatDexFiles() const;
+  const std::vector<const OatDexFile*>& GetOatDexFiles() const {
+    return oat_dex_files_storage_;
+  }
 
   size_t Size() const {
     return End() - Begin();
@@ -297,6 +310,9 @@
   // dlopen handle during runtime.
   void* dlopen_handle_;
 
+  // Owning storage for the OatDexFile objects.
+  std::vector<const OatDexFile*> oat_dex_files_storage_;
+
   // NOTE: We use a StringPiece as the key type to avoid a memory allocation on every
   // lookup with a const char* key. The StringPiece doesn't own its backing storage,
   // therefore we're using the OatDexFile::dex_file_location_ as the backing storage
@@ -304,11 +320,11 @@
   // of keys in secondary_oat_dex_files_ and oat_dex_files_by_canonical_location_.
   typedef AllocationTrackingSafeMap<StringPiece, const OatDexFile*, kAllocatorTagOatFile> Table;
 
-  // Map each plain dex file location retrieved from the oat file to its OatDexFile.
-  // This map doesn't change after it's constructed in Setup() and therefore doesn't
-  // need any locking and provides the cheapest dex file lookup for GetOatDexFile()
-  // for a very frequent use case. Never contains a nullptr value.
-  Table oat_dex_files_;                         // Owns the OatDexFile* values.
+  // Map each location and canonical location (if different) retrieved from the
+  // oat file to its OatDexFile. This map doesn't change after it's constructed in Setup()
+  // and therefore doesn't need any locking and provides the cheapest dex file lookup
+  // for GetOatDexFile() for a very frequent use case. Never contains a nullptr value.
+  Table oat_dex_files_;
 
   // Lock guarding all members needed for secondary lookup in GetOatDexFile().
   mutable Mutex secondary_lookup_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
@@ -319,10 +335,6 @@
   // location and use oat_dex_files_by_canonical_location_.
   mutable Table secondary_oat_dex_files_ GUARDED_BY(secondary_lookup_lock_);
 
-  // Map the canonical location to an OatDexFile. This lazily constructed map is used
-  // when we're doing the secondary lookup for a given location for the first time.
-  mutable Table oat_dex_files_by_canonical_location_ GUARDED_BY(secondary_lookup_lock_);
-
   // Cache of strings. Contains the backing storage for keys in the secondary_oat_dex_files_
   // and the lazily initialized oat_dex_files_by_canonical_location_.
   // NOTE: We're keeping references to contained strings in form of StringPiece and adding
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 4f28dda..4e2bfa0 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -601,9 +601,7 @@
     return false;
   }
 
-  std::vector<const OatFile::OatDexFile*> oat_dex_files = oat_file->GetOatDexFiles();
-  for (size_t i = 0; i < oat_dex_files.size(); i++) {
-    const OatFile::OatDexFile* oat_dex_file = oat_dex_files[i];
+  for (const OatFile::OatDexFile* oat_dex_file : oat_file->GetOatDexFiles()) {
     if (oat_dex_file == nullptr) {
       *failures += 1;
       continue;
diff --git a/runtime/signal_catcher.cc b/runtime/signal_catcher.cc
index c13776d..11e06fe 100644
--- a/runtime/signal_catcher.cc
+++ b/runtime/signal_catcher.cc
@@ -28,6 +28,7 @@
 #include "base/unix_file/fd_file.h"
 #include "class_linker.h"
 #include "gc/heap.h"
+#include "instruction_set.h"
 #include "os.h"
 #include "runtime.h"
 #include "scoped_thread_state_change.h"
@@ -42,20 +43,21 @@
 #if defined(__linux__)
   // Show the original command line, and the current command line too if it's changed.
   // On Android, /proc/self/cmdline will have been rewritten to something like "system_server".
+  // Note: The string "Cmd line:" is chosen to match the format used by debuggerd.
   std::string current_cmd_line;
   if (ReadFileToString("/proc/self/cmdline", &current_cmd_line)) {
-    current_cmd_line.resize(current_cmd_line.size() - 1);  // Lose the trailing '\0'.
+    current_cmd_line.resize(current_cmd_line.find_last_not_of('\0') + 1);  // trim trailing '\0's
     std::replace(current_cmd_line.begin(), current_cmd_line.end(), '\0', ' ');
 
-    os << "Cmdline: " << current_cmd_line;
+    os << "Cmd line: " << current_cmd_line << "\n";
     const char* stashed_cmd_line = GetCmdLine();
-    if (stashed_cmd_line != NULL && current_cmd_line != stashed_cmd_line) {
-      os << "Original command line: " << stashed_cmd_line;
+    if (stashed_cmd_line != NULL && current_cmd_line != stashed_cmd_line
+            && strcmp(stashed_cmd_line, "<unset>") != 0) {
+      os << "Original command line: " << stashed_cmd_line << "\n";
     }
   }
-  os << "\n";
 #else
-  os << "Cmdline: " << GetCmdLine() << "\n";
+  os << "Cmd line: " << GetCmdLine() << "\n";
 #endif
 }
 
@@ -133,6 +135,9 @@
 
   DumpCmdLine(os);
 
+  // Note: The string "ABI:" is chosen to match the format used by debuggerd.
+  os << "ABI: " << GetInstructionSetString(runtime->GetInstructionSet()) << "\n";
+
   os << "Build type: " << (kIsDebugBuild ? "debug" : "optimized") << "\n";
 
   runtime->DumpForSigQuit(os);
diff --git a/runtime/utils.h b/runtime/utils.h
index a34a01d..942b6ad 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -20,6 +20,7 @@
 #include <pthread.h>
 
 #include <limits>
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -499,6 +500,18 @@
   }
 };
 
+// Deleter using free() for use with std::unique_ptr<>. See also UniqueCPtr<> below.
+struct FreeDelete {
+  // NOTE: Deleting a const object is valid but free() takes a non-const pointer.
+  void operator()(const void* ptr) const {
+    free(const_cast<void*>(ptr));
+  }
+};
+
+// Alias for std::unique_ptr<> that uses the C function free() to delete objects.
+template <typename T>
+using UniqueCPtr = std::unique_ptr<T, FreeDelete>;
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_UTILS_H_
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 7068a4d..6b67dfa 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -97,11 +97,18 @@
 jfieldID WellKnownClasses::java_lang_ThreadGroup_mainThreadGroup;
 jfieldID WellKnownClasses::java_lang_ThreadGroup_name;
 jfieldID WellKnownClasses::java_lang_ThreadGroup_systemThreadGroup;
+jfieldID WellKnownClasses::java_lang_Throwable_cause;
+jfieldID WellKnownClasses::java_lang_Throwable_detailMessage;
+jfieldID WellKnownClasses::java_lang_Throwable_stackTrace;
+jfieldID WellKnownClasses::java_lang_Throwable_stackState;
+jfieldID WellKnownClasses::java_lang_Throwable_suppressedExceptions;
 jfieldID WellKnownClasses::java_lang_reflect_AbstractMethod_artMethod;
 jfieldID WellKnownClasses::java_lang_reflect_Field_artField;
 jfieldID WellKnownClasses::java_lang_reflect_Proxy_h;
 jfieldID WellKnownClasses::java_nio_DirectByteBuffer_capacity;
 jfieldID WellKnownClasses::java_nio_DirectByteBuffer_effectiveDirectAddress;
+jfieldID WellKnownClasses::java_util_Collections_EMPTY_LIST;
+jfieldID WellKnownClasses::libcore_util_EmptyArray_STACK_TRACE_ELEMENT;
 jfieldID WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_data;
 jfieldID WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_length;
 jfieldID WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_offset;
@@ -205,11 +212,18 @@
   java_lang_ThreadGroup_mainThreadGroup = CacheField(env, java_lang_ThreadGroup, true, "mainThreadGroup", "Ljava/lang/ThreadGroup;");
   java_lang_ThreadGroup_name = CacheField(env, java_lang_ThreadGroup, false, "name", "Ljava/lang/String;");
   java_lang_ThreadGroup_systemThreadGroup = CacheField(env, java_lang_ThreadGroup, true, "systemThreadGroup", "Ljava/lang/ThreadGroup;");
+  java_lang_Throwable_cause = CacheField(env, java_lang_Throwable, false, "cause", "Ljava/lang/Throwable;");
+  java_lang_Throwable_detailMessage = CacheField(env, java_lang_Throwable, false, "detailMessage", "Ljava/lang/String;");
+  java_lang_Throwable_stackTrace = CacheField(env, java_lang_Throwable, false, "stackTrace", "[Ljava/lang/StackTraceElement;");
+  java_lang_Throwable_stackState = CacheField(env, java_lang_Throwable, false, "stackState", "Ljava/lang/Object;");
+  java_lang_Throwable_suppressedExceptions = CacheField(env, java_lang_Throwable, false, "suppressedExceptions", "Ljava/util/List;");
   java_lang_reflect_AbstractMethod_artMethod = CacheField(env, java_lang_reflect_AbstractMethod, false, "artMethod", "Ljava/lang/reflect/ArtMethod;");
   java_lang_reflect_Field_artField = CacheField(env, java_lang_reflect_Field, false, "artField", "Ljava/lang/reflect/ArtField;");
   java_lang_reflect_Proxy_h = CacheField(env, java_lang_reflect_Proxy, false, "h", "Ljava/lang/reflect/InvocationHandler;");
   java_nio_DirectByteBuffer_capacity = CacheField(env, java_nio_DirectByteBuffer, false, "capacity", "I");
   java_nio_DirectByteBuffer_effectiveDirectAddress = CacheField(env, java_nio_DirectByteBuffer, false, "effectiveDirectAddress", "J");
+  java_util_Collections_EMPTY_LIST = CacheField(env, java_util_Collections, true, "EMPTY_LIST", "Ljava/util/List;");
+  libcore_util_EmptyArray_STACK_TRACE_ELEMENT = CacheField(env, libcore_util_EmptyArray, true, "STACK_TRACE_ELEMENT", "[Ljava/lang/StackTraceElement;");
   org_apache_harmony_dalvik_ddmc_Chunk_data = CacheField(env, org_apache_harmony_dalvik_ddmc_Chunk, false, "data", "[B");
   org_apache_harmony_dalvik_ddmc_Chunk_length = CacheField(env, org_apache_harmony_dalvik_ddmc_Chunk, false, "length", "I");
   org_apache_harmony_dalvik_ddmc_Chunk_offset = CacheField(env, org_apache_harmony_dalvik_ddmc_Chunk, false, "offset", "I");
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index b10106c..3780733 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -114,8 +114,15 @@
   static jfieldID java_lang_ThreadGroup_mainThreadGroup;
   static jfieldID java_lang_ThreadGroup_name;
   static jfieldID java_lang_ThreadGroup_systemThreadGroup;
+  static jfieldID java_lang_Throwable_cause;
+  static jfieldID java_lang_Throwable_detailMessage;
+  static jfieldID java_lang_Throwable_stackTrace;
+  static jfieldID java_lang_Throwable_stackState;
+  static jfieldID java_lang_Throwable_suppressedExceptions;
   static jfieldID java_nio_DirectByteBuffer_capacity;
   static jfieldID java_nio_DirectByteBuffer_effectiveDirectAddress;
+  static jfieldID java_util_Collections_EMPTY_LIST;
+  static jfieldID libcore_util_EmptyArray_STACK_TRACE_ELEMENT;
   static jfieldID org_apache_harmony_dalvik_ddmc_Chunk_data;
   static jfieldID org_apache_harmony_dalvik_ddmc_Chunk_length;
   static jfieldID org_apache_harmony_dalvik_ddmc_Chunk_offset;
diff --git a/test/116-nodex2oat/nodex2oat.cc b/test/116-nodex2oat/nodex2oat.cc
index 4326db0..04cac45 100644
--- a/test/116-nodex2oat/nodex2oat.cc
+++ b/test/116-nodex2oat/nodex2oat.cc
@@ -28,9 +28,9 @@
     ScopedObjectAccess soa(Thread::Current());
     mirror::Class* klass = soa.Decode<mirror::Class*>(cls);
     const DexFile& dex_file = klass->GetDexFile();
-    const OatFile* oat_file =
-        Runtime::Current()->GetClassLinker()->FindOpenedOatFileForDexFile(dex_file);
-    return oat_file != nullptr;
+    const OatFile::OatDexFile* oat_dex_file =
+        Runtime::Current()->GetClassLinker()->FindOpenedOatDexFileForDexFile(dex_file);
+    return oat_dex_file != nullptr;
   }
 };
 
diff --git a/test/117-nopatchoat/nopatchoat.cc b/test/117-nopatchoat/nopatchoat.cc
index ced7f6e..5994653 100644
--- a/test/117-nopatchoat/nopatchoat.cc
+++ b/test/117-nopatchoat/nopatchoat.cc
@@ -28,9 +28,9 @@
     ScopedObjectAccess soa(Thread::Current());
     mirror::Class* klass = soa.Decode<mirror::Class*>(cls);
     const DexFile& dex_file = klass->GetDexFile();
-    const OatFile* oat_file =
-        Runtime::Current()->GetClassLinker()->FindOpenedOatFileForDexFile(dex_file);
-    return oat_file != nullptr && oat_file->IsExecutable();
+    const OatFile::OatDexFile* oat_dex_file =
+        Runtime::Current()->GetClassLinker()->FindOpenedOatDexFileForDexFile(dex_file);
+    return oat_dex_file != nullptr && oat_dex_file->GetOatFile()->IsExecutable();
   }
 };
 
diff --git a/test/118-noimage-dex2oat/noimage-dex2oat.cc b/test/118-noimage-dex2oat/noimage-dex2oat.cc
index 4a3d33c..7340d9e 100644
--- a/test/118-noimage-dex2oat/noimage-dex2oat.cc
+++ b/test/118-noimage-dex2oat/noimage-dex2oat.cc
@@ -28,9 +28,9 @@
     ScopedObjectAccess soa(Thread::Current());
     mirror::Class* klass = soa.Decode<mirror::Class*>(cls);
     const DexFile& dex_file = klass->GetDexFile();
-    const OatFile* oat_file =
-        Runtime::Current()->GetClassLinker()->FindOpenedOatFileForDexFile(dex_file);
-    return oat_file != nullptr;
+    const OatFile::OatDexFile* oat_dex_file =
+        Runtime::Current()->GetClassLinker()->FindOpenedOatDexFileForDexFile(dex_file);
+    return oat_dex_file != nullptr;
   }
 };