Merge "Add PreResolved strings dex cache array"
diff --git a/cmdline/token_range.h b/cmdline/token_range.h
index 642bb1d..e28ead9 100644
--- a/cmdline/token_range.h
+++ b/cmdline/token_range.h
@@ -325,7 +325,7 @@
     string_idx += remaining;
     maybe_push_wildcard_token();
 
-    return std::unique_ptr<TokenRange>(new TokenRange(std::move(new_token_list)));
+    return std::make_unique<TokenRange>(std::move(new_token_list));
   }
 
   // Do a quick match token-by-token, and see if they match.
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc
index 586891a..fc8cd52 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -328,6 +328,8 @@
                                             (size_t)120 * 1024 * 1024,  // 120MB
                                             PROT_NONE,
                                             false /* no need for 4gb flag with fixed mmap */,
+                                            /*reuse=*/ false,
+                                            /*reservation=*/ nullptr,
                                             &error_msg);
   CHECK(image_reservation_.IsValid()) << error_msg;
 }
diff --git a/compiler/driver/simple_compiler_options_map.h b/compiler/driver/simple_compiler_options_map.h
index 3860da9..e7a51a4 100644
--- a/compiler/driver/simple_compiler_options_map.h
+++ b/compiler/driver/simple_compiler_options_map.h
@@ -50,7 +50,7 @@
 
 static inline Parser CreateSimpleParser(bool ignore_unrecognized) {
   std::unique_ptr<Parser::Builder> parser_builder =
-      std::unique_ptr<Parser::Builder>(new Parser::Builder());
+      std::make_unique<Parser::Builder>();
 
   AddCompilerOptionsArgumentParserOptions<SimpleParseArgumentMap>(*parser_builder);
 
diff --git a/dex2oat/dex2oat_options.cc b/dex2oat/dex2oat_options.cc
index 710f14c..236c1fc 100644
--- a/dex2oat/dex2oat_options.cc
+++ b/dex2oat/dex2oat_options.cc
@@ -187,7 +187,7 @@
 }
 
 static Parser CreateArgumentParser() {
-  std::unique_ptr<Builder> parser_builder = std::unique_ptr<Builder>(new Builder());
+  std::unique_ptr<Builder> parser_builder = std::make_unique<Builder>();
 
   AddInputMappings(*parser_builder);
   AddGeneratedArtifactMappings(*parser_builder);
@@ -267,7 +267,7 @@
     return nullptr;
   }
 
-  return std::unique_ptr<Dex2oatArgumentMap>(new Dex2oatArgumentMap(parser.ReleaseArgumentsMap()));
+  return std::make_unique<Dex2oatArgumentMap>(parser.ReleaseArgumentsMap());
 }
 
 #pragma GCC diagnostic pop
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index 88ce324..10d2b6f 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -39,6 +39,7 @@
 #include "dex/dex_file_loader.h"
 #include "dex2oat_environment_test.h"
 #include "dex2oat_return_codes.h"
+#include "gc_root-inl.h"
 #include "intern_table-inl.h"
 #include "oat.h"
 #include "oat_file.h"
diff --git a/dex2oat/linker/elf_writer_quick.cc b/dex2oat/linker/elf_writer_quick.cc
index 9a7f93d..9fbcca4 100644
--- a/dex2oat/linker/elf_writer_quick.cc
+++ b/dex2oat/linker/elf_writer_quick.cc
@@ -17,6 +17,7 @@
 #include "elf_writer_quick.h"
 
 #include <openssl/sha.h>
+#include <memory>
 #include <unordered_map>
 #include <unordered_set>
 
@@ -263,16 +264,15 @@
   if (!debug_info.Empty() && compiler_options_.GetGenerateMiniDebugInfo()) {
     // Prepare the mini-debug-info in background while we do other I/O.
     Thread* self = Thread::Current();
-    debug_info_task_ = std::unique_ptr<DebugInfoTask>(
-        new DebugInfoTask(builder_->GetIsa(),
-                          compiler_options_.GetInstructionSetFeatures(),
-                          builder_->GetText()->GetAddress(),
-                          text_size_,
-                          builder_->GetDex()->Exists() ? builder_->GetDex()->GetAddress() : 0,
-                          dex_section_size_,
-                          debug_info));
-    debug_info_thread_pool_ = std::unique_ptr<ThreadPool>(
-        new ThreadPool("Mini-debug-info writer", 1));
+    debug_info_task_ = std::make_unique<DebugInfoTask>(
+        builder_->GetIsa(),
+        compiler_options_.GetInstructionSetFeatures(),
+        builder_->GetText()->GetAddress(),
+        text_size_,
+        builder_->GetDex()->Exists() ? builder_->GetDex()->GetAddress() : 0,
+        dex_section_size_,
+        debug_info);
+    debug_info_thread_pool_ = std::make_unique<ThreadPool>("Mini-debug-info writer", 1);
     debug_info_thread_pool_->AddTask(self, debug_info_task_.get());
     debug_info_thread_pool_->StartWorkers(self);
   }
diff --git a/dex2oat/linker/elf_writer_test.cc b/dex2oat/linker/elf_writer_test.cc
index 1d578ab..b381765 100644
--- a/dex2oat/linker/elf_writer_test.cc
+++ b/dex2oat/linker/elf_writer_test.cc
@@ -68,9 +68,9 @@
   {
     std::string error_msg;
     std::unique_ptr<ElfFile> ef(ElfFile::Open(file.get(),
-                                              /* writable */ false,
-                                              /* program_header_only */ false,
-                                              /*low_4gb*/false,
+                                              /*writable=*/ false,
+                                              /*program_header_only=*/ false,
+                                              /*low_4gb=*/false,
                                               &error_msg));
     CHECK(ef.get() != nullptr) << error_msg;
     EXPECT_ELF_FILE_ADDRESS(ef, dl_oatdata, "oatdata", false);
@@ -80,9 +80,9 @@
   {
     std::string error_msg;
     std::unique_ptr<ElfFile> ef(ElfFile::Open(file.get(),
-                                              /* writable */ false,
-                                              /* program_header_only */ false,
-                                              /* low_4gb */ false,
+                                              /*writable=*/ false,
+                                              /*program_header_only=*/ false,
+                                              /*low_4gb=*/ false,
                                               &error_msg));
     CHECK(ef.get() != nullptr) << error_msg;
     EXPECT_ELF_FILE_ADDRESS(ef, dl_oatdata, "oatdata", true);
@@ -92,24 +92,23 @@
   {
     std::string error_msg;
     std::unique_ptr<ElfFile> ef(ElfFile::Open(file.get(),
-                                              /* writable */ false,
-                                              /* program_header_only */ true,
-                                              /* low_4gb */ false,
+                                              /*writable=*/ false,
+                                              /*program_header_only=*/ true,
+                                              /*low_4gb=*/ false,
                                               &error_msg));
     CHECK(ef.get() != nullptr) << error_msg;
     size_t size;
     bool success = ef->GetLoadedSize(&size, &error_msg);
     CHECK(success) << error_msg;
     MemMap reservation = MemMap::MapAnonymous("ElfWriterTest#dlsym reservation",
-                                              /* addr */ nullptr,
                                               RoundUp(size, kPageSize),
                                               PROT_NONE,
-                                              /* low_4gb */ true,
+                                              /*low_4gb=*/ true,
                                               &error_msg);
     CHECK(reservation.IsValid()) << error_msg;
     uint8_t* base = reservation.Begin();
     success =
-        ef->Load(file.get(), /* executable */ false, /* low_4gb */ false, &reservation, &error_msg);
+        ef->Load(file.get(), /*executable=*/ false, /*low_4gb=*/ false, &reservation, &error_msg);
     CHECK(success) << error_msg;
     CHECK(!reservation.IsValid());
     EXPECT_EQ(reinterpret_cast<uintptr_t>(dl_oatdata) + reinterpret_cast<uintptr_t>(base),
@@ -131,9 +130,9 @@
   {
     std::string error_msg;
     std::unique_ptr<ElfFile> ef(ElfFile::Open(file.get(),
-                                              /* writable */ false,
-                                              /* program_header_only */ false,
-                                              /* low_4gb */ false,
+                                              /*writable=*/ false,
+                                              /*program_header_only=*/ false,
+                                              /*low_4gb=*/ false,
                                               &error_msg));
     CHECK(ef.get() != nullptr) << error_msg;
     EXPECT_TRUE(ef->HasSection(".note.gnu.build-id"));
diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc
index 33af833..fd10b6b 100644
--- a/dex2oat/linker/image_writer.cc
+++ b/dex2oat/linker/image_writer.cc
@@ -1098,10 +1098,9 @@
 
     std::string error_msg;
     image_info.image_ = MemMap::MapAnonymous("image writer image",
-                                             /* addr */ nullptr,
                                              length,
                                              PROT_READ | PROT_WRITE,
-                                             /* low_4gb */ false,
+                                             /*low_4gb=*/ false,
                                              &error_msg);
     if (UNLIKELY(!image_info.image_.IsValid())) {
       LOG(ERROR) << "Failed to allocate memory for image file generation: " << error_msg;
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index 23c486d..01c24fc 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -3401,11 +3401,6 @@
 }
 
 bool OatWriter::LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_file) {
-  // Open dex files and write them into `out`.
-  // Note that we only verify dex files which do not belong to the boot class path.
-  // This is because those have been processed by `hiddenapi` and would not pass
-  // some of the checks. No guarantees are lost, however, as `hiddenapi` verifies
-  // the dex files prior to processing.
   TimingLogger::ScopedTiming split("Dex Layout", timings_);
   std::string error_msg;
   std::string location(oat_dex_file->GetLocation());
@@ -3426,7 +3421,7 @@
     dex_file = dex_file_loader.Open(location,
                                     zip_entry->GetCrc32(),
                                     std::move(mem_map),
-                                    /* verify */ !GetCompilerOptions().IsBootImage(),
+                                    /* verify */ true,
                                     /* verify_checksum */ true,
                                     &error_msg);
   } else if (oat_dex_file->source_.IsRawFile()) {
@@ -3438,7 +3433,7 @@
     }
     TimingLogger::ScopedTiming extract("Open", timings_);
     dex_file = dex_file_loader.OpenDex(dup_fd, location,
-                                       /* verify */ !GetCompilerOptions().IsBootImage(),
+                                       /* verify */ true,
                                        /* verify_checksum */ true,
                                        /* mmap_shared */ false,
                                        &error_msg);
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc
index 6b2a1b9..2b59342 100644
--- a/dexdump/dexdump.cc
+++ b/dexdump/dexdump.cc
@@ -1208,7 +1208,7 @@
  */
 static void dumpMethod(const ClassAccessor::Method& method, int i) {
   // Bail for anything private if export only requested.
-  const uint32_t flags = method.GetRawAccessFlags();
+  const uint32_t flags = method.GetAccessFlags();
   if (gOptions.exportsOnly && (flags & (kAccPublic | kAccProtected)) == 0) {
     return;
   }
@@ -1319,7 +1319,7 @@
  */
 static void dumpField(const ClassAccessor::Field& field, int i, const u1** data = nullptr) {
   // Bail for anything private if export only requested.
-  const uint32_t flags = field.GetRawAccessFlags();
+  const uint32_t flags = field.GetAccessFlags();
   if (gOptions.exportsOnly && (flags & (kAccPublic | kAccProtected)) == 0) {
     return;
   }
diff --git a/dexlayout/compact_dex_writer.cc b/dexlayout/compact_dex_writer.cc
index a04cfb6..a7dad07 100644
--- a/dexlayout/compact_dex_writer.cc
+++ b/dexlayout/compact_dex_writer.cc
@@ -441,6 +441,7 @@
   WriteTypeLists(data_stream);
   WriteClassDatas(data_stream);
   WriteStringDatas(data_stream);
+  WriteHiddenapiClassData(data_stream);
 
   // Write delayed id sections that depend on data sections.
   {
diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h
index 598f7df..20ebc17 100644
--- a/dexlayout/dex_ir.h
+++ b/dexlayout/dex_ir.h
@@ -21,11 +21,11 @@
 
 #include <stdint.h>
 
-#include <map>
 #include <vector>
 
 #include "base/iteration_range.h"
 #include "base/leb128.h"
+#include "base/safe_map.h"
 #include "base/stl_util.h"
 #include "dex/dex_file-inl.h"
 #include "dex/dex_file_types.h"
@@ -50,6 +50,7 @@
 class FieldId;
 class FieldItem;
 class Header;
+class HiddenapiClassData;
 class MapList;
 class MapItem;
 class MethodHandleItem;
@@ -101,6 +102,7 @@
   virtual void Dispatch(AnnotationSetItem* annotation_set_item) = 0;
   virtual void Dispatch(AnnotationSetRefList* annotation_set_ref_list) = 0;
   virtual void Dispatch(AnnotationsDirectoryItem* annotations_directory_item) = 0;
+  virtual void Dispatch(HiddenapiClassData* hiddenapi_class_data) = 0;
   virtual void Dispatch(MapList* map_list) = 0;
   virtual void Dispatch(MapItem* map_item) = 0;
 
@@ -216,6 +218,7 @@
   uint32_t GetOffset() const { return offset_; }
   void SetOffset(uint32_t new_offset) { offset_ = new_offset; }
   virtual uint32_t Size() const = 0;
+  bool Empty() const { return Size() == 0u; }
 
  private:
   // Start out unassigned.
@@ -476,6 +479,12 @@
   const CollectionVector<AnnotationsDirectoryItem>& AnnotationsDirectoryItems() const {
     return annotations_directory_items_;
   }
+  IndexedCollectionVector<HiddenapiClassData>& HiddenapiClassDatas() {
+    return hiddenapi_class_datas_;
+  }
+  const IndexedCollectionVector<HiddenapiClassData>& HiddenapiClassDatas() const {
+    return hiddenapi_class_datas_;
+  }
   CollectionVector<DebugInfoItem>& DebugInfoItems() { return debug_info_items_; }
   const CollectionVector<DebugInfoItem>& DebugInfoItems() const { return debug_info_items_; }
   CollectionVector<CodeItem>& CodeItems() { return code_items_; }
@@ -553,6 +562,7 @@
   IndexedCollectionVector<AnnotationSetItem> annotation_set_items_;
   IndexedCollectionVector<AnnotationSetRefList> annotation_set_ref_lists_;
   IndexedCollectionVector<AnnotationsDirectoryItem> annotations_directory_items_;
+  IndexedCollectionVector<HiddenapiClassData> hiddenapi_class_datas_;
   // The order of the vectors controls the layout of the output file by index order, to change the
   // layout just sort the vector. Note that you may only change the order of the non indexed vectors
   // below. Indexed vectors are accessed by indices in other places, changing the sorting order will
@@ -1264,6 +1274,49 @@
   DISALLOW_COPY_AND_ASSIGN(MethodHandleItem);
 };
 
+using HiddenapiFlagsMap = SafeMap<const Item*, uint32_t>;
+
+class HiddenapiClassData : public IndexedItem {
+ public:
+  HiddenapiClassData(const ClassDef* class_def, std::unique_ptr<HiddenapiFlagsMap> flags)
+      : class_def_(class_def), flags_(std::move(flags)) { }
+  ~HiddenapiClassData() override { }
+
+  const ClassDef* GetClassDef() const { return class_def_; }
+
+  uint32_t GetFlags(const Item* field_or_method_item) const {
+    return (flags_ == nullptr) ? 0u : flags_->Get(field_or_method_item);
+  }
+
+  static uint32_t GetFlags(Header* header, ClassDef* class_def, const Item* field_or_method_item) {
+    DCHECK(header != nullptr);
+    DCHECK(class_def != nullptr);
+    return (header->HiddenapiClassDatas().Empty())
+        ? 0u
+        : header->HiddenapiClassDatas()[class_def->GetIndex()]->GetFlags(field_or_method_item);
+  }
+
+  uint32_t ItemSize() const {
+    uint32_t size = 0u;
+    bool has_non_zero_entries = false;
+    if (flags_ != nullptr) {
+      for (const auto& entry : *flags_) {
+        size += UnsignedLeb128Size(entry.second);
+        has_non_zero_entries |= (entry.second != 0u);
+      }
+    }
+    return has_non_zero_entries ? size : 0u;
+  }
+
+  void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); }
+
+ private:
+  const ClassDef* class_def_;
+  std::unique_ptr<HiddenapiFlagsMap> flags_;
+
+  DISALLOW_COPY_AND_ASSIGN(HiddenapiClassData);
+};
+
 // TODO(sehr): implement MapList.
 class MapList : public Item {
  public:
diff --git a/dexlayout/dex_ir_builder.cc b/dexlayout/dex_ir_builder.cc
index 947d3d5..92e438c 100644
--- a/dexlayout/dex_ir_builder.cc
+++ b/dexlayout/dex_ir_builder.cc
@@ -17,6 +17,7 @@
  */
 
 #include <stdint.h>
+#include <memory>
 #include <vector>
 
 #include "dex_ir_builder.h"
@@ -170,6 +171,7 @@
   void AddAnnotationsFromMapListSection(const DexFile& dex_file,
                                         uint32_t start_offset,
                                         uint32_t count);
+  void AddHiddenapiClassDataFromMapListSection(const DexFile& dex_file, uint32_t offset);
 
   void CheckAndSetRemainingOffsets(const DexFile& dex_file, const Options& options);
 
@@ -408,6 +410,10 @@
       case DexFile::kDexTypeAnnotationsDirectoryItem:
         header_->AnnotationsDirectoryItems().SetOffset(item->offset_);
         break;
+      case DexFile::kDexTypeHiddenapiClassData:
+        header_->HiddenapiClassDatas().SetOffset(item->offset_);
+        AddHiddenapiClassDataFromMapListSection(dex_file, item->offset_);
+        break;
       default:
         LOG(ERROR) << "Unknown map list item type.";
     }
@@ -624,6 +630,44 @@
   }
 }
 
+void BuilderMaps::AddHiddenapiClassDataFromMapListSection(const DexFile& dex_file,
+                                                          uint32_t offset) {
+  const DexFile::HiddenapiClassData* hiddenapi_class_data =
+      dex_file.GetHiddenapiClassDataAtOffset(offset);
+  DCHECK(hiddenapi_class_data == dex_file.GetHiddenapiClassData());
+
+  for (auto& class_def : header_->ClassDefs()) {
+    uint32_t index = class_def->GetIndex();
+    ClassData* class_data = class_def->GetClassData();
+    const uint8_t* ptr = hiddenapi_class_data->GetFlagsPointer(index);
+
+    std::unique_ptr<HiddenapiFlagsMap> flags = nullptr;
+    if (ptr != nullptr) {
+      DCHECK(class_data != nullptr);
+      flags = std::make_unique<HiddenapiFlagsMap>();
+      for (const dex_ir::FieldItem& field : *class_data->StaticFields()) {
+        flags->emplace(&field, DecodeUnsignedLeb128(&ptr));
+      }
+      for (const dex_ir::FieldItem& field : *class_data->InstanceFields()) {
+        flags->emplace(&field, DecodeUnsignedLeb128(&ptr));
+      }
+      for (const dex_ir::MethodItem& method : *class_data->DirectMethods()) {
+        flags->emplace(&method, DecodeUnsignedLeb128(&ptr));
+      }
+      for (const dex_ir::MethodItem& method : *class_data->VirtualMethods()) {
+        flags->emplace(&method, DecodeUnsignedLeb128(&ptr));
+      }
+    }
+
+    CreateAndAddIndexedItem(header_->HiddenapiClassDatas(),
+                            header_->HiddenapiClassDatas().GetOffset() +
+                                hiddenapi_class_data->flags_offset_[index],
+                            index,
+                            class_def.get(),
+                            std::move(flags));
+  }
+}
+
 AnnotationItem* BuilderMaps::CreateAnnotationItem(const DexFile& dex_file,
                                                   const DexFile::AnnotationItem* annotation) {
   const uint8_t* const start_data = reinterpret_cast<const uint8_t*>(annotation);
@@ -698,8 +742,8 @@
       uint32_t annotation_set_offset = fields[i].annotations_off_;
       AnnotationSetItem* annotation_set_item =
           CreateAnnotationSetItem(dex_file, field_set_item, annotation_set_offset);
-      field_annotations->push_back(std::unique_ptr<FieldAnnotation>(
-          new FieldAnnotation(field_id, annotation_set_item)));
+      field_annotations->push_back(std::make_unique<FieldAnnotation>(
+          field_id, annotation_set_item));
     }
   }
   const DexFile::MethodAnnotationsItem* methods =
@@ -714,8 +758,8 @@
       uint32_t annotation_set_offset = methods[i].annotations_off_;
       AnnotationSetItem* annotation_set_item =
           CreateAnnotationSetItem(dex_file, method_set_item, annotation_set_offset);
-      method_annotations->push_back(std::unique_ptr<MethodAnnotation>(
-          new MethodAnnotation(method_id, annotation_set_item)));
+      method_annotations->push_back(std::make_unique<MethodAnnotation>(
+          method_id, annotation_set_item));
     }
   }
   const DexFile::ParameterAnnotationsItem* parameters =
@@ -908,13 +952,13 @@
     FieldItemVector* static_fields = new FieldItemVector();
     for (const ClassAccessor::Field& field : accessor.GetStaticFields()) {
       FieldId* field_item = header_->FieldIds()[field.GetIndex()];
-      uint32_t access_flags = field.GetRawAccessFlags();
+      uint32_t access_flags = field.GetAccessFlags();
       static_fields->emplace_back(access_flags, field_item);
     }
     FieldItemVector* instance_fields = new FieldItemVector();
     for (const ClassAccessor::Field& field : accessor.GetInstanceFields()) {
       FieldId* field_item = header_->FieldIds()[field.GetIndex()];
-      uint32_t access_flags = field.GetRawAccessFlags();
+      uint32_t access_flags = field.GetAccessFlags();
       instance_fields->emplace_back(access_flags, field_item);
     }
     // Direct methods.
@@ -1160,9 +1204,9 @@
       // Decode all name=value pairs.
       for (uint32_t i = 0; i < size; i++) {
         const uint32_t name_index = DecodeUnsignedLeb128(data);
-        elements->push_back(std::unique_ptr<AnnotationElement>(
-            new AnnotationElement(header_->StringIds()[name_index],
-                                  ReadEncodedValue(dex_file, data))));
+        elements->push_back(std::make_unique<AnnotationElement>(
+            header_->StringIds()[name_index],
+            ReadEncodedValue(dex_file, data)));
       }
       item->SetEncodedAnnotation(new EncodedAnnotation(header_->TypeIds()[type_idx], elements));
       break;
@@ -1180,7 +1224,7 @@
 MethodItem BuilderMaps::GenerateMethodItem(const DexFile& dex_file,
                                            const ClassAccessor::Method& method) {
   MethodId* method_id = header_->MethodIds()[method.GetIndex()];
-  uint32_t access_flags = method.GetRawAccessFlags();
+  uint32_t access_flags = method.GetAccessFlags();
   const DexFile::CodeItem* disk_code_item = method.GetCodeItem();
   // Temporary hack to prevent incorrectly deduping code items if they have the same offset since
   // they may have different debug info streams.
diff --git a/dexlayout/dex_writer.cc b/dexlayout/dex_writer.cc
index 365171b..ef6ccf9 100644
--- a/dexlayout/dex_writer.cc
+++ b/dexlayout/dex_writer.cc
@@ -462,6 +462,59 @@
   }
 }
 
+void DexWriter::WriteHiddenapiClassData(Stream* stream) {
+  if (header_->HiddenapiClassDatas().Empty()) {
+    return;
+  }
+  DCHECK_EQ(header_->HiddenapiClassDatas().Size(), header_->ClassDefs().Size());
+
+  stream->AlignTo(SectionAlignment(DexFile::kDexTypeHiddenapiClassData));
+  const uint32_t start = stream->Tell();
+
+  // Compute offsets for each class def and write the header.
+  // data_header[0]: total size of the section
+  // data_header[i + 1]: offset of class def[i] from the beginning of the section,
+  //                     or zero if no data
+  std::vector<uint32_t> data_header(header_->ClassDefs().Size() + 1, 0);
+  data_header[0] = sizeof(uint32_t) * (header_->ClassDefs().Size() + 1);
+  for (uint32_t i = 0; i < header_->ClassDefs().Size(); ++i) {
+    uint32_t item_size = header_->HiddenapiClassDatas()[i]->ItemSize();
+    data_header[i + 1] = item_size == 0u ? 0 : data_header[0];
+    data_header[0] += item_size;
+  }
+  stream->Write(data_header.data(), sizeof(uint32_t) * data_header.size());
+
+  // Write class data streams.
+  for (uint32_t i = 0; i < header_->ClassDefs().Size(); ++i) {
+    dex_ir::ClassDef* class_def = header_->ClassDefs()[i];
+    const auto& item = header_->HiddenapiClassDatas()[i];
+    DCHECK(item->GetClassDef() == class_def);
+
+    if (data_header[i + 1] != 0u) {
+      dex_ir::ClassData* class_data = class_def->GetClassData();
+      DCHECK(class_data != nullptr);
+      DCHECK_EQ(data_header[i + 1], stream->Tell() - start);
+      for (const dex_ir::FieldItem& field : *class_data->StaticFields()) {
+        stream->WriteUleb128(item->GetFlags(&field));
+      }
+      for (const dex_ir::FieldItem& field : *class_data->InstanceFields()) {
+        stream->WriteUleb128(item->GetFlags(&field));
+      }
+      for (const dex_ir::MethodItem& method : *class_data->DirectMethods()) {
+        stream->WriteUleb128(item->GetFlags(&method));
+      }
+      for (const dex_ir::MethodItem& method : *class_data->VirtualMethods()) {
+        stream->WriteUleb128(item->GetFlags(&method));
+      }
+    }
+  }
+  DCHECK_EQ(stream->Tell() - start, data_header[0]);
+
+  if (compute_offsets_ && start != stream->Tell()) {
+    header_->HiddenapiClassDatas().SetOffset(start);
+  }
+}
+
 void DexWriter::WriteDebugInfoItem(Stream* stream, dex_ir::DebugInfoItem* debug_info) {
   stream->AlignTo(SectionAlignment(DexFile::kDexTypeDebugInfoItem));
   ProcessOffset(stream, debug_info);
@@ -730,6 +783,9 @@
   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationsDirectoryItem,
                               header_->AnnotationsDirectoryItems().Size(),
                               header_->AnnotationsDirectoryItems().GetOffset()));
+  queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeHiddenapiClassData,
+                              header_->HiddenapiClassDatas().Empty() ? 0u : 1u,
+                              header_->HiddenapiClassDatas().GetOffset()));
   WriteMapItems(stream, &queue);
 }
 
@@ -829,6 +885,7 @@
   WriteTypeLists(stream);
   WriteClassDatas(stream);
   WriteStringDatas(stream);
+  WriteHiddenapiClassData(stream);
 
   // Write delayed id sections that depend on data sections.
   {
diff --git a/dexlayout/dex_writer.h b/dexlayout/dex_writer.h
index dd2ebad..98041d3 100644
--- a/dexlayout/dex_writer.h
+++ b/dexlayout/dex_writer.h
@@ -257,6 +257,7 @@
   void WriteStringDatas(Stream* stream);
   void WriteClassDatas(Stream* stream);
   void WriteMethodHandles(Stream* stream);
+  void WriteHiddenapiClassData(Stream* stream);
   void WriteMapItems(Stream* stream, MapItemQueue* queue);
   void GenerateAndWriteMapItems(Stream* stream);
 
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index 8905aa3..09f0b20 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -222,6 +222,17 @@
   return str;
 }
 
