Merge "Prevent UAF issues caused by static destructors"
diff --git a/adbconnection/adbconnection.cc b/adbconnection/adbconnection.cc
index 6b82be6..a0c9966 100644
--- a/adbconnection/adbconnection.cc
+++ b/adbconnection/adbconnection.cc
@@ -555,7 +555,10 @@
 void AdbConnectionState::RunPollLoop(art::Thread* self) {
   CHECK_NE(agent_name_, "");
   CHECK_EQ(self->GetState(), art::kNative);
-  art::Locks::mutator_lock_->AssertNotHeld(self);
+  // TODO: Clang prebuilt for r316199 produces bogus thread safety analysis warning for holding both
+  // exclusive and shared lock in the same scope. Remove the assertion as a temporary workaround.
+  // http://b/71769596
+  // art::Locks::mutator_lock_->AssertNotHeld(self);
   self->SetState(art::kWaitingInMainDebuggerLoop);
   // shutting_down_ set by StopDebuggerThreads
   while (!shutting_down_) {
diff --git a/compiler/compiled_method.cc b/compiler/compiled_method.cc
index 0f69dba..e413718 100644
--- a/compiler/compiled_method.cc
+++ b/compiler/compiled_method.cc
@@ -159,10 +159,4 @@
   storage->ReleaseMethodInfo(method_info_);
 }
 
-void CompiledMethod::ReleaseVMapTable() {
-  CompiledMethodStorage* storage = GetCompilerDriver()->GetCompiledMethodStorage();
-  storage->ReleaseVMapTable(vmap_table_);
-  vmap_table_ = nullptr;
-}
-
 }  // namespace art
diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h
index 4e8f3ef..acdce26 100644
--- a/compiler/compiled_method.h
+++ b/compiler/compiled_method.h
@@ -168,10 +168,6 @@
 
   ArrayRef<const linker::LinkerPatch> GetPatches() const;
 
-  // The compiler sometimes unquickens shared code items. In that case, we need to clear the vmap
-  // table to avoid writing the quicken info to the vdex file.
-  void ReleaseVMapTable();
-
  private:
   static constexpr size_t kIsIntrinsicLsb = kNumberOfCompiledCodePackedBits;
   static constexpr size_t kIsIntrinsicSize = 1u;
@@ -190,7 +186,7 @@
   // For quick code, method specific information that is not very dedupe friendly (method indices).
   const LengthPrefixedArray<uint8_t>* const method_info_;
   // For quick code, holds code infos which contain stack maps, inline information, and etc.
-  const LengthPrefixedArray<uint8_t>* vmap_table_;
+  const LengthPrefixedArray<uint8_t>* const vmap_table_;
   // For quick code, a FDE entry for the debug_frame section.
   const LengthPrefixedArray<uint8_t>* const cfi_info_;
   // For quick code, linker patches needed by the method.
diff --git a/compiler/debug/elf_symtab_writer.h b/compiler/debug/elf_symtab_writer.h
index 9c9e8b3..4b19547 100644
--- a/compiler/debug/elf_symtab_writer.h
+++ b/compiler/debug/elf_symtab_writer.h
@@ -101,7 +101,7 @@
       }
     }
   }
-  // Add symbols for interpreted methods (with address range of the method's bytecode).
+  // Add symbols for dex files.
   if (!debug_info.dex_files.empty() && builder->GetDex()->Exists()) {
     auto dex = builder->GetDex();
     for (auto it : debug_info.dex_files) {
@@ -109,33 +109,6 @@
       const DexFile* dex_file = it.second;
       typename ElfTypes::Word dex_name = strtab->Write(kDexFileSymbolName);
       symtab->Add(dex_name, dex, dex_address, dex_file->Size(), STB_GLOBAL, STT_FUNC);
-      if (mini_debug_info) {
-        continue;  // Don't add interpreter method names to mini-debug-info for now.
-      }
-      for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) {
-        const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
-        const uint8_t* class_data = dex_file->GetClassData(class_def);
-        if (class_data == nullptr) {
-          continue;
-        }
-        for (ClassDataItemIterator item(*dex_file, class_data); item.HasNext(); item.Next()) {
-          if (!item.IsAtMethod()) {
-            continue;
-          }
-          const DexFile::CodeItem* code_item = item.GetMethodCodeItem();
-          if (code_item == nullptr) {
-            continue;
-          }
-          CodeItemInstructionAccessor code(*dex_file, code_item);
-          DCHECK(code.HasCodeItem());
-          std::string name = dex_file->PrettyMethod(item.GetMemberIndex(), !mini_debug_info);
-          size_t name_offset = strtab->Write(name);
-          uint64_t offset = reinterpret_cast<const uint8_t*>(code.Insns()) - dex_file->Begin();
-          uint64_t address = dex_address + offset;
-          size_t size = code.InsnsSizeInCodeUnits() * sizeof(uint16_t);
-          symtab->Add(name_offset, dex, address, size, STB_GLOBAL, STT_FUNC);
-        }
-      }
     }
   }
   strtab->End();
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index 28c7fe2..9f0aaa4 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -45,6 +45,85 @@
 // Control check-cast elision.
 const bool kEnableCheckCastEllision = true;
 
+// Holds the state for compiling a single method.
+struct DexToDexCompiler::CompilationState {
+  struct QuickenedInfo {
+    QuickenedInfo(uint32_t pc, uint16_t index) : dex_pc(pc), dex_member_index(index) {}
+
+    uint32_t dex_pc;
+    uint16_t dex_member_index;
+  };
+
+  CompilationState(DexToDexCompiler* compiler,
+                   const DexCompilationUnit& unit,
+                   const CompilationLevel compilation_level,
+                   const std::vector<uint8_t>* quicken_data);
+
+  const std::vector<QuickenedInfo>& GetQuickenedInfo() const {
+    return quickened_info_;
+  }
+
+  // Returns the quickening info, or an empty array if it was not quickened.
+  // If already_quickened is true, then don't change anything but still return what the quicken
+  // data would have been.
+  std::vector<uint8_t> Compile();
+
+  const DexFile& GetDexFile() const;
+
+  // Compiles a RETURN-VOID into a RETURN-VOID-BARRIER within a constructor where
+  // a barrier is required.
+  void CompileReturnVoid(Instruction* inst, uint32_t dex_pc);
+
+  // Compiles a CHECK-CAST into 2 NOP instructions if it is known to be safe. In
+  // this case, returns the second NOP instruction pointer. Otherwise, returns
+  // the given "inst".
+  Instruction* CompileCheckCast(Instruction* inst, uint32_t dex_pc);
+
+  // Compiles a field access into a quick field access.
+  // The field index is replaced by an offset within an Object where we can read
+  // from / write to this field. Therefore, this does not involve any resolution
+  // at runtime.
+  // Since the field index is encoded with 16 bits, we can replace it only if the
+  // field offset can be encoded with 16 bits too.
+  void CompileInstanceFieldAccess(Instruction* inst, uint32_t dex_pc,
+                                  Instruction::Code new_opcode, bool is_put);
+
+  // Compiles a virtual method invocation into a quick virtual method invocation.
+  // The method index is replaced by the vtable index where the corresponding
+  // executable can be found. Therefore, this does not involve any resolution
+  // at runtime.
+  // Since the method index is encoded with 16 bits, we can replace it only if the
+  // vtable index can be encoded with 16 bits too.
+  void CompileInvokeVirtual(Instruction* inst, uint32_t dex_pc,
+                            Instruction::Code new_opcode, bool is_range);
+
+  // Return the next index.
+  uint16_t NextIndex();
+
+  // Returns the dequickened index if an instruction is quickened, otherwise return index.
+  uint16_t GetIndexForInstruction(const Instruction* inst, uint32_t index);
+
+  DexToDexCompiler* const compiler_;
+  CompilerDriver& driver_;
+  const DexCompilationUnit& unit_;
+  const CompilationLevel compilation_level_;
+
+  // Filled by the compiler when quickening, in order to encode that information
+  // in the .oat file. The runtime will use that information to get to the original
+  // opcodes.
+  std::vector<QuickenedInfo> quickened_info_;
+
+  // True if we optimized a return void to a return void no barrier.
+  bool optimized_return_void_ = false;
+
+  // If the code item was already quickened previously.
+  const bool already_quickened_;
+  const QuickenInfoTable existing_quicken_info_;
+  uint32_t quicken_index_ = 0u;
+
+  DISALLOW_COPY_AND_ASSIGN(CompilationState);
+};
+
 DexToDexCompiler::DexToDexCompiler(CompilerDriver* driver)
     : driver_(driver),
       lock_("Quicken lock", kDexToDexCompilerLock) {
@@ -55,16 +134,13 @@
   MutexLock lock(Thread::Current(), lock_);
   active_dex_file_ = nullptr;
   active_bit_vector_ = nullptr;
-  seen_code_items_.clear();
   should_quicken_.clear();
-  shared_code_items_.clear();
-  blacklisted_code_items_.clear();
   shared_code_item_quicken_info_.clear();
 }
 
-size_t DexToDexCompiler::NumUniqueCodeItems(Thread* self) const {
+size_t DexToDexCompiler::NumCodeItemsToQuicken(Thread* self) const {
   MutexLock lock(self, lock_);
-  return seen_code_items_.size();
+  return num_code_items_;
 }
 
 BitVector* DexToDexCompiler::GetOrAddBitVectorForDex(const DexFile* dex_file) {
@@ -80,17 +156,13 @@
 }
 
 void DexToDexCompiler::MarkForCompilation(Thread* self,
-                                          const MethodReference& method_ref,
-                                          const DexFile::CodeItem* code_item) {
+                                          const MethodReference& method_ref) {
   MutexLock lock(self, lock_);
   BitVector* const bitmap = GetOrAddBitVectorForDex(method_ref.dex_file);
   DCHECK(bitmap != nullptr);
   DCHECK(!bitmap->IsBitSet(method_ref.index));
   bitmap->SetBit(method_ref.index);
-  // Detect the shared code items.
-  if (!seen_code_items_.insert(code_item).second) {
-    shared_code_items_.insert(code_item);
-  }
+  ++num_code_items_;
 }
 
 DexToDexCompiler::CompilationState::CompilationState(DexToDexCompiler* compiler,
@@ -316,6 +388,7 @@
                  << " at dex pc " << StringPrintf("0x%x", dex_pc) << " in method "
                  << GetDexFile().PrettyMethod(unit_.GetDexMethodIndex(), true);
   inst->SetOpcode(Instruction::RETURN_VOID_NO_BARRIER);
+  optimized_return_void_ = true;
 }
 
 Instruction* DexToDexCompiler::CompilationState::CompileCheckCast(Instruction* inst,
@@ -464,51 +537,48 @@
   // If the code item is shared with multiple different method ids, make sure that we quicken only
   // once and verify that all the dequicken maps match.
   if (UNLIKELY(shared_code_items_.find(code_item) != shared_code_items_.end())) {
-    // For shared code items, use a lock to prevent races.
-    MutexLock mu(soa.Self(), lock_);
-    // Blacklisted means there was a quickening conflict previously, bail early.
-    if (blacklisted_code_items_.find(code_item) != blacklisted_code_items_.end()) {
+    // Avoid quickening the shared code items for now because the existing conflict detection logic
+    // does not currently handle cases where the code item is quickened in one place but
+    // compiled in another.
+    static constexpr bool kAvoidQuickeningSharedCodeItems = true;
+    if (kAvoidQuickeningSharedCodeItems) {
       return nullptr;
     }
+    // For shared code items, use a lock to prevent races.
+    MutexLock mu(soa.Self(), lock_);
     auto existing = shared_code_item_quicken_info_.find(code_item);
-    const bool already_quickened = existing != shared_code_item_quicken_info_.end();
+    QuickenState* existing_data = nullptr;
+    std::vector<uint8_t>* existing_quicken_data = nullptr;
+    if (existing != shared_code_item_quicken_info_.end()) {
+      existing_data = &existing->second;
+      if (existing_data->conflict_) {
+        return nullptr;
+      }
+      existing_quicken_data = &existing_data->quicken_data_;
+    }
+    bool optimized_return_void;
     {
-      CompilationState state(this,
-                             unit,
-                             compilation_level,
-                             already_quickened ? &existing->second.quicken_data_ : nullptr);
+      CompilationState state(this, unit, compilation_level, existing_quicken_data);
       quicken_data = state.Compile();
+      optimized_return_void = state.optimized_return_void_;
     }
 
     // Already quickened, check that the data matches what was previously seen.
     MethodReference method_ref(&dex_file, method_idx);
-    if (already_quickened) {
-      QuickenState* const existing_data = &existing->second;
-      if (existing_data->quicken_data_ != quicken_data) {
-        VLOG(compiler) << "Quicken data mismatch, dequickening method "
+    if (existing_data != nullptr) {
+      if (*existing_quicken_data != quicken_data ||
+          existing_data->optimized_return_void_ != optimized_return_void) {
+        VLOG(compiler) << "Quicken data mismatch, for method "
                        << dex_file.PrettyMethod(method_idx);
-        // Unquicken using the existing quicken data.
-        optimizer::ArtDecompileDEX(dex_file,
-                                   *code_item,
-                                   ArrayRef<const uint8_t>(existing_data->quicken_data_),
-                                   /* decompile_return_instruction*/ false);
-        // Go clear the vmaps for all the methods that were already quickened to avoid writing them
-        // out during oat writing.
-        for (const MethodReference& ref : existing_data->methods_) {
-          CompiledMethod* method = driver_->GetCompiledMethod(ref);
-          DCHECK(method != nullptr);
-          method->ReleaseVMapTable();
-        }
-        // Blacklist the method to never attempt to quicken it in the future.
-        blacklisted_code_items_.insert(code_item);
-        shared_code_item_quicken_info_.erase(existing);
-        return nullptr;
+        // Mark the method as a conflict to never attempt to quicken it in the future.
+        existing_data->conflict_ = true;
       }
       existing_data->methods_.push_back(method_ref);
     } else {
       QuickenState new_state;
       new_state.methods_.push_back(method_ref);
       new_state.quicken_data_ = quicken_data;
+      new_state.optimized_return_void_ = optimized_return_void;
       bool inserted = shared_code_item_quicken_info_.emplace(code_item, new_state).second;
       CHECK(inserted) << "Failed to insert " << dex_file.PrettyMethod(method_idx);
     }
@@ -556,9 +626,65 @@
       ArrayRef<const uint8_t>(quicken_data),       // vmap_table
       ArrayRef<const uint8_t>(),                   // cfi data
       ArrayRef<const linker::LinkerPatch>());
+  DCHECK(ret != nullptr);
   return ret;
 }
 
+void DexToDexCompiler::SetDexFiles(const std::vector<const DexFile*>& dex_files) {
+  // Record what code items are already seen to detect when multiple methods have the same code
+  // item.
+  std::unordered_set<const DexFile::CodeItem*> seen_code_items;
+  for (const DexFile* dex_file : dex_files) {
+    for (size_t i = 0; i < dex_file->NumClassDefs(); ++i) {
+      const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
+      const uint8_t* class_data = dex_file->GetClassData(class_def);
+      if (class_data == nullptr) {
+        continue;
+      }
+      ClassDataItemIterator it(*dex_file, class_data);
+      it.SkipAllFields();
+      for (; it.HasNextMethod(); it.Next()) {
+        const DexFile::CodeItem* code_item = it.GetMethodCodeItem();
+        // Detect the shared code items.
+        if (!seen_code_items.insert(code_item).second) {
+          shared_code_items_.insert(code_item);
+        }
+      }
+    }
+  }
+  VLOG(compiler) << "Shared code items " << shared_code_items_.size();
+}
+
+void DexToDexCompiler::UnquickenConflictingMethods() {
+  MutexLock mu(Thread::Current(), lock_);
+  size_t unquicken_count = 0;
+  for (const auto& pair : shared_code_item_quicken_info_) {
+    const DexFile::CodeItem* code_item = pair.first;
+    const QuickenState& state = pair.second;
+    CHECK_GE(state.methods_.size(), 1u);
+    if (state.conflict_) {
+      // Unquicken using the existing quicken data.
+      // TODO: Do we really need to pass a dex file in?
+      optimizer::ArtDecompileDEX(*state.methods_[0].dex_file,
+                                 *code_item,
+                                 ArrayRef<const uint8_t>(state.quicken_data_),
+                                 /* decompile_return_instruction*/ true);
+      ++unquicken_count;
+      // Go clear the vmaps for all the methods that were already quickened to avoid writing them
+      // out during oat writing.
+      for (const MethodReference& ref : state.methods_) {
+        CompiledMethod* method = driver_->RemoveCompiledMethod(ref);
+        if (method != nullptr) {
+          // There is up to one compiled method for each method ref. Releasing it leaves the
+          // deduped data intact, this means its safe to do even when other threads might be
+          // compiling.
+          CompiledMethod::ReleaseSwapAllocatedCompiledMethod(driver_, method);
+        }
+      }
+    }
+  }
+}
+
 }  // namespace optimizer
 
 }  // namespace art
diff --git a/compiler/dex/dex_to_dex_compiler.h b/compiler/dex/dex_to_dex_compiler.h
index 2105a9d..7df09f1 100644
--- a/compiler/dex/dex_to_dex_compiler.h
+++ b/compiler/dex/dex_to_dex_compiler.h
@@ -59,99 +59,35 @@
                                 const CompilationLevel compilation_level) WARN_UNUSED;
 
   void MarkForCompilation(Thread* self,
-                          const MethodReference& method_ref,
-                          const DexFile::CodeItem* code_item);
+                          const MethodReference& method_ref);
 
   void ClearState();
 