+static const char* GetHiddenapiFlagStr(uint32_t hiddenapi_flags) {
+  static const char* const kValue[] = {
+    "WHITELIST",             /* 0x0 */
+    "LIGHT_GREYLIST",        /* 0x1 */
+    "DARK_GREYLIST",         /* 0x2 */
+    "BLACKLIST",             /* 0x3 */
+  };
+  DCHECK_LT(hiddenapi_flags, arraysize(kValue));
+  return kValue[hiddenapi_flags];
+}
+
 static std::string GetSignatureForProtoId(const dex_ir::ProtoId* proto) {
   if (proto == nullptr) {
     return "<no signature>";
@@ -1147,7 +1158,11 @@
 /*
  * Dumps a method.
  */
-void DexLayout::DumpMethod(uint32_t idx, uint32_t flags, const dex_ir::CodeItem* code, int i) {
+void DexLayout::DumpMethod(uint32_t idx,
+                           uint32_t flags,
+                           uint32_t hiddenapi_flags,
+                           const dex_ir::CodeItem* code,
+                           int i) {
   // Bail for anything private if export only requested.
   if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) {
     return;
@@ -1158,12 +1173,16 @@
   char* type_descriptor = strdup(GetSignatureForProtoId(method_id->Proto()).c_str());
   const char* back_descriptor = method_id->Class()->GetStringId()->Data();
   char* access_str = CreateAccessFlagStr(flags, kAccessForMethod);
+  const char* hiddenapi_str = GetHiddenapiFlagStr(hiddenapi_flags);
 
   if (options_.output_format_ == kOutputPlain) {
     fprintf(out_file_, "    #%d              : (in %s)\n", i, back_descriptor);
     fprintf(out_file_, "      name          : '%s'\n", name);
     fprintf(out_file_, "      type          : '%s'\n", type_descriptor);
     fprintf(out_file_, "      access        : 0x%04x (%s)\n", flags, access_str);
+    if (hiddenapi_flags != 0u) {
+      fprintf(out_file_, "      hiddenapi     : 0x%04x (%s)\n", hiddenapi_flags, hiddenapi_str);
+    }
     if (code == nullptr) {
       fprintf(out_file_, "      code          : (none)\n");
     } else {
@@ -1257,7 +1276,11 @@
 /*
  * Dumps a static (class) field.
  */
-void DexLayout::DumpSField(uint32_t idx, uint32_t flags, int i, dex_ir::EncodedValue* init) {
+void DexLayout::DumpSField(uint32_t idx,
+                           uint32_t flags,
+                           uint32_t hiddenapi_flags,
+                           int i,
+                           dex_ir::EncodedValue* init) {
   // Bail for anything private if export only requested.
   if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) {
     return;
@@ -1268,12 +1291,16 @@
   const char* type_descriptor = field_id->Type()->GetStringId()->Data();
   const char* back_descriptor = field_id->Class()->GetStringId()->Data();
   char* access_str = CreateAccessFlagStr(flags, kAccessForField);
+  const char* hiddenapi_str = GetHiddenapiFlagStr(hiddenapi_flags);
 
   if (options_.output_format_ == kOutputPlain) {
     fprintf(out_file_, "    #%d              : (in %s)\n", i, back_descriptor);
     fprintf(out_file_, "      name          : '%s'\n", name);
     fprintf(out_file_, "      type          : '%s'\n", type_descriptor);
     fprintf(out_file_, "      access        : 0x%04x (%s)\n", flags, access_str);
+    if (hiddenapi_flags != 0u) {
+      fprintf(out_file_, "      hiddenapi     : 0x%04x (%s)\n", hiddenapi_flags, hiddenapi_str);
+    }
     if (init != nullptr) {
       fputs("      value         : ", out_file_);
       DumpEncodedValue(init);
@@ -1304,8 +1331,11 @@
 /*
  * Dumps an instance field.
  */
-void DexLayout::DumpIField(uint32_t idx, uint32_t flags, int i) {
-  DumpSField(idx, flags, i, nullptr);
+void DexLayout::DumpIField(uint32_t idx,
+                           uint32_t flags,
+                           uint32_t hiddenapi_flags,
+                           int i) {
+  DumpSField(idx, flags, hiddenapi_flags, i, nullptr);
 }
 
 /*
@@ -1431,6 +1461,7 @@
       for (uint32_t i = 0; i < static_fields->size(); i++) {
         DumpSField((*static_fields)[i].GetFieldId()->GetIndex(),
                    (*static_fields)[i].GetAccessFlags(),
+                   dex_ir::HiddenapiClassData::GetFlags(header_, class_def, &(*static_fields)[i]),
                    i,
                    i < encoded_values_size ? (*encoded_values)[i].get() : nullptr);
       }  // for
@@ -1447,6 +1478,7 @@
       for (uint32_t i = 0; i < instance_fields->size(); i++) {
         DumpIField((*instance_fields)[i].GetFieldId()->GetIndex(),
                    (*instance_fields)[i].GetAccessFlags(),
+                   dex_ir::HiddenapiClassData::GetFlags(header_, class_def, &(*instance_fields)[i]),
                    i);
       }  // for
     }
@@ -1462,8 +1494,9 @@
       for (uint32_t i = 0; i < direct_methods->size(); i++) {
         DumpMethod((*direct_methods)[i].GetMethodId()->GetIndex(),
                    (*direct_methods)[i].GetAccessFlags(),
+                   dex_ir::HiddenapiClassData::GetFlags(header_, class_def, &(*direct_methods)[i]),
                    (*direct_methods)[i].GetCodeItem(),
-                 i);
+                   i);
       }  // for
     }
   }
@@ -1478,6 +1511,7 @@
       for (uint32_t i = 0; i < virtual_methods->size(); i++) {
         DumpMethod((*virtual_methods)[i].GetMethodId()->GetIndex(),
                    (*virtual_methods)[i].GetAccessFlags(),
+                   dex_ir::HiddenapiClassData::GetFlags(header_, class_def, &(*virtual_methods)[i]),
                    (*virtual_methods)[i].GetCodeItem(),
                    i);
       }  // for
diff --git a/dexlayout/dexlayout.h b/dexlayout/dexlayout.h
index 2bca10d..6e006b7 100644
--- a/dexlayout/dexlayout.h
+++ b/dexlayout/dexlayout.h
@@ -148,7 +148,7 @@
   void DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation);
   void DumpEncodedValue(const dex_ir::EncodedValue* data);
   void DumpFileHeader();
-  void DumpIField(uint32_t idx, uint32_t flags, int i);
+  void DumpIField(uint32_t idx, uint32_t flags, uint32_t hiddenapi_flags, int i);
   void DumpInstruction(const dex_ir::CodeItem* code,
                        uint32_t code_offset,
                        uint32_t insn_idx,
@@ -156,9 +156,17 @@
                        const Instruction* dec_insn);
   void DumpInterface(const dex_ir::TypeId* type_item, int i);
   void DumpLocalInfo(const dex_ir::CodeItem* code);
-  void DumpMethod(uint32_t idx, uint32_t flags, const dex_ir::CodeItem* code, int i);
+  void DumpMethod(uint32_t idx,
+                  uint32_t flags,
+                  uint32_t hiddenapi_flags,
+                  const dex_ir::CodeItem* code,
+                  int i);
   void DumpPositionInfo(const dex_ir::CodeItem* code);
-  void DumpSField(uint32_t idx, uint32_t flags, int i, dex_ir::EncodedValue* init);
+  void DumpSField(uint32_t idx,
+                  uint32_t flags,
+                  uint32_t hiddenapi_flags,
+                  int i,
+                  dex_ir::EncodedValue* init);
   void DumpDexFile();
 
   void LayoutClassDefsAndClassData(const DexFile* dex_file);
diff --git a/dexlist/dexlist.cc b/dexlist/dexlist.cc
index 7d3ae71..bdf3ca6 100644
--- a/dexlist/dexlist.cc
+++ b/dexlist/dexlist.cc
@@ -146,7 +146,7 @@
     dumpMethod(pDexFile,
                fileName,
                method.GetIndex(),
-               method.GetRawAccessFlags(),
+               method.GetAccessFlags(),
                method.GetCodeItem(),
                method.GetCodeItemOffset());
   }
diff --git a/libartbase/base/mem_map.h b/libartbase/base/mem_map.h
index 4f92492..525e622 100644
--- a/libartbase/base/mem_map.h
+++ b/libartbase/base/mem_map.h
@@ -139,18 +139,32 @@
                              /*out*/std::string* error_msg,
                              bool use_debug_name = true);
   static MemMap MapAnonymous(const char* name,
-                             uint8_t* addr,
                              size_t byte_count,
                              int prot,
                              bool low_4gb,
                              /*out*/std::string* error_msg) {
     return MapAnonymous(name,
-                        addr,
+                        /*addr=*/ nullptr,
                         byte_count,
                         prot,
                         low_4gb,
-                        /* reuse */ false,
-                        /* reservation */ nullptr,
+                        /*reuse=*/ false,
+                        /*reservation=*/ nullptr,
+                        error_msg);
+  }
+  static MemMap MapAnonymous(const char* name,
+                             size_t byte_count,
+                             int prot,
+                             bool low_4gb,
+                             MemMap* reservation,
+                             /*out*/std::string* error_msg) {
+    return MapAnonymous(name,
+                        /*addr=*/ (reservation != nullptr) ? reservation->Begin() : nullptr,
+                        byte_count,
+                        prot,
+                        low_4gb,
+                        /*reuse=*/ false,
+                        reservation,
                         error_msg);
   }
 
@@ -178,10 +192,10 @@
                             flags,
                             fd,
                             start,
-                            /* low_4gb */ low_4gb,
+                            /*low_4gb=*/ low_4gb,
                             filename,
-                            /* reuse */ false,
-                            /* reservation */ nullptr,
+                            /*reuse=*/ false,
+                            /*reservation=*/ nullptr,
                             error_msg);
   }
 
diff --git a/libartbase/base/mem_map_test.cc b/libartbase/base/mem_map_test.cc
index 813d90d..2d9cd59 100644
--- a/libartbase/base/mem_map_test.cc
+++ b/libartbase/base/mem_map_test.cc
@@ -54,7 +54,6 @@
     // Find a valid map address and unmap it before returning.
     std::string error_msg;
     MemMap map = MemMap::MapAnonymous("temp",
-                                      /* addr= */ nullptr,
                                       size,
                                       PROT_READ,
                                       low_4gb,
@@ -69,7 +68,6 @@
     const size_t page_size = static_cast<size_t>(kPageSize);
     // Map a two-page memory region.
     MemMap m0 = MemMap::MapAnonymous("MemMapTest_RemapAtEndTest_map0",
-                                     /* addr= */ nullptr,
                                      2 * page_size,
                                      PROT_READ | PROT_WRITE,
                                      low_4gb,
@@ -166,17 +164,15 @@
 TEST_F(MemMapTest, ReplaceMapping_SameSize) {
   std::string error_msg;
   MemMap dest = MemMap::MapAnonymous("MapAnonymousEmpty-atomic-replace-dest",
-                                     /* addr= */ nullptr,
                                      kPageSize,
                                      PROT_READ,
-                                     /* low_4gb= */ false,
+                                     /*low_4gb=*/ false,
                                      &error_msg);
   ASSERT_TRUE(dest.IsValid());
   MemMap source = MemMap::MapAnonymous("MapAnonymous-atomic-replace-source",
-                                       /* addr= */ nullptr,
                                        kPageSize,
                                        PROT_WRITE | PROT_READ,
-                                       /* low_4gb= */ false,
+                                       /*low_4gb=*/ false,
                                        &error_msg);
   ASSERT_TRUE(source.IsValid());
   void* source_addr = source.Begin();
@@ -201,21 +197,19 @@
 TEST_F(MemMapTest, ReplaceMapping_MakeLarger) {
   std::string error_msg;
   MemMap dest = MemMap::MapAnonymous("MapAnonymousEmpty-atomic-replace-dest",
-                                     /* addr= */ nullptr,
                                      5 * kPageSize,  // Need to make it larger
                                                      // initially so we know
                                                      // there won't be mappings
                                                      // in the way we we move
                                                      // source.
                                      PROT_READ,
-                                     /* low_4gb= */ false,
+                                     /*low_4gb=*/ false,
                                      &error_msg);
   ASSERT_TRUE(dest.IsValid());
   MemMap source = MemMap::MapAnonymous("MapAnonymous-atomic-replace-source",
-                                       /* addr= */ nullptr,
                                        3 * kPageSize,
                                        PROT_WRITE | PROT_READ,
-                                       /* low_4gb= */ false,
+                                       /*low_4gb=*/ false,
                                        &error_msg);
   ASSERT_TRUE(source.IsValid());
   uint8_t* source_addr = source.Begin();
@@ -247,17 +241,15 @@
 TEST_F(MemMapTest, ReplaceMapping_MakeSmaller) {
   std::string error_msg;
   MemMap dest = MemMap::MapAnonymous("MapAnonymousEmpty-atomic-replace-dest",
-                                     /* addr= */ nullptr,
                                      3 * kPageSize,
                                      PROT_READ,
-                                     /* low_4gb= */ false,
+                                     /*low_4gb=*/ false,
                                      &error_msg);
   ASSERT_TRUE(dest.IsValid());
   MemMap source = MemMap::MapAnonymous("MapAnonymous-atomic-replace-source",
-                                       /* addr= */ nullptr,
                                        kPageSize,
                                        PROT_WRITE | PROT_READ,
-                                       /* low_4gb= */ false,
+                                       /*low_4gb=*/ false,
                                        &error_msg);
   ASSERT_TRUE(source.IsValid());
   uint8_t* source_addr = source.Begin();
@@ -286,11 +278,10 @@
   MemMap dest =
       MemMap::MapAnonymous(
           "MapAnonymousEmpty-atomic-replace-dest",
-          /* addr= */ nullptr,
           3 * kPageSize,  // Need to make it larger initially so we know there won't be mappings in
                           // the way we we move source.
           PROT_READ | PROT_WRITE,
-          /* low_4gb= */ false,
+          /*low_4gb=*/ false,
           &error_msg);
   ASSERT_TRUE(dest.IsValid());
   // Resize down to 1 page so we can remap the rest.
@@ -300,7 +291,9 @@
                                        dest.Begin() + kPageSize,
                                        2 * kPageSize,
                                        PROT_WRITE | PROT_READ,
-                                       /* low_4gb= */ false,
+                                       /*low_4gb=*/ false,
+                                       /*reuse=*/ false,
+                                       /*reservation=*/ nullptr,
                                        &error_msg);
   ASSERT_TRUE(source.IsValid());
   ASSERT_EQ(dest.Begin() + kPageSize, source.Begin());
@@ -333,20 +326,18 @@
   CommonInit();
   std::string error_msg;
   MemMap map = MemMap::MapAnonymous("MapAnonymousEmpty",
-                                    /* addr= */ nullptr,
-                                    0,
+                                    /*byte_count=*/ 0,
                                     PROT_READ,
-                                    /* low_4gb= */ false,
+                                    /*low_4gb=*/ false,
                                     &error_msg);
   ASSERT_FALSE(map.IsValid()) << error_msg;
   ASSERT_FALSE(error_msg.empty());
 
   error_msg.clear();
   map = MemMap::MapAnonymous("MapAnonymousNonEmpty",
-                             /* addr= */ nullptr,
                              kPageSize,
                              PROT_READ | PROT_WRITE,
-                             /* low_4gb= */ false,
+                             /*low_4gb=*/ false,
                              &error_msg);
   ASSERT_TRUE(map.IsValid()) << error_msg;
   ASSERT_TRUE(error_msg.empty());
@@ -359,7 +350,9 @@
                                     reinterpret_cast<uint8_t*>(kPageSize),
                                     0x20000,
                                     PROT_READ | PROT_WRITE,
-                                    /* low_4gb= */ false,
+                                    /*low_4gb=*/ false,
+                                    /*reuse=*/ false,
+                                    /*reservation=*/ nullptr,
                                     nullptr);
   ASSERT_FALSE(map.IsValid());
 }
@@ -369,20 +362,18 @@
   CommonInit();
   std::string error_msg;
   MemMap map = MemMap::MapAnonymous("MapAnonymousEmpty",
-                                    /* addr= */ nullptr,
-                                    0,
+                                    /*byte_count=*/ 0,
                                     PROT_READ,
-                                    /* low_4gb= */ true,
+                                    /*low_4gb=*/ true,
                                     &error_msg);
   ASSERT_FALSE(map.IsValid()) << error_msg;
   ASSERT_FALSE(error_msg.empty());
 
   error_msg.clear();
   map = MemMap::MapAnonymous("MapAnonymousNonEmpty",
-                             /* addr= */ nullptr,
                              kPageSize,
                              PROT_READ | PROT_WRITE,
-                             /* low_4gb= */ true,
+                             /*low_4gb=*/ true,
                              &error_msg);
   ASSERT_TRUE(map.IsValid()) << error_msg;
   ASSERT_TRUE(error_msg.empty());
@@ -411,6 +402,12 @@
 #endif
 
 TEST_F(MemMapTest, MapAnonymousExactAddr) {
+  // TODO: The semantics of the MemMap::MapAnonymous() with a given address but without
+  // `reuse == true` or `reservation != nullptr` is weird. We should either drop support
+  // for it, or take it only as a hint and allow the result to be mapped elsewhere.
+  // Currently we're seeing failures with ASAN. b/118408378
+  TEST_DISABLED_FOR_MEMORY_TOOL();
+
   CommonInit();
   std::string error_msg;
   // Find a valid address.
@@ -420,17 +417,18 @@
                                      valid_address,
                                      kPageSize,
                                      PROT_READ | PROT_WRITE,
-                                     /* low_4gb= */ false,
+                                     /*low_4gb=*/ false,
+                                     /*reuse=*/ false,
+                                     /*reservation=*/ nullptr,
                                      &error_msg);
   ASSERT_TRUE(map0.IsValid()) << error_msg;
   ASSERT_TRUE(error_msg.empty());
   ASSERT_TRUE(map0.BaseBegin() == valid_address);
   // Map at an unspecified address, which should succeed.
   MemMap map1 = MemMap::MapAnonymous("MapAnonymous1",
-                                     /* addr= */ nullptr,
                                      kPageSize,
                                      PROT_READ | PROT_WRITE,
-                                     /* low_4gb= */ false,
+                                     /*low_4gb=*/ false,
                                      &error_msg);
   ASSERT_TRUE(map1.IsValid()) << error_msg;
   ASSERT_TRUE(error_msg.empty());
@@ -440,7 +438,9 @@
                                      reinterpret_cast<uint8_t*>(map1.BaseBegin()),
                                      kPageSize,
                                      PROT_READ | PROT_WRITE,
-                                     /* low_4gb= */ false,
+                                     /*low_4gb=*/ false,
+                                     /*reuse=*/ false,
+                                     /*reservation=*/ nullptr,
                                      &error_msg);
   ASSERT_FALSE(map2.IsValid()) << error_msg;
   ASSERT_TRUE(!error_msg.empty());
@@ -524,6 +524,8 @@
                                size,
                                PROT_READ | PROT_WRITE,
                                /*low_4gb=*/ true,
+                               /*reuse=*/ false,
+                               /*reservation=*/ nullptr,
                                &error_msg);
     if (map.IsValid()) {
       break;
@@ -544,7 +546,9 @@
                                     reinterpret_cast<uint8_t*>(ptr),
                                     2 * kPageSize,  // brings it over the top.
                                     PROT_READ | PROT_WRITE,
-                                    /* low_4gb= */ false,
+                                    /*low_4gb=*/ false,
+                                    /*reuse=*/ false,
+                                    /*reservation=*/ nullptr,
                                     &error_msg);
   ASSERT_FALSE(map.IsValid());
   ASSERT_FALSE(error_msg.empty());
@@ -559,7 +563,9 @@
                            reinterpret_cast<uint8_t*>(UINT64_C(0x100000000)),
                            kPageSize,
                            PROT_READ | PROT_WRITE,
-                           /* low_4gb= */ true,
+                           /*low_4gb=*/ true,
+                           /*reuse=*/ false,
+                           /*reservation=*/ nullptr,
                            &error_msg);
   ASSERT_FALSE(map.IsValid());
   ASSERT_FALSE(error_msg.empty());
@@ -572,7 +578,9 @@
                                     reinterpret_cast<uint8_t*>(0xF0000000),
                                     0x20000000,
                                     PROT_READ | PROT_WRITE,
-                                    /* low_4gb= */ true,
+                                    /*low_4gb=*/ true,
+                                    /*reuse=*/ false,
+                                    /*reservation=*/ nullptr,
                                     &error_msg);
   ASSERT_FALSE(map.IsValid());
   ASSERT_FALSE(error_msg.empty());
@@ -583,12 +591,9 @@
   CommonInit();
   std::string error_msg;
   MemMap map = MemMap::MapAnonymous("MapAnonymousReserve",
-                                    nullptr,
                                     0x20000,
                                     PROT_READ | PROT_WRITE,
-                                    /* low_4gb= */ false,
-                                    /* reuse= */ false,
-                                    /* reservation= */ nullptr,
+                                    /*low_4gb=*/ false,
                                     &error_msg);
   ASSERT_TRUE(map.IsValid());
   ASSERT_TRUE(error_msg.empty());
@@ -596,9 +601,9 @@
                                      reinterpret_cast<uint8_t*>(map.BaseBegin()),
                                      0x10000,
                                      PROT_READ | PROT_WRITE,
-                                     /* low_4gb= */ false,
-                                     /* reuse= */ true,
-                                     /* reservation= */ nullptr,
+                                     /*low_4gb=*/ false,
+                                     /*reuse=*/ true,
+                                     /*reservation=*/ nullptr,
                                      &error_msg);
   ASSERT_TRUE(map2.IsValid());
   ASSERT_TRUE(error_msg.empty());
@@ -609,45 +614,45 @@
   std::string error_msg;
   constexpr size_t kNumPages = 3;
   // Map a 3-page mem map.
-  MemMap map = MemMap::MapAnonymous("MapAnonymous0",
-                                    /* addr= */ nullptr,
-                                    kPageSize * kNumPages,
-                                    PROT_READ | PROT_WRITE,
-                                    /* low_4gb= */ false,
-                                    &error_msg);
-  ASSERT_TRUE(map.IsValid()) << error_msg;
+  MemMap reservation = MemMap::MapAnonymous("MapAnonymous0",
+                                            kPageSize * kNumPages,
+                                            PROT_READ | PROT_WRITE,
+                                            /*low_4gb=*/ false,
+                                            &error_msg);
+  ASSERT_TRUE(reservation.IsValid()) << error_msg;
   ASSERT_TRUE(error_msg.empty());
   // Record the base address.
-  uint8_t* map_base = reinterpret_cast<uint8_t*>(map.BaseBegin());
-  // Unmap it.
-  map.Reset();
+  uint8_t* map_base = reinterpret_cast<uint8_t*>(reservation.BaseBegin());
 
-  // Map at the same address, but in page-sized separate mem maps,
-  // assuming the space at the address is still available.
+  // Map at the same address, taking from the `map` reservation.
   MemMap map0 = MemMap::MapAnonymous("MapAnonymous0",
-                                     map_base,
                                      kPageSize,
                                      PROT_READ | PROT_WRITE,
-                                     /* low_4gb= */ false,
+                                     /*low_4gb=*/ false,
+                                     &reservation,
                                      &error_msg);
   ASSERT_TRUE(map0.IsValid()) << error_msg;
   ASSERT_TRUE(error_msg.empty());
+  ASSERT_EQ(map_base, map0.Begin());
   MemMap map1 = MemMap::MapAnonymous("MapAnonymous1",
-                                     map_base + kPageSize,
                                      kPageSize,
                                      PROT_READ | PROT_WRITE,
-                                     /* low_4gb= */ false,
+                                     /*low_4gb=*/ false,
+                                     &reservation,
                                      &error_msg);
   ASSERT_TRUE(map1.IsValid()) << error_msg;
   ASSERT_TRUE(error_msg.empty());
+  ASSERT_EQ(map_base + kPageSize, map1.Begin());
   MemMap map2 = MemMap::MapAnonymous("MapAnonymous2",
-                                     map_base + kPageSize * 2,
                                      kPageSize,
                                      PROT_READ | PROT_WRITE,
-                                     /* low_4gb= */ false,
+                                     /*low_4gb=*/ false,
+                                     &reservation,
                                      &error_msg);
   ASSERT_TRUE(map2.IsValid()) << error_msg;
   ASSERT_TRUE(error_msg.empty());
+  ASSERT_EQ(map_base + 2 * kPageSize, map2.Begin());
+  ASSERT_FALSE(reservation.IsValid());  // The entire reservation was used.
 
   // One-map cases.
   ASSERT_TRUE(MemMap::CheckNoGaps(map0, map0));
@@ -673,10 +678,9 @@
   const size_t page_size = static_cast<size_t>(kPageSize);
   // Map a region.
   MemMap m0 = MemMap::MapAnonymous("MemMapTest_AlignByTest_map0",
-                                   /* addr= */ nullptr,
                                    14 * page_size,
                                    PROT_READ | PROT_WRITE,
-                                   /* low_4gb= */ false,
+                                   /*low_4gb=*/ false,
                                    &error_msg);
   ASSERT_TRUE(m0.IsValid());
   uint8_t* base0 = m0.Begin();
@@ -779,10 +783,9 @@
   ASSERT_TRUE(scratch_file.GetFile()->WriteFully(&data[0], kMapSize));
 
   MemMap reservation = MemMap::MapAnonymous("Test reservation",
-                                            /* addr= */ nullptr,
                                             kMapSize,
                                             PROT_NONE,
-                                            /* low_4gb= */ false,
+                                            /*low_4gb=*/ false,
                                             &error_msg);
   ASSERT_TRUE(reservation.IsValid());
   ASSERT_TRUE(error_msg.empty());
@@ -792,14 +795,14 @@
   static_assert(kChunk1Size < kMapSize, "We want to split the reservation.");
   uint8_t* addr1 = reservation.Begin();
   MemMap map1 = MemMap::MapFileAtAddress(addr1,
-                                         /* byte_count= */ kChunk1Size,
+                                         /*byte_count=*/ kChunk1Size,
                                          PROT_READ,
                                          MAP_PRIVATE,
                                          scratch_file.GetFd(),
-                                         /* start= */ 0,
-                                         /* low_4gb= */ false,
+                                         /*start=*/ 0,
+                                         /*low_4gb=*/ false,
                                          scratch_file.GetFilename().c_str(),
-                                         /* reuse= */ false,
+                                         /*reuse=*/ false,
                                          &reservation,
                                          &error_msg);
   ASSERT_TRUE(map1.IsValid()) << error_msg;
@@ -817,10 +820,10 @@
   uint8_t* addr2 = reservation.Begin();
   MemMap map2 = MemMap::MapAnonymous("MiddleReservation",
                                      addr2,
-                                     /* byte_count= */ kChunk2Size,
+                                     /*byte_count=*/ kChunk2Size,
                                      PROT_READ,
-                                     /* low_4gb= */ false,
-                                     /* reuse= */ false,
+                                     /*low_4gb=*/ false,
+                                     /*reuse=*/ false,
                                      &reservation,
                                      &error_msg);
   ASSERT_TRUE(map2.IsValid()) << error_msg;
@@ -834,14 +837,14 @@
   const size_t kChunk3Size = reservation.Size() - 1u;
   uint8_t* addr3 = reservation.Begin();
   MemMap map3 = MemMap::MapFileAtAddress(addr3,
-                                         /* byte_count= */ kChunk3Size,
+                                         /*byte_count=*/ kChunk3Size,
                                          PROT_READ,
                                          MAP_PRIVATE,
                                          scratch_file.GetFd(),
-                                         /* start= */ dchecked_integral_cast<size_t>(addr3 - addr1),
-                                         /* low_4gb= */ false,
+                                         /*start=*/ dchecked_integral_cast<size_t>(addr3 - addr1),
+                                         /*low_4gb=*/ false,
                                          scratch_file.GetFilename().c_str(),
-                                         /* reuse= */ false,
+                                         /*reuse=*/ false,
                                          &reservation,
                                          &error_msg);
   ASSERT_TRUE(map3.IsValid()) << error_msg;
diff --git a/libartbase/base/zip_archive.cc b/libartbase/base/zip_archive.cc
index f5761cf..8ceea83 100644
--- a/libartbase/base/zip_archive.cc
+++ b/libartbase/base/zip_archive.cc
@@ -75,10 +75,9 @@
   name += " extracted in memory from ";
   name += zip_filename;
   MemMap map = MemMap::MapAnonymous(name.c_str(),
-                                    /* addr= */ nullptr,
                                     GetUncompressedLength(),
                                     PROT_READ | PROT_WRITE,
-                                    /* low_4gb= */ false,
+                                    /*low_4gb=*/ false,
                                     error_msg);
   if (!map.IsValid()) {
     DCHECK(!error_msg->empty());
@@ -138,7 +137,7 @@
                       MAP_PRIVATE,
                       zip_fd,
                       offset,
-                      /* low_4gb= */ false,
+                      /*low_4gb=*/ false,
                       name.c_str(),
                       error_msg);
 
diff --git a/libdexfile/dex/class_accessor-inl.h b/libdexfile/dex/class_accessor-inl.h
index 21db2cf..e9e3a98 100644
--- a/libdexfile/dex/class_accessor-inl.h
+++ b/libdexfile/dex/class_accessor-inl.h
@@ -28,34 +28,54 @@
 inline ClassAccessor::ClassAccessor(const ClassIteratorData& data)
     : ClassAccessor(data.dex_file_, data.class_def_idx_) {}
 
-inline ClassAccessor::ClassAccessor(const DexFile& dex_file, const DexFile::ClassDef& class_def)
-    : ClassAccessor(dex_file, dex_file.GetIndexForClassDef(class_def)) {}
+inline ClassAccessor::ClassAccessor(const DexFile& dex_file,
+                                    const DexFile::ClassDef& class_def,
+                                    bool parse_hiddenapi_class_data)
+    : ClassAccessor(dex_file,
+                    dex_file.GetClassData(class_def),
+                    dex_file.GetIndexForClassDef(class_def),
+                    parse_hiddenapi_class_data) {}
 
 inline ClassAccessor::ClassAccessor(const DexFile& dex_file, uint32_t class_def_index)
-    : ClassAccessor(dex_file,
-                    dex_file.GetClassData(dex_file.GetClassDef(class_def_index)),
-                    class_def_index) {}
+    : ClassAccessor(dex_file, dex_file.GetClassDef(class_def_index)) {}
 
 inline ClassAccessor::ClassAccessor(const DexFile& dex_file,
                                     const uint8_t* class_data,
-                                    uint32_t class_def_index)
+                                    uint32_t class_def_index,
+                                    bool parse_hiddenapi_class_data)
     : dex_file_(dex_file),
       class_def_index_(class_def_index),
       ptr_pos_(class_data),
+      hiddenapi_ptr_pos_(nullptr),
       num_static_fields_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u),
       num_instance_fields_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u),
       num_direct_methods_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u),
-      num_virtual_methods_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u) {}
+      num_virtual_methods_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u) {
+  if (parse_hiddenapi_class_data && class_def_index != DexFile::kDexNoIndex32) {
+    const DexFile::HiddenapiClassData* hiddenapi_class_data = dex_file.GetHiddenapiClassData();
+    if (hiddenapi_class_data != nullptr) {
+      hiddenapi_ptr_pos_ = hiddenapi_class_data->GetFlagsPointer(class_def_index);
+    }
+  }
+}
 
 inline void ClassAccessor::Method::Read() {
   index_ += DecodeUnsignedLeb128(&ptr_pos_);
   access_flags_ = DecodeUnsignedLeb128(&ptr_pos_);
   code_off_ = DecodeUnsignedLeb128(&ptr_pos_);
+  if (hiddenapi_ptr_pos_ != nullptr) {
+    hiddenapi_flags_ = DecodeUnsignedLeb128(&hiddenapi_ptr_pos_);
+    DCHECK(hiddenapi::AreValidFlags(hiddenapi_flags_));
+  }
 }
 
 inline void ClassAccessor::Field::Read() {
   index_ += DecodeUnsignedLeb128(&ptr_pos_);
   access_flags_ = DecodeUnsignedLeb128(&ptr_pos_);
+  if (hiddenapi_ptr_pos_ != nullptr) {
+    hiddenapi_flags_ = DecodeUnsignedLeb128(&hiddenapi_ptr_pos_);
+    DCHECK(hiddenapi::AreValidFlags(hiddenapi_flags_));
+  }
 }
 
 template <typename DataType, typename Visitor>
@@ -78,12 +98,12 @@
     const InstanceFieldVisitor& instance_field_visitor,
     const DirectMethodVisitor& direct_method_visitor,
     const VirtualMethodVisitor& virtual_method_visitor) const {
-  Field field(dex_file_, ptr_pos_);
+  Field field(dex_file_, ptr_pos_, hiddenapi_ptr_pos_);
   VisitMembers(num_static_fields_, static_field_visitor, &field);
   field.NextSection();
   VisitMembers(num_instance_fields_, instance_field_visitor, &field);
 
-  Method method(dex_file_, field.ptr_pos_, /*is_static_or_direct*/ true);
+  Method method(dex_file_, field.ptr_pos_, field.hiddenapi_ptr_pos_, /*is_static_or_direct*/ true);
   VisitMembers(num_direct_methods_, direct_method_visitor, &method);
   method.NextSection();
   VisitMembers(num_virtual_methods_, virtual_method_visitor, &method);
@@ -131,19 +151,43 @@
 
 inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Field>>
     ClassAccessor::GetFieldsInternal(size_t count) const {
-  return { DataIterator<Field>(dex_file_, 0u, num_static_fields_, count, ptr_pos_),
-           DataIterator<Field>(dex_file_, count, num_static_fields_, count, ptr_pos_) };
+  return {
+      DataIterator<Field>(dex_file_,
+                          0u,
+                          num_static_fields_,
+                          count,
+                          ptr_pos_,
+                          hiddenapi_ptr_pos_),
+      DataIterator<Field>(dex_file_,
+                          count,
+                          num_static_fields_,
+                          count,
+                          // The following pointers are bogus but unused in the `end` iterator.
+                          ptr_pos_,
+                          hiddenapi_ptr_pos_) };
 }
 
 // Return an iteration range for the first <count> methods.
 inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Method>>
     ClassAccessor::GetMethodsInternal(size_t count) const {
   // Skip over the fields.
-  Field field(dex_file_, ptr_pos_);
+  Field field(dex_file_, ptr_pos_, hiddenapi_ptr_pos_);
   VisitMembers(NumFields(), VoidFunctor(), &field);
   // Return the iterator pair.
-  return { DataIterator<Method>(dex_file_, 0u, num_direct_methods_, count, field.ptr_pos_),
-           DataIterator<Method>(dex_file_, count, num_direct_methods_, count, field.ptr_pos_) };
+  return {
+      DataIterator<Method>(dex_file_,
+                           0u,
+                           num_direct_methods_,
+                           count,
+                           field.ptr_pos_,
+                           field.hiddenapi_ptr_pos_),
+      DataIterator<Method>(dex_file_,
+                           count,
+                           num_direct_methods_,
+                           count,
+                           // The following pointers are bogus but unused in the `end` iterator.
+                           field.ptr_pos_,
+                           field.hiddenapi_ptr_pos_) };
 }
 
 inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Field>> ClassAccessor::GetFields()
@@ -181,14 +225,6 @@
   return { std::next(methods.begin(), NumDirectMethods()), methods.end() };
 }
 