+  // Unquicken all methods that have conflicting quicken info. This is not done during the
+  // quickening process to avoid race conditions.
+  void UnquickenConflictingMethods();
+
   CompilerDriver* GetDriver() {
     return driver_;
   }
 
   bool ShouldCompileMethod(const MethodReference& ref);
 
-  size_t NumUniqueCodeItems(Thread* self) const;
+  // Return the number of code items to quicken.
+  size_t NumCodeItemsToQuicken(Thread* self) const;
+
+  void SetDexFiles(const std::vector<const DexFile*>& dex_files);
 
  private:
   // Holds the state for compiling a single method.
-  struct CompilationState {
-    struct QuickenedInfo {
-      QuickenedInfo(uint32_t pc, uint16_t index) : dex_pc(pc), dex_member_index(index) {}
+  struct CompilationState;
 
-      uint32_t dex_pc;
-      uint16_t dex_member_index;
-    };
-
-    CompilationState(DexToDexCompiler* compiler,
-                     const DexCompilationUnit& unit,
-                     const CompilationLevel compilation_level,
-                     const std::vector<uint8_t>* quicken_data);
-
-    const std::vector<QuickenedInfo>& GetQuickenedInfo() const {
-      return quickened_info_;
-    }
-
-    // Returns the quickening info, or an empty array if it was not quickened.
-    // If already_quickened is true, then don't change anything but still return what the quicken
-    // data would have been.
-    std::vector<uint8_t> Compile();
-
-    const DexFile& GetDexFile() const;
-
-    // Compiles a RETURN-VOID into a RETURN-VOID-BARRIER within a constructor where
-    // a barrier is required.
-    void CompileReturnVoid(Instruction* inst, uint32_t dex_pc);
-
-    // Compiles a CHECK-CAST into 2 NOP instructions if it is known to be safe. In
-    // this case, returns the second NOP instruction pointer. Otherwise, returns
-    // the given "inst".
-    Instruction* CompileCheckCast(Instruction* inst, uint32_t dex_pc);
-
-    // Compiles a field access into a quick field access.
-    // The field index is replaced by an offset within an Object where we can read
-    // from / write to this field. Therefore, this does not involve any resolution
-    // at runtime.
-    // Since the field index is encoded with 16 bits, we can replace it only if the
-    // field offset can be encoded with 16 bits too.
-    void CompileInstanceFieldAccess(Instruction* inst, uint32_t dex_pc,
-                                    Instruction::Code new_opcode, bool is_put);
-
-    // Compiles a virtual method invocation into a quick virtual method invocation.
-    // The method index is replaced by the vtable index where the corresponding
-    // executable can be found. Therefore, this does not involve any resolution
-    // at runtime.
-    // Since the method index is encoded with 16 bits, we can replace it only if the
-    // vtable index can be encoded with 16 bits too.
-    void CompileInvokeVirtual(Instruction* inst, uint32_t dex_pc,
-                              Instruction::Code new_opcode, bool is_range);
-
-    // Return the next index.
-    uint16_t NextIndex();
-
-    // Returns the dequickened index if an instruction is quickened, otherwise return index.
-    uint16_t GetIndexForInstruction(const Instruction* inst, uint32_t index);
-
-    DexToDexCompiler* const compiler_;
-    CompilerDriver& driver_;
-    const DexCompilationUnit& unit_;
-    const CompilationLevel compilation_level_;
-
-    // Filled by the compiler when quickening, in order to encode that information
-    // in the .oat file. The runtime will use that information to get to the original
-    // opcodes.
-    std::vector<QuickenedInfo> quickened_info_;
-
-    // If the code item was already quickened previously.
-    const bool already_quickened_;
-    const QuickenInfoTable existing_quicken_info_;
-    uint32_t quicken_index_ = 0u;
-
-    DISALLOW_COPY_AND_ASSIGN(CompilationState);
-  };
-
+  // Quicken state for a code item, may be referenced by multiple methods.
   struct QuickenState {
     std::vector<MethodReference> methods_;
     std::vector<uint8_t> quicken_data_;
+    bool optimized_return_void_ = false;
+    bool conflict_ = false;
   };
 
   BitVector* GetOrAddBitVectorForDex(const DexFile* dex_file) REQUIRES(lock_);
@@ -166,15 +102,14 @@
   mutable Mutex lock_;
   // Record what method references are going to get quickened.
   std::unordered_map<const DexFile*, BitVector> should_quicken_;
-  // Record what code items are already seen to detect when multiple methods have the same code
-  // item.
-  std::unordered_set<const DexFile::CodeItem*> seen_code_items_ GUARDED_BY(lock_);
   // Guarded by lock_ during writing, accessed without a lock during quickening.
   // This is safe because no thread is adding to the shared code items during the quickening phase.
   std::unordered_set<const DexFile::CodeItem*> shared_code_items_;
-  std::unordered_set<const DexFile::CodeItem*> blacklisted_code_items_ GUARDED_BY(lock_);
+  // Blacklisted code items are unquickened in UnquickenConflictingMethods.
   std::unordered_map<const DexFile::CodeItem*, QuickenState> shared_code_item_quicken_info_
       GUARDED_BY(lock_);
+  // Number of added code items.
+  size_t num_code_items_ GUARDED_BY(lock_) = 0u;
 };
 
 std::ostream& operator<<(std::ostream& os, const DexToDexCompiler::CompilationLevel& rhs);
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index b3adf10..fb428b8 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -656,7 +656,7 @@
               optimizer::DexToDexCompiler::CompilationLevel::kDontDexToDexCompile) {
         DCHECK(!Runtime::Current()->UseJitCompilation());
         // TODO: add a command-line option to disable DEX-to-DEX compilation ?
-        driver->GetDexToDexCompiler().MarkForCompilation(self, method_ref, code_item);
+        driver->GetDexToDexCompiler().MarkForCompilation(self, method_ref);
       }
     }
     return compiled_method;
@@ -730,7 +730,7 @@
                      true,
                      dex_cache);
 