-inline void ClassAccessor::Field::UnHideAccessFlags() const {
-  DexFile::UnHideAccessFlags(const_cast<uint8_t*>(ptr_pos_), GetAccessFlags(), /*is_method*/ false);
-}
-
-inline void ClassAccessor::Method::UnHideAccessFlags() const {
-  DexFile::UnHideAccessFlags(const_cast<uint8_t*>(ptr_pos_), GetAccessFlags(), /*is_method*/ true);
-}
-
 inline dex::TypeIndex ClassAccessor::GetClassIdx() const {
   return dex_file_.GetClassDef(class_def_index_).class_idx_;
 }
diff --git a/libdexfile/dex/class_accessor.h b/libdexfile/dex/class_accessor.h
index d40577f..e9c1a82 100644
--- a/libdexfile/dex/class_accessor.h
+++ b/libdexfile/dex/class_accessor.h
@@ -20,7 +20,6 @@
 #include "base/utils.h"
 #include "code_item_accessors.h"
 #include "dex_file.h"
-#include "hidden_api_access_flags.h"
 #include "invoke_type.h"
 #include "method_reference.h"
 #include "modifiers.h"
@@ -35,22 +34,20 @@
   class BaseItem {
    public:
     explicit BaseItem(const DexFile& dex_file,
-                      const uint8_t* ptr_pos) : dex_file_(dex_file), ptr_pos_(ptr_pos) {}
+                      const uint8_t* ptr_pos,
+                      const uint8_t* hiddenapi_ptr_pos)
+        : dex_file_(dex_file), ptr_pos_(ptr_pos), hiddenapi_ptr_pos_(hiddenapi_ptr_pos) {}
 
     uint32_t GetIndex() const {
       return index_;
     }
 
-    uint32_t GetRawAccessFlags() const {
+    uint32_t GetAccessFlags() const {
       return access_flags_;
     }
 
-    uint32_t GetAccessFlags() const {
-      return HiddenApiAccessFlags::RemoveFromDex(access_flags_);
-    }
-
-    HiddenApiAccessFlags::ApiList DecodeHiddenAccessFlags() const {
-      return HiddenApiAccessFlags::DecodeFromDex(access_flags_);
+    uint32_t GetHiddenapiFlags() const {
+      return hiddenapi_flags_;
     }
 
     bool IsFinal() const {
@@ -66,19 +63,21 @@
     }
 
     bool MemberIsNative() const {
-      return GetRawAccessFlags() & kAccNative;
+      return GetAccessFlags() & kAccNative;
     }
 
     bool MemberIsFinal() const {
-      return GetRawAccessFlags() & kAccFinal;
+      return GetAccessFlags() & kAccFinal;
     }
 
    protected:
     // Internal data pointer for reading.
     const DexFile& dex_file_;
     const uint8_t* ptr_pos_ = nullptr;
+    const uint8_t* hiddenapi_ptr_pos_ = nullptr;
     uint32_t index_ = 0u;
     uint32_t access_flags_ = 0u;
+    uint32_t hiddenapi_flags_ = 0u;
   };
 
   // A decoded version of the method of a class_data_item.
@@ -107,14 +106,13 @@
       return is_static_or_direct_;
     }
 
-    // Unhide the hidden API access flags at the iterator position. TODO: Deprecate.
-    void UnHideAccessFlags() const;
-
    private:
-    explicit Method(const DexFile& dex_file,
-                    const uint8_t* ptr_pos,
-                    bool is_static_or_direct = true)
-        : BaseItem(dex_file, ptr_pos), is_static_or_direct_(is_static_or_direct) {}
+    Method(const DexFile& dex_file,
+           const uint8_t* ptr_pos,
+           const uint8_t* hiddenapi_ptr_pos = nullptr,
+           bool is_static_or_direct = true)
+        : BaseItem(dex_file, ptr_pos, hiddenapi_ptr_pos),
+          is_static_or_direct_(is_static_or_direct) {}
 
     void Read();
 
@@ -150,16 +148,15 @@
   // A decoded version of the field of a class_data_item.
   class Field : public BaseItem {
    public:
-    explicit Field(const DexFile& dex_file,
-                   const uint8_t* ptr_pos) : BaseItem(dex_file, ptr_pos) {}
+    Field(const DexFile& dex_file,
+          const uint8_t* ptr_pos,
+          const uint8_t* hiddenapi_ptr_pos = nullptr)
+        : BaseItem(dex_file, ptr_pos, hiddenapi_ptr_pos) {}
 
     bool IsStatic() const {
      return is_static_;
     }
 
-    // Unhide the hidden API access flags at the iterator position. TODO: Deprecate.
-    void UnHideAccessFlags() const;
-
    private:
     void Read();
 
@@ -185,8 +182,9 @@
                  uint32_t position,
                  uint32_t partition_pos,
                  uint32_t iterator_end,
-                 const uint8_t* ptr_pos)
-        : data_(dex_file, ptr_pos),
+                 const uint8_t* ptr_pos,
+                 const uint8_t* hiddenapi_ptr_pos)
+        : data_(dex_file, ptr_pos, hiddenapi_ptr_pos),
           position_(position),
           partition_pos_(partition_pos),
           iterator_end_(iterator_end) {
@@ -268,13 +266,16 @@
   // Not explicit specifically for range-based loops.
   ALWAYS_INLINE ClassAccessor(const ClassIteratorData& data);
 
-  ALWAYS_INLINE ClassAccessor(const DexFile& dex_file, const DexFile::ClassDef& class_def);
+  ALWAYS_INLINE ClassAccessor(const DexFile& dex_file,
+                              const DexFile::ClassDef& class_def,
+                              bool parse_hiddenapi_class_data = false);
 
   ALWAYS_INLINE ClassAccessor(const DexFile& dex_file, uint32_t class_def_index);
 
   ClassAccessor(const DexFile& dex_file,
                 const uint8_t* class_data,
-                uint32_t class_def_index = DexFile::kDexNoIndex32);
+                uint32_t class_def_index = DexFile::kDexNoIndex32,
+                bool parse_hiddenapi_class_data = false);
 
   // Return the code item for a method.
   const DexFile::CodeItem* GetCodeItem(const Method& method) const;
@@ -353,6 +354,10 @@
     return ptr_pos_ != nullptr;
   }
 
+  bool HasHiddenapiClassData() const {
+    return hiddenapi_ptr_pos_ != nullptr;
+  }
+
   uint32_t GetClassDefIndex() const {
     return class_def_index_;
   }
@@ -377,6 +382,7 @@
   const DexFile& dex_file_;
   const uint32_t class_def_index_;
   const uint8_t* ptr_pos_ = nullptr;  // Pointer into stream of class_data_item.
+  const uint8_t* hiddenapi_ptr_pos_ = nullptr;  // Pointer into stream of hiddenapi_metadata.
   const uint32_t num_static_fields_ = 0u;
   const uint32_t num_instance_fields_ = 0u;
   const uint32_t num_direct_methods_ = 0u;
diff --git a/libdexfile/dex/dex_file.cc b/libdexfile/dex/dex_file.cc
index 48f38ca..7ccb9c0 100644
--- a/libdexfile/dex/dex_file.cc
+++ b/libdexfile/dex/dex_file.cc
@@ -46,31 +46,6 @@
 static_assert(sizeof(dex::TypeIndex) == sizeof(uint16_t), "TypeIndex size is wrong");
 static_assert(std::is_trivially_copyable<dex::TypeIndex>::value, "TypeIndex not trivial");
 
-void DexFile::UnHideAccessFlags(uint8_t* data_ptr,
-                                uint32_t new_access_flags,
-                                bool is_method) {
-  // Go back 1 uleb to start.
-  data_ptr = ReverseSearchUnsignedLeb128(data_ptr);
-  if (is_method) {
-    // Methods have another uleb field before the access flags
-    data_ptr = ReverseSearchUnsignedLeb128(data_ptr);
-  }
-  DCHECK_EQ(HiddenApiAccessFlags::RemoveFromDex(DecodeUnsignedLeb128WithoutMovingCursor(data_ptr)),
-            new_access_flags);
-  UpdateUnsignedLeb128(data_ptr, new_access_flags);
-}
-
-void DexFile::UnhideApis() const {
-  for (ClassAccessor accessor : GetClasses()) {
-    for (const ClassAccessor::Field& field : accessor.GetFields()) {
-      field.UnHideAccessFlags();
-    }
-    for (const ClassAccessor::Method& method : accessor.GetMethods()) {
-      method.UnHideAccessFlags();
-    }
-  }
-}
-
 uint32_t DexFile::CalculateChecksum() const {
   return CalculateChecksum(Begin(), Size());
 }
@@ -130,6 +105,7 @@
       num_method_handles_(0),
       call_site_ids_(nullptr),
       num_call_site_ids_(0),
+      hiddenapi_class_data_(nullptr),
       oat_dex_file_(oat_dex_file),
       container_(std::move(container)),
       is_compact_dex_(is_compact_dex),
@@ -205,6 +181,11 @@
     } else if (map_item.type_ == kDexTypeCallSiteIdItem) {
       call_site_ids_ = reinterpret_cast<const CallSiteIdItem*>(Begin() + map_item.offset_);
       num_call_site_ids_ = map_item.size_;
+    } else if (map_item.type_ == kDexTypeHiddenapiClassData) {
+      hiddenapi_class_data_ = GetHiddenapiClassDataAtOffset(map_item.offset_);
+    } else {
+      // Pointers to other sections are not necessary to retain in the DexFile struct.
+      // Other items have pointers directly into their data.
     }
   }
 }
diff --git a/libdexfile/dex/dex_file.h b/libdexfile/dex/dex_file.h
index 30d8b6d..6a52f67 100644
--- a/libdexfile/dex/dex_file.h
+++ b/libdexfile/dex/dex_file.h
@@ -92,7 +92,7 @@
     uint32_t endian_tag_ = 0;
     uint32_t link_size_ = 0;  // unused
     uint32_t link_off_ = 0;  // unused
-    uint32_t map_off_ = 0;  // unused
+    uint32_t map_off_ = 0;  // map list offset from data_off_
     uint32_t string_ids_size_ = 0;  // number of StringIds
     uint32_t string_ids_off_ = 0;  // file offset of StringIds array
     uint32_t type_ids_size_ = 0;  // number of TypeIds, we don't support more than 65535
@@ -134,6 +134,7 @@
     kDexTypeAnnotationItem           = 0x2004,
     kDexTypeEncodedArrayItem         = 0x2005,
     kDexTypeAnnotationsDirectoryItem = 0x2006,
+    kDexTypeHiddenapiClassData       = 0xF000,
   };
 
   struct MapItem {
@@ -147,6 +148,8 @@
     uint32_t size_;
     MapItem list_[1];
 
+    size_t Size() const { return sizeof(uint32_t) + (size_ * sizeof(MapItem)); }
+
    private:
     DISALLOW_COPY_AND_ASSIGN(MapList);
   };
@@ -419,6 +422,27 @@
     DISALLOW_COPY_AND_ASSIGN(AnnotationItem);
   };
 
+  struct HiddenapiClassData {
+    uint32_t size_;             // total size of the item
+    uint32_t flags_offset_[1];  // array of offsets from the beginning of this item,
+                                // indexed by class def index
+
+    // Returns a pointer to the beginning of a uleb128-stream of hiddenapi
+    // flags for a class def of given index. Values are in the same order
+    // as fields/methods in the class data. Returns null if the class does
+    // not have class data.
+    const uint8_t* GetFlagsPointer(uint32_t class_def_idx) const {
+      if (flags_offset_[class_def_idx] == 0) {
+        return nullptr;
+      } else {
+        return reinterpret_cast<const uint8_t*>(this) + flags_offset_[class_def_idx];
+      }
+    }
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(HiddenapiClassData);
+  };
+
   enum AnnotationResultStyle {  // private
     kAllObjects,
     kPrimitivesOrObjects,
@@ -837,6 +861,14 @@
     return DataPointer<AnnotationItem>(offset);
   }
 
+  ALWAYS_INLINE const HiddenapiClassData* GetHiddenapiClassDataAtOffset(uint32_t offset) const {
+    return DataPointer<HiddenapiClassData>(offset);
+  }
+
+  ALWAYS_INLINE const HiddenapiClassData* GetHiddenapiClassData() const {
+    return hiddenapi_class_data_;
+  }
+
   const AnnotationItem* GetAnnotationItem(const AnnotationSetItem* set_item, uint32_t index) const {
     DCHECK_LE(index, set_item->size_);
     return GetAnnotationItemAtOffset(set_item->entries_[index]);
@@ -992,12 +1024,6 @@
     return container_.get();
   }
 
-  // Changes the dex class data pointed to by data_ptr it to not have any hiddenapi flags.
-  static void UnHideAccessFlags(uint8_t* data_ptr, uint32_t new_access_flags, bool is_method);
-
-  // Iterate dex classes and remove hiddenapi flags in fields and methods.
-  void UnhideApis() const;
-
   IterationRange<ClassIterator> GetClasses() const;
 
   template <typename Visitor>
@@ -1080,6 +1106,10 @@
   // Number of elements in the call sites list.
   size_t num_call_site_ids_;
 
+  // Points to the base of the hiddenapi class data item_, or nullptr if the dex
+  // file does not have one.
+  const HiddenapiClassData* hiddenapi_class_data_;
+
   // If this dex file was loaded from an oat file, oat_dex_file_ contains a
   // pointer to the OatDexFile it was loaded from. Otherwise oat_dex_file_ is
   // null.
diff --git a/libdexfile/dex/dex_file_verifier.cc b/libdexfile/dex/dex_file_verifier.cc
index 499a89b..4d33cd5 100644
--- a/libdexfile/dex/dex_file_verifier.cc
+++ b/libdexfile/dex/dex_file_verifier.cc
@@ -67,6 +67,7 @@
     case DexFile::kDexTypeAnnotationItem:           return 1 << 17;
     case DexFile::kDexTypeEncodedArrayItem:         return 1 << 18;
     case DexFile::kDexTypeAnnotationsDirectoryItem: return 1 << 19;
+    case DexFile::kDexTypeHiddenapiClassData:       return 1 << 20;
   }
   return 0;
 }
@@ -94,6 +95,7 @@
     case DexFile::kDexTypeAnnotationItem:
     case DexFile::kDexTypeEncodedArrayItem:
     case DexFile::kDexTypeAnnotationsDirectoryItem:
+    case DexFile::kDexTypeHiddenapiClassData:
       return true;
   }
   return true;
@@ -1096,7 +1098,7 @@
       return false;
     }
     if (!CheckClassDataItemField(curr_index,
-                                 field->GetRawAccessFlags(),
+                                 field->GetAccessFlags(),
                                  (*class_def)->access_flags_,
                                  *class_type_index,
                                  kStatic)) {
@@ -1147,7 +1149,7 @@
       return false;
     }
     if (!CheckClassDataItemMethod(curr_index,
-                                  method->GetRawAccessFlags(),
+                                  method->GetAccessFlags(),
                                   (*class_def)->access_flags_,
                                   *class_type_index,
                                   method->GetCodeItemOffset(),
@@ -1555,6 +1557,107 @@
   return true;
 }
 
+bool DexFileVerifier::CheckIntraHiddenapiClassData() {
+  const DexFile::HiddenapiClassData* item =
+      reinterpret_cast<const DexFile::HiddenapiClassData*>(ptr_);
+
+  // Check expected header size.
+  uint32_t num_header_elems = dex_file_->NumClassDefs() + 1;
+  uint32_t elem_size = sizeof(uint32_t);
+  uint32_t header_size = num_header_elems * elem_size;
+  if (!CheckListSize(item, num_header_elems, elem_size, "hiddenapi class data section header")) {
+    return false;
+  }
+
+  // Check total size.
+  if (!CheckListSize(item, item->size_, 1u, "hiddenapi class data section")) {
+    return false;
+  }
+
+  // Check that total size can fit header.
+  if (item->size_ < header_size) {
+    ErrorStringPrintf(
+        "Hiddenapi class data too short to store header (%u < %u)", item->size_, header_size);
+    return false;
+  }
+
+  const uint8_t* data_end = ptr_ + item->size_;
+  ptr_ += header_size;
+
+  // Check offsets for each class def.
+  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);
+    uint32_t offset = item->flags_offset_[i];
+
+    if (offset == 0) {
+      continue;
+    }
+
+    // Check that class defs with no class data do not have any hiddenapi class data.
+    if (class_data == nullptr) {
+      ErrorStringPrintf(
+          "Hiddenapi class data offset not zero for class def %u with no class data", i);
+      return false;
+    }
+
+    // Check that the offset is within the section.
+    if (offset > item->size_) {
+      ErrorStringPrintf(
+          "Hiddenapi class data offset out of section bounds (%u > %u) for class def %u",
+          offset, item->size_, i);
+      return false;
+    }
+
+    // Check that the offset matches current pointer position. We do not allow
+    // offsets into already parsed data, or gaps between class def data.
+    uint32_t ptr_offset = ptr_ - reinterpret_cast<const uint8_t*>(item);
+    if (offset != ptr_offset) {
+      ErrorStringPrintf(
+          "Hiddenapi class data unexpected offset (%u != %u) for class def %u",
+          offset, ptr_offset, i);
+      return false;
+    }
+
+    // Parse a uleb128 value for each field and method of this class.
+    bool failure = false;
+    auto fn_member = [&](const ClassAccessor::BaseItem& member, const char* member_type) {
+      if (failure) {
+        return;
+      }
+      uint32_t decoded_flags;
+      if (!DecodeUnsignedLeb128Checked(&ptr_, data_end, &decoded_flags)) {
+        ErrorStringPrintf("Hiddenapi class data value out of bounds (%p > %p) for %s %i",
+                          ptr_, data_end, member_type, member.GetIndex());
+        failure = true;
+        return;
+      }
+      if (!hiddenapi::AreValidFlags(decoded_flags)) {
+        ErrorStringPrintf("Hiddenapi class data flags invalid (%u) for %s %i",
+                          decoded_flags, member_type, member.GetIndex());
+        failure = true;
+        return;
+      }
+    };
+    auto fn_field = [&](const ClassAccessor::Field& field) { fn_member(field, "field"); };
+    auto fn_method = [&](const ClassAccessor::Method& method) { fn_member(method, "method"); };
+    ClassAccessor accessor(*dex_file_, class_data);
+    accessor.VisitFieldsAndMethods(fn_field, fn_field, fn_method, fn_method);
+    if (failure) {
+      return false;
+    }
+  }
+
+  if (ptr_ != data_end) {
+    ErrorStringPrintf("Hiddenapi class data wrong reported size (%u != %u)",
+                       static_cast<uint32_t>(ptr_ - reinterpret_cast<const uint8_t*>(item)),
+                       item->size_);
+    return false;
+  }
+
+  return true;
+}
+
 bool DexFileVerifier::CheckIntraAnnotationsDirectoryItem() {
   const DexFile::AnnotationsDirectoryItem* item =
       reinterpret_cast<const DexFile::AnnotationsDirectoryItem*>(ptr_);
@@ -1769,6 +1872,12 @@
         }
         break;
       }
+      case DexFile::kDexTypeHiddenapiClassData: {
+        if (!CheckIntraHiddenapiClassData()) {
+          return false;
+        }
+        break;
+      }
       case DexFile::kDexTypeHeaderItem:
       case DexFile::kDexTypeMapList:
         break;
@@ -1973,6 +2082,7 @@
       CHECK_INTRA_DATA_SECTION_CASE(DexFile::kDexTypeAnnotationItem)
       CHECK_INTRA_DATA_SECTION_CASE(DexFile::kDexTypeEncodedArrayItem)
       CHECK_INTRA_DATA_SECTION_CASE(DexFile::kDexTypeAnnotationsDirectoryItem)
+      CHECK_INTRA_DATA_SECTION_CASE(DexFile::kDexTypeHiddenapiClassData)
 #undef CHECK_INTRA_DATA_SECTION_CASE
     }
 
@@ -2736,6 +2846,7 @@
       case DexFile::kDexTypeDebugInfoItem:
       case DexFile::kDexTypeAnnotationItem:
       case DexFile::kDexTypeEncodedArrayItem:
+      case DexFile::kDexTypeHiddenapiClassData:
         break;
       case DexFile::kDexTypeStringIdItem: {
         if (!CheckInterStringIdItem()) {
@@ -2868,7 +2979,8 @@
       case DexFile::kDexTypeAnnotationSetRefList:
       case DexFile::kDexTypeAnnotationSetItem:
       case DexFile::kDexTypeClassDataItem:
-      case DexFile::kDexTypeAnnotationsDirectoryItem: {
+      case DexFile::kDexTypeAnnotationsDirectoryItem:
+      case DexFile::kDexTypeHiddenapiClassData: {
         if (!CheckInterSectionIterate(section_offset, section_count, type)) {
           return false;
         }
diff --git a/libdexfile/dex/dex_file_verifier.h b/libdexfile/dex/dex_file_verifier.h
index 79ddea4..a81df48 100644
--- a/libdexfile/dex/dex_file_verifier.h
+++ b/libdexfile/dex/dex_file_verifier.h
@@ -126,6 +126,7 @@
   bool CheckIntraDebugInfoItem();
   bool CheckIntraAnnotationItem();
   bool CheckIntraAnnotationsDirectoryItem();
+  bool CheckIntraHiddenapiClassData();
 
   template <DexFile::MapItemType kType>
   bool CheckIntraSectionIterate(size_t offset, uint32_t count);
diff --git a/libdexfile/dex/dex_instruction_iterator.h b/libdexfile/dex/dex_instruction_iterator.h
index b75a95b..6c7f42a 100644
--- a/libdexfile/dex/dex_instruction_iterator.h
+++ b/libdexfile/dex/dex_instruction_iterator.h
@@ -63,7 +63,6 @@
   using value_type = std::iterator<std::forward_iterator_tag, DexInstructionPcPair>::value_type;
   using difference_type = std::iterator<std::forward_iterator_tag, value_type>::difference_type;
 
-  DexInstructionIteratorBase() = default;
   explicit DexInstructionIteratorBase(const Instruction* inst, uint32_t dex_pc)
       : data_(reinterpret_cast<const uint16_t*>(inst), dex_pc) {}
 
diff --git a/libdexfile/dex/hidden_api_access_flags.h b/libdexfile/dex/hidden_api_access_flags.h
index 369615d..fd5c865 100644
--- a/libdexfile/dex/hidden_api_access_flags.h
+++ b/libdexfile/dex/hidden_api_access_flags.h
@@ -21,152 +21,80 @@
 #include "base/macros.h"
 #include "dex/modifiers.h"
 
-namespace art {
-
 /* This class is used for encoding and decoding access flags of class members
  * from the boot class path. These access flags might contain additional two bits
  * of information on whether the given class member should be hidden from apps
  * and under what circumstances.
  *
- * The encoding is different inside DexFile, where we are concerned with size,
- * and at runtime where we want to optimize for speed of access. The class
- * provides helper functions to decode/encode both of them.
+ * Two bits are encoded for each class member in the HiddenapiClassData item,
+ * stored in a stream of uleb128-encoded values for each ClassDef item.
+ * The two bits correspond to values in the ApiList enum below.
  *
- * Encoding in DexFile
- * ===================
- *
- * First bit is encoded as inversion of visibility flags (public/private/protected).
- * At most one can be set for any given class member. If two or three are set,
- * this is interpreted as the first bit being set and actual visibility flags
- * being the complement of the encoded flags.
- *
- * Second bit is either encoded as bit 5 for fields and non-native methods, where
- * it carries no other meaning. If a method is native (bit 8 set), bit 9 is used.
- *
- * Bits were selected so that they never increase the length of unsigned LEB-128
- * encoding of the access flags.
- *
- * Encoding at runtime
- * ===================
- *
- * Two bits are set aside in the uint32_t access flags in the intrinsics ordinal
- * space (thus intrinsics need to be special-cased). These are two consecutive
- * bits and they are directly used to store the integer value of the ApiList
- * enum values.
+ * At runtime, two bits are set aside in the uint32_t access flags in the
+ * intrinsics ordinal space (thus intrinsics need to be special-cased). These are
+ * two consecutive bits and they are directly used to store the integer value of
+ * the ApiList enum values.
  *
  */
-class HiddenApiAccessFlags {
- public:
-  enum ApiList {
-    kWhitelist = 0,
-    kLightGreylist,
-    kDarkGreylist,
-    kBlacklist,
-    kNoList,
-  };
 
-  static ALWAYS_INLINE ApiList DecodeFromDex(uint32_t dex_access_flags) {
-    DexHiddenAccessFlags flags(dex_access_flags);
-    uint32_t int_value = (flags.IsFirstBitSet() ? 1 : 0) + (flags.IsSecondBitSet() ? 2 : 0);
-    return static_cast<ApiList>(int_value);
-  }
+namespace art {
+namespace hiddenapi {
 
-  static ALWAYS_INLINE uint32_t RemoveFromDex(uint32_t dex_access_flags) {
-    DexHiddenAccessFlags flags(dex_access_flags);
-    flags.SetFirstBit(false);
-    flags.SetSecondBit(false);
-    return flags.GetEncoding();
-  }
-
-  static ALWAYS_INLINE uint32_t EncodeForDex(uint32_t dex_access_flags, ApiList value) {
-    DexHiddenAccessFlags flags(RemoveFromDex(dex_access_flags));
-    uint32_t int_value = static_cast<uint32_t>(value);
-    flags.SetFirstBit((int_value & 1) != 0);
-    flags.SetSecondBit((int_value & 2) != 0);
-    return flags.GetEncoding();
-  }
-
-  static ALWAYS_INLINE ApiList DecodeFromRuntime(uint32_t runtime_access_flags) {
-    // This is used in the fast path, only DCHECK here.
-    DCHECK_EQ(runtime_access_flags & kAccIntrinsic, 0u);
-    uint32_t int_value = (runtime_access_flags & kAccHiddenApiBits) >> kAccFlagsShift;
-    return static_cast<ApiList>(int_value);
-  }
-
-  static ALWAYS_INLINE uint32_t EncodeForRuntime(uint32_t runtime_access_flags, ApiList value) {
-    CHECK_EQ(runtime_access_flags & kAccIntrinsic, 0u);
-
-    uint32_t hidden_api_flags = static_cast<uint32_t>(value) << kAccFlagsShift;
-    CHECK_EQ(hidden_api_flags & ~kAccHiddenApiBits, 0u);
-
-    runtime_access_flags &= ~kAccHiddenApiBits;
-    return runtime_access_flags | hidden_api_flags;
-  }
-
- private:
-  static const int kAccFlagsShift = CTZ(kAccHiddenApiBits);
-  static_assert(IsPowerOfTwo((kAccHiddenApiBits >> kAccFlagsShift) + 1),
-                "kAccHiddenApiBits are not continuous");
-
-  struct DexHiddenAccessFlags {
-    explicit DexHiddenAccessFlags(uint32_t access_flags) : access_flags_(access_flags) {}
-
-    ALWAYS_INLINE uint32_t GetSecondFlag() {
-      return ((access_flags_ & kAccNative) != 0) ? kAccDexHiddenBitNative : kAccDexHiddenBit;
-    }
-
-    ALWAYS_INLINE bool IsFirstBitSet() {
-      static_assert(IsPowerOfTwo(0u), "Following statement checks if *at most* one bit is set");
-      return !IsPowerOfTwo(access_flags_ & kAccVisibilityFlags);
-    }
-
-    ALWAYS_INLINE void SetFirstBit(bool value) {
-      if (IsFirstBitSet() != value) {
-        access_flags_ ^= kAccVisibilityFlags;
-      }
-    }
-
-    ALWAYS_INLINE bool IsSecondBitSet() {
-      return (access_flags_ & GetSecondFlag()) != 0;
-    }
-
-    ALWAYS_INLINE void SetSecondBit(bool value) {
-      if (value) {
-        access_flags_ |= GetSecondFlag();
-      } else {
-        access_flags_ &= ~GetSecondFlag();
-      }
-    }
-
-    ALWAYS_INLINE uint32_t GetEncoding() const {
-      return access_flags_;
-    }
-
-    uint32_t access_flags_;
-  };
+enum class ApiList {
+  kWhitelist = 0,
+  kLightGreylist,
+  kDarkGreylist,
+  kBlacklist,
+  kNoList,
 };
 
-inline std::ostream& operator<<(std::ostream& os, HiddenApiAccessFlags::ApiList value) {
+static const int kAccFlagsShift = CTZ(kAccHiddenApiBits);
+static_assert(IsPowerOfTwo((kAccHiddenApiBits >> kAccFlagsShift) + 1),
+              "kAccHiddenApiBits are not continuous");
+
+inline ApiList DecodeFromRuntime(uint32_t runtime_access_flags) {
+  // This is used in the fast path, only DCHECK here.
+  DCHECK_EQ(runtime_access_flags & kAccIntrinsic, 0u);
+  uint32_t int_value = (runtime_access_flags & kAccHiddenApiBits) >> kAccFlagsShift;
+  return static_cast<ApiList>(int_value);
+}
+
+inline uint32_t EncodeForRuntime(uint32_t runtime_access_flags, ApiList value) {
+  CHECK_EQ(runtime_access_flags & kAccIntrinsic, 0u);
+
+  uint32_t hidden_api_flags = static_cast<uint32_t>(value) << kAccFlagsShift;
+  CHECK_EQ(hidden_api_flags & ~kAccHiddenApiBits, 0u);
+
+  runtime_access_flags &= ~kAccHiddenApiBits;
+  return runtime_access_flags | hidden_api_flags;
+}
+
+inline bool AreValidFlags(uint32_t flags) {
+  return flags <= static_cast<uint32_t>(ApiList::kBlacklist);
+}
+
+inline std::ostream& operator<<(std::ostream& os, ApiList value) {
   switch (value) {
-    case HiddenApiAccessFlags::kWhitelist:
+    case ApiList::kWhitelist:
       os << "whitelist";
       break;
-    case HiddenApiAccessFlags::kLightGreylist:
+    case ApiList::kLightGreylist:
       os << "light greylist";
       break;
-    case HiddenApiAccessFlags::kDarkGreylist:
+    case ApiList::kDarkGreylist:
       os << "dark greylist";
       break;
-    case HiddenApiAccessFlags::kBlacklist:
+    case ApiList::kBlacklist:
       os << "blacklist";
       break;
-    case HiddenApiAccessFlags::kNoList:
+    case ApiList::kNoList:
       os << "no list";
       break;
   }
   return os;
 }
 
+}  // namespace hiddenapi
 }  // namespace art
 
 
diff --git a/libdexfile/dex/modifiers.h b/libdexfile/dex/modifiers.h
index 38f8455..018b141 100644
--- a/libdexfile/dex/modifiers.h
+++ b/libdexfile/dex/modifiers.h
@@ -42,11 +42,6 @@
 
 static constexpr uint32_t kAccJavaFlagsMask = 0xffff;  // bits set from Java sources (low 16)
 
-// The following flags are used to insert hidden API access flags into boot class path dex files.
-// They are decoded by ClassAccessor and removed from the access flags before used by the runtime.
-static constexpr uint32_t kAccDexHiddenBit =          0x00000020;  // field, method (not native)
-static constexpr uint32_t kAccDexHiddenBitNative =    0x00000200;  // method (native)
-
 static constexpr uint32_t kAccConstructor =           0x00010000;  // method (dex only) <(cl)init>
 static constexpr uint32_t kAccDeclaredSynchronized =  0x00020000;  // method (dex only)
 static constexpr uint32_t kAccClassIsProxy =          0x00040000;  // class  (dex only)
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 0610b97..e26ec95 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -628,9 +628,6 @@
         CHECK(oat_dex_file != nullptr);
         CHECK(vdex_dex_file != nullptr);
 
-        // Remove hiddenapis
-        vdex_dex_file->UnhideApis();
-
         // If a CompactDex file is detected within a Vdex container, DexLayout is used to convert
         // back to a StandardDex file. Since the converted DexFile will most likely not reproduce
         // the original input Dex file, the `update_checksum_` option is used to recompute the
@@ -1078,7 +1075,7 @@
                          dex_file,
                          method.GetIndex(),
                          method.GetCodeItem(),
-                         method.GetRawAccessFlags(),
+                         method.GetAccessFlags(),
                          &addr_found)) {
         success = false;
       }
diff --git a/openjdkjvmti/OpenjdkJvmTi.cc b/openjdkjvmti/OpenjdkJvmTi.cc
index a2fabbf..bd5b598 100644
--- a/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/openjdkjvmti/OpenjdkJvmTi.cc
@@ -29,6 +29,7 @@
  * questions.
  */
 
+#include <memory>
 #include <string>
 #include <type_traits>
 #include <vector>
@@ -1492,7 +1493,7 @@
       capabilities(),
       event_info_mutex_("jvmtiEnv_EventInfoMutex"),
       last_error_mutex_("jvmtiEnv_LastErrorMutex", art::LockLevel::kGenericBottomLock) {
-  object_tag_table = std::unique_ptr<ObjectTagTable>(new ObjectTagTable(event_handler, this));
+  object_tag_table = std::make_unique<ObjectTagTable>(event_handler, this);
   functions = &gJvmtiInterface;
 }
 
diff --git a/openjdkjvmti/fixed_up_dex_file.cc b/openjdkjvmti/fixed_up_dex_file.cc
index 6745d91..41e4291 100644
--- a/openjdkjvmti/fixed_up_dex_file.cc
+++ b/openjdkjvmti/fixed_up_dex_file.cc
@@ -71,7 +71,6 @@
                            original_dex_file,
                            /* decompile_return_instruction= */ true);
   }
-  new_dex_file.UnhideApis();
 }
 
 static void DCheckVerifyDexFile(const art::DexFile& dex) {
@@ -106,9 +105,6 @@
     // this before unquickening.
     art::Options options;
     options.compact_dex_level_ = art::CompactDexLevel::kCompactDexLevelNone;
-    // Never verify the output since hidden API flags may cause the dex file verifier to fail.
-    // See b/74063493
-    options.verify_output_ = false;
     // Add a filter to only include the class that has the matching descriptor.
     static constexpr bool kFilterByDescriptor = true;
     if (kFilterByDescriptor) {
diff --git a/openjdkjvmti/ti_class_definition.cc b/openjdkjvmti/ti_class_definition.cc
index 9e8288f..2a56512 100644
--- a/openjdkjvmti/ti_class_definition.cc
+++ b/openjdkjvmti/ti_class_definition.cc
@@ -246,14 +246,12 @@
     mmap_name += name_;
     std::string error;
     dex_data_mmap_ = art::MemMap::MapAnonymous(mmap_name.c_str(),
-                                               /* addr= */ nullptr,
                                                dequick_size,
                                                PROT_NONE,
                                                /*low_4gb=*/ false,
                                                &error);
     mmap_name += "-TEMP";
     temp_mmap_ = art::MemMap::MapAnonymous(mmap_name.c_str(),
-                                           /* addr= */ nullptr,
                                            dequick_size,
                                            PROT_READ | PROT_WRITE,
                                            /*low_4gb=*/ false,
diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc
index f3f45d9..7cd1039 100644
--- a/openjdkjvmti/ti_redefine.cc
+++ b/openjdkjvmti/ti_redefine.cc
@@ -309,7 +309,6 @@
                                         std::string* error_msg) {
   art::MemMap map = art::MemMap::MapAnonymous(
       StringPrintf("%s-transformed", original_location.c_str()).c_str(),
-      /* addr= */ nullptr,
       data.size(),
       PROT_READ|PROT_WRITE,
       /*low_4gb=*/ false,
diff --git a/openjdkjvmti/transform.cc b/openjdkjvmti/transform.cc
index 653f944..8bd10da 100644
--- a/openjdkjvmti/transform.cc
+++ b/openjdkjvmti/transform.cc
@@ -48,6 +48,7 @@
 #include "events-inl.h"
 #include "fault_handler.h"
 #include "gc_root-inl.h"
+#include "handle_scope-inl.h"
 #include "jni/jni_env_ext-inl.h"
 #include "jvalue.h"
 #include "jvmti.h"
diff --git a/runtime/art_field.h b/runtime/art_field.h
index 5afd000..dc7f985 100644
--- a/runtime/art_field.h
+++ b/runtime/art_field.h
@@ -180,8 +180,8 @@
     return (GetAccessFlags() & kAccVolatile) != 0;
   }
 
-  HiddenApiAccessFlags::ApiList GetHiddenApiAccessFlags() REQUIRES_SHARED(Locks::mutator_lock_) {
-    return HiddenApiAccessFlags::DecodeFromRuntime(GetAccessFlags());
+  hiddenapi::ApiList GetHiddenApiAccessFlags() REQUIRES_SHARED(Locks::mutator_lock_) {
+    return hiddenapi::DecodeFromRuntime(GetAccessFlags());
   }
 
   // Returns an instance field with this offset in the given class or null if not found.
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index f693524..e9c17ee 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -367,7 +367,7 @@
   return (GetAccessFlags() & kAccSingleImplementation) != 0;
 }
 
-inline HiddenApiAccessFlags::ApiList ArtMethod::GetHiddenApiAccessFlags()
+inline hiddenapi::ApiList ArtMethod::GetHiddenApiAccessFlags()
     REQUIRES_SHARED(Locks::mutator_lock_) {
   if (UNLIKELY(IsIntrinsic())) {
     switch (static_cast<Intrinsics>(GetIntrinsic())) {
@@ -407,7 +407,7 @@
         // Note that the DCHECK currently won't fail if the dex methods are
         // whitelisted, e.g. in the core image (b/77733081). As a result, we
         // might print warnings but we won't change the semantics.
-        return HiddenApiAccessFlags::kLightGreylist;
+        return hiddenapi::ApiList::kLightGreylist;
       case Intrinsics::kStringNewStringFromBytes:
       case Intrinsics::kStringNewStringFromChars:
       case Intrinsics::kStringNewStringFromString:
@@ -417,7 +417,7 @@
       case Intrinsics::kMemoryPokeIntNative:
       case Intrinsics::kMemoryPokeLongNative:
       case Intrinsics::kMemoryPokeShortNative:
-        return HiddenApiAccessFlags::kDarkGreylist;
+        return hiddenapi::ApiList::kDarkGreylist;
       case Intrinsics::kVarHandleFullFence:
       case Intrinsics::kVarHandleAcquireFence:
       case Intrinsics::kVarHandleReleaseFence:
@@ -460,13 +460,13 @@
         // whitelisted, e.g. in the core image (b/77733081). Given that they are
         // exclusively VarHandle intrinsics, they should not be used outside
         // tests that do not enable hidden API checks.
-        return HiddenApiAccessFlags::kBlacklist;
+        return hiddenapi::ApiList::kBlacklist;
       default:
         // Remaining intrinsics are public API. We DCHECK that in SetIntrinsic().
-        return HiddenApiAccessFlags::kWhitelist;
+        return hiddenapi::ApiList::kWhitelist;
     }
   } else {
-    return HiddenApiAccessFlags::DecodeFromRuntime(GetAccessFlags());
+    return hiddenapi::DecodeFromRuntime(GetAccessFlags());
   }
 }
 
@@ -492,7 +492,7 @@
     bool is_default_conflict = IsDefaultConflicting();
     bool is_compilable = IsCompilable();
     bool must_count_locks = MustCountLocks();
-    HiddenApiAccessFlags::ApiList hidden_api_flags = GetHiddenApiAccessFlags();
+    hiddenapi::ApiList hidden_api_flags = GetHiddenApiAccessFlags();
     SetAccessFlags(new_value);
     DCHECK_EQ(java_flags, (GetAccessFlags() & kAccJavaFlagsMask));
     DCHECK_EQ(is_constructor, IsConstructor());
@@ -512,7 +512,7 @@
     // these because (a) warnings on greylist do not change semantics, and
     // (b) only VarHandle intrinsics are blacklisted at the moment and they
     // should not be used outside tests with disabled API checks.
-    if (hidden_api_flags != HiddenApiAccessFlags::kWhitelist) {
+    if (hidden_api_flags != hiddenapi::ApiList::kWhitelist) {
       DCHECK_EQ(hidden_api_flags, GetHiddenApiAccessFlags()) << PrettyMethod();
     }
   } else {
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 4a19b10..9bf31ed 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -688,13 +688,13 @@
   }
 
   // Query the hidden API access flags of the intrinsic.
-  HiddenApiAccessFlags::ApiList intrinsic_api_list = GetHiddenApiAccessFlags();
+  hiddenapi::ApiList intrinsic_api_list = GetHiddenApiAccessFlags();
 
   // Clear intrinsic-related access flags.
   ClearAccessFlags(kAccIntrinsic | kAccIntrinsicBits);
 
   // Re-apply hidden API access flags now that the method is not an intrinsic.
-  SetAccessFlags(HiddenApiAccessFlags::EncodeForRuntime(GetAccessFlags(), intrinsic_api_list));
+  SetAccessFlags(hiddenapi::EncodeForRuntime(GetAccessFlags(), intrinsic_api_list));
   DCHECK_EQ(GetHiddenApiAccessFlags(), intrinsic_api_list);
 }
 
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 18ddcc0..e56f3fd 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -326,7 +326,7 @@
     AddAccessFlags(kAccMustCountLocks);
   }
 
-  HiddenApiAccessFlags::ApiList GetHiddenApiAccessFlags() REQUIRES_SHARED(Locks::mutator_lock_);
+  hiddenapi::ApiList GetHiddenApiAccessFlags() REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Returns true if this method could be overridden by a default method.
   bool IsOverridableByDefaultMethod() REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/base/mem_map_arena_pool.cc b/runtime/base/mem_map_arena_pool.cc
index 50b42d4..ae7db45 100644
--- a/runtime/base/mem_map_arena_pool.cc
+++ b/runtime/base/mem_map_arena_pool.cc
@@ -58,7 +58,6 @@
   size = RoundUp(size, kPageSize);
   std::string error_msg;
   MemMap map = MemMap::MapAnonymous(name,
-                                    /* addr= */ nullptr,
                                     size,
                                     PROT_READ | PROT_WRITE,
                                     low_4gb,
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 9b45b48..f43791a 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -3294,7 +3294,9 @@
                             const DexFile& dex_file,
                             const DexFile::ClassDef& dex_class_def,
                             Handle<mirror::Class> klass) {
-  ClassAccessor accessor(dex_file, dex_class_def);
+  ClassAccessor accessor(dex_file,
+                         dex_class_def,
+                         /* parse_hiddenapi_class_data= */ klass->IsBootStrapClassLoaded());
   if (!accessor.HasClassData()) {
     return;
   }
@@ -3410,8 +3412,8 @@
   // also set its runtime hidden API access flags.
   uint32_t access_flags = field.GetAccessFlags();
   if (klass->IsBootStrapClassLoaded()) {
-    access_flags =
-        HiddenApiAccessFlags::EncodeForRuntime(access_flags, field.DecodeHiddenAccessFlags());
+    access_flags = hiddenapi::EncodeForRuntime(
+        access_flags, static_cast<hiddenapi::ApiList>(field.GetHiddenapiFlags()));
   }
   dst->SetAccessFlags(access_flags);
 }
@@ -3432,10 +3434,9 @@
   // Get access flags from the DexFile. If this is a boot class path class,
   // also set its runtime hidden API access flags.
   uint32_t access_flags = method.GetAccessFlags();
-
   if (klass->IsBootStrapClassLoaded()) {
-    access_flags =
-        HiddenApiAccessFlags::EncodeForRuntime(access_flags, method.DecodeHiddenAccessFlags());
+    access_flags = hiddenapi::EncodeForRuntime(
+        access_flags, static_cast<hiddenapi::ApiList>(method.GetHiddenapiFlags()));
   }
 
   if (UNLIKELY(strcmp("finalize", method_name) == 0)) {
diff --git a/runtime/dexopt_test.cc b/runtime/dexopt_test.cc
index 13f5fcb..ed3a18d 100644
--- a/runtime/dexopt_test.cc
+++ b/runtime/dexopt_test.cc
@@ -206,7 +206,9 @@
                                                       reinterpret_cast<uint8_t*>(start),
                                                       end - start,
                                                       PROT_NONE,
-                                                      /* low_4gb=*/ false,
+                                                      /*low_4gb=*/ false,
+                                                      /*reuse=*/ false,
+                                                      /*reservation=*/ nullptr,
                                                       &error_msg));
     ASSERT_TRUE(image_reservation_.back().IsValid()) << error_msg;
     LOG(INFO) << "Reserved space for image " <<
diff --git a/runtime/gc/accounting/atomic_stack.h b/runtime/gc/accounting/atomic_stack.h
index 313b2b4..9431f80 100644
--- a/runtime/gc/accounting/atomic_stack.h
+++ b/runtime/gc/accounting/atomic_stack.h
@@ -253,10 +253,9 @@
   void Init() {
     std::string error_msg;
     mem_map_ = MemMap::MapAnonymous(name_.c_str(),
-                                    /* addr= */ nullptr,
                                     capacity_ * sizeof(begin_[0]),
                                     PROT_READ | PROT_WRITE,
-                                    /* low_4gb= */ false,
+                                    /*low_4gb=*/ false,
                                     &error_msg);
     CHECK(mem_map_.IsValid()) << "couldn't allocate mark stack.\n" << error_msg;
     uint8_t* addr = mem_map_.Begin();
diff --git a/runtime/gc/accounting/bitmap.cc b/runtime/gc/accounting/bitmap.cc
index 80c4c76..8a15af2 100644
--- a/runtime/gc/accounting/bitmap.cc
+++ b/runtime/gc/accounting/bitmap.cc
@@ -49,10 +49,9 @@
       RoundUp(num_bits, kBitsPerBitmapWord) / kBitsPerBitmapWord * sizeof(uintptr_t), kPageSize);
   std::string error_msg;
   MemMap mem_map = MemMap::MapAnonymous(name.c_str(),
-                                        /* addr= */ nullptr,
                                         bitmap_size,
                                         PROT_READ | PROT_WRITE,
-                                        /* low_4gb= */ false,
+                                        /*low_4gb=*/ false,
                                         &error_msg);
   if (UNLIKELY(!mem_map.IsValid())) {
     LOG(ERROR) << "Failed to allocate bitmap " << name << ": " << error_msg;
diff --git a/runtime/gc/accounting/card_table.cc b/runtime/gc/accounting/card_table.cc
index 9a5bde8..fdf1615 100644
--- a/runtime/gc/accounting/card_table.cc
+++ b/runtime/gc/accounting/card_table.cc
@@ -65,10 +65,9 @@
   /* Allocate an extra 256 bytes to allow fixed low-byte of base */
   std::string error_msg;
   MemMap mem_map = MemMap::MapAnonymous("card table",
-                                        /* addr= */ nullptr,
                                         capacity + 256,
                                         PROT_READ | PROT_WRITE,
-                                        /* low_4gb= */ false,
+                                        /*low_4gb=*/ false,
                                         &error_msg);
   CHECK(mem_map.IsValid()) << "couldn't allocate card table: " << error_msg;
   // All zeros is the correct initial value; all clean. Anonymous mmaps are initialized to zero, we
diff --git a/runtime/gc/accounting/mod_union_table_test.cc b/runtime/gc/accounting/mod_union_table_test.cc
index a617789..b39628b 100644
--- a/runtime/gc/accounting/mod_union_table_test.cc
+++ b/runtime/gc/accounting/mod_union_table_test.cc
@@ -185,7 +185,7 @@
   ResetClass();
   // Create another space that we can put references in.
   std::unique_ptr<space::DlMallocSpace> other_space(space::DlMallocSpace::Create(
-      "other space", 128 * KB, 4 * MB, 4 * MB, nullptr, false));
+      "other space", 128 * KB, 4 * MB, 4 * MB, /*can_move_objects=*/ false));
   ASSERT_TRUE(other_space.get() != nullptr);
   {
     ScopedThreadSuspension sts(self, kSuspended);
diff --git a/runtime/gc/accounting/read_barrier_table.h b/runtime/gc/accounting/read_barrier_table.h
index b369a66..7eca792 100644
--- a/runtime/gc/accounting/read_barrier_table.h
+++ b/runtime/gc/accounting/read_barrier_table.h
@@ -40,10 +40,9 @@
               static_cast<uint64_t>(static_cast<size_t>(kHeapCapacity / kRegionSize)));
     std::string error_msg;
     mem_map_ = MemMap::MapAnonymous("read barrier table",
-                                    /* addr= */ nullptr,
                                     capacity,
                                     PROT_READ | PROT_WRITE,
-                                    /* low_4gb= */ false,
+                                    /*low_4gb=*/ false,
                                     &error_msg);
     CHECK(mem_map_.IsValid() && mem_map_.Begin() != nullptr)
         << "couldn't allocate read barrier table: " << error_msg;
diff --git a/runtime/gc/accounting/space_bitmap.cc b/runtime/gc/accounting/space_bitmap.cc
index 76d5d9d..dc223db 100644
--- a/runtime/gc/accounting/space_bitmap.cc
+++ b/runtime/gc/accounting/space_bitmap.cc
@@ -85,10 +85,9 @@
   const size_t bitmap_size = ComputeBitmapSize(heap_capacity);
   std::string error_msg;
   MemMap mem_map = MemMap::MapAnonymous(name.c_str(),
-                                        /* addr= */ nullptr,
                                         bitmap_size,
                                         PROT_READ | PROT_WRITE,
-                                        /* low_4gb= */ false,
+                                        /*low_4gb=*/ false,
                                         &error_msg);
   if (UNLIKELY(!mem_map.IsValid())) {
     LOG(ERROR) << "Failed to allocate bitmap " << name << ": " << error_msg;
diff --git a/runtime/gc/allocator/rosalloc.cc b/runtime/gc/allocator/rosalloc.cc
index 4e2cf2b..b90a95d 100644
--- a/runtime/gc/allocator/rosalloc.cc
+++ b/runtime/gc/allocator/rosalloc.cc
@@ -92,10 +92,9 @@
   size_t max_num_of_pages = max_capacity_ / kPageSize;
   std::string error_msg;
   page_map_mem_map_ = MemMap::MapAnonymous("rosalloc page map",
-                                           /* addr= */ nullptr,
                                            RoundUp(max_num_of_pages, kPageSize),
                                            PROT_READ | PROT_WRITE,
-                                           /* low_4gb= */ false,
+                                           /*low_4gb=*/ false,
                                            &error_msg);
   CHECK(page_map_mem_map_.IsValid()) << "Couldn't allocate the page map : " << error_msg;
   page_map_ = page_map_mem_map_.Begin();
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index 2ae4676..be1014c 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -135,10 +135,9 @@
     std::string error_msg;
     sweep_array_free_buffer_mem_map_ = MemMap::MapAnonymous(
         "concurrent copying sweep array free buffer",
-        /* addr= */ nullptr,
         RoundUp(kSweepArrayChunkFreeSize * sizeof(mirror::Object*), kPageSize),
         PROT_READ | PROT_WRITE,
-        /* low_4gb= */ false,
+        /*low_4gb=*/ false,
         &error_msg);
     CHECK(sweep_array_free_buffer_mem_map_.IsValid())
         << "Couldn't allocate sweep array free buffer: " << error_msg;
@@ -1650,12 +1649,38 @@
 
 inline void ConcurrentCopying::ProcessMarkStackRef(mirror::Object* to_ref) {
   DCHECK(!region_space_->IsInFromSpace(to_ref));
-  if (kUseBakerReadBarrier) {
-    DCHECK(to_ref->GetReadBarrierState() == ReadBarrier::GrayState())
-        << " " << to_ref << " " << to_ref->GetReadBarrierState()
-        << " is_marked=" << IsMarked(to_ref);
-  }
   space::RegionSpace::RegionType rtype = region_space_->GetRegionType(to_ref);
+  auto find_space_from_ref = [this] (mirror::Object* ref)
+      REQUIRES_SHARED(Locks::mutator_lock_) -> space::Space* {
+    for (const auto& space : heap_->GetContinuousSpaces()) {
+      if (space->Contains(ref)) {
+        return space;
+      }
+    }
+    for (const auto& space : heap_->GetDiscontinuousSpaces()) {
+      if (space->Contains(ref)) {
+        return space;
+      }
+    }
+    return nullptr;
+  };
+  if (kUseBakerReadBarrier &&
+      kIsDebugBuild &&
+      to_ref->GetReadBarrierState() != ReadBarrier::GrayState()) {
+        space::Space* space = find_space_from_ref(to_ref);
+        LOG(FATAL_WITHOUT_ABORT) << " " << to_ref
+                                 << " " << to_ref->GetReadBarrierState()
+                                 << " is_marked=" << IsMarked(to_ref)
+                                 << " type=" << to_ref->PrettyTypeOf()
+                                 << " is_young_gc=" << young_gen_;
+        if (space == region_space_) {
+          LOG(FATAL) << " region_type=" << rtype;
+        } else if (space != nullptr) {
+          LOG(FATAL) << " space=" << space->GetName();
+        } else {
+          LOG(FATAL) << "no space";
+        }
+  }
   bool add_to_live_bytes = false;
   // Invariant: There should be no object from a newly-allocated
   // region (either large or non-large) on the mark stack.
@@ -1690,10 +1715,22 @@
       Scan<false>(to_ref);
     }
   }
-  if (kUseBakerReadBarrier) {
-    DCHECK(to_ref->GetReadBarrierState() == ReadBarrier::GrayState())
-        << " " << to_ref << " " << to_ref->GetReadBarrierState()
-        << " is_marked=" << IsMarked(to_ref);
+  if (kUseBakerReadBarrier &&
+      kIsDebugBuild &&
+      to_ref->GetReadBarrierState() != ReadBarrier::GrayState()) {
+        space::Space* space = find_space_from_ref(to_ref);
+        LOG(FATAL_WITHOUT_ABORT) << " " << to_ref
+                                 << " " << to_ref->GetReadBarrierState()
+                                 << " is_marked=" << IsMarked(to_ref)
+                                 << " type=" << to_ref->PrettyTypeOf()
+                                 << " is_young_gc=" << young_gen_;
+        if (space == region_space_) {
+          LOG(FATAL) << " region_type=" << rtype;
+        } else if (space != nullptr) {
+          LOG(FATAL) << " space=" << space->GetName();
+        } else {
+          LOG(FATAL) << "no space";
+        }
   }
 #ifdef USE_BAKER_OR_BROOKS_READ_BARRIER
   mirror::Object* referent = nullptr;
diff --git a/runtime/gc/collector/immune_spaces_test.cc b/runtime/gc/collector/immune_spaces_test.cc
index 0e5fac1..c2a67bf 100644
--- a/runtime/gc/collector/immune_spaces_test.cc
+++ b/runtime/gc/collector/immune_spaces_test.cc
@@ -78,18 +78,20 @@
   }
 
   // Create an image space, the oat file is optional.
-  DummyImageSpace* CreateImageSpace(uint8_t* image_begin,
-                                    size_t image_size,
-                                    uint8_t* oat_begin,
-                                    size_t oat_size) {
+  DummyImageSpace* CreateImageSpace(size_t image_size,
+                                    size_t oat_size,
+                                    MemMap* image_reservation,
+                                    MemMap* oat_reservation) {
+    DCHECK(image_reservation != nullptr);
+    DCHECK(oat_reservation != nullptr);
     std::string error_str;
-    MemMap map = MemMap::MapAnonymous("DummyImageSpace",
-                                      image_begin,
-                                      image_size,
-                                      PROT_READ | PROT_WRITE,
-                                      /*low_4gb=*/true,
-                                      &error_str);
-    if (!map.IsValid()) {
+    MemMap image_map = MemMap::MapAnonymous("DummyImageSpace",
+                                            image_size,
+                                            PROT_READ | PROT_WRITE,
+                                            /*low_4gb=*/ true,
+                                            /*reservation=*/ image_reservation,
+                                            &error_str);
+    if (!image_map.IsValid()) {
       LOG(ERROR) << error_str;
       return nullptr;
     }
@@ -97,10 +99,10 @@
     std::unique_ptr<accounting::ContinuousSpaceBitmap> live_bitmap(std::move(live_bitmaps_.back()));
     live_bitmaps_.pop_back();
     MemMap oat_map = MemMap::MapAnonymous("OatMap",
-                                          oat_begin,
                                           oat_size,
                                           PROT_READ | PROT_WRITE,
-                                          /*low_4gb=*/true,
+                                          /*low_4gb=*/ true,
+                                          /*reservation=*/ oat_reservation,
                                           &error_str);
     if (!oat_map.IsValid()) {
       LOG(ERROR) << error_str;
@@ -109,17 +111,17 @@
     std::unique_ptr<DummyOatFile> oat_file(new DummyOatFile(oat_map.Begin(), oat_map.End()));
     // Create image header.
     ImageSection sections[ImageHeader::kSectionCount];
-    new (map.Begin()) ImageHeader(
-        /*image_begin=*/PointerToLowMemUInt32(map.Begin()),
-        /*image_size=*/map.Size(),
+    new (image_map.Begin()) ImageHeader(
+        /*image_begin=*/ PointerToLowMemUInt32(image_map.Begin()),
+        /*image_size=*/ image_map.Size(),
         sections,
-        /*image_roots=*/PointerToLowMemUInt32(map.Begin()) + 1,
-        /*oat_checksum=*/0u,
+        /*image_roots=*/ PointerToLowMemUInt32(image_map.Begin()) + 1,
+        /*oat_checksum=*/ 0u,
         // The oat file data in the header is always right after the image space.
-        /*oat_file_begin=*/PointerToLowMemUInt32(oat_begin),
-        /*oat_data_begin=*/PointerToLowMemUInt32(oat_begin),
-        /*oat_data_end=*/PointerToLowMemUInt32(oat_begin + oat_size),
-        /*oat_file_end=*/PointerToLowMemUInt32(oat_begin + oat_size),
+        /*oat_file_begin=*/ PointerToLowMemUInt32(oat_map.Begin()),
+        /*oat_data_begin=*/PointerToLowMemUInt32(oat_map.Begin()),
+        /*oat_data_end=*/PointerToLowMemUInt32(oat_map.Begin() + oat_size),
+        /*oat_file_end=*/PointerToLowMemUInt32(oat_map.Begin() + oat_size),
         /*boot_image_begin=*/0u,
         /*boot_image_size=*/0u,
         /*boot_oat_begin=*/0u,
@@ -127,29 +129,12 @@
         /*pointer_size=*/sizeof(void*),
         ImageHeader::kStorageModeUncompressed,
         /*data_size=*/0u);
-    return new DummyImageSpace(std::move(map),
+    return new DummyImageSpace(std::move(image_map),
                                std::move(live_bitmap),
                                std::move(oat_file),
                                std::move(oat_map));
   }
 
-  // Does not reserve the memory, the caller needs to be sure no other threads will map at the
-  // returned address.
-  static uint8_t* GetContinuousMemoryRegion(size_t size) {
-    std::string error_str;
-    MemMap map = MemMap::MapAnonymous("reserve",
-                                      /* addr= */ nullptr,
-                                      size,
-                                      PROT_READ | PROT_WRITE,
-                                      /*low_4gb=*/ true,
-                                      &error_str);
-    if (!map.IsValid()) {
-      LOG(ERROR) << "Failed to allocate memory region " << error_str;
-      return nullptr;
-    }
-    return map.Begin();
-  }
-
  private:
   // Bitmap pool for pre-allocated dummy bitmaps. We need to pre-allocate them since we don't want
   // them to randomly get placed somewhere where we want an image space.
@@ -206,13 +191,25 @@
   constexpr size_t kImageOatSize = 321 * kPageSize;
   constexpr size_t kOtherSpaceSize = 100 * kPageSize;
 
-  uint8_t* memory = GetContinuousMemoryRegion(kImageSize + kImageOatSize + kOtherSpaceSize);
+  std::string error_str;
+  MemMap reservation = MemMap::MapAnonymous("reserve",
+                                            kImageSize + kImageOatSize + kOtherSpaceSize,
+                                            PROT_READ | PROT_WRITE,
+                                            /*low_4gb=*/ true,
+                                            &error_str);
+  ASSERT_TRUE(reservation.IsValid()) << "Failed to allocate memory region " << error_str;
+  MemMap image_reservation = reservation.TakeReservedMemory(kImageSize);
+  ASSERT_TRUE(image_reservation.IsValid());
+  ASSERT_TRUE(reservation.IsValid());
 
-  std::unique_ptr<DummyImageSpace> image_space(CreateImageSpace(memory,
-                                                                kImageSize,
-                                                                memory + kImageSize,
-                                                                kImageOatSize));
+  std::unique_ptr<DummyImageSpace> image_space(CreateImageSpace(kImageSize,
+                                                                kImageOatSize,
+                                                                &image_reservation,
+                                                                &reservation));
   ASSERT_TRUE(image_space != nullptr);
+  ASSERT_FALSE(image_reservation.IsValid());
+  ASSERT_TRUE(reservation.IsValid());
+
   const ImageHeader& image_header = image_space->GetImageHeader();
   DummySpace space(image_header.GetOatFileEnd(), image_header.GetOatFileEnd() + kOtherSpaceSize);
 
@@ -257,36 +254,44 @@
   constexpr size_t kImage3OatSize = kPageSize;
   constexpr size_t kImageBytes = kImage1Size + kImage2Size + kImage3Size;
   constexpr size_t kMemorySize = kImageBytes + kImage1OatSize + kImage2OatSize + kImage3OatSize;
-  uint8_t* memory = GetContinuousMemoryRegion(kMemorySize);
-  uint8_t* space1_begin = memory;
-  memory += kImage1Size;
-  uint8_t* space2_begin = memory;
-  memory += kImage2Size;
-  uint8_t* space1_oat_begin = memory;
-  memory += kImage1OatSize;
-  uint8_t* space2_oat_begin = memory;
-  memory += kImage2OatSize;
-  uint8_t* space3_begin = memory;
+  std::string error_str;
+  MemMap reservation = MemMap::MapAnonymous("reserve",
+                                            kMemorySize,
+                                            PROT_READ | PROT_WRITE,
+                                            /*low_4gb=*/ true,
+                                            &error_str);
+  ASSERT_TRUE(reservation.IsValid()) << "Failed to allocate memory region " << error_str;
+  MemMap image_reservation = reservation.TakeReservedMemory(kImage1Size + kImage2Size);
+  ASSERT_TRUE(image_reservation.IsValid());
+  ASSERT_TRUE(reservation.IsValid());
 
-  std::unique_ptr<DummyImageSpace> space1(CreateImageSpace(space1_begin,
-                                                           kImage1Size,
-                                                           space1_oat_begin,
-                                                           kImage1OatSize));
+  std::unique_ptr<DummyImageSpace> space1(CreateImageSpace(kImage1Size,
+                                                           kImage1OatSize,
+                                                           &image_reservation,
+                                                           &reservation));
   ASSERT_TRUE(space1 != nullptr);
+  ASSERT_TRUE(image_reservation.IsValid());
+  ASSERT_TRUE(reservation.IsValid());
 
-
-  std::unique_ptr<DummyImageSpace> space2(CreateImageSpace(space2_begin,
-                                                           kImage2Size,
-                                                           space2_oat_begin,
-                                                           kImage2OatSize));
+  std::unique_ptr<DummyImageSpace> space2(CreateImageSpace(kImage2Size,
+                                                           kImage2OatSize,
+                                                           &image_reservation,
+                                                           &reservation));
   ASSERT_TRUE(space2 != nullptr);
+  ASSERT_FALSE(image_reservation.IsValid());
+  ASSERT_TRUE(reservation.IsValid());
 
   // Finally put a 3rd image space.
-  std::unique_ptr<DummyImageSpace> space3(CreateImageSpace(space3_begin,
-                                                           kImage3Size,
-                                                           space3_begin + kImage3Size,
-                                                           kImage3OatSize));
+  image_reservation = reservation.TakeReservedMemory(kImage3Size);
+  ASSERT_TRUE(image_reservation.IsValid());
+  ASSERT_TRUE(reservation.IsValid());
+  std::unique_ptr<DummyImageSpace> space3(CreateImageSpace(kImage3Size,
+                                                           kImage3OatSize,
+                                                           &image_reservation,
+                                                           &reservation));
   ASSERT_TRUE(space3 != nullptr);
+  ASSERT_FALSE(image_reservation.IsValid());
+  ASSERT_FALSE(reservation.IsValid());
 
   // Check that we do not include the oat if there is no space after.
   ImmuneSpaces spaces;
@@ -323,12 +328,29 @@
   constexpr size_t kGuardSize = kPageSize;
   constexpr size_t kImage4Size = kImageBytes - kPageSize;
   constexpr size_t kImage4OatSize = kPageSize;
-  uint8_t* memory2 = GetContinuousMemoryRegion(kImage4Size + kImage4OatSize + kGuardSize * 2);
-  std::unique_ptr<DummyImageSpace> space4(CreateImageSpace(memory2 + kGuardSize,
-                                                           kImage4Size,
-                                                           memory2 + kGuardSize + kImage4Size,
-                                                           kImage4OatSize));
+
+  reservation = MemMap::MapAnonymous("reserve",
+                                     kImage4Size + kImage4OatSize + kGuardSize * 2,
+                                     PROT_READ | PROT_WRITE,
+                                     /*low_4gb=*/ true,
+                                     &error_str);
+  ASSERT_TRUE(reservation.IsValid()) << "Failed to allocate memory region " << error_str;
+  MemMap guard = reservation.TakeReservedMemory(kGuardSize);
+  ASSERT_TRUE(guard.IsValid());
+  ASSERT_TRUE(reservation.IsValid());
+  guard.Reset();  // Release the guard memory.
+  image_reservation = reservation.TakeReservedMemory(kImage4Size);
+  ASSERT_TRUE(image_reservation.IsValid());
+  ASSERT_TRUE(reservation.IsValid());
+  std::unique_ptr<DummyImageSpace> space4(CreateImageSpace(kImage4Size,
+                                                           kImage4OatSize,
+                                                           &image_reservation,
+                                                           &reservation));
   ASSERT_TRUE(space4 != nullptr);
+  ASSERT_FALSE(image_reservation.IsValid());
+  ASSERT_TRUE(reservation.IsValid());
+  ASSERT_EQ(reservation.Size(), kGuardSize);
+  reservation.Reset();  // Release the guard memory.
   {
     WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
     LOG(INFO) << "Adding space4 " << reinterpret_cast<const void*>(space4->Begin());
@@ -346,12 +368,28 @@
   // Layout:  [guard page][image][oat][guard page]
   constexpr size_t kImage5Size = kImageBytes + kPageSize;
   constexpr size_t kImage5OatSize = kPageSize;
-  uint8_t* memory3 = GetContinuousMemoryRegion(kImage5Size + kImage5OatSize + kGuardSize * 2);
-  std::unique_ptr<DummyImageSpace> space5(CreateImageSpace(memory3 + kGuardSize,
-                                                           kImage5Size,
-                                                           memory3 + kGuardSize + kImage5Size,
-                                                           kImage5OatSize));
+  reservation = MemMap::MapAnonymous("reserve",
+                                     kImage5Size + kImage5OatSize + kGuardSize * 2,
+                                     PROT_READ | PROT_WRITE,
+                                     /*low_4gb=*/ true,
+                                     &error_str);
+  ASSERT_TRUE(reservation.IsValid()) << "Failed to allocate memory region " << error_str;
+  guard = reservation.TakeReservedMemory(kGuardSize);
+  ASSERT_TRUE(guard.IsValid());
+  ASSERT_TRUE(reservation.IsValid());
+  guard.Reset();  // Release the guard memory.
+  image_reservation = reservation.TakeReservedMemory(kImage5Size);
+  ASSERT_TRUE(image_reservation.IsValid());
+  ASSERT_TRUE(reservation.IsValid());
+  std::unique_ptr<DummyImageSpace> space5(CreateImageSpace(kImage5Size,
+                                                           kImage5OatSize,
+                                                           &image_reservation,
+                                                           &reservation));
   ASSERT_TRUE(space5 != nullptr);
+  ASSERT_FALSE(image_reservation.IsValid());
+  ASSERT_TRUE(reservation.IsValid());
+  ASSERT_EQ(reservation.Size(), kGuardSize);
+  reservation.Reset();  // Release the guard memory.
   {
     WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
     LOG(INFO) << "Adding space5 " << reinterpret_cast<const void*>(space5->Begin());
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index 399f9ff..9e5cb9c 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -105,10 +105,9 @@
   std::string error_msg;
   sweep_array_free_buffer_mem_map_ = MemMap::MapAnonymous(
       "mark sweep sweep array free buffer",
-      /* addr= */ nullptr,
       RoundUp(kSweepArrayChunkFreeSize * sizeof(mirror::Object*), kPageSize),
       PROT_READ | PROT_WRITE,
-      /* low_4gb= */ false,
+      /*low_4gb=*/ false,
       &error_msg);
   CHECK(sweep_array_free_buffer_mem_map_.IsValid())
       << "Couldn't allocate sweep array free buffer: " << error_msg;
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index a31cbe7..467b22c 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -505,11 +505,11 @@
       // Create bump pointer spaces instead of a backup space.
       main_mem_map_2.Reset();
       bump_pointer_space_ = space::BumpPointerSpace::Create(
-          "Bump pointer space 1", kGSSBumpPointerSpaceCapacity, /* requested_begin= */ nullptr);
+          "Bump pointer space 1", kGSSBumpPointerSpaceCapacity);
       CHECK(bump_pointer_space_ != nullptr);
       AddSpace(bump_pointer_space_);
       temp_space_ = space::BumpPointerSpace::Create(
-          "Bump pointer space 2", kGSSBumpPointerSpaceCapacity, /* requested_begin= */ nullptr);
+          "Bump pointer space 2", kGSSBumpPointerSpaceCapacity);
       CHECK(temp_space_ != nullptr);
       AddSpace(temp_space_);
     } else if (main_mem_map_2.IsValid()) {
@@ -529,8 +529,7 @@
   CHECK(!non_moving_space_->CanMoveObjects());
   // Allocate the large object space.
   if (large_object_space_type == space::LargeObjectSpaceType::kFreeList) {
-    large_object_space_ = space::FreeListSpace::Create("free list large object space", nullptr,
-                                                       capacity_);
+    large_object_space_ = space::FreeListSpace::Create("free list large object space", capacity_);
     CHECK(large_object_space_ != nullptr) << "Failed to create large object space";
   } else if (large_object_space_type == space::LargeObjectSpaceType::kMap) {
     large_object_space_ = space::LargeObjectMapSpace::Create("mem map large object space");
@@ -696,7 +695,9 @@
                                       request_begin,
                                       capacity,
                                       PROT_READ | PROT_WRITE,
-                                      /* low_4gb=*/ true,
+                                      /*low_4gb=*/ true,
+                                      /*reuse=*/ false,
+                                      /*reservation=*/ nullptr,
                                       out_error_str);
     if (map.IsValid() || request_begin == nullptr) {
       return map;
diff --git a/runtime/gc/heap_test.cc b/runtime/gc/heap_test.cc
index f6db070..fa10150 100644
--- a/runtime/gc/heap_test.cc
+++ b/runtime/gc/heap_test.cc
@@ -39,6 +39,8 @@
                                      16 * KB,
                                      PROT_READ,
                                      /*low_4gb=*/ true,
+                                     /*reuse=*/ false,
+                                     /*reservation=*/ nullptr,
                                      &error_msg);
     ASSERT_TRUE(reserved_.IsValid()) << error_msg;
     CommonRuntimeTest::SetUp();
diff --git a/runtime/gc/space/bump_pointer_space.cc b/runtime/gc/space/bump_pointer_space.cc
index 497a0c2..609ccee 100644
--- a/runtime/gc/space/bump_pointer_space.cc
+++ b/runtime/gc/space/bump_pointer_space.cc
@@ -24,15 +24,13 @@
 namespace gc {
 namespace space {
 
-BumpPointerSpace* BumpPointerSpace::Create(const std::string& name, size_t capacity,
-                                           uint8_t* requested_begin) {
+BumpPointerSpace* BumpPointerSpace::Create(const std::string& name, size_t capacity) {
   capacity = RoundUp(capacity, kPageSize);
   std::string error_msg;
   MemMap mem_map = MemMap::MapAnonymous(name.c_str(),
-                                        requested_begin,
                                         capacity,
                                         PROT_READ | PROT_WRITE,
-                                        /* low_4gb= */ true,
+                                        /*low_4gb=*/ true,
                                         &error_msg);
   if (!mem_map.IsValid()) {
     LOG(ERROR) << "Failed to allocate pages for alloc space (" << name << ") of size "
diff --git a/runtime/gc/space/bump_pointer_space.h b/runtime/gc/space/bump_pointer_space.h
index 59d4d27..383bf7a 100644
--- a/runtime/gc/space/bump_pointer_space.h
+++ b/runtime/gc/space/bump_pointer_space.h
@@ -46,7 +46,7 @@
   // Create a bump pointer space with the requested sizes. The requested base address is not
   // guaranteed to be granted, if it is required, the caller should call Begin on the returned
   // space to confirm the request was granted.
-  static BumpPointerSpace* Create(const std::string& name, size_t capacity, uint8_t* requested_begin);
+  static BumpPointerSpace* Create(const std::string& name, size_t capacity);
   static BumpPointerSpace* CreateFromMemMap(const std::string& name, MemMap&& mem_map);
 
   // Allocate num_bytes, returns null if the space is full.
diff --git a/runtime/gc/space/dlmalloc_space.cc b/runtime/gc/space/dlmalloc_space.cc
index 73582a0..7955ff9 100644
--- a/runtime/gc/space/dlmalloc_space.cc
+++ b/runtime/gc/space/dlmalloc_space.cc
@@ -108,8 +108,10 @@
   }
 }
 
-DlMallocSpace* DlMallocSpace::Create(const std::string& name, size_t initial_size,
-                                     size_t growth_limit, size_t capacity, uint8_t* requested_begin,
+DlMallocSpace* DlMallocSpace::Create(const std::string& name,
+                                     size_t initial_size,
+                                     size_t growth_limit,
+                                     size_t capacity,
                                      bool can_move_objects) {
   uint64_t start_time = 0;
   if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
@@ -117,8 +119,7 @@
     LOG(INFO) << "DlMallocSpace::Create entering " << name
         << " initial_size=" << PrettySize(initial_size)
         << " growth_limit=" << PrettySize(growth_limit)
-        << " capacity=" << PrettySize(capacity)
-        << " requested_begin=" << reinterpret_cast<void*>(requested_begin);
+        << " capacity=" << PrettySize(capacity);
   }
 
   // Memory we promise to dlmalloc before it asks for morecore.
@@ -126,8 +127,7 @@
   // will ask for this memory from sys_alloc which will fail as the footprint (this value plus the
   // size of the large allocation) will be greater than the footprint limit.
   size_t starting_size = kPageSize;
-  MemMap mem_map =
-      CreateMemMap(name, starting_size, &initial_size, &growth_limit, &capacity, requested_begin);
+  MemMap mem_map = CreateMemMap(name, starting_size, &initial_size, &growth_limit, &capacity);
   if (!mem_map.IsValid()) {
     LOG(ERROR) << "Failed to create mem map for alloc space (" << name << ") of size "
                << PrettySize(capacity);
diff --git a/runtime/gc/space/dlmalloc_space.h b/runtime/gc/space/dlmalloc_space.h
index c63ff71..e91602f 100644
--- a/runtime/gc/space/dlmalloc_space.h
+++ b/runtime/gc/space/dlmalloc_space.h
@@ -46,8 +46,11 @@
   // base address is not guaranteed to be granted, if it is required,
   // the caller should call Begin on the returned space to confirm the
   // request was granted.
-  static DlMallocSpace* Create(const std::string& name, size_t initial_size, size_t growth_limit,
-                               size_t capacity, uint8_t* requested_begin, bool can_move_objects);
+  static DlMallocSpace* Create(const std::string& name,
+                               size_t initial_size,
+                               size_t growth_limit,
+                               size_t capacity,
+                               bool can_move_objects);
 
   // Virtual to allow MemoryToolMallocSpace to intercept.
   mirror::Object* AllocWithGrowth(Thread* self,
diff --git a/runtime/gc/space/dlmalloc_space_random_test.cc b/runtime/gc/space/dlmalloc_space_random_test.cc
index f9b41da..92b56bd 100644
--- a/runtime/gc/space/dlmalloc_space_random_test.cc
+++ b/runtime/gc/space/dlmalloc_space_random_test.cc
@@ -22,14 +22,16 @@
 namespace gc {
 namespace space {
 
-MallocSpace* CreateDlMallocSpace(const std::string& name, size_t initial_size, size_t growth_limit,
-                                 size_t capacity, uint8_t* requested_begin) {
-  return DlMallocSpace::Create(name, initial_size, growth_limit, capacity, requested_begin, false);
+MallocSpace* CreateDlMallocSpace(const std::string& name,
+                                 size_t initial_size,
+                                 size_t growth_limit,
+                                 size_t capacity) {
+  return DlMallocSpace::Create(
+      name, initial_size, growth_limit, capacity, /*can_move_objects=*/ false);
 }
 
 TEST_SPACE_CREATE_FN_RANDOM(DlMallocSpace, CreateDlMallocSpace)
 
-
 }  // namespace space
 }  // namespace gc
 }  // namespace art
diff --git a/runtime/gc/space/dlmalloc_space_static_test.cc b/runtime/gc/space/dlmalloc_space_static_test.cc
index 5758e0c..550d1bb 100644
--- a/runtime/gc/space/dlmalloc_space_static_test.cc
+++ b/runtime/gc/space/dlmalloc_space_static_test.cc
@@ -22,14 +22,16 @@
 namespace gc {
 namespace space {
 
-MallocSpace* CreateDlMallocSpace(const std::string& name, size_t initial_size, size_t growth_limit,
-                                 size_t capacity, uint8_t* requested_begin) {
-  return DlMallocSpace::Create(name, initial_size, growth_limit, capacity, requested_begin, false);
+MallocSpace* CreateDlMallocSpace(const std::string& name,
+                                 size_t initial_size,
+                                 size_t growth_limit,
+                                 size_t capacity) {
+  return DlMallocSpace::Create(
+      name, initial_size, growth_limit, capacity, /*can_move_objects=*/ false);
 }
 
 TEST_SPACE_CREATE_FN_STATIC(DlMallocSpace, CreateDlMallocSpace)
 
-
 }  // namespace space
 }  // namespace gc
 }  // namespace art
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index db4a48c..96a2cea 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -622,9 +622,9 @@
                               /*inout*/MemMap* image_reservation,
                               /*out*/std::string* error_msg) {
     TimingLogger::ScopedTiming timing("MapImageFile", logger);
-    uint8_t* address = (image_reservation != nullptr) ? image_reservation->Begin() : nullptr;
     const ImageHeader::StorageMode storage_mode = image_header.GetStorageMode();
     if (storage_mode == ImageHeader::kStorageModeUncompressed) {
+      uint8_t* address = (image_reservation != nullptr) ? image_reservation->Begin() : nullptr;
       return MemMap::MapFileAtAddress(address,
                                       image_header.GetImageSize(),
                                       PROT_READ | PROT_WRITE,
@@ -649,11 +649,9 @@
 
     // Reserve output and decompress into it.
     MemMap map = MemMap::MapAnonymous(image_location,
-                                      address,
                                       image_header.GetImageSize(),
                                       PROT_READ | PROT_WRITE,
                                       /*low_4gb=*/ true,
-                                      /*reuse=*/ false,
                                       image_reservation,
                                       error_msg);
     if (map.IsValid()) {
diff --git a/runtime/gc/space/large_object_space.cc b/runtime/gc/space/large_object_space.cc
index a7f82f6..1658dba 100644
--- a/runtime/gc/space/large_object_space.cc
+++ b/runtime/gc/space/large_object_space.cc
@@ -137,10 +137,9 @@
                                            size_t* bytes_tl_bulk_allocated) {
   std::string error_msg;
   MemMap mem_map = MemMap::MapAnonymous("large object space allocation",
-                                        /* addr= */ nullptr,
                                         num_bytes,
                                         PROT_READ | PROT_WRITE,
-                                        /* low_4gb= */ true,
+                                        /*low_4gb=*/ true,
                                         &error_msg);
   if (UNLIKELY(!mem_map.IsValid())) {
     LOG(WARNING) << "Large object allocation failed: " << error_msg;
@@ -346,14 +345,13 @@
   return reinterpret_cast<uintptr_t>(a) < reinterpret_cast<uintptr_t>(b);
 }
 
-FreeListSpace* FreeListSpace::Create(const std::string& name, uint8_t* requested_begin, size_t size) {
+FreeListSpace* FreeListSpace::Create(const std::string& name, size_t size) {
   CHECK_EQ(size % kAlignment, 0U);
   std::string error_msg;
   MemMap mem_map = MemMap::MapAnonymous(name.c_str(),
-                                        requested_begin,
                                         size,
                                         PROT_READ | PROT_WRITE,
-                                        /* low_4gb= */ true,
+                                        /*low_4gb=*/ true,
                                         &error_msg);
   CHECK(mem_map.IsValid()) << "Failed to allocate large object space mem map: " << error_msg;
   return new FreeListSpace(name, std::move(mem_map), mem_map.Begin(), mem_map.End());
@@ -372,10 +370,9 @@
   std::string error_msg;
   allocation_info_map_ =
       MemMap::MapAnonymous("large object free list space allocation info map",
-                           /* addr= */ nullptr,
                            alloc_info_size,
                            PROT_READ | PROT_WRITE,
-                           /* low_4gb= */ false,
+                           /*low_4gb=*/ false,
                            &error_msg);
   CHECK(allocation_info_map_.IsValid()) << "Failed to allocate allocation info map" << error_msg;
   allocation_info_ = reinterpret_cast<AllocationInfo*>(allocation_info_map_.Begin());
diff --git a/runtime/gc/space/large_object_space.h b/runtime/gc/space/large_object_space.h
index 47167fa..a4d6a24 100644
--- a/runtime/gc/space/large_object_space.h
+++ b/runtime/gc/space/large_object_space.h
@@ -184,7 +184,7 @@
   static constexpr size_t kAlignment = kPageSize;
 
   virtual ~FreeListSpace();
-  static FreeListSpace* Create(const std::string& name, uint8_t* requested_begin, size_t capacity);
+  static FreeListSpace* Create(const std::string& name, size_t capacity);
   size_t AllocationSize(mirror::Object* obj, size_t* usable_size) override
       REQUIRES(lock_);
   mirror::Object* Alloc(Thread* self, size_t num_bytes, size_t* bytes_allocated,
diff --git a/runtime/gc/space/large_object_space_test.cc b/runtime/gc/space/large_object_space_test.cc
index d55ccd6..62bc26e 100644
--- a/runtime/gc/space/large_object_space_test.cc
+++ b/runtime/gc/space/large_object_space_test.cc
@@ -42,7 +42,7 @@
     if (i == 0) {
       los = space::LargeObjectMapSpace::Create("large object space");
     } else {
-      los = space::FreeListSpace::Create("large object space", nullptr, capacity);
+      los = space::FreeListSpace::Create("large object space", capacity);
     }
 
     // Make sure the bitmap is not empty and actually covers at least how much we expect.
@@ -157,7 +157,7 @@
     if (los_type == 0) {
       los = space::LargeObjectMapSpace::Create("large object space");
     } else {
-      los = space::FreeListSpace::Create("large object space", nullptr, 128 * MB);
+      los = space::FreeListSpace::Create("large object space", 128 * MB);
     }
 
     Thread* self = Thread::Current();
diff --git a/runtime/gc/space/malloc_space.cc b/runtime/gc/space/malloc_space.cc
index 189aeb5..b5e6b62 100644
--- a/runtime/gc/space/malloc_space.cc
+++ b/runtime/gc/space/malloc_space.cc
@@ -82,8 +82,7 @@
                                  size_t starting_size,
                                  size_t* initial_size,
                                  size_t* growth_limit,
-                                 size_t* capacity,
-                                 uint8_t* requested_begin) {
+                                 size_t* capacity) {
   // Sanity check arguments
   if (starting_size > *initial_size) {
     *initial_size = starting_size;
@@ -107,10 +106,9 @@
 
   std::string error_msg;
   MemMap mem_map = MemMap::MapAnonymous(name.c_str(),
-                                        requested_begin,
                                         *capacity,
                                         PROT_READ | PROT_WRITE,
-                                        /* low_4gb= */ true,
+                                        /*low_4gb=*/ true,
                                         &error_msg);
   if (!mem_map.IsValid()) {
     LOG(ERROR) << "Failed to allocate pages for alloc space (" << name << ") of size "
diff --git a/runtime/gc/space/malloc_space.h b/runtime/gc/space/malloc_space.h
index 6bf2d71..5dd8136 100644
--- a/runtime/gc/space/malloc_space.h
+++ b/runtime/gc/space/malloc_space.h
@@ -157,8 +157,7 @@
                              size_t starting_size,
                              size_t* initial_size,
                              size_t* growth_limit,
-                             size_t* capacity,
-                             uint8_t* requested_begin);
+                             size_t* capacity);
 
   // When true the low memory mode argument specifies that the heap wishes the created allocator to
   // be more aggressive in releasing unused pages.
diff --git a/runtime/gc/space/region_space.cc b/runtime/gc/space/region_space.cc
index 31bbfb8..2774e26 100644
--- a/runtime/gc/space/region_space.cc
+++ b/runtime/gc/space/region_space.cc
@@ -58,7 +58,9 @@
                                    requested_begin,
                                    capacity + kRegionSize,
                                    PROT_READ | PROT_WRITE,
-                                   /* low_4gb= */ true,
+                                   /*low_4gb=*/ true,
+                                   /*reuse=*/ false,
+                                   /*reservation=*/ nullptr,
                                    &error_msg);
     if (mem_map.IsValid() || requested_begin == nullptr) {
       break;
diff --git a/runtime/gc/space/rosalloc_space.cc b/runtime/gc/space/rosalloc_space.cc
index 10ff1c1..36fd864 100644
--- a/runtime/gc/space/rosalloc_space.cc
+++ b/runtime/gc/space/rosalloc_space.cc
@@ -133,17 +133,19 @@
   delete rosalloc_;
 }
 
-RosAllocSpace* RosAllocSpace::Create(const std::string& name, size_t initial_size,
-                                     size_t growth_limit, size_t capacity, uint8_t* requested_begin,
-                                     bool low_memory_mode, bool can_move_objects) {
+RosAllocSpace* RosAllocSpace::Create(const std::string& name,
+                                     size_t initial_size,
+                                     size_t growth_limit,
+                                     size_t capacity,
+                                     bool low_memory_mode,
+                                     bool can_move_objects) {
   uint64_t start_time = 0;
   if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
     start_time = NanoTime();
     VLOG(startup) << "RosAllocSpace::Create entering " << name
                   << " initial_size=" << PrettySize(initial_size)
                   << " growth_limit=" << PrettySize(growth_limit)
-                  << " capacity=" << PrettySize(capacity)
-                  << " requested_begin=" << reinterpret_cast<void*>(requested_begin);
+                  << " capacity=" << PrettySize(capacity);
   }
 
   // Memory we promise to rosalloc before it asks for morecore.
@@ -151,8 +153,7 @@
   // will ask for this memory from sys_alloc which will fail as the footprint (this value plus the
   // size of the large allocation) will be greater than the footprint limit.
   size_t starting_size = Heap::kDefaultStartingSize;
-  MemMap mem_map =
-      CreateMemMap(name, starting_size, &initial_size, &growth_limit, &capacity, requested_begin);
+  MemMap mem_map = CreateMemMap(name, starting_size, &initial_size, &growth_limit, &capacity);
   if (!mem_map.IsValid()) {
     LOG(ERROR) << "Failed to create mem map for alloc space (" << name << ") of size "
                << PrettySize(capacity);
diff --git a/runtime/gc/space/rosalloc_space.h b/runtime/gc/space/rosalloc_space.h
index 5162a06..9e95c16 100644
--- a/runtime/gc/space/rosalloc_space.h
+++ b/runtime/gc/space/rosalloc_space.h
@@ -38,8 +38,11 @@
   // base address is not guaranteed to be granted, if it is required,
   // the caller should call Begin on the returned space to confirm the
   // request was granted.
-  static RosAllocSpace* Create(const std::string& name, size_t initial_size, size_t growth_limit,
-                               size_t capacity, uint8_t* requested_begin, bool low_memory_mode,
+  static RosAllocSpace* Create(const std::string& name,
+                               size_t initial_size,
+                               size_t growth_limit,
+                               size_t capacity,
+                               bool low_memory_mode,
                                bool can_move_objects);
   static RosAllocSpace* CreateFromMemMap(MemMap&& mem_map,
                                          const std::string& name,
diff --git a/runtime/gc/space/rosalloc_space_random_test.cc b/runtime/gc/space/rosalloc_space_random_test.cc
index b50859b..f0b3231 100644
--- a/runtime/gc/space/rosalloc_space_random_test.cc
+++ b/runtime/gc/space/rosalloc_space_random_test.cc
@@ -22,15 +22,20 @@
 namespace gc {
 namespace space {
 
-MallocSpace* CreateRosAllocSpace(const std::string& name, size_t initial_size, size_t growth_limit,
-                                 size_t capacity, uint8_t* requested_begin) {
-  return RosAllocSpace::Create(name, initial_size, growth_limit, capacity, requested_begin,
-                               Runtime::Current()->GetHeap()->IsLowMemoryMode(), false);
+MallocSpace* CreateRosAllocSpace(const std::string& name,
+                                 size_t initial_size,
+                                 size_t growth_limit,
+                                 size_t capacity) {
+  return RosAllocSpace::Create(name,
+                               initial_size,
+                               growth_limit,
+                               capacity,
+                               Runtime::Current()->GetHeap()->IsLowMemoryMode(),
+                               /*can_move_objects=*/ false);
 }
 
 TEST_SPACE_CREATE_FN_RANDOM(RosAllocSpace, CreateRosAllocSpace)
 
-
 }  // namespace space
 }  // namespace gc
 }  // namespace art
diff --git a/runtime/gc/space/rosalloc_space_static_test.cc b/runtime/gc/space/rosalloc_space_static_test.cc
index 5e7ced6..d7e7e90 100644
--- a/runtime/gc/space/rosalloc_space_static_test.cc
+++ b/runtime/gc/space/rosalloc_space_static_test.cc
@@ -22,15 +22,19 @@
 namespace gc {
 namespace space {
 
-MallocSpace* CreateRosAllocSpace(const std::string& name, size_t initial_size, size_t growth_limit,
-                                 size_t capacity, uint8_t* requested_begin) {
-  return RosAllocSpace::Create(name, initial_size, growth_limit, capacity, requested_begin,
-                               Runtime::Current()->GetHeap()->IsLowMemoryMode(), false);
+MallocSpace* CreateRosAllocSpace(const std::string& name,
+                                 size_t initial_size,
+                                 size_t growth_limit,
+                                 size_t capacity) {
+  return RosAllocSpace::Create(name, initial_size,
+                               growth_limit,
+                               capacity,
+                               Runtime::Current()->GetHeap()->IsLowMemoryMode(),
+                               /*can_move_objects=*/ false);
 }
 
 TEST_SPACE_CREATE_FN_STATIC(RosAllocSpace, CreateRosAllocSpace)
 
-
 }  // namespace space
 }  // namespace gc
 }  // namespace art
diff --git a/runtime/gc/space/space_create_test.cc b/runtime/gc/space/space_create_test.cc
index ca5f306..d3db679 100644
--- a/runtime/gc/space/space_create_test.cc
+++ b/runtime/gc/space/space_create_test.cc
@@ -34,25 +34,22 @@
   MallocSpace* CreateSpace(const std::string& name,
                            size_t initial_size,
                            size_t growth_limit,
-                           size_t capacity,
-                           uint8_t* requested_begin) {
+                           size_t capacity) {
     const MallocSpaceType type = GetParam();
     if (type == kMallocSpaceDlMalloc) {
       return DlMallocSpace::Create(name,
                                    initial_size,
                                    growth_limit,
                                    capacity,
-                                   requested_begin,
-                                   false);
+                                   /*can_move_objects=*/ false);
     }
     DCHECK_EQ(static_cast<uint32_t>(type), static_cast<uint32_t>(kMallocSpaceRosAlloc));
     return RosAllocSpace::Create(name,
                                  initial_size,
                                  growth_limit,
                                  capacity,
-                                 requested_begin,
                                  Runtime::Current()->GetHeap()->IsLowMemoryMode(),
-                                 false);
+                                 /*can_move_objects=*/ false);
   }
 };
 
@@ -62,25 +59,25 @@
 
   {
     // Init < max == growth
-    std::unique_ptr<Space> space(CreateSpace("test", 16 * MB, 32 * MB, 32 * MB, nullptr));
+    std::unique_ptr<Space> space(CreateSpace("test", 16 * MB, 32 * MB, 32 * MB));
     EXPECT_TRUE(space != nullptr);
     // Init == max == growth
-    space.reset(CreateSpace("test", 16 * MB, 16 * MB, 16 * MB, nullptr));
+    space.reset(CreateSpace("test", 16 * MB, 16 * MB, 16 * MB));
     EXPECT_TRUE(space != nullptr);
     // Init > max == growth
-    space.reset(CreateSpace("test", 32 * MB, 16 * MB, 16 * MB, nullptr));
+    space.reset(CreateSpace("test", 32 * MB, 16 * MB, 16 * MB));
     EXPECT_TRUE(space == nullptr);
     // Growth == init < max
-    space.reset(CreateSpace("test", 16 * MB, 16 * MB, 32 * MB, nullptr));
+    space.reset(CreateSpace("test", 16 * MB, 16 * MB, 32 * MB));
     EXPECT_TRUE(space != nullptr);
     // Growth < init < max
-    space.reset(CreateSpace("test", 16 * MB, 8 * MB, 32 * MB, nullptr));
+    space.reset(CreateSpace("test", 16 * MB, 8 * MB, 32 * MB));
     EXPECT_TRUE(space == nullptr);
     // Init < growth < max
-    space.reset(CreateSpace("test", 8 * MB, 16 * MB, 32 * MB, nullptr));
+    space.reset(CreateSpace("test", 8 * MB, 16 * MB, 32 * MB));
     EXPECT_TRUE(space != nullptr);
     // Init < max < growth
-    space.reset(CreateSpace("test", 8 * MB, 32 * MB, 16 * MB, nullptr));
+    space.reset(CreateSpace("test", 8 * MB, 32 * MB, 16 * MB));
     EXPECT_TRUE(space == nullptr);
   }
 }
@@ -91,7 +88,7 @@
 // the GC works with the ZygoteSpace.
 TEST_P(SpaceCreateTest, ZygoteSpaceTestBody) {
   size_t dummy;
-  MallocSpace* space(CreateSpace("test", 4 * MB, 16 * MB, 16 * MB, nullptr));
+  MallocSpace* space(CreateSpace("test", 4 * MB, 16 * MB, 16 * MB));
   ASSERT_TRUE(space != nullptr);
 
   // Make space findable to the heap, will also delete space when runtime is cleaned up
@@ -225,7 +222,7 @@
 
 TEST_P(SpaceCreateTest, AllocAndFreeTestBody) {
   size_t dummy = 0;
-  MallocSpace* space(CreateSpace("test", 4 * MB, 16 * MB, 16 * MB, nullptr));
+  MallocSpace* space(CreateSpace("test", 4 * MB, 16 * MB, 16 * MB));
   ASSERT_TRUE(space != nullptr);
   Thread* self = Thread::Current();
   ScopedObjectAccess soa(self);
@@ -301,7 +298,7 @@
 }
 
 TEST_P(SpaceCreateTest, AllocAndFreeListTestBody) {
-  MallocSpace* space(CreateSpace("test", 4 * MB, 16 * MB, 16 * MB, nullptr));
+  MallocSpace* space(CreateSpace("test", 4 * MB, 16 * MB, 16 * MB));
   ASSERT_TRUE(space != nullptr);
 
   // Make space findable to the heap, will also delete space when runtime is cleaned up
diff --git a/runtime/gc/space/space_test.h b/runtime/gc/space/space_test.h
index 5aac217..1b111e3 100644
--- a/runtime/gc/space/space_test.h
+++ b/runtime/gc/space/space_test.h
@@ -123,8 +123,10 @@
     return mirror::Array::DataOffset(Primitive::ComponentSize(Primitive::kPrimByte)).Uint32Value();
   }
 
-  typedef MallocSpace* (*CreateSpaceFn)(const std::string& name, size_t initial_size, size_t growth_limit,
-                                        size_t capacity, uint8_t* requested_begin);
+  typedef MallocSpace* (*CreateSpaceFn)(const std::string& name,
+                                        size_t initial_size,
+                                        size_t growth_limit,
+                                        size_t capacity);
 
   void SizeFootPrintGrowthLimitAndTrimBody(MallocSpace* space, intptr_t object_size,
                                            int round, size_t growth_limit);
@@ -323,7 +325,7 @@
   size_t initial_size = 4 * MB;
   size_t growth_limit = 8 * MB;
   size_t capacity = 16 * MB;
-  MallocSpace* space(create_space("test", initial_size, growth_limit, capacity, nullptr));
+  MallocSpace* space(create_space("test", initial_size, growth_limit, capacity));
   ASSERT_TRUE(space != nullptr);
 
   // Basic sanity
diff --git a/runtime/hidden_api.cc b/runtime/hidden_api.cc
index 5729800..f355276 100644
--- a/runtime/hidden_api.cc
+++ b/runtime/hidden_api.cc
@@ -60,14 +60,14 @@
   return os;
 }
 
-static constexpr bool EnumsEqual(EnforcementPolicy policy, HiddenApiAccessFlags::ApiList apiList) {
+static constexpr bool EnumsEqual(EnforcementPolicy policy, hiddenapi::ApiList apiList) {
   return static_cast<int>(policy) == static_cast<int>(apiList);
 }
 
 // GetMemberAction-related static_asserts.
 static_assert(
-    EnumsEqual(EnforcementPolicy::kDarkGreyAndBlackList, HiddenApiAccessFlags::kDarkGreylist) &&
-    EnumsEqual(EnforcementPolicy::kBlacklistOnly, HiddenApiAccessFlags::kBlacklist),
+    EnumsEqual(EnforcementPolicy::kDarkGreyAndBlackList, hiddenapi::ApiList::kDarkGreylist) &&
+    EnumsEqual(EnforcementPolicy::kBlacklistOnly, hiddenapi::ApiList::kBlacklist),
     "Mismatch between EnforcementPolicy and ApiList enums");
 static_assert(
     EnforcementPolicy::kJustWarn < EnforcementPolicy::kDarkGreyAndBlackList &&
@@ -133,8 +133,7 @@
   }
 }
 
-void MemberSignature::WarnAboutAccess(AccessMethod access_method,
-                                      HiddenApiAccessFlags::ApiList list) {
+void MemberSignature::WarnAboutAccess(AccessMethod access_method, hiddenapi::ApiList list) {
   LOG(WARNING) << "Accessing hidden " << (type_ == kField ? "field " : "method ")
                << Dumpable<MemberSignature>(*this) << " (" << list << ", " << access_method << ")";
 }
@@ -200,14 +199,14 @@
 static ALWAYS_INLINE void MaybeWhitelistMember(Runtime* runtime, T* member)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   if (CanUpdateMemberAccessFlags(member) && runtime->ShouldDedupeHiddenApiWarnings()) {
-    member->SetAccessFlags(HiddenApiAccessFlags::EncodeForRuntime(
-        member->GetAccessFlags(), HiddenApiAccessFlags::kWhitelist));
+    member->SetAccessFlags(hiddenapi::EncodeForRuntime(
+        member->GetAccessFlags(), hiddenapi::ApiList::kWhitelist));
   }
 }
 
 template<typename T>
 Action GetMemberActionImpl(T* member,
-                           HiddenApiAccessFlags::ApiList api_list,
+                           hiddenapi::ApiList api_list,
                            Action action,
                            AccessMethod access_method) {
   DCHECK_NE(action, kAllow);
@@ -276,11 +275,11 @@
 
 // Need to instantiate this.
 template Action GetMemberActionImpl<ArtField>(ArtField* member,
-                                              HiddenApiAccessFlags::ApiList api_list,
+                                              hiddenapi::ApiList api_list,
                                               Action action,
                                               AccessMethod access_method);
 template Action GetMemberActionImpl<ArtMethod>(ArtMethod* member,
-                                               HiddenApiAccessFlags::ApiList api_list,
+                                               hiddenapi::ApiList api_list,
                                                Action action,
                                                AccessMethod access_method);
 }  // namespace detail
diff --git a/runtime/hidden_api.h b/runtime/hidden_api.h
index c16e7f3..57f1a59 100644
--- a/runtime/hidden_api.h
+++ b/runtime/hidden_api.h
@@ -68,8 +68,8 @@
   kAccessDenied  = 1 << 1,
 };
 
-inline Action GetActionFromAccessFlags(HiddenApiAccessFlags::ApiList api_list) {
-  if (api_list == HiddenApiAccessFlags::kWhitelist) {
+inline Action GetActionFromAccessFlags(ApiList api_list) {
+  if (api_list == ApiList::kWhitelist) {
     return kAllow;
   }
 
@@ -85,9 +85,9 @@
   }
   DCHECK(policy >= EnforcementPolicy::kDarkGreyAndBlackList);
   // The logic below relies on equality of values in the enums EnforcementPolicy and
-  // HiddenApiAccessFlags::ApiList, and their ordering. Assertions are in hidden_api.cc.
+  // ApiList, and their ordering. Assertions are in hidden_api.cc.
   if (static_cast<int>(policy) > static_cast<int>(api_list)) {
-    return api_list == HiddenApiAccessFlags::kDarkGreylist
+    return api_list == ApiList::kDarkGreylist
         ? kAllowButWarnAndToast
         : kAllowButWarn;
   } else {
@@ -144,14 +144,14 @@
 
   bool IsExempted(const std::vector<std::string>& exemptions);
 
-  void WarnAboutAccess(AccessMethod access_method, HiddenApiAccessFlags::ApiList list);
+  void WarnAboutAccess(AccessMethod access_method, ApiList list);
 
   void LogAccessToEventLog(AccessMethod access_method, Action action_taken);
 };
 
 template<typename T>
 Action GetMemberActionImpl(T* member,
-                           HiddenApiAccessFlags::ApiList api_list,
+                           ApiList api_list,
                            Action action,
                            AccessMethod access_method)
     REQUIRES_SHARED(Locks::mutator_lock_);
@@ -208,7 +208,7 @@
   // cannot change Java semantics. We should, however, decode the access flags
   // once and use it throughout this function, otherwise we may get inconsistent
   // results, e.g. print whitelist warnings (b/78327881).
-  HiddenApiAccessFlags::ApiList api_list = member->GetHiddenApiAccessFlags();
+  ApiList api_list = member->GetHiddenApiAccessFlags();
 
   Action action = GetActionFromAccessFlags(member->GetHiddenApiAccessFlags());
   if (action == kAllow) {
diff --git a/runtime/hidden_api_test.cc b/runtime/hidden_api_test.cc
index 4c7efe6..1727af0 100644
--- a/runtime/hidden_api_test.cc
+++ b/runtime/hidden_api_test.cc
@@ -89,39 +89,39 @@
 
 TEST_F(HiddenApiTest, CheckGetActionFromRuntimeFlags) {
   runtime_->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kNoChecks);
-  ASSERT_EQ(GetActionFromAccessFlags(HiddenApiAccessFlags::kWhitelist), hiddenapi::kAllow);
-  ASSERT_EQ(GetActionFromAccessFlags(HiddenApiAccessFlags::kLightGreylist), hiddenapi::kAllow);
-  ASSERT_EQ(GetActionFromAccessFlags(HiddenApiAccessFlags::kDarkGreylist), hiddenapi::kAllow);
-  ASSERT_EQ(GetActionFromAccessFlags(HiddenApiAccessFlags::kBlacklist), hiddenapi::kAllow);
+  ASSERT_EQ(GetActionFromAccessFlags(hiddenapi::ApiList::kWhitelist), hiddenapi::kAllow);
+  ASSERT_EQ(GetActionFromAccessFlags(hiddenapi::ApiList::kLightGreylist), hiddenapi::kAllow);
+  ASSERT_EQ(GetActionFromAccessFlags(hiddenapi::ApiList::kDarkGreylist), hiddenapi::kAllow);
+  ASSERT_EQ(GetActionFromAccessFlags(hiddenapi::ApiList::kBlacklist), hiddenapi::kAllow);
 
   runtime_->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kJustWarn);
-  ASSERT_EQ(GetActionFromAccessFlags(HiddenApiAccessFlags::kWhitelist),
+  ASSERT_EQ(GetActionFromAccessFlags(hiddenapi::ApiList::kWhitelist),
             hiddenapi::kAllow);
-  ASSERT_EQ(GetActionFromAccessFlags(HiddenApiAccessFlags::kLightGreylist),
+  ASSERT_EQ(GetActionFromAccessFlags(hiddenapi::ApiList::kLightGreylist),
             hiddenapi::kAllowButWarn);
-  ASSERT_EQ(GetActionFromAccessFlags(HiddenApiAccessFlags::kDarkGreylist),
+  ASSERT_EQ(GetActionFromAccessFlags(hiddenapi::ApiList::kDarkGreylist),
             hiddenapi::kAllowButWarn);
-  ASSERT_EQ(GetActionFromAccessFlags(HiddenApiAccessFlags::kBlacklist),
+  ASSERT_EQ(GetActionFromAccessFlags(hiddenapi::ApiList::kBlacklist),
             hiddenapi::kAllowButWarn);
 
   runtime_->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kDarkGreyAndBlackList);
-  ASSERT_EQ(GetActionFromAccessFlags(HiddenApiAccessFlags::kWhitelist),
+  ASSERT_EQ(GetActionFromAccessFlags(hiddenapi::ApiList::kWhitelist),
             hiddenapi::kAllow);
-  ASSERT_EQ(GetActionFromAccessFlags(HiddenApiAccessFlags::kLightGreylist),
+  ASSERT_EQ(GetActionFromAccessFlags(hiddenapi::ApiList::kLightGreylist),
             hiddenapi::kAllowButWarn);
-  ASSERT_EQ(GetActionFromAccessFlags(HiddenApiAccessFlags::kDarkGreylist),
+  ASSERT_EQ(GetActionFromAccessFlags(hiddenapi::ApiList::kDarkGreylist),
             hiddenapi::kDeny);
-  ASSERT_EQ(GetActionFromAccessFlags(HiddenApiAccessFlags::kBlacklist),
+  ASSERT_EQ(GetActionFromAccessFlags(hiddenapi::ApiList::kBlacklist),
             hiddenapi::kDeny);
 
   runtime_->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kBlacklistOnly);
-  ASSERT_EQ(GetActionFromAccessFlags(HiddenApiAccessFlags::kWhitelist),
+  ASSERT_EQ(GetActionFromAccessFlags(hiddenapi::ApiList::kWhitelist),
             hiddenapi::kAllow);
-  ASSERT_EQ(GetActionFromAccessFlags(HiddenApiAccessFlags::kLightGreylist),
+  ASSERT_EQ(GetActionFromAccessFlags(hiddenapi::ApiList::kLightGreylist),
             hiddenapi::kAllowButWarn);
-  ASSERT_EQ(GetActionFromAccessFlags(HiddenApiAccessFlags::kDarkGreylist),
+  ASSERT_EQ(GetActionFromAccessFlags(hiddenapi::ApiList::kDarkGreylist),
             hiddenapi::kAllowButWarnAndToast);
-  ASSERT_EQ(GetActionFromAccessFlags(HiddenApiAccessFlags::kBlacklist),
+  ASSERT_EQ(GetActionFromAccessFlags(hiddenapi::ApiList::kBlacklist),
             hiddenapi::kDeny);
 }
 
diff --git a/runtime/indirect_reference_table.cc b/runtime/indirect_reference_table.cc
index 6db4790..361dccb 100644
--- a/runtime/indirect_reference_table.cc
+++ b/runtime/indirect_reference_table.cc
@@ -80,10 +80,9 @@
 
   const size_t table_bytes = max_count * sizeof(IrtEntry);
   table_mem_map_ = MemMap::MapAnonymous("indirect ref table",
-                                        /* addr= */ nullptr,
                                         table_bytes,
                                         PROT_READ | PROT_WRITE,
-                                        /* low_4gb= */ false,
+                                        /*low_4gb=*/ false,
                                         error_msg);
   if (!table_mem_map_.IsValid() && error_msg->empty()) {
     *error_msg = "Unable to map memory for indirect ref table";
@@ -223,10 +222,9 @@
 
   const size_t table_bytes = new_size * sizeof(IrtEntry);
   MemMap new_map = MemMap::MapAnonymous("indirect ref table",
-                                        /* addr= */ nullptr,
                                         table_bytes,
                                         PROT_READ | PROT_WRITE,
-                                        /* low_4gb= */ false,
+                                        /*low_4gb=*/ false,
                                         error_msg);
   if (!new_map.IsValid()) {
     return false;
diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h
index b3fae25..3bd4fb5 100644
--- a/runtime/instrumentation.h
+++ b/runtime/instrumentation.h
@@ -384,15 +384,6 @@
         have_exception_handled_listeners_;
   }
 
-  // Any instrumentation *other* than what is needed for Jit profiling active?
-  bool NonJitProfilingActive() const REQUIRES_SHARED(Locks::mutator_lock_) {
-    return have_dex_pc_listeners_ || have_method_exit_listeners_ ||
-        have_field_read_listeners_ || have_field_write_listeners_ ||
-        have_exception_thrown_listeners_ || have_method_unwind_listeners_ ||
-        have_branch_listeners_ || have_watched_frame_pop_listeners_ ||
-        have_exception_handled_listeners_;
-  }
-
   // Inform listeners that a method has been entered. A dex PC is provided as we may install
   // listeners into executing code and get method enter events for methods already on the stack.
   void MethodEnterEvent(Thread* thread, mirror::Object* this_object,
diff --git a/runtime/intern_table.cc b/runtime/intern_table.cc
index 6fbfbdd..2449121 100644
--- a/runtime/intern_table.cc
+++ b/runtime/intern_table.cc
@@ -23,6 +23,7 @@
 #include "gc/space/image_space.h"
 #include "gc/weak_root_state.h"
 #include "gc_root-inl.h"
+#include "handle_scope-inl.h"
 #include "image-inl.h"
 #include "mirror/dex_cache-inl.h"
 #include "mirror/object-inl.h"
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index b37a278..5784b9b 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -248,6 +248,14 @@
     bool from_deoptimize = false) REQUIRES_SHARED(Locks::mutator_lock_) {
   DCHECK(!shadow_frame.GetMethod()->IsAbstract());
   DCHECK(!shadow_frame.GetMethod()->IsNative());
+
+  // Check that we are using the right interpreter.
+  if (kIsDebugBuild && self->UseMterp() != CanUseMterp()) {
+    // The flag might be currently being updated on all threads. Retry with lock.
+    MutexLock tll_mu(self, *Locks::thread_list_lock_);
+    DCHECK_EQ(self->UseMterp(), CanUseMterp());
+  }
+
   if (LIKELY(!from_deoptimize)) {  // Entering the method, but not via deoptimization.
     if (kIsDebugBuild) {
       CHECK_EQ(shadow_frame.GetDexPC(), 0u);
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 96588c8..9f4403e 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -128,10 +128,8 @@
 static ALWAYS_INLINE bool UseInterpreterToInterpreterFastPath(ArtMethod* method)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   Runtime* runtime = Runtime::Current();
-  if (!runtime->IsStarted()) {
-    return false;
-  }
   const void* quick_code = method->GetEntryPointFromQuickCompiledCode();
+  DCHECK(runtime->IsStarted());
   if (!runtime->GetClassLinker()->IsQuickToInterpreterBridge(quick_code)) {
     return false;
   }
@@ -144,16 +142,11 @@
   if (type == kStatic && !method->GetDeclaringClass()->IsInitialized()) {
     return false;
   }
-  if (runtime->IsActiveTransaction() || runtime->GetInstrumentation()->HasMethodEntryListeners()) {
-    return false;
-  }
+  DCHECK(!runtime->IsActiveTransaction());
   ProfilingInfo* profiling_info = method->GetProfilingInfo(kRuntimePointerSize);
   if ((profiling_info != nullptr) && (profiling_info->GetSavedEntryPoint() != nullptr)) {
     return false;
   }
-  if (runtime->GetJit() != nullptr && runtime->GetJit()->JitAtFirstUse()) {
-    return false;
-  }
   return true;
 }
 
@@ -171,7 +164,9 @@
                                    JValue* result)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   // Make sure to check for async exceptions before anything else.
-  if (UNLIKELY(self->ObserveAsyncException())) {
+  if (is_mterp && self->UseMterp()) {
+    DCHECK(!self->ObserveAsyncException());
+  } else if (UNLIKELY(self->ObserveAsyncException())) {
     return false;
   }
   const uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
@@ -229,7 +224,7 @@
     }
   }
 
-  if (is_mterp && UseInterpreterToInterpreterFastPath<type>(called_method)) {
+  if (is_mterp && self->UseMterp() && UseInterpreterToInterpreterFastPath<type>(called_method)) {
     const uint16_t number_of_inputs =
         (is_range) ? inst->VRegA_3rc(inst_data) : inst->VRegA_35c(inst_data);
     CodeItemDataAccessor accessor(called_method->DexInstructionData());
@@ -242,6 +237,10 @@
       return false;
     }
 
+    if (jit != nullptr) {
+      jit->AddSamples(self, called_method, 1, /* with_backedges */false);
+    }
+
     // Create shadow frame on the stack.
     const char* old_cause = self->StartAssertNoThreadSuspension("DoFastInvoke");
     ShadowFrameAllocaUniquePtr shadow_frame_unique_ptr =
@@ -261,13 +260,9 @@
         *new_shadow_frame->GetShadowRefAddr(dst) = *shadow_frame.GetShadowRefAddr(arg[i]);
       }
     }
+    self->PushShadowFrame(new_shadow_frame);
     self->EndAssertNoThreadSuspension(old_cause);
 
-    if (jit != nullptr) {
-      jit->AddSamples(self, called_method, 1, /* with_backedges */false);
-    }
-
-    self->PushShadowFrame(new_shadow_frame);
     DCheckStaticState(self, called_method);
     while (true) {
       // Mterp does not support all instrumentation/debugging.
diff --git a/runtime/interpreter/interpreter_switch_impl-inl.h b/runtime/interpreter/interpreter_switch_impl-inl.h
index 4774d69..c430de2 100644
--- a/runtime/interpreter/interpreter_switch_impl-inl.h
+++ b/runtime/interpreter/interpreter_switch_impl-inl.h
@@ -36,7 +36,7 @@
 namespace interpreter {
 
 #define CHECK_FORCE_RETURN()                                                        \
-  do {                                                                              \
+  {                                                                                 \
     if (UNLIKELY(shadow_frame.GetForcePopFrame())) {                                \
       DCHECK(PrevFrameWillRetry(self, shadow_frame))                                \
           << "Pop frame forced without previous frame ready to retry instruction!"; \
@@ -53,10 +53,11 @@
       ctx->result = JValue(); /* Handled in caller. */                              \
       return;                                                                       \
     }                                                                               \
-  } while (false)
+  }                                                                                 \
+  do {} while (false)
 
 #define HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(instr)                                    \
-  do {                                                                                          \
+  {                                                                                             \
     DCHECK(self->IsExceptionPending());                                                         \
     self->AllowThreadSuspension();                                                              \
     CHECK_FORCE_RETURN();                                                                       \
@@ -74,13 +75,15 @@
       int32_t displacement =                                                                    \
           static_cast<int32_t>(shadow_frame.GetDexPC()) - static_cast<int32_t>(dex_pc);         \
       inst = inst->RelativeAt(displacement);                                                    \
+      break;  /* Stop executing this opcode and continue in the exception handler. */           \
     }                                                                                           \
-  } while (false)
+  }                                                                                             \
+  do {} while (false)
 
 #define HANDLE_PENDING_EXCEPTION() HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(instrumentation)
 
 #define POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_IMPL(_is_exception_pending, _next_function) \
-  do {                                                                                          \
+  {                                                                                             \
     if (UNLIKELY(shadow_frame.GetForceRetryInstruction())) {                                    \
       /* Don't need to do anything except clear the flag and exception. We leave the */         \
       /* instruction the same so it will be re-executed on the next go-around.       */         \
@@ -101,7 +104,8 @@
     } else {                                                                                    \
       inst = inst->_next_function();                                                            \
     }                                                                                           \
-  } while (false)
+  }                                                                                             \
+  do {} while (false)
 
 #define POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_POLYMORPHIC(_is_exception_pending) \
   POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_IMPL(_is_exception_pending, Next_4xx)
@@ -109,7 +113,7 @@
   POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_IMPL(_is_exception_pending, Next_3xx)
 
 #define POSSIBLY_HANDLE_PENDING_EXCEPTION(_is_exception_pending, _next_function)  \
-  do {                                                                            \
+  {                                                                               \
     /* Should only be on invoke instructions. */                                  \
     DCHECK(!shadow_frame.GetForceRetryInstruction());                             \
     if (UNLIKELY(_is_exception_pending)) {                                        \
@@ -117,7 +121,8 @@
     } else {                                                                      \
       inst = inst->_next_function();                                              \
     }                                                                             \
-  } while (false)
+  }                                                                               \
+  do {} while (false)
 
 #define HANDLE_MONITOR_CHECKS()                                                                   \
   if (!DoMonitorCheckOnExit<do_assignability_check>(self, &shadow_frame)) {                       \
@@ -148,7 +153,7 @@
 #define PREAMBLE() PREAMBLE_SAVE(nullptr)
 
 #define BRANCH_INSTRUMENTATION(offset)                                                         \
-  do {                                                                                         \
+  {                                                                                            \
     if (UNLIKELY(instrumentation->HasBranchListeners())) {                                     \
       instrumentation->Branch(self, shadow_frame.GetMethod(), dex_pc, offset);                 \
     }                                                                                          \
@@ -165,31 +170,33 @@
       ctx->result = result;                                                                    \
       return;                                                                                  \
     }                                                                                          \
-  } while (false)
+  }                                                                                            \
+  do {} while (false)
 
 #define HOTNESS_UPDATE()                                                                       \
-  do {                                                                                         \
+  {                                                                                            \
     if (jit != nullptr) {                                                                      \
       jit->AddSamples(self, shadow_frame.GetMethod(), 1, /*with_backedges=*/ true);            \
     }                                                                                          \
-  } while (false)
+  }                                                                                            \
+  do {} while (false)
 
 #define HANDLE_ASYNC_EXCEPTION()                                                               \
   if (UNLIKELY(self->ObserveAsyncException())) {                                               \
     HANDLE_PENDING_EXCEPTION();                                                                \
-    break;                                                                                     \
   }                                                                                            \
   do {} while (false)
 
 #define HANDLE_BACKWARD_BRANCH(offset)                                                         \
-  do {                                                                                         \
+  {                                                                                            \
     if (IsBackwardBranch(offset)) {                                                            \
       HOTNESS_UPDATE();                                                                        \
       /* Record new dex pc early to have consistent suspend point at loop header. */           \
       shadow_frame.SetDexPC(inst->GetDexPc(insns));                                            \
       self->AllowThreadSuspension();                                                           \
     }                                                                                          \
-  } while (false)
+  }                                                                                            \
+  do {} while (false)
 
 // Unlike most other events the DexPcMovedEvent can be sent when there is a pending exception (if
 // the next instruction is MOVE_EXCEPTION). This means it needs to be handled carefully to be able
diff --git a/runtime/interpreter/mterp/arm/arithmetic.S b/runtime/interpreter/mterp/arm/arithmetic.S
index 6413b63..7a373c7 100644
--- a/runtime/interpreter/mterp/arm/arithmetic.S
+++ b/runtime/interpreter/mterp/arm/arithmetic.S
@@ -234,7 +234,7 @@
      * that specifies an instruction that performs "result = op r0/r1", where
      * "result" is a 32-bit quantity in r0.
      *
-     * For: long-to-float, double-to-int, double-to-float
+     * For: long-to-float
      *
      * (This would work for long-to-int, but that instruction is actually
      * an exact match for op_move.)
diff --git a/runtime/interpreter/mterp/arm/floating_point.S b/runtime/interpreter/mterp/arm/floating_point.S
index 6bf54e8..21c386e 100644
--- a/runtime/interpreter/mterp/arm/floating_point.S
+++ b/runtime/interpreter/mterp/arm/floating_point.S
@@ -19,8 +19,7 @@
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
     $instr                              @ s2<- op
     GET_INST_OPCODE ip                  @ extract opcode from rINST
-    VREG_INDEX_TO_ADDR r9, r9           @ r9<- &vAA
-    fsts    s2, [r9]                    @ vAA<- s2
+    SET_VREG_FLOAT s2, r9, lr           @ vAA<- s2
     GOTO_OPCODE ip                      @ jump to next instruction
 
 %def fbinop2addr(instr=""):
@@ -41,7 +40,7 @@
     flds    s0, [r9]                    @ s0<- vA
     $instr                              @ s2<- op
     GET_INST_OPCODE ip                  @ extract opcode from rINST
-    fsts    s2, [r9]                    @ vAA<- s2
+    fsts    s2, [r9]                    @ vAA<- s2 No need to clear as it's 2addr
     GOTO_OPCODE ip                      @ jump to next instruction
 
 %def fbinopWide(instr=""):
@@ -107,8 +106,7 @@
     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
     $instr                              @ s1<- op
     GET_INST_OPCODE ip                  @ extract opcode from rINST
-    VREG_INDEX_TO_ADDR r9, r9           @ r9<- &vA
-    fsts    s1, [r9]                    @ vA<- s1
+    SET_VREG_FLOAT s1, r9, lr           @ vA<- s1
     GOTO_OPCODE ip                      @ jump to next instruction
 
 %def funopNarrower(instr=""):
@@ -126,8 +124,7 @@
     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
     $instr                              @ s0<- op
     GET_INST_OPCODE ip                  @ extract opcode from rINST
-    VREG_INDEX_TO_ADDR r9, r9           @ r9<- &vA
-    fsts    s0, [r9]                    @ vA<- s0
+    SET_VREG_FLOAT s0, r9, lr           @ vA<- s0
     GOTO_OPCODE ip                      @ jump to next instruction
 
 %def funopWider(instr=""):
diff --git a/runtime/interpreter/mterp/arm/main.S b/runtime/interpreter/mterp/arm/main.S
index a9cffe7..6d6b190 100644
--- a/runtime/interpreter/mterp/arm/main.S
+++ b/runtime/interpreter/mterp/arm/main.S
@@ -274,6 +274,12 @@
 .macro SET_VREG_SHADOW reg, vreg
     str     \reg, [rREFS, \vreg, lsl #2]
 .endm
+.macro SET_VREG_FLOAT reg, vreg, tmpreg
+    add     \tmpreg, rFP, \vreg, lsl #2
+    fsts    \reg, [\tmpreg]
+    mov     \tmpreg, #0
+    str     \tmpreg, [rREFS, \vreg, lsl #2]
+.endm
 
 /*
  * Clear the corresponding shadow regs for a vreg pair
diff --git a/runtime/interpreter/mterp/mterp.cc b/runtime/interpreter/mterp/mterp.cc
index 4b6f430..ba109bc 100644
--- a/runtime/interpreter/mterp/mterp.cc
+++ b/runtime/interpreter/mterp/mterp.cc
@@ -146,15 +146,18 @@
     REQUIRES_SHARED(Locks::mutator_lock_) {
   const Runtime* const runtime = Runtime::Current();
   return
+      runtime->IsStarted() &&
+      !runtime->IsAotCompiler() &&
       !Dbg::IsDebuggerActive() &&
-      !runtime->GetInstrumentation()->NonJitProfilingActive() &&
+      !runtime->GetInstrumentation()->IsActive() &&
       // mterp only knows how to deal with the normal exits. It cannot handle any of the
       // non-standard force-returns.
       !runtime->AreNonStandardExitsEnabled() &&
       // An async exception has been thrown. We need to go to the switch interpreter. MTerp doesn't
       // know how to deal with these so we could end up never dealing with it if we are in an
       // infinite loop.
-      !runtime->AreAsyncExceptionsThrown();
+      !runtime->AreAsyncExceptionsThrown() &&
+      (runtime->GetJit() == nullptr || !runtime->GetJit()->JitAtFirstUse());
 }
 
 
@@ -560,6 +563,7 @@
     MutexLock tll_mu(self, *Locks::thread_list_lock_);
     DCHECK_EQ(self->UseMterp(), CanUseMterp());
   }
+  DCHECK(!Runtime::Current()->IsActiveTransaction());
   const Instruction* inst = Instruction::At(dex_pc_ptr);
   uint16_t inst_data = inst->Fetch16(0);
   if (inst->Opcode(inst_data) == Instruction::MOVE_EXCEPTION) {
diff --git a/runtime/interpreter/shadow_frame.h b/runtime/interpreter/shadow_frame.h
index c0920a8..6609021 100644
--- a/runtime/interpreter/shadow_frame.h
+++ b/runtime/interpreter/shadow_frame.h
@@ -375,6 +375,17 @@
     UpdateFrameFlag(enable, FrameFlags::kForceRetryInst);
   }
 
+  void CheckConsistentVRegs() const {
+    if (kIsDebugBuild) {
+      // A shadow frame visible to GC requires the following rule: for a given vreg,
+      // its vreg reference equivalent should be the same, or null.
+      for (uint32_t i = 0; i < NumberOfVRegs(); ++i) {
+        int32_t reference_value = References()[i].AsVRegValue();
+        CHECK((GetVReg(i) == reference_value) || (reference_value == 0));
+      }
+    }
+  }
+
  private:
   ShadowFrame(uint32_t num_vregs, ShadowFrame* link, ArtMethod* method,
               uint32_t dex_pc, bool has_reference_array)
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 8239602..082b311 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -304,12 +304,9 @@
     base_flags = MAP_PRIVATE | MAP_ANON;
     data_pages = MemMap::MapAnonymous(
         "data-code-cache",
-        /* addr= */ nullptr,
         data_capacity + exec_capacity,
         kProtRW,
         /* low_4gb= */ true,
-        /* reuse= */ false,
-        /* reservation= */ nullptr,
         &error_str);
   }
 
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 6a378f0..e655052 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -32,6 +32,7 @@
 #include "dex/dex_file_annotations.h"
 #include "dex_cache.h"
 #include "gc/accounting/card_table-inl.h"
+#include "gc/heap-inl.h"
 #include "handle_scope-inl.h"
 #include "subtype_check.h"
 #include "method.h"
diff --git a/runtime/monitor_test.cc b/runtime/monitor_test.cc
index 8610899..8ddd50f 100644
--- a/runtime/monitor_test.cc
+++ b/runtime/monitor_test.cc
@@ -16,6 +16,7 @@
 
 #include "monitor.h"
 
+#include <memory>
 #include <string>
 
 #include "base/atomic.h"
@@ -251,8 +252,8 @@
                                                                               "hello, world!"));
 
   // Create the barrier used to synchronize.
-  test->barrier_ = std::unique_ptr<Barrier>(new Barrier(2));
-  test->complete_barrier_ = std::unique_ptr<Barrier>(new Barrier(3));
+  test->barrier_ = std::make_unique<Barrier>(2);
+  test->complete_barrier_ = std::make_unique<Barrier>(3);
   test->completed_ = false;
 
   // Our job: Fill the heap, then try Wait.
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index f9f87d8..203d200 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -175,10 +175,9 @@
   std::string error_message;
   size_t length = static_cast<size_t>(end - start);
   MemMap dex_mem_map = MemMap::MapAnonymous("DEX data",
-                                            /* addr= */ nullptr,
                                             length,
                                             PROT_READ | PROT_WRITE,
-                                            /* low_4gb= */ false,
+                                            /*low_4gb=*/ false,
                                             &error_message);
   if (!dex_mem_map.IsValid()) {
     ScopedObjectAccess soa(env);
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index f54bf87..f5c0704 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -225,7 +225,9 @@
   if ((runtime_flags & DEBUG_ALWAYS_JIT) != 0) {
     jit::JitOptions* jit_options = runtime->GetJITOptions();
     CHECK(jit_options != nullptr);
-    jit_options->SetJitAtFirstUse();
+    Runtime::Current()->DoAndMaybeSwitchInterpreter([=]() {
+        jit_options->SetJitAtFirstUse();
+    });
     runtime_flags &= ~DEBUG_ALWAYS_JIT;
   }
 
diff --git a/runtime/native/java_lang_String.cc b/runtime/native/java_lang_String.cc
index 8976058..78ec859 100644
--- a/runtime/native/java_lang_String.cc
+++ b/runtime/native/java_lang_String.cc
@@ -19,6 +19,7 @@
 #include "nativehelper/jni_macros.h"
 
 #include "common_throws.h"
+#include "handle_scope-inl.h"
 #include "jni/jni_internal.h"
 #include "mirror/array.h"
 #include "mirror/object-inl.h"
diff --git a/runtime/native/java_lang_StringFactory.cc b/runtime/native/java_lang_StringFactory.cc
index 3978ca8..c6ad4e4 100644
--- a/runtime/native/java_lang_StringFactory.cc
+++ b/runtime/native/java_lang_StringFactory.cc
@@ -17,6 +17,7 @@
 #include "java_lang_StringFactory.h"
 
 #include "common_throws.h"
+#include "handle_scope-inl.h"
 #include "jni/jni_internal.h"
 #include "mirror/object-inl.h"
 #include "mirror/string-inl.h"
diff --git a/runtime/native/libcore_util_CharsetUtils.cc b/runtime/native/libcore_util_CharsetUtils.cc
index 2429804..95e0d79 100644
--- a/runtime/native/libcore_util_CharsetUtils.cc
+++ b/runtime/native/libcore_util_CharsetUtils.cc
@@ -18,6 +18,7 @@
 
 #include <string.h>
 
+#include "handle_scope-inl.h"
 #include "jni/jni_internal.h"
 #include "mirror/string-inl.h"
 #include "mirror/string.h"
diff --git a/runtime/native_stack_dump.cc b/runtime/native_stack_dump.cc
index ce295aa..10f5898 100644
--- a/runtime/native_stack_dump.cc
+++ b/runtime/native_stack_dump.cc
@@ -16,6 +16,7 @@
 
 #include "native_stack_dump.h"
 
+#include <memory>
 #include <ostream>
 
 #include <stdio.h>
@@ -128,10 +129,10 @@
   } else {
     close(caller_to_addr2line[0]);
     close(addr2line_to_caller[1]);
-    return std::unique_ptr<Addr2linePipe>(new Addr2linePipe(addr2line_to_caller[0],
-                                                            caller_to_addr2line[1],
-                                                            name,
-                                                            pid));
+    return std::make_unique<Addr2linePipe>(addr2line_to_caller[0],
+                                           caller_to_addr2line[1],
+                                           name,
+                                           pid);
   }
 }
 
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 2e495cc..7157928 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -16,6 +16,7 @@
 
 #include "parsed_options.h"
 
+#include <memory>
 #include <sstream>
 
 #include <android-base/logging.h>
@@ -67,7 +68,7 @@
   using M = RuntimeArgumentMap;
 
   std::unique_ptr<RuntimeParser::Builder> parser_builder =
-      std::unique_ptr<RuntimeParser::Builder>(new RuntimeParser::Builder());
+      std::make_unique<RuntimeParser::Builder>();
 
   parser_builder->
        Define("-Xzygote")
@@ -346,7 +347,7 @@
 
   // TODO: Move Usage information into this DSL.
 
-  return std::unique_ptr<RuntimeParser>(new RuntimeParser(parser_builder->Build()));
+  return std::make_unique<RuntimeParser>(parser_builder->Build());
 }
 
 #pragma GCC diagnostic pop
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 40c7301..c312126 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -744,7 +744,7 @@
 
   self->TransitionFromRunnableToSuspended(kNative);
 
-  started_ = true;
+  DoAndMaybeSwitchInterpreter([=](){ started_ = true; });
 
   if (!IsImageDex2OatEnabled() || !GetHeap()->HasBootImageSpace()) {
     ScopedObjectAccess soa(self);
@@ -1161,8 +1161,10 @@
                                                  reinterpret_cast<uint8_t*>(kSentinelAddr),
                                                  kPageSize,
                                                  PROT_NONE,
-                                                 /* low_4gb= */ true,
-                                                 /* error_msg= */ nullptr);
+                                                 /*low_4gb=*/ true,
+                                                 /*reuse=*/ false,
+                                                 /*reservation=*/ nullptr,
+                                                 /*error_msg=*/ nullptr);
     if (!protected_fault_page_.IsValid()) {
       LOG(WARNING) << "Could not reserve sentinel fault page";
     } else if (reinterpret_cast<uintptr_t>(protected_fault_page_.Begin()) != kSentinelAddr) {
@@ -2488,7 +2490,8 @@
     DCHECK(!jit_options_->UseJitCompilation());
   }
   std::string error_msg;
-  jit_.reset(jit::Jit::Create(jit_options_.get(), &error_msg));
+  jit::Jit* jit = jit::Jit::Create(jit_options_.get(), &error_msg);
+  DoAndMaybeSwitchInterpreter([=](){ jit_.reset(jit); });
   if (jit_.get() == nullptr) {
     LOG(WARNING) << "Failed to create JIT " << error_msg;
     return;
diff --git a/runtime/runtime_callbacks_test.cc b/runtime/runtime_callbacks_test.cc
index 20b3327..f2e5012 100644
--- a/runtime/runtime_callbacks_test.cc
+++ b/runtime/runtime_callbacks_test.cc
@@ -191,10 +191,9 @@
 TEST_F(ThreadLifecycleCallbackRuntimeCallbacksTest, ThreadLifecycleCallbackAttach) {
   std::string error_msg;
   MemMap stack = MemMap::MapAnonymous("ThreadLifecycleCallback Thread",
-                                      /* addr= */ nullptr,
                                       128 * kPageSize,  // Just some small stack.
                                       PROT_READ | PROT_WRITE,
-                                      /* low_4gb= */ false,
+                                      /*low_4gb=*/ false,
                                       &error_msg);
   ASSERT_TRUE(stack.IsValid()) << error_msg;
 
diff --git a/runtime/thread-inl.h b/runtime/thread-inl.h
index 91c27af..0c00fb9 100644
--- a/runtime/thread-inl.h
+++ b/runtime/thread-inl.h
@@ -385,6 +385,7 @@
 }
 
 inline ShadowFrame* Thread::PushShadowFrame(ShadowFrame* new_top_frame) {
+  new_top_frame->CheckConsistentVRegs();
   return tlsPtr_.managed_stack.PushShadowFrame(new_top_frame);
 }
 
diff --git a/runtime/thread_pool.cc b/runtime/thread_pool.cc
index a245f65..8723c99 100644
--- a/runtime/thread_pool.cc
+++ b/runtime/thread_pool.cc
@@ -47,10 +47,9 @@
   stack_size += kPageSize;
   std::string error_msg;
   stack_ = MemMap::MapAnonymous(name.c_str(),
-                                /* addr= */ nullptr,
                                 stack_size,
                                 PROT_READ | PROT_WRITE,
-                                /* low_4gb= */ false,
+                                /*low_4gb=*/ false,
                                 &error_msg);
   CHECK(stack_.IsValid()) << error_msg;
   CHECK_ALIGNED(stack_.Begin(), kPageSize);
diff --git a/test/etc/default-build b/test/etc/default-build
index 8542ad0..3e6699a 100755
--- a/test/etc/default-build
+++ b/test/etc/default-build
@@ -323,7 +323,8 @@
 function make_hiddenapi() {
   local args=( "encode" )
   while [[ $# -gt 0 ]]; do
-    args+=("--dex=$1")
+    args+=("--input-dex=$1")
+    args+=("--output-dex=$1")
     shift
   done
   if [ -f api-light-greylist.txt ]; then
diff --git a/tools/hiddenapi/hiddenapi.cc b/tools/hiddenapi/hiddenapi.cc
index 68211a1..f61b3e8 100644
--- a/tools/hiddenapi/hiddenapi.cc
+++ b/tools/hiddenapi/hiddenapi.cc
@@ -22,6 +22,8 @@
 #include "android-base/stringprintf.h"
 #include "android-base/strings.h"
 
+#include "base/bit_utils.h"
+#include "base/stl_util.h"
 #include "base/mem_map.h"
 #include "base/os.h"
 #include "base/unix_file/fd_file.h"
@@ -66,8 +68,9 @@
   UsageError("Usage: hiddenapi [command_name] [options]...");
   UsageError("");
   UsageError("  Command \"encode\": encode API list membership in boot dex files");
-  UsageError("    --dex=<filename>: dex file which belongs to boot class path,");
-  UsageError("                      the file will be overwritten");
+  UsageError("    --input-dex=<filename>: dex file which belongs to boot class path");
+  UsageError("    --output-dex=<filename>: file to write encoded dex into");
+  UsageError("        input and output dex files are paired in order of appearance");
   UsageError("");
   UsageError("    --light-greylist=<filename>:");
   UsageError("    --dark-greylist=<filename>:");
@@ -147,30 +150,6 @@
 
   inline const DexClass& GetDeclaringClass() const { return klass_; }
 
-  // Sets hidden bits in access flags and writes them back into the DEX in memory.
-  // Note that this will not update the cached data of the class accessor
-  // until it iterates over this item again and therefore will fail a CHECK if
-  // it is called multiple times on the same DexMember.
-  void SetHidden(HiddenApiAccessFlags::ApiList value) const {
-    const uint32_t old_flags = item_.GetRawAccessFlags();
-    const uint32_t new_flags = HiddenApiAccessFlags::EncodeForDex(old_flags, value);
-    CHECK_EQ(UnsignedLeb128Size(new_flags), UnsignedLeb128Size(old_flags));
-
-    // Locate the LEB128-encoded access flags in class data.
-    // `ptr` initially points to the next ClassData item. We iterate backwards
-    // until we hit the terminating byte of the previous Leb128 value.
-    const uint8_t* ptr = item_.GetDataPointer();
-    if (IsMethod()) {
-      ptr = ReverseSearchUnsignedLeb128(ptr);
-      DCHECK_EQ(DecodeUnsignedLeb128WithoutMovingCursor(ptr), GetMethod().GetCodeItemOffset());
-    }
-    ptr = ReverseSearchUnsignedLeb128(ptr);
-    DCHECK_EQ(DecodeUnsignedLeb128WithoutMovingCursor(ptr), old_flags);
-
-    // Overwrite the access flags.
-    UpdateUnsignedLeb128(const_cast<uint8_t*>(ptr), new_flags);
-  }
-
   inline bool IsMethod() const { return is_method_; }
   inline bool IsVirtualMethod() const { return IsMethod() && !GetMethod().IsStaticOrDirect(); }
   inline bool IsConstructor() const { return IsMethod() && HasAccessFlags(kAccConstructor); }
@@ -262,6 +241,10 @@
     });
   }
 
+  std::vector<const DexFile*> GetDexFiles() const {
+    return MakeNonOwningPointerVector(dex_files_);
+  }
+
   void UpdateDexChecksums() {
     for (auto& dex_file : dex_files_) {
       // Obtain a writeable pointer to the dex header.
@@ -559,6 +542,317 @@
   std::map<std::string, HierarchyClass> classes_;
 };
 
+// Builder of dex section containing hiddenapi flags.
+class HiddenapiClassDataBuilder final {
+ public:
+  explicit HiddenapiClassDataBuilder(const DexFile& dex_file)
+      : num_classdefs_(dex_file.NumClassDefs()),
+        next_class_def_idx_(0u),
+        class_def_has_non_zero_flags_(false),
+        dex_file_has_non_zero_flags_(false),
+        data_(sizeof(uint32_t) * (num_classdefs_ + 1), 0u) {
+    *GetSizeField() = GetCurrentDataSize();
+  }
+
+  // Notify the builder that new flags for the next class def
+  // will be written now. The builder records the current offset
+  // into the header.
+  void BeginClassDef(uint32_t idx) {
+    CHECK_EQ(next_class_def_idx_, idx);
+    CHECK_LT(idx, num_classdefs_);
+    GetOffsetArray()[idx] = GetCurrentDataSize();
+    class_def_has_non_zero_flags_ = false;
+  }
+
+  // Notify the builder that all flags for this class def have been
+  // written. The builder updates the total size of the data struct
+  // and may set offset for class def in header to zero if no data
+  // has been written.
+  void EndClassDef(uint32_t idx) {
+    CHECK_EQ(next_class_def_idx_, idx);
+    CHECK_LT(idx, num_classdefs_);
+
+    ++next_class_def_idx_;
+
+    if (!class_def_has_non_zero_flags_) {
+      // No need to store flags for this class. Remove the written flags
+      // and set offset in header to zero.
+      data_.resize(GetOffsetArray()[idx]);
+      GetOffsetArray()[idx] = 0u;
+    }
+
+    dex_file_has_non_zero_flags_ |= class_def_has_non_zero_flags_;
+
+    if (idx == num_classdefs_ - 1) {
+      if (dex_file_has_non_zero_flags_) {
+        // This was the last class def and we have generated non-zero hiddenapi
+        // flags. Update total size in the header.
+        *GetSizeField() = GetCurrentDataSize();
+      } else {
+        // This was the last class def and we have not generated any non-zero
+        // hiddenapi flags. Clear all the data.
+        data_.clear();
+      }
+    }
+  }
+
+  // Append flags at the end of the data struct. This should be called
+  // between BeginClassDef and EndClassDef in the order of appearance of
+  // fields/methods in the class data stream.
+  void WriteFlags(hiddenapi::ApiList flags) {
+    uint32_t uint_flags = static_cast<uint32_t>(flags);
+    EncodeUnsignedLeb128(&data_, uint_flags);
+    class_def_has_non_zero_flags_ |= (uint_flags != 0u);
+  }
+
+  // Return backing data, assuming that all flags have been written.
+  const std::vector<uint8_t>& GetData() const {
+    CHECK_EQ(next_class_def_idx_, num_classdefs_) << "Incomplete data";
+    return data_;
+  }
+
+ private:
+  // Returns pointer to the size field in the header of this dex section.
+  uint32_t* GetSizeField() {
+    // Assume malloc() aligns allocated memory to at least uint32_t.
+    CHECK(IsAligned<sizeof(uint32_t)>(data_.data()));
+    return reinterpret_cast<uint32_t*>(data_.data());
+  }
+
+  // Returns pointer to array of offsets (indexed by class def indices) in the
+  // header of this dex section.
+  uint32_t* GetOffsetArray() { return &GetSizeField()[1]; }
+  uint32_t GetCurrentDataSize() const { return data_.size(); }
+
+  // Number of class defs in this dex file.
+  const uint32_t num_classdefs_;
+
+  // Next expected class def index.
+  uint32_t next_class_def_idx_;
+
+  // Whether non-zero flags have been encountered for this class def.
+  bool class_def_has_non_zero_flags_;
+
+  // Whether any non-zero flags have been encountered for this dex file.
+  bool dex_file_has_non_zero_flags_;
+
+  // Vector containing the data of the built data structure.
+  std::vector<uint8_t> data_;
+};
+
+// Edits a dex file, inserting a new HiddenapiClassData section.
+class DexFileEditor final {
+ public:
+  DexFileEditor(const DexFile& old_dex, const std::vector<uint8_t>& hiddenapi_class_data)
+      : old_dex_(old_dex),
+        hiddenapi_class_data_(hiddenapi_class_data),
+        loaded_dex_header_(nullptr),
+        loaded_dex_maplist_(nullptr) {}
+
+  // Copies dex file into a backing data vector, appends the given HiddenapiClassData
+  // and updates the MapList.
+  void Encode() {
+    // We do not support non-standard dex encodings, e.g. compact dex.
+    CHECK(old_dex_.IsStandardDexFile());
+
+    // If there are no data to append, copy the old dex file and return.
+    if (hiddenapi_class_data_.empty()) {
+      AllocateMemory(old_dex_.Size());
+      Append(old_dex_.Begin(), old_dex_.Size(), /* update_header= */ false);
+      return;
+    }
+
+    // Find the old MapList, find its size.
+    const DexFile::MapList* old_map = old_dex_.GetMapList();
+    CHECK_LT(old_map->size_, std::numeric_limits<uint32_t>::max());
+
+    // Compute the size of the new dex file. We append the HiddenapiClassData,
+    // one MapItem and possibly some padding to align the new MapList.
+    CHECK(IsAligned<kMapListAlignment>(old_dex_.Size()))
+        << "End of input dex file is not 4-byte aligned, possibly because its MapList is not "
+        << "at the end of the file.";
+    size_t size_delta =
+        RoundUp(hiddenapi_class_data_.size(), kMapListAlignment) + sizeof(DexFile::MapItem);
+    size_t new_size = old_dex_.Size() + size_delta;
+    AllocateMemory(new_size);
+
+    // Copy the old dex file into the backing data vector. Load the copied
+    // dex file to obtain pointers to its header and MapList.
+    Append(old_dex_.Begin(), old_dex_.Size(), /* update_header= */ false);
+    ReloadDex(/* verify= */ false);
+
+    // Truncate the new dex file before the old MapList. This assumes that
+    // the MapList is the last entry in the dex file. This is currently true
+    // for our tooling.
+    // TODO: Implement the general case by zero-ing the old MapList (turning
+    // it into padding.
+    RemoveOldMapList();
+
+    // Append HiddenapiClassData.
+    size_t payload_offset = AppendHiddenapiClassData();
+
+    // Wrute new MapList with an entry for HiddenapiClassData.
+    CreateMapListWithNewItem(payload_offset);
+
+    // Check that the pre-computed size matches the actual size.
+    CHECK_EQ(offset_, new_size);
+
+    // Reload to all data structures.
+    ReloadDex(/* verify= */ false);
+
+    // Update the dex checksum.
+    UpdateChecksum();
+
+    // Run DexFileVerifier on the new dex file as a CHECK.
+    ReloadDex(/* verify= */ true);
+  }
+
+  // Writes the edited dex file into a file.
+  void WriteTo(const std::string& path) {
+    CHECK(!data_.empty());
+    std::ofstream ofs(path.c_str(), std::ofstream::out | std::ofstream::binary);
+    ofs.write(reinterpret_cast<const char*>(data_.data()), data_.size());
+    ofs.flush();
+    CHECK(ofs.good());
+    ofs.close();
+  }
+
+ private:
+  static constexpr size_t kMapListAlignment = 4u;
+  static constexpr size_t kHiddenapiClassDataAlignment = 4u;
+
+  void ReloadDex(bool verify) {
+    std::string error_msg;
+    DexFileLoader loader;
+    loaded_dex_ = loader.Open(
+        data_.data(),
+        data_.size(),
+        "test_location",
+        old_dex_.GetLocationChecksum(),
+        /* oat_dex_file= */ nullptr,
+        /* verify= */ verify,
+        /* verify_checksum= */ verify,
+        &error_msg);
+    if (loaded_dex_.get() == nullptr) {
+      LOG(FATAL) << "Failed to load edited dex file: " << error_msg;
+      UNREACHABLE();
+    }
+
+    // Load the location of header and map list before we start editing the file.
+    loaded_dex_header_ = const_cast<DexFile::Header*>(&loaded_dex_->GetHeader());
+    loaded_dex_maplist_ = const_cast<DexFile::MapList*>(loaded_dex_->GetMapList());
+  }
+
+  DexFile::Header& GetHeader() const {
+    CHECK(loaded_dex_header_ != nullptr);
+    return *loaded_dex_header_;
+  }
+
+  DexFile::MapList& GetMapList() const {
+    CHECK(loaded_dex_maplist_ != nullptr);
+    return *loaded_dex_maplist_;
+  }
+
+  void AllocateMemory(size_t total_size) {
+    data_.clear();
+    data_.resize(total_size);
+    CHECK(IsAligned<kMapListAlignment>(data_.data()));
+    CHECK(IsAligned<kHiddenapiClassDataAlignment>(data_.data()));
+    offset_ = 0;
+  }
+
+  uint8_t* GetCurrentDataPtr() {
+    return data_.data() + offset_;
+  }
+
+  void UpdateDataSize(off_t delta, bool update_header) {
+    offset_ += delta;
+    if (update_header) {
+      DexFile::Header& header = GetHeader();
+      header.file_size_ += delta;
+      header.data_size_ += delta;
+    }
+  }
+
+  template<typename T>
+  T* Append(const T* src, size_t len, bool update_header = true) {
+    CHECK_LE(offset_ + len, data_.size());
+    uint8_t* dst = GetCurrentDataPtr();
+    memcpy(dst, src, len);
+    UpdateDataSize(len, update_header);
+    return reinterpret_cast<T*>(dst);
+  }
+
+  void InsertPadding(size_t alignment) {
+    size_t len = RoundUp(offset_, alignment) - offset_;
+    std::vector<uint8_t> padding(len, 0);
+    Append(padding.data(), padding.size());
+  }
+
+  void RemoveOldMapList() {
+    size_t map_size = GetMapList().Size();
+    uint8_t* map_start = reinterpret_cast<uint8_t*>(&GetMapList());
+    CHECK_EQ(map_start + map_size, GetCurrentDataPtr()) << "MapList not at the end of dex file";
+    UpdateDataSize(-static_cast<off_t>(map_size), /* update_header= */ true);
+    CHECK_EQ(map_start, GetCurrentDataPtr());
+    loaded_dex_maplist_ = nullptr;  // do not use this map list any more
+  }
+
+  void CreateMapListWithNewItem(size_t payload_offset) {
+    InsertPadding(/* alignment= */ kMapListAlignment);
+
+    size_t new_map_offset = offset_;
+    DexFile::MapList* map = Append(old_dex_.GetMapList(), old_dex_.GetMapList()->Size());
+
+    // Check last map entry is a pointer to itself.
+    DexFile::MapItem& old_item = map->list_[map->size_ - 1];
+    CHECK(old_item.type_ == DexFile::kDexTypeMapList);
+    CHECK_EQ(old_item.size_, 1u);
+    CHECK_EQ(old_item.offset_, GetHeader().map_off_);
+
+    // Create a new MapItem entry with new MapList details.
+    DexFile::MapItem new_item;
+    new_item.type_ = old_item.type_;
+    new_item.size_ = old_item.size_;
+    new_item.offset_ = new_map_offset;
+
+    // Update pointer in the header.
+    GetHeader().map_off_ = new_map_offset;
+
+    // Append a new MapItem and return its pointer.
+    map->size_++;
+    Append(&new_item, sizeof(DexFile::MapItem));
+
+    // Change penultimate entry to point to metadata.
+    old_item.type_ = DexFile::kDexTypeHiddenapiClassData;
+    old_item.size_ = 1u;  // there is only one section
+    old_item.offset_ = payload_offset;
+  }
+
+  size_t AppendHiddenapiClassData() {
+    size_t payload_offset = offset_;
+    CHECK_EQ(kMapListAlignment, kHiddenapiClassDataAlignment);
+    CHECK(IsAligned<kHiddenapiClassDataAlignment>(payload_offset))
+        << "Should not need to align the section, previous data was already aligned";
+    Append(hiddenapi_class_data_.data(), hiddenapi_class_data_.size());
+    return payload_offset;
+  }
+
+  void UpdateChecksum() {
+    GetHeader().checksum_ = loaded_dex_->CalculateChecksum();
+  }
+
+  const DexFile& old_dex_;
+  const std::vector<uint8_t>& hiddenapi_class_data_;
+
+  std::vector<uint8_t> data_;
+  size_t offset_;
+
+  std::unique_ptr<const DexFile> loaded_dex_;
+  DexFile::Header* loaded_dex_header_;
+  DexFile::MapList* loaded_dex_maplist_;
+};
+
 class HiddenApi final {
  public:
   HiddenApi() {}
@@ -590,8 +884,10 @@
       if (command == "encode") {
         for (int i = 1; i < argc; ++i) {
           const StringPiece option(argv[i]);
-          if (option.starts_with("--dex=")) {
-            boot_dex_paths_.push_back(option.substr(strlen("--dex=")).ToString());
+          if (option.starts_with("--input-dex=")) {
+            boot_dex_paths_.push_back(option.substr(strlen("--input-dex=")).ToString());
+          } else if (option.starts_with("--output-dex=")) {
+            output_dex_paths_.push_back(option.substr(strlen("--output-dex=")).ToString());
           } else if (option.starts_with("--light-greylist=")) {
             light_greylist_path_ = option.substr(strlen("--light-greylist=")).ToString();
           } else if (option.starts_with("--dark-greylist=")) {
@@ -630,30 +926,57 @@
 
   void EncodeAccessFlags() {
     if (boot_dex_paths_.empty()) {
-      Usage("No boot DEX files specified");
+      Usage("No input DEX files specified");
+    } else if (output_dex_paths_.size() != boot_dex_paths_.size()) {
+      Usage("Number of input DEX files does not match number of output DEX files");
     }
 
     // Load dex signatures.
-    std::map<std::string, HiddenApiAccessFlags::ApiList> api_list;
-    OpenApiFile(light_greylist_path_, api_list, HiddenApiAccessFlags::kLightGreylist);
-    OpenApiFile(dark_greylist_path_, api_list, HiddenApiAccessFlags::kDarkGreylist);
-    OpenApiFile(blacklist_path_, api_list, HiddenApiAccessFlags::kBlacklist);
+    std::map<std::string, hiddenapi::ApiList> api_list;
+    OpenApiFile(light_greylist_path_, api_list, hiddenapi::ApiList::kLightGreylist);
+    OpenApiFile(dark_greylist_path_, api_list, hiddenapi::ApiList::kDarkGreylist);
+    OpenApiFile(blacklist_path_, api_list, hiddenapi::ApiList::kBlacklist);
 
-    // Open all dex files.
-    ClassPath boot_classpath(boot_dex_paths_, /* open_writable= */ true);
+    // Iterate over input dex files and insert HiddenapiClassData sections.
+    for (size_t i = 0; i < boot_dex_paths_.size(); ++i) {
+      const std::string& input_path = boot_dex_paths_[i];
+      const std::string& output_path = output_dex_paths_[i];
 
-    // Set access flags of all members.
-    boot_classpath.ForEachDexMember([&api_list](const DexMember& boot_member) {
-      auto it = api_list.find(boot_member.GetApiEntry());
-      boot_member.SetHidden(it == api_list.end() ? HiddenApiAccessFlags::kWhitelist : it->second);
-    });
+      ClassPath boot_classpath({ input_path }, /* open_writable= */ false);
+      std::vector<const DexFile*> input_dex_files = boot_classpath.GetDexFiles();
+      CHECK_EQ(input_dex_files.size(), 1u);
+      const DexFile& input_dex = *input_dex_files[0];
 
-    boot_classpath.UpdateDexChecksums();
+      HiddenapiClassDataBuilder builder(input_dex);
+      boot_classpath.ForEachDexClass([&api_list, &builder](const DexClass& boot_class) {
+        builder.BeginClassDef(boot_class.GetClassDefIndex());
+        if (boot_class.GetData() != nullptr) {
+          auto fn_shared = [&](const DexMember& boot_member) {
+            // TODO: Load whitelist and CHECK that entry was found.
+            auto it = api_list.find(boot_member.GetApiEntry());
+            builder.WriteFlags(
+                (it == api_list.end()) ? hiddenapi::ApiList::kWhitelist : it->second);
+          };
+          auto fn_field = [&](const ClassAccessor::Field& boot_field) {
+            fn_shared(DexMember(boot_class, boot_field));
+          };
+          auto fn_method = [&](const ClassAccessor::Method& boot_method) {
+            fn_shared(DexMember(boot_class, boot_method));
+          };
+          boot_class.VisitFieldsAndMethods(fn_field, fn_field, fn_method, fn_method);
+        }
+        builder.EndClassDef(boot_class.GetClassDefIndex());
+      });
+
+      DexFileEditor dex_editor(input_dex, builder.GetData());
+      dex_editor.Encode();
+      dex_editor.WriteTo(output_path);
+    }
   }
 
   void OpenApiFile(const std::string& path,
-                   std::map<std::string, HiddenApiAccessFlags::ApiList>& api_list,
-                   HiddenApiAccessFlags::ApiList membership) {
+                   std::map<std::string, hiddenapi::ApiList>& api_list,
+                   hiddenapi::ApiList membership) {
     if (path.empty()) {
       return;
     }
@@ -748,6 +1071,9 @@
   // Paths to DEX files which should be processed.
   std::vector<std::string> boot_dex_paths_;
 
+  // Output paths where modified DEX files should be written.
+  std::vector<std::string> output_dex_paths_;
+
   // Set of public API stub classpaths. Each classpath is formed by a list
   // of DEX/APK files in the order they appear on the classpath.
   std::vector<std::vector<std::string>> stub_classpaths_;
@@ -765,6 +1091,8 @@
 }  // namespace art
 
 int main(int argc, char** argv) {
+  art::original_argc = argc;
+  art::original_argv = argv;
   android::base::InitLogging(argv);
   art::MemMap::Init();
   art::HiddenApi().Run(argc, argv);
diff --git a/tools/hiddenapi/hiddenapi_test.cc b/tools/hiddenapi/hiddenapi_test.cc
index 799546e..0010b784 100644
--- a/tools/hiddenapi/hiddenapi_test.cc
+++ b/tools/hiddenapi/hiddenapi_test.cc
@@ -47,6 +47,7 @@
                                               const std::vector<std::string>& extra_args,
                                               ScratchFile* out_dex) {
     std::string error;
+    ScratchFile in_dex;
     std::unique_ptr<ZipArchive> jar(
         ZipArchive::Open(GetTestDexFileName("HiddenApi").c_str(), &error));
     if (jar == nullptr) {
@@ -58,7 +59,7 @@
       LOG(FATAL) << "Could not find classes.dex in test file " << GetTestDexFileName("HiddenApi")
                  << ": " << error;
       UNREACHABLE();
-    } else if (!jar_classes_dex->ExtractToFile(*out_dex->GetFile(), &error)) {
+    } else if (!jar_classes_dex->ExtractToFile(*in_dex.GetFile(), &error)) {
       LOG(FATAL) << "Could not extract classes.dex from test file "
                  << GetTestDexFileName("HiddenApi") << ": " << error;
       UNREACHABLE();
@@ -68,7 +69,8 @@
     argv_str.push_back(GetHiddenApiCmd());
     argv_str.insert(argv_str.end(), extra_args.begin(), extra_args.end());
     argv_str.push_back("encode");
-    argv_str.push_back("--dex=" + out_dex->GetFilename());
+    argv_str.push_back("--input-dex=" + in_dex.GetFilename());
+    argv_str.push_back("--output-dex=" + out_dex->GetFilename());
     argv_str.push_back("--light-greylist=" + light_greylist.GetFilename());
     argv_str.push_back("--dark-greylist=" + dark_greylist.GetFilename());
     argv_str.push_back("--blacklist=" + blacklist.GetFilename());
@@ -92,7 +94,7 @@
     }
 
     std::unique_ptr<const DexFile> dex_file(dex_loader.OpenDex(
-        fd.Release(), /* location= */ file.GetFilename(), /* verify= */ false,
+        fd.Release(), /* location= */ file.GetFilename(), /* verify= */ true,
         /* verify_checksum= */ true, /* mmap_shared= */ false, &error_msg));
     if (dex_file.get() == nullptr) {
       LOG(FATAL) << "Open failed for '" << file.GetFilename() << "' " << error_msg;
@@ -122,20 +124,24 @@
     return *found;
   }
 
-  HiddenApiAccessFlags::ApiList GetFieldHiddenFlags(const char* name,
-                                                    uint32_t expected_visibility,
-                                                    const DexFile::ClassDef& class_def,
-                                                    const DexFile& dex_file) {
-    ClassAccessor accessor(dex_file, class_def);
+  hiddenapi::ApiList GetFieldHiddenFlags(const char* name,
+                                         uint32_t expected_visibility,
+                                         const DexFile::ClassDef& class_def,
+                                         const DexFile& dex_file) {
+    ClassAccessor accessor(dex_file, class_def, /* parse hiddenapi flags */ true);
     CHECK(accessor.HasClassData()) << "Class " << accessor.GetDescriptor() << " has no data";
 
+    if (!accessor.HasHiddenapiClassData()) {
+      return hiddenapi::ApiList::kWhitelist;
+    }
+
     for (const ClassAccessor::Field& field : accessor.GetFields()) {
       const DexFile::FieldId& fid = dex_file.GetFieldId(field.GetIndex());
       if (strcmp(name, dex_file.GetFieldName(fid)) == 0) {
         const uint32_t actual_visibility = field.GetAccessFlags() & kAccVisibilityFlags;
         CHECK_EQ(actual_visibility, expected_visibility)
             << "Field " << name << " in class " << accessor.GetDescriptor();
-        return field.DecodeHiddenAccessFlags();
+        return static_cast<hiddenapi::ApiList>(field.GetHiddenapiFlags());
       }
     }
 
@@ -144,14 +150,18 @@
     UNREACHABLE();
   }
 
-  HiddenApiAccessFlags::ApiList GetMethodHiddenFlags(const char* name,
-                                                     uint32_t expected_visibility,
-                                                     bool expected_native,
-                                                     const DexFile::ClassDef& class_def,
-                                                     const DexFile& dex_file) {
-    ClassAccessor accessor(dex_file, class_def);
+  hiddenapi::ApiList GetMethodHiddenFlags(const char* name,
+                                          uint32_t expected_visibility,
+                                          bool expected_native,
+                                          const DexFile::ClassDef& class_def,
+                                          const DexFile& dex_file) {
+    ClassAccessor accessor(dex_file, class_def, /* parse hiddenapi flags */ true);
     CHECK(accessor.HasClassData()) << "Class " << accessor.GetDescriptor() << " has no data";
 
+    if (!accessor.HasHiddenapiClassData()) {
+      return hiddenapi::ApiList::kWhitelist;
+    }
+
     for (const ClassAccessor::Method& method : accessor.GetMethods()) {
       const DexFile::MethodId& mid = dex_file.GetMethodId(method.GetIndex());
       if (strcmp(name, dex_file.GetMethodName(mid)) == 0) {
@@ -160,7 +170,7 @@
         const uint32_t actual_visibility = method.GetAccessFlags() & kAccVisibilityFlags;
         CHECK_EQ(actual_visibility, expected_visibility)
             << "Method " << name << " in class " << accessor.GetDescriptor();
-        return method.DecodeHiddenAccessFlags();
+        return static_cast<hiddenapi::ApiList>(method.GetHiddenapiFlags());
       }
     }
 
@@ -169,20 +179,20 @@
     UNREACHABLE();
   }
 
-  HiddenApiAccessFlags::ApiList GetIFieldHiddenFlags(const DexFile& dex_file) {
+  hiddenapi::ApiList GetIFieldHiddenFlags(const DexFile& dex_file) {
     return GetFieldHiddenFlags("ifield", kAccPublic, FindClass("LMain;", dex_file), dex_file);
   }
 
-  HiddenApiAccessFlags::ApiList GetSFieldHiddenFlags(const DexFile& dex_file) {
+  hiddenapi::ApiList GetSFieldHiddenFlags(const DexFile& dex_file) {
     return GetFieldHiddenFlags("sfield", kAccPrivate, FindClass("LMain;", dex_file), dex_file);
   }
 
-  HiddenApiAccessFlags::ApiList GetIMethodHiddenFlags(const DexFile& dex_file) {
+  hiddenapi::ApiList GetIMethodHiddenFlags(const DexFile& dex_file) {
     return GetMethodHiddenFlags(
         "imethod", 0, /* expected_native= */ false, FindClass("LMain;", dex_file), dex_file);
   }
 
-  HiddenApiAccessFlags::ApiList GetSMethodHiddenFlags(const DexFile& dex_file) {
+  hiddenapi::ApiList GetSMethodHiddenFlags(const DexFile& dex_file) {
     return GetMethodHiddenFlags("smethod",
                                 kAccPublic,
                                 /* expected_native= */ false,
@@ -190,7 +200,7 @@
                                 dex_file);
   }
 
-  HiddenApiAccessFlags::ApiList GetINMethodHiddenFlags(const DexFile& dex_file) {
+  hiddenapi::ApiList GetINMethodHiddenFlags(const DexFile& dex_file) {
     return GetMethodHiddenFlags("inmethod",
                                 kAccPublic,
                                 /* expected_native= */ true,
@@ -198,7 +208,7 @@
                                 dex_file);
   }
 
-  HiddenApiAccessFlags::ApiList GetSNMethodHiddenFlags(const DexFile& dex_file) {
+  hiddenapi::ApiList GetSNMethodHiddenFlags(const DexFile& dex_file) {
     return GetMethodHiddenFlags("snmethod",
                                 kAccProtected,
                                 /* expected_native= */ true,
@@ -214,7 +224,7 @@
   OpenStream(blacklist) << "LMain;->ifield:LBadType3;" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
   ASSERT_NE(dex_file.get(), nullptr);
-  ASSERT_EQ(HiddenApiAccessFlags::kWhitelist, GetIFieldHiddenFlags(*dex_file));
+  ASSERT_EQ(hiddenapi::ApiList::kWhitelist, GetIFieldHiddenFlags(*dex_file));
 }
 
 TEST_F(HiddenApiTest, InstanceFieldLightGreylistMatch) {
@@ -224,7 +234,7 @@
   OpenStream(blacklist) << "LMain;->ifield:LBadType3;" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
   ASSERT_NE(dex_file.get(), nullptr);
-  ASSERT_EQ(HiddenApiAccessFlags::kLightGreylist, GetIFieldHiddenFlags(*dex_file));
+  ASSERT_EQ(hiddenapi::ApiList::kLightGreylist, GetIFieldHiddenFlags(*dex_file));
 }
 
 TEST_F(HiddenApiTest, InstanceFieldDarkGreylistMatch) {
@@ -234,7 +244,7 @@
   OpenStream(blacklist) << "LMain;->ifield:LBadType3;" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
   ASSERT_NE(dex_file.get(), nullptr);
-  ASSERT_EQ(HiddenApiAccessFlags::kDarkGreylist, GetIFieldHiddenFlags(*dex_file));
+  ASSERT_EQ(hiddenapi::ApiList::kDarkGreylist, GetIFieldHiddenFlags(*dex_file));
 }
 
 TEST_F(HiddenApiTest, InstanceFieldBlacklistMatch) {
@@ -244,7 +254,7 @@
   OpenStream(blacklist) << "LMain;->ifield:I" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
   ASSERT_NE(dex_file.get(), nullptr);
-  ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetIFieldHiddenFlags(*dex_file));
+  ASSERT_EQ(hiddenapi::ApiList::kBlacklist, GetIFieldHiddenFlags(*dex_file));
 }
 
 TEST_F(HiddenApiTest, InstanceFieldTwoListsMatch1) {
@@ -281,7 +291,7 @@
   OpenStream(blacklist) << "LMain;->sfield:LBadType3;" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
   ASSERT_NE(dex_file.get(), nullptr);
-  ASSERT_EQ(HiddenApiAccessFlags::kWhitelist, GetSFieldHiddenFlags(*dex_file));
+  ASSERT_EQ(hiddenapi::ApiList::kWhitelist, GetSFieldHiddenFlags(*dex_file));
 }
 
 TEST_F(HiddenApiTest, StaticFieldLightGreylistMatch) {
@@ -291,7 +301,7 @@
   OpenStream(blacklist) << "LMain;->sfield:LBadType3;" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
   ASSERT_NE(dex_file.get(), nullptr);
-  ASSERT_EQ(HiddenApiAccessFlags::kLightGreylist, GetSFieldHiddenFlags(*dex_file));
+  ASSERT_EQ(hiddenapi::ApiList::kLightGreylist, GetSFieldHiddenFlags(*dex_file));
 }
 
 TEST_F(HiddenApiTest, StaticFieldDarkGreylistMatch) {
@@ -301,7 +311,7 @@
   OpenStream(blacklist) << "LMain;->sfield:LBadType3;" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
   ASSERT_NE(dex_file.get(), nullptr);
-  ASSERT_EQ(HiddenApiAccessFlags::kDarkGreylist, GetSFieldHiddenFlags(*dex_file));
+  ASSERT_EQ(hiddenapi::ApiList::kDarkGreylist, GetSFieldHiddenFlags(*dex_file));
 }
 
 TEST_F(HiddenApiTest, StaticFieldBlacklistMatch) {
@@ -311,7 +321,7 @@
   OpenStream(blacklist) << "LMain;->sfield:Ljava/lang/Object;" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
   ASSERT_NE(dex_file.get(), nullptr);
-  ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetSFieldHiddenFlags(*dex_file));
+  ASSERT_EQ(hiddenapi::ApiList::kBlacklist, GetSFieldHiddenFlags(*dex_file));
 }
 
 TEST_F(HiddenApiTest, StaticFieldTwoListsMatch1) {
@@ -348,7 +358,7 @@
   OpenStream(blacklist) << "LMain;->imethod(LBadType3;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
   ASSERT_NE(dex_file.get(), nullptr);
-  ASSERT_EQ(HiddenApiAccessFlags::kWhitelist, GetIMethodHiddenFlags(*dex_file));
+  ASSERT_EQ(hiddenapi::ApiList::kWhitelist, GetIMethodHiddenFlags(*dex_file));
 }
 
 TEST_F(HiddenApiTest, InstanceMethodLightGreylistMatch) {
@@ -358,7 +368,7 @@
   OpenStream(blacklist) << "LMain;->imethod(LBadType3;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
   ASSERT_NE(dex_file.get(), nullptr);
-  ASSERT_EQ(HiddenApiAccessFlags::kLightGreylist, GetIMethodHiddenFlags(*dex_file));
+  ASSERT_EQ(hiddenapi::ApiList::kLightGreylist, GetIMethodHiddenFlags(*dex_file));
 }
 
 TEST_F(HiddenApiTest, InstanceMethodDarkGreylistMatch) {
@@ -368,7 +378,7 @@
   OpenStream(blacklist) << "LMain;->imethod(LBadType3;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
   ASSERT_NE(dex_file.get(), nullptr);
-  ASSERT_EQ(HiddenApiAccessFlags::kDarkGreylist, GetIMethodHiddenFlags(*dex_file));
+  ASSERT_EQ(hiddenapi::ApiList::kDarkGreylist, GetIMethodHiddenFlags(*dex_file));
 }
 
 TEST_F(HiddenApiTest, InstanceMethodBlacklistMatch) {
@@ -378,7 +388,7 @@
   OpenStream(blacklist) << "LMain;->imethod(J)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
   ASSERT_NE(dex_file.get(), nullptr);
-  ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetIMethodHiddenFlags(*dex_file));
+  ASSERT_EQ(hiddenapi::ApiList::kBlacklist, GetIMethodHiddenFlags(*dex_file));
 }
 
 TEST_F(HiddenApiTest, InstanceMethodTwoListsMatch1) {
@@ -415,7 +425,7 @@
   OpenStream(blacklist) << "LMain;->smethod(LBadType3;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
   ASSERT_NE(dex_file.get(), nullptr);
-  ASSERT_EQ(HiddenApiAccessFlags::kWhitelist, GetSMethodHiddenFlags(*dex_file));
+  ASSERT_EQ(hiddenapi::ApiList::kWhitelist, GetSMethodHiddenFlags(*dex_file));
 }
 
 TEST_F(HiddenApiTest, StaticMethodLightGreylistMatch) {
@@ -425,7 +435,7 @@
   OpenStream(blacklist) << "LMain;->smethod(LBadType3;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
   ASSERT_NE(dex_file.get(), nullptr);
-  ASSERT_EQ(HiddenApiAccessFlags::kLightGreylist, GetSMethodHiddenFlags(*dex_file));
+  ASSERT_EQ(hiddenapi::ApiList::kLightGreylist, GetSMethodHiddenFlags(*dex_file));
 }
 
 TEST_F(HiddenApiTest, StaticMethodDarkGreylistMatch) {
@@ -435,7 +445,7 @@
   OpenStream(blacklist) << "LMain;->smethod(LBadType3;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
   ASSERT_NE(dex_file.get(), nullptr);
-  ASSERT_EQ(HiddenApiAccessFlags::kDarkGreylist, GetSMethodHiddenFlags(*dex_file));
+  ASSERT_EQ(hiddenapi::ApiList::kDarkGreylist, GetSMethodHiddenFlags(*dex_file));
 }
 
 TEST_F(HiddenApiTest, StaticMethodBlacklistMatch) {
@@ -445,7 +455,7 @@
   OpenStream(blacklist) << "LMain;->smethod(Ljava/lang/Object;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
   ASSERT_NE(dex_file.get(), nullptr);
-  ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetSMethodHiddenFlags(*dex_file));
+  ASSERT_EQ(hiddenapi::ApiList::kBlacklist, GetSMethodHiddenFlags(*dex_file));
 }
 
 TEST_F(HiddenApiTest, StaticMethodTwoListsMatch1) {
@@ -482,7 +492,7 @@
   OpenStream(blacklist) << "LMain;->inmethod(LBadType3;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
   ASSERT_NE(dex_file.get(), nullptr);
-  ASSERT_EQ(HiddenApiAccessFlags::kWhitelist, GetINMethodHiddenFlags(*dex_file));
+  ASSERT_EQ(hiddenapi::ApiList::kWhitelist, GetINMethodHiddenFlags(*dex_file));
 }
 
 TEST_F(HiddenApiTest, InstanceNativeMethodLightGreylistMatch) {
@@ -492,7 +502,7 @@
   OpenStream(blacklist) << "LMain;->inmethod(LBadType3;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
   ASSERT_NE(dex_file.get(), nullptr);
-  ASSERT_EQ(HiddenApiAccessFlags::kLightGreylist, GetINMethodHiddenFlags(*dex_file));
+  ASSERT_EQ(hiddenapi::ApiList::kLightGreylist, GetINMethodHiddenFlags(*dex_file));
 }
 
 TEST_F(HiddenApiTest, InstanceNativeMethodDarkGreylistMatch) {
@@ -502,7 +512,7 @@
   OpenStream(blacklist) << "LMain;->inmethod(LBadType3;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
   ASSERT_NE(dex_file.get(), nullptr);
-  ASSERT_EQ(HiddenApiAccessFlags::kDarkGreylist, GetINMethodHiddenFlags(*dex_file));
+  ASSERT_EQ(hiddenapi::ApiList::kDarkGreylist, GetINMethodHiddenFlags(*dex_file));
 }
 
 TEST_F(HiddenApiTest, InstanceNativeMethodBlacklistMatch) {
@@ -512,7 +522,7 @@
   OpenStream(blacklist) << "LMain;->inmethod(C)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
   ASSERT_NE(dex_file.get(), nullptr);
-  ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetINMethodHiddenFlags(*dex_file));
+  ASSERT_EQ(hiddenapi::ApiList::kBlacklist, GetINMethodHiddenFlags(*dex_file));
 }
 
 TEST_F(HiddenApiTest, InstanceNativeMethodTwoListsMatch1) {
@@ -549,7 +559,7 @@
   OpenStream(blacklist) << "LMain;->snmethod(LBadType3;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
   ASSERT_NE(dex_file.get(), nullptr);
-  ASSERT_EQ(HiddenApiAccessFlags::kWhitelist, GetSNMethodHiddenFlags(*dex_file));
+  ASSERT_EQ(hiddenapi::ApiList::kWhitelist, GetSNMethodHiddenFlags(*dex_file));
 }
 
 TEST_F(HiddenApiTest, StaticNativeMethodLightGreylistMatch) {
@@ -559,7 +569,7 @@
   OpenStream(blacklist) << "LMain;->snmethod(LBadType3;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
   ASSERT_NE(dex_file.get(), nullptr);
-  ASSERT_EQ(HiddenApiAccessFlags::kLightGreylist, GetSNMethodHiddenFlags(*dex_file));
+  ASSERT_EQ(hiddenapi::ApiList::kLightGreylist, GetSNMethodHiddenFlags(*dex_file));
 }
 
 TEST_F(HiddenApiTest, StaticNativeMethodDarkGreylistMatch) {
@@ -569,7 +579,7 @@
   OpenStream(blacklist) << "LMain;->snmethod(LBadType3;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
   ASSERT_NE(dex_file.get(), nullptr);
-  ASSERT_EQ(HiddenApiAccessFlags::kDarkGreylist, GetSNMethodHiddenFlags(*dex_file));
+  ASSERT_EQ(hiddenapi::ApiList::kDarkGreylist, GetSNMethodHiddenFlags(*dex_file));
 }
 
 TEST_F(HiddenApiTest, StaticNativeMethodBlacklistMatch) {
@@ -579,7 +589,7 @@
   OpenStream(blacklist) << "LMain;->snmethod(Ljava/lang/Integer;)V" << std::endl;
   auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex);
   ASSERT_NE(dex_file.get(), nullptr);
-  ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetSNMethodHiddenFlags(*dex_file));
+  ASSERT_EQ(hiddenapi::ApiList::kBlacklist, GetSNMethodHiddenFlags(*dex_file));
 }
 
 TEST_F(HiddenApiTest, StaticNativeMethodTwoListsMatch1) {
diff --git a/tools/veridex/hidden_api.h b/tools/veridex/hidden_api.h
index 68485bd..da9f058 100644
--- a/tools/veridex/hidden_api.h
+++ b/tools/veridex/hidden_api.h
@@ -43,22 +43,22 @@
     FillList(whitelist, whitelist_);
   }
 
-  HiddenApiAccessFlags::ApiList GetApiList(const std::string& name) const {
+  hiddenapi::ApiList GetApiList(const std::string& name) const {
     if (IsInList(name, blacklist_)) {
-      return HiddenApiAccessFlags::kBlacklist;
+      return hiddenapi::ApiList::kBlacklist;
     } else if (IsInList(name, dark_greylist_)) {
-      return HiddenApiAccessFlags::kDarkGreylist;
+      return hiddenapi::ApiList::kDarkGreylist;
     } else if (IsInList(name, light_greylist_)) {
-      return HiddenApiAccessFlags::kLightGreylist;
+      return hiddenapi::ApiList::kLightGreylist;
     } else if (IsInList(name, whitelist_)) {
-      return HiddenApiAccessFlags::kWhitelist;
+      return hiddenapi::ApiList::kWhitelist;
     } else {
-      return HiddenApiAccessFlags::kNoList;
+      return hiddenapi::ApiList::kNoList;
     }
   }
 
   bool IsInAnyList(const std::string& name) const {
-    return GetApiList(name) != HiddenApiAccessFlags::kNoList;
+    return GetApiList(name) != hiddenapi::ApiList::kNoList;
   }
 
   static std::string GetApiMethodName(const DexFile& dex_file, uint32_t method_index);
diff --git a/tools/veridex/hidden_api_finder.cc b/tools/veridex/hidden_api_finder.cc
index a8c53b3..e24d151 100644
--- a/tools/veridex/hidden_api_finder.cc
+++ b/tools/veridex/hidden_api_finder.cc
@@ -179,8 +179,8 @@
   // Dump methods from hidden APIs linked against.
   for (const std::pair<const std::string,
                        std::vector<MethodReference>>& pair : method_locations_) {
-    HiddenApiAccessFlags::ApiList api_list = hidden_api_.GetApiList(pair.first);
-    stats->api_counts[api_list]++;
+    hiddenapi::ApiList api_list = hidden_api_.GetApiList(pair.first);
+    stats->api_counts[static_cast<unsigned>(api_list)]++;
     os << "#" << ++stats->count << ": Linking " << api_list << " " << pair.first << " use(s):";
     os << std::endl;
     HiddenApiFinder::DumpReferences(os, pair.second);
@@ -190,8 +190,8 @@
   // Dump fields from hidden APIs linked against.
   for (const std::pair<const std::string,
                        std::vector<MethodReference>>& pair : field_locations_) {
-    HiddenApiAccessFlags::ApiList api_list = hidden_api_.GetApiList(pair.first);
-    stats->api_counts[api_list]++;
+    hiddenapi::ApiList api_list = hidden_api_.GetApiList(pair.first);
+    stats->api_counts[static_cast<unsigned>(api_list)]++;
     os << "#" << ++stats->count << ": Linking " << api_list << " " << pair.first << " use(s):";
     os << std::endl;
     HiddenApiFinder::DumpReferences(os, pair.second);
@@ -203,9 +203,9 @@
     for (const std::string& cls : classes_) {
       for (const std::string& name : strings_) {
         std::string full_name = cls + "->" + name;
-        HiddenApiAccessFlags::ApiList api_list = hidden_api_.GetApiList(full_name);
-        stats->api_counts[api_list]++;
-        if (api_list != HiddenApiAccessFlags::kNoList) {
+        hiddenapi::ApiList api_list = hidden_api_.GetApiList(full_name);
+        stats->api_counts[static_cast<unsigned>(api_list)]++;
+        if (api_list != hiddenapi::ApiList::kNoList) {
           stats->reflection_count++;
           os << "#" << ++stats->count << ": Reflection " << api_list << " " << full_name
              << " potential use(s):";
diff --git a/tools/veridex/precise_hidden_api_finder.cc b/tools/veridex/precise_hidden_api_finder.cc
index 9e02cbf..6aef89f 100644
--- a/tools/veridex/precise_hidden_api_finder.cc
+++ b/tools/veridex/precise_hidden_api_finder.cc
@@ -91,8 +91,8 @@
       std::string cls(info.cls.ToString());
       std::string name(info.name.ToString());
       std::string full_name = cls + "->" + name;
-      HiddenApiAccessFlags::ApiList api_list = hidden_api_.GetApiList(full_name);
-      if (api_list != HiddenApiAccessFlags::kNoList) {
+      hiddenapi::ApiList api_list = hidden_api_.GetApiList(full_name);
+      if (api_list != hiddenapi::ApiList::kNoList) {
         named_uses[full_name].push_back(ref);
       }
     }
@@ -101,8 +101,8 @@
   for (auto& it : named_uses) {
     ++stats->reflection_count;
     const std::string& full_name = it.first;
-    HiddenApiAccessFlags::ApiList api_list = hidden_api_.GetApiList(full_name);
-    stats->api_counts[api_list]++;
+    hiddenapi::ApiList api_list = hidden_api_.GetApiList(full_name);
+    stats->api_counts[static_cast<unsigned>(api_list)]++;
     os << "#" << ++stats->count << ": Reflection " << api_list << " " << full_name << " use(s):";
     os << std::endl;
     for (const MethodReference& ref : it.second) {
diff --git a/tools/veridex/veridex.cc b/tools/veridex/veridex.cc
index 7206c7d..179e391 100644
--- a/tools/veridex/veridex.cc
+++ b/tools/veridex/veridex.cc
@@ -271,16 +271,17 @@
                                const VeridexOptions& options) {
     static const char* kPrefix = "       ";
     if (options.only_report_sdk_uses) {
-      os << stats.api_counts[HiddenApiAccessFlags::kWhitelist] << " SDK API uses." << std::endl;
+      os << stats.api_counts[static_cast<unsigned>(hiddenapi::ApiList::kWhitelist)]
+         << " SDK API uses." << std::endl;
     } else {
       os << stats.count << " hidden API(s) used: "
          << stats.linking_count << " linked against, "
          << stats.reflection_count << " through reflection" << std::endl;
-      os << kPrefix << stats.api_counts[HiddenApiAccessFlags::kBlacklist]
+      os << kPrefix << stats.api_counts[static_cast<unsigned>(hiddenapi::ApiList::kBlacklist)]
          << " in blacklist" << std::endl;
-      os << kPrefix << stats.api_counts[HiddenApiAccessFlags::kDarkGreylist]
+      os << kPrefix << stats.api_counts[static_cast<unsigned>(hiddenapi::ApiList::kDarkGreylist)]
          << " in dark greylist" << std::endl;
-      os << kPrefix << stats.api_counts[HiddenApiAccessFlags::kLightGreylist]
+      os << kPrefix << stats.api_counts[static_cast<unsigned>(hiddenapi::ApiList::kLightGreylist)]
          << " in light greylist" << std::endl;
     }
   }