-  const size_t num_methods = dex_to_dex_compiler_.NumUniqueCodeItems(self);
+  const size_t num_methods = dex_to_dex_compiler_.NumCodeItemsToQuicken(self);
   if (num_methods != 0) {
     DCHECK_EQ(num_methods, 1u);
     CompileMethodDex2Dex(self,
@@ -2808,7 +2808,7 @@
     Runtime::Current()->ReclaimArenaPoolMemory();
   }
 
-  if (dex_to_dex_compiler_.NumUniqueCodeItems(Thread::Current()) > 0u) {
+  if (dex_to_dex_compiler_.NumCodeItemsToQuicken(Thread::Current()) > 0u) {
     // TODO: Not visit all of the dex files, its probably rare that only one would have quickened
     // methods though.
     for (const DexFile* dex_file : dex_files) {
@@ -2840,6 +2840,12 @@
   DCHECK(GetCompiledMethod(method_ref) != nullptr) << method_ref.PrettyMethod();
 }
 
+CompiledMethod* CompilerDriver::RemoveCompiledMethod(const MethodReference& method_ref) {
+  CompiledMethod* ret = nullptr;
+  CHECK(compiled_methods_.Remove(method_ref, &ret));
+  return ret;
+}
+
 bool CompilerDriver::GetCompiledClass(const ClassReference& ref, ClassStatus* status) const {
   DCHECK(status != nullptr);
   // The table doesn't know if something wasn't inserted. For this case it will return
@@ -3013,6 +3019,7 @@
 void CompilerDriver::SetDexFilesForOatFile(const std::vector<const DexFile*>& dex_files) {
   dex_files_for_oat_file_ = dex_files;
   compiled_classes_.AddDexFiles(dex_files);
+  dex_to_dex_compiler_.SetDexFiles(dex_files);
 }
 
 void CompilerDriver::SetClasspathDexFiles(const std::vector<const DexFile*>& dex_files) {
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index e32b5c4..2b524a3 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -165,6 +165,7 @@
   void AddCompiledMethod(const MethodReference& method_ref,
                          CompiledMethod* const compiled_method,
                          size_t non_relative_linker_patch_count);
+  CompiledMethod* RemoveCompiledMethod(const MethodReference& method_ref);
 
   void SetRequiresConstructorBarrier(Thread* self,
                                      const DexFile* dex_file,
diff --git a/compiler/linker/elf_builder.h b/compiler/linker/elf_builder.h
index 1c87518..3145497 100644
--- a/compiler/linker/elf_builder.h
+++ b/compiler/linker/elf_builder.h
@@ -18,7 +18,6 @@
 #define ART_COMPILER_LINKER_ELF_BUILDER_H_
 
 #include <vector>
-#include <unordered_map>
 
 #include "arch/instruction_set.h"
 #include "arch/mips/instruction_set_features_mips.h"
@@ -310,24 +309,27 @@
                   /* info */ 0,
                   align,
                   /* entsize */ 0),
-          current_offset_(0) {
+          current_offset_(0),
+          last_offset_(0) {
     }
 
     Elf_Word Write(const std::string& name) {
       if (current_offset_ == 0) {
         DCHECK(name.empty());
+      } else if (name == last_name_) {
+        return last_offset_;  // Very simple string de-duplication.
       }
-      auto res = written_names_.emplace(name, current_offset_);
-      if (res.second) {  // Inserted.
-        this->WriteFully(name.c_str(), name.length() + 1);
-        current_offset_ += name.length() + 1;
-      }
-      return res.first->second;  // Offset.
+      last_name_ = name;
+      last_offset_ = current_offset_;
+      this->WriteFully(name.c_str(), name.length() + 1);
+      current_offset_ += name.length() + 1;
+      return last_offset_;
     }
 
    private:
     Elf_Word current_offset_;
-    std::unordered_map<std::string, Elf_Word> written_names_;  // Dedup strings.
+    std::string last_name_;
+    Elf_Word last_offset_;
   };
 
   // Writer of .dynsym and .symtab sections.
diff --git a/compiler/utils/atomic_dex_ref_map-inl.h b/compiler/utils/atomic_dex_ref_map-inl.h
index 203e484..7023b9a 100644
--- a/compiler/utils/atomic_dex_ref_map-inl.h
+++ b/compiler/utils/atomic_dex_ref_map-inl.h
@@ -75,6 +75,18 @@
 }
 
 template <typename DexFileReferenceType, typename Value>
+inline bool AtomicDexRefMap<DexFileReferenceType, Value>::Remove(const DexFileReferenceType& ref,
+                                                                 Value* out) {
+  ElementArray* const array = GetArray(ref.dex_file);
+  if (array == nullptr) {
+    return false;
+  }
+  *out = (*array)[ref.index].LoadRelaxed();
+  (*array)[ref.index].StoreSequentiallyConsistent(nullptr);
+  return true;
+}
+
+template <typename DexFileReferenceType, typename Value>
 inline void AtomicDexRefMap<DexFileReferenceType, Value>::AddDexFile(const DexFile* dex_file) {
   arrays_.Put(dex_file, std::move(ElementArray(NumberOfDexIndices(dex_file))));
 }
diff --git a/compiler/utils/atomic_dex_ref_map.h b/compiler/utils/atomic_dex_ref_map.h
index 9ff506d..3474e16 100644
--- a/compiler/utils/atomic_dex_ref_map.h
+++ b/compiler/utils/atomic_dex_ref_map.h
@@ -45,6 +45,9 @@
   // Retreive an item, returns false if the dex file is not added.
   bool Get(const DexFileReferenceType& ref, Value* out) const;
 
+  // Remove an item and return the existing value. Returns false if the dex file is not added.
+  bool Remove(const DexFileReferenceType& ref, Value* out);
+
   // Dex files must be added before method references belonging to them can be used as keys. Not
   // thread safe.
   void AddDexFile(const DexFile* dex_file);
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index d245cd1..0953e08 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -4364,12 +4364,15 @@
 debug::DebugInfo OatWriter::GetDebugInfo() const {
   debug::DebugInfo debug_info{};
   debug_info.compiled_methods = ArrayRef<const debug::MethodDebugInfo>(method_info_);
-  if (dex_files_ != nullptr) {
+  if (VdexWillContainDexFiles()) {
     DCHECK_EQ(dex_files_->size(), oat_dex_files_.size());
     for (size_t i = 0, size = dex_files_->size(); i != size; ++i) {
       const DexFile* dex_file = (*dex_files_)[i];
       const OatDexFile& oat_dex_file = oat_dex_files_[i];
-      debug_info.dex_files.emplace(oat_dex_file.dex_file_offset_, dex_file);
+      uint32_t dex_file_offset = oat_dex_file.dex_file_offset_;
+      if (dex_file_offset != 0) {
+        debug_info.dex_files.emplace(dex_file_offset, dex_file);
+      }
     }
   }
   return debug_info;
diff --git a/dex2oat/linker/oat_writer.h b/dex2oat/linker/oat_writer.h
index dfcaafc..7edb032 100644
--- a/dex2oat/linker/oat_writer.h
+++ b/dex2oat/linker/oat_writer.h
@@ -340,6 +340,10 @@
 
   bool MayHaveCompiledMethods() const;
 
+  bool VdexWillContainDexFiles() const {
+    return dex_files_ != nullptr && !only_contains_uncompressed_zip_entries_;
+  }
+
   // Find the address of the GcRoot<String> in the InternTable for a boot image string.
   const uint8_t* LookupBootImageInternTableSlot(const DexFile& dex_file,
                                                 dex::StringIndex string_idx);
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc
index 01b28b5..8778b12 100644
--- a/dexdump/dexdump.cc
+++ b/dexdump/dexdump.cc
@@ -1176,14 +1176,20 @@
 
   // Iterate over all instructions.
   CodeItemDataAccessor accessor(*pDexFile, pCode);
+  const u4 maxPc = accessor.InsnsSizeInCodeUnits();
   for (const DexInstructionPcPair& pair : accessor) {
+    const u4 dexPc = pair.DexPc();
+    if (dexPc >= maxPc) {
+      LOG(WARNING) << "GLITCH: run-away instruction at idx=0x" << std::hex << dexPc;
+      break;
+    }
     const Instruction* instruction = &pair.Inst();
     const u4 insnWidth = instruction->SizeInCodeUnits();
     if (insnWidth == 0) {
-      LOG(WARNING) << "GLITCH: zero-width instruction at idx=0x" << std::hex << pair.DexPc();
+      LOG(WARNING) << "GLITCH: zero-width instruction at idx=0x" << std::hex << dexPc;
       break;
     }
-    dumpInstruction(pDexFile, pCode, codeOffset, pair.DexPc(), insnWidth, instruction);
+    dumpInstruction(pDexFile, pCode, codeOffset, dexPc, insnWidth, instruction);
   }  // for
 }
 
diff --git a/dexlayout/compact_dex_writer.cc b/dexlayout/compact_dex_writer.cc
index 08438c4..ca13f758 100644
--- a/dexlayout/compact_dex_writer.cc
+++ b/dexlayout/compact_dex_writer.cc
@@ -162,11 +162,18 @@
 
   static constexpr size_t kPayloadInstructionRequiredAlignment = 4;
   const uint32_t current_code_item_start = stream->Tell() + preheader_bytes;
-  if (!IsAlignedParam(current_code_item_start, kPayloadInstructionRequiredAlignment)) {
+  if (!IsAlignedParam(current_code_item_start, kPayloadInstructionRequiredAlignment) ||
+      kIsDebugBuild) {
     // If the preheader is going to make the code unaligned, consider adding 2 bytes of padding
     // before if required.
-    for (const DexInstructionPcPair& instruction : code_item->Instructions()) {
-      const Instruction::Code opcode = instruction->Opcode();
+    IterationRange<DexInstructionIterator> instructions = code_item->Instructions();
+    SafeDexInstructionIterator it(instructions.begin(), instructions.end());
+    for (; !it.IsErrorState() && it < instructions.end(); ++it) {
+      // In case the instruction goes past the end of the code item, make sure to not process it.
+      if (std::next(it).IsErrorState()) {
+        break;
+      }
+      const Instruction::Code opcode = it->Opcode();
       // Payload instructions possibly require special alignment for their data.
       if (opcode == Instruction::FILL_ARRAY_DATA ||
           opcode == Instruction::PACKED_SWITCH ||
@@ -460,6 +467,11 @@
     // Rewrite the header with the calculated checksum.
     WriteHeader(main_stream);
   }
+
+  // Clear the dedupe to prevent interdex code item deduping. This does not currently work well with
+  // dex2oat's class unloading. The issue is that verification encounters quickened opcodes after
+  // the first dex gets unloaded.
+  code_item_dedupe_->Clear();
 }
 
 std::unique_ptr<DexContainer> CompactDexWriter::CreateDexContainer() const {
diff --git a/dexlayout/compact_dex_writer.h b/dexlayout/compact_dex_writer.h
index 24d0fbf..ea9f7d1 100644
--- a/dexlayout/compact_dex_writer.h
+++ b/dexlayout/compact_dex_writer.h
@@ -44,6 +44,11 @@
     // Returns the offset of the deduplicated data or kDidNotDedupe did deduplication did not occur.
     uint32_t Dedupe(uint32_t data_start, uint32_t data_end, uint32_t item_offset);
 
+    // Clear dedupe state to prevent deduplication against existing items in the future.
+    void Clear() {
+      dedupe_map_.clear();
+    }
+
    private:
     class HashedMemoryRange {
      public:
diff --git a/dexlayout/dexlayout.h b/dexlayout/dexlayout.h
index d2f9cb9..5635271 100644
--- a/dexlayout/dexlayout.h
+++ b/dexlayout/dexlayout.h
@@ -66,8 +66,7 @@
   bool visualize_pattern_ = false;
   bool update_checksum_ = false;
   CompactDexLevel compact_dex_level_ = CompactDexLevel::kCompactDexLevelNone;
-  // Disabled until dex2oat properly handles quickening of deduped code items.
-  bool dedupe_code_items_ = false;
+  bool dedupe_code_items_ = true;
   OutputFormat output_format_ = kOutputPlain;
   const char* output_dex_directory_ = nullptr;
   const char* output_file_name_ = nullptr;
diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc
index be272fc..bebdc20 100644
--- a/dexlayout/dexlayout_test.cc
+++ b/dexlayout/dexlayout_test.cc
@@ -221,6 +221,12 @@
     "AHAAAAACAAAAAwAAAIwAAAADAAAAAQAAAJgAAAAFAAAABAAAAKQAAAAGAAAAAQAAAMQAAAABIAAA"
     "AwAAAOQAAAACIAAABwAAACQBAAADIAAAAwAAAFYBAAAAIAAAAQAAAGUBAAAAEAAAAQAAAHgBAAA=";
 
+// Returns the default compact dex option for dexlayout based on kDefaultCompactDexLevel.
+static std::vector<std::string> DefaultCompactDexOption() {
+  return (kDefaultCompactDexLevel == CompactDexLevel::kCompactDexLevelFast) ?
+      std::vector<std::string>{"-x", "fast"} : std::vector<std::string>{"-x", "none"};
+}
+
 static void WriteBase64ToFile(const char* base64, File* file) {
   // Decode base64.
   CHECK(base64 != nullptr);
@@ -289,7 +295,7 @@
     for (const std::string &dex_file : GetLibCoreDexFileNames()) {
       std::vector<std::string> dexlayout_args =
           { "-w", tmp_dir, "-o", tmp_name, dex_file };
-      if (!DexLayoutExec(dexlayout_args, error_msg)) {
+      if (!DexLayoutExec(dexlayout_args, error_msg, /*pass_default_cdex_option*/ false)) {
         return false;
       }
       size_t dex_file_last_slash = dex_file.rfind('/');
@@ -304,12 +310,10 @@
       if (!::art::Exec(diff_exec_argv, error_msg)) {
         return false;
       }
-      std::vector<std::string> rm_zip_exec_argv = { "/bin/rm", tmp_dir + "classes.dex" };
-      if (!::art::Exec(rm_zip_exec_argv, error_msg)) {
+      if (!UnlinkFile(tmp_dir + "classes.dex")) {
         return false;
       }
-      std::vector<std::string> rm_out_exec_argv = { "/bin/rm", tmp_dir + dex_file_name };
-      if (!::art::Exec(rm_out_exec_argv, error_msg)) {
+      if (!UnlinkFile(tmp_dir + dex_file_name)) {
         return false;
       }
     }
@@ -426,10 +430,7 @@
     }
 
     // -v makes sure that the layout did not corrupt the dex file.
-
-    std::vector<std::string> rm_exec_argv =
-        { "/bin/rm", dex_file, profile_file, output_dex };
-    if (!::art::Exec(rm_exec_argv, error_msg)) {
+    if (!UnlinkFile(dex_file) || !UnlinkFile(profile_file) || !UnlinkFile(output_dex)) {
       return false;
     }
     return true;
@@ -467,7 +468,7 @@
     // -v makes sure that the layout did not corrupt the dex file.
     std::vector<std::string> dexlayout_args =
         { "-i", "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, dex_file };
-    if (!DexLayoutExec(dexlayout_args, error_msg)) {
+    if (!DexLayoutExec(dexlayout_args, error_msg, /*pass_default_cdex_option*/ false)) {
       return false;
     }
 
@@ -479,7 +480,7 @@
     // -i since the checksum won't match from the first layout.
     std::vector<std::string> second_dexlayout_args =
         { "-i", "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, output_dex };
-    if (!DexLayoutExec(second_dexlayout_args, error_msg)) {
+    if (!DexLayoutExec(second_dexlayout_args, error_msg, /*pass_default_cdex_option*/ false)) {
       return false;
     }
 
@@ -490,10 +491,11 @@
       diff_result = false;
     }
 
-    std::vector<std::string> rm_exec_argv =
-        { "/bin/rm", dex_file, profile_file, output_dex, second_output_dex };
-    if (!::art::Exec(rm_exec_argv, error_msg)) {
-      return false;
+    std::vector<std::string> test_files = { dex_file, profile_file, output_dex, second_output_dex };
+    for (auto test_file : test_files) {
+      if (!UnlinkFile(test_file)) {
+        return false;
+      }
     }
 
     return diff_result;
@@ -512,7 +514,7 @@
     std::string output_dex = tmp_dir + "classes.dex.new";
 
     std::vector<std::string> dexlayout_args = { "-w", tmp_dir, "-o", "/dev/null", input_dex };
-    if (!DexLayoutExec(dexlayout_args, error_msg)) {
+    if (!DexLayoutExec(dexlayout_args, error_msg, /*pass_default_cdex_option*/ false)) {
       return false;
     }
 
@@ -522,9 +524,11 @@
       return false;
     }
 
-    std::vector<std::string> rm_exec_argv = { "/bin/rm", input_dex, output_dex };
-    if (!::art::Exec(rm_exec_argv, error_msg)) {
-      return false;
+    std::vector<std::string> dex_files = { input_dex, output_dex };
+    for (auto dex_file : dex_files) {
+      if (!UnlinkFile(dex_file)) {
+        return false;
+      }
     }
     return true;
   }
@@ -550,17 +554,27 @@
     return true;
   }
 
-  bool DexLayoutExec(const std::vector<std::string>& dexlayout_args, std::string* error_msg) {
+  bool DexLayoutExec(const std::vector<std::string>& dexlayout_args,
+                     std::string* error_msg,
+                     bool pass_default_cdex_option = true) {
     std::vector<std::string> argv;
 
     std::string dexlayout = GetDexLayoutPath();
     CHECK(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
     argv.push_back(dexlayout);
+    if (pass_default_cdex_option) {
+      std::vector<std::string> cdex_level = DefaultCompactDexOption();
+      argv.insert(argv.end(), cdex_level.begin(), cdex_level.end());
+    }
 
     argv.insert(argv.end(), dexlayout_args.begin(), dexlayout_args.end());
 
     return ::art::Exec(argv, error_msg);
   }
+
+  bool UnlinkFile(const std::string& file_path) {
+    return unix_file::FdFile(file_path, 0, false).Unlink();
+  }
 };
 
 
@@ -730,11 +744,29 @@
     CHECK(mutated_successfully)
         << "Failed to find candidate code item with only one code unit in last instruction.";
   });
-  std::vector<std::string> dexlayout_args = { "-i", "-o", "/dev/null", temp_dex.GetFilename() };
+
+  std::string error_msg;
+
+  ScratchFile tmp_file;
+  const std::string& tmp_name = tmp_file.GetFilename();
+  size_t tmp_last_slash = tmp_name.rfind('/');
+  std::string tmp_dir = tmp_name.substr(0, tmp_last_slash + 1);
+  ScratchFile profile_file;
+
+  std::vector<std::string> dexlayout_args =
+      { "-i",
+        "-v",
+        "-w", tmp_dir,
+        "-o", tmp_name,
+        "-p", profile_file.GetFilename(),
+        temp_dex.GetFilename()
+      };
+  // -v makes sure that the layout did not corrupt the dex file.
   ASSERT_TRUE(DexLayoutExec(&temp_dex,
                             /*dex_filename*/ nullptr,
-                            nullptr /* profile_file */,
+                            &profile_file,
                             dexlayout_args));
+  ASSERT_TRUE(UnlinkFile(temp_dex.GetFilename() + ".new"));
 }
 
 // Test that link data is written out (or at least the header is updated).
@@ -772,11 +804,7 @@
                             /*dex_filename*/ nullptr,
                             &profile_file,
                             dexlayout_args));
-
-  std::string output_dex = temp_dex.GetFilename() + ".new";
-  std::vector<std::string> rm_exec_argv =
-      { "/bin/rm", output_dex };
-  ASSERT_TRUE(::art::Exec(rm_exec_argv, &error_msg));
+  ASSERT_TRUE(UnlinkFile(temp_dex.GetFilename() + ".new"));
 }
 
 TEST_F(DexLayoutTest, ClassFilter) {
diff --git a/openjdkjvmti/ti_class_definition.h b/openjdkjvmti/ti_class_definition.h
index e0b9b31..31c3611 100644
--- a/openjdkjvmti/ti_class_definition.h
+++ b/openjdkjvmti/ti_class_definition.h
@@ -49,8 +49,7 @@
 class ArtClassDefinition {
  public:
   // If we support doing a on-demand dex-dequickening using signal handlers.
-  // TODO Make this true. We currently have some ASAN issues with this.
-  static constexpr bool kEnableOnDemandDexDequicken = false;
+  static constexpr bool kEnableOnDemandDexDequicken = true;
 
   ArtClassDefinition()
       : klass_(nullptr),
diff --git a/openjdkjvmti/transform.cc b/openjdkjvmti/transform.cc
index 7b19a24..dc9f69a 100644
--- a/openjdkjvmti/transform.cc
+++ b/openjdkjvmti/transform.cc
@@ -128,6 +128,11 @@
       }
     }
 
+    if (LIKELY(self != nullptr)) {
+      CHECK_EQ(self->GetState(), art::ThreadState::kNative)
+          << "Transformation fault handler occurred outside of native mode";
+    }
+
     VLOG(signals) << "Lazy initialization of dex file for transformation of " << res->GetName()
                   << " during SEGV";
     res->InitializeMemory();
@@ -250,6 +255,10 @@
   static_assert(kEvent == ArtJvmtiEvent::kClassFileLoadHookNonRetransformable ||
                 kEvent == ArtJvmtiEvent::kClassFileLoadHookRetransformable,
                 "bad event type");
+  // We don't want to do transitions between calling the event and setting the new data so change to
+  // native state early. This also avoids any problems that the FaultHandler might have in
+  // determining if an access to the dex_data is from generated code or not.
+  art::ScopedThreadStateChange stsc(self, art::ThreadState::kNative);
   ScopedDefinitionHandler handler(def);
   jint new_len = -1;
   unsigned char* new_data = nullptr;
diff --git a/runtime/dex/dex_file_layout.h b/runtime/dex/dex_file_layout.h
index a7b9051..793e3b5 100644
--- a/runtime/dex/dex_file_layout.h
+++ b/runtime/dex/dex_file_layout.h
@@ -83,7 +83,7 @@
     }
 
     void CombineSection(uint32_t start_offset, uint32_t end_offset) {
-      DCHECK_LT(start_offset, end_offset);
+      DCHECK_LE(start_offset, end_offset);
       if (start_offset_ == end_offset_) {
         start_offset_ = start_offset;
         end_offset_ = end_offset;
diff --git a/runtime/gc/allocator/dlmalloc.cc b/runtime/gc/allocator/dlmalloc.cc
index 6506220..4570e9c 100644
--- a/runtime/gc/allocator/dlmalloc.cc
+++ b/runtime/gc/allocator/dlmalloc.cc
@@ -37,6 +37,7 @@
 #pragma GCC diagnostic ignored "-Wredundant-decls"
 #pragma GCC diagnostic ignored "-Wempty-body"
 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#pragma GCC diagnostic ignored "-Wnull-pointer-arithmetic"
 #include "../../../external/dlmalloc/malloc.c"
 // Note: malloc.c uses a DEBUG define to drive debug code. This interferes with the DEBUG severity
 //       of libbase, so undefine it now.
diff --git a/runtime/gc/allocator/dlmalloc.h b/runtime/gc/allocator/dlmalloc.h
index 29b96ee..b12691a 100644
--- a/runtime/gc/allocator/dlmalloc.h
+++ b/runtime/gc/allocator/dlmalloc.h
@@ -32,6 +32,7 @@
 
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wredundant-decls"
+#pragma GCC diagnostic ignored "-Wnull-pointer-arithmetic"
 #include "../../external/dlmalloc/malloc.h"
 #pragma GCC diagnostic pop
 
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index b1932d1..cf5bd4a 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -1890,7 +1890,10 @@
   count_requested_homogeneous_space_compaction_++;
   // Store performed homogeneous space compaction at a new request arrival.
   ScopedThreadStateChange tsc(self, kWaitingPerformingGc);
-  Locks::mutator_lock_->AssertNotHeld(self);
+  // TODO: Clang prebuilt for r316199 produces bogus thread safety analysis warning for holding both
+  // exclusive and shared lock in the same scope. Remove the assertion as a temporary workaround.
+  // http://b/71769596
+  // Locks::mutator_lock_->AssertNotHeld(self);
   {
     ScopedThreadStateChange tsc2(self, kWaitingForGcToComplete);
     MutexLock mu(self, *gc_complete_lock_);
@@ -1968,7 +1971,10 @@
   Runtime* const runtime = Runtime::Current();
   Thread* const self = Thread::Current();
   ScopedThreadStateChange tsc(self, kWaitingPerformingGc);
-  Locks::mutator_lock_->AssertNotHeld(self);
+  // TODO: Clang prebuilt for r316199 produces bogus thread safety analysis warning for holding both
+  // exclusive and shared lock in the same scope. Remove the assertion as a temporary workaround.
+  // http://b/71769596
+  // Locks::mutator_lock_->AssertNotHeld(self);
   // Busy wait until we can GC (StartGC can fail if we have a non-zero
   // compacting_gc_disable_count_, this should rarely occurs).
   for (;;) {
@@ -2511,7 +2517,10 @@
     }
   }
   ScopedThreadStateChange tsc(self, kWaitingPerformingGc);
-  Locks::mutator_lock_->AssertNotHeld(self);
+  // TODO: Clang prebuilt for r316199 produces bogus thread safety analysis warning for holding both
+  // exclusive and shared lock in the same scope. Remove the assertion as a temporary workaround.
+  // http://b/71769596
+  // Locks::mutator_lock_->AssertNotHeld(self);
   if (self->IsHandlingStackOverflow()) {
     // If we are throwing a stack overflow error we probably don't have enough remaining stack
     // space to run the GC.
diff --git a/runtime/gc/heap_test.cc b/runtime/gc/heap_test.cc
index 6d426c2..9d8e5d2 100644
--- a/runtime/gc/heap_test.cc
+++ b/runtime/gc/heap_test.cc
@@ -81,6 +81,7 @@
   void SetUpRuntimeOptions(RuntimeOptions* options) {
     CommonRuntimeTest::SetUpRuntimeOptions(options);
     options->push_back(std::make_pair("-Xzygote", nullptr));
+    options->push_back(std::make_pair("-Xno-hidden-api-checks", nullptr));
   }
 };
 
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 25d83df..3afd320 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1172,11 +1172,15 @@
 
   target_sdk_version_ = runtime_options.GetOrDefault(Opt::TargetSdkVersion);
 
-  // Check whether to enforce hidden API access checks. Zygote needs to be exempt
-  // but checks may be enabled for forked processes (see dalvik_system_ZygoteHooks).
-  if (is_zygote_ || runtime_options.Exists(Opt::NoHiddenApiChecks)) {
-    do_hidden_api_checks_ = false;
-  }
+  // Check whether to enforce hidden API access checks. The checks are disabled
+  // by default and we only enable them if:
+  // (a) runtime was started with a flag that enables the checks, or
+  // (b) Zygote forked a new process that is not exempt (see ZygoteHooks).
+  // TODO(dbrazdil): Turn the NoHiddenApiChecks negative flag into a positive one
+  // to clean up this logic.
+  do_hidden_api_checks_ = IsAotCompiler() && !runtime_options.Exists(Opt::NoHiddenApiChecks);
+  DCHECK(!is_zygote_ || !do_hidden_api_checks_)
+      << "Zygote should not be started with hidden API checks";
 
   no_sig_chain_ = runtime_options.Exists(Opt::NoSigChain);
   force_native_bridge_ = runtime_options.Exists(Opt::ForceNativeBridge);
diff --git a/test/137-cfi/cfi.cc b/test/137-cfi/cfi.cc
index bdfb44a..83234f0 100644
--- a/test/137-cfi/cfi.cc
+++ b/test/137-cfi/cfi.cc
@@ -83,7 +83,7 @@
   printf("Cannot find %s in backtrace:\n", seq[cur_search_index].c_str());
   for (Backtrace::const_iterator it = bt->begin(); it != bt->end(); ++it) {
     if (BacktraceMap::IsValid(it->map)) {
-      printf("  %s\n", it->func_name.c_str());
+      printf("  %s\n", Backtrace::FormatFrameData(&*it).c_str());
     }
   }
 
@@ -130,6 +130,7 @@
       "Java_Main_unwindInProcess",                   // This function.
       "Main.unwindInProcess",                        // The corresponding Java native method frame.
       "java.util.Arrays.binarySearch0",              // Framework method.
+      "Base.runBase",                                // Method in other dex file.
       "Main.main"                                    // The Java entry method.
   };
 
@@ -230,6 +231,7 @@
                                                      // resolved, so don't look for it right now.
         "Main.sleep",                                // The corresponding Java native method frame.
         "java.util.Arrays.binarySearch0",            // Framework method.
+        "Base.runBase",                              // Method in other dex file.
         "Main.main"                                  // The Java entry method.
     };
 
diff --git a/test/137-cfi/src-multidex/Base.java b/test/137-cfi/src-multidex/Base.java
new file mode 100644
index 0000000..d3f8a56
--- /dev/null
+++ b/test/137-cfi/src-multidex/Base.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+public abstract class Base {
+  abstract public void runImpl();
+  public void runBase() {
+    runImpl();
+  }
+}
diff --git a/test/137-cfi/src/Main.java b/test/137-cfi/src/Main.java
index 1ec7072..9a2e352 100644
--- a/test/137-cfi/src/Main.java
+++ b/test/137-cfi/src/Main.java
@@ -20,7 +20,7 @@
 import java.util.Arrays;
 import java.util.Comparator;
 
-public class Main implements Comparator<Main> {
+public class Main extends Base implements Comparator<Main> {
   // Whether to test local unwinding.
   private boolean testLocal;
 
@@ -57,10 +57,10 @@
   }
 
   public static void main(String[] args) throws Exception {
-      new Main(args).run();
+      new Main(args).runBase();
   }
 
-  private void run() {
+  public void runImpl() {
       if (secondary) {
           if (!testRemote) {
               throw new RuntimeException("Should not be running secondary!");
diff --git a/test/ManyMethods/ManyMethods.java b/test/ManyMethods/ManyMethods.java
index b3a57f6..98b9faf 100644
--- a/test/ManyMethods/ManyMethods.java
+++ b/test/ManyMethods/ManyMethods.java
@@ -26,6 +26,8 @@
     public static String msg7 = "Hello World7";
     public static String msg8 = "Hello World8";
     public static String msg9 = "Hello World9";
+    public static String msg10 = "Hello World10";
+    public static String msg11 = "Hello World11";
   }
 
   static class Printer {
@@ -57,35 +59,35 @@
   }
 
   public static void Print4() {
-    Printer.Print(Strings.msg2);
+    Printer.Print(Strings.msg4);
   }
 
   public static void Print5() {
-    Printer.Print(Strings.msg3);
-  }
-
-  public static void Print6() {
-    Printer2.Print(Strings.msg4);
-  }
-
-  public static void Print7() {
     Printer.Print(Strings.msg5);
   }
 
+  public static void Print6() {
+    Printer2.Print(Strings.msg6);
+  }
+
+  public static void Print7() {
+    Printer.Print(Strings.msg7);
+  }
+
   public static void Print8() {
-    Printer.Print(Strings.msg6);
+    Printer.Print(Strings.msg8);
   }
 
   public static void Print9() {
-    Printer2.Print(Strings.msg7);
+    Printer2.Print(Strings.msg9);
   }
 
   public static void Print10() {
-    Printer2.Print(Strings.msg8);
+    Printer2.Print(Strings.msg10);
   }
 
   public static void Print11() {
-    Printer.Print(Strings.msg9);
+    Printer.Print(Strings.msg11);
   }
 
   public static void main(String args[]) {
diff --git a/test/ti-stress/stress.cc b/test/ti-stress/stress.cc
index 6e29e36..7fc289f 100644
--- a/test/ti-stress/stress.cc
+++ b/test/ti-stress/stress.cc
@@ -809,7 +809,7 @@
     .can_signal_thread                               = 0,
     .can_get_source_file_name                        = 1,
     .can_get_line_numbers                            = 1,
-    .can_get_source_debug_extension                  = 0,
+    .can_get_source_debug_extension                  = 1,
     .can_access_local_variables                      = 0,
     .can_maintain_original_method_order              = 0,
     .can_generate_single_step_events                 = 1,