Add shared separate data section for compact dex

Added a shared dex data buffer for compact dex files, this buffer
is referenced by all compact dex files in a vdex file. Repurposed
the existing data_off / data_size fields in the header.

After the shared buffer is filled up, it is placed after the dex
files in the oat writer and the dex file headers are fixed up to have
the correct offsets / sizes to the shared buffer.

Motivation:
Make it easy to deduplicate data across dexes.

Bug: 63756964
Test: test-art-host
Change-Id: I17855a0c78b20be3d323d12dedb9c695962be3ed
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index b3a92e5..c7e9cda 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -372,6 +372,7 @@
     dex_files_(nullptr),
     vdex_size_(0u),
     vdex_dex_files_offset_(0u),
+    vdex_dex_shared_data_offset_(0u),
     vdex_verifier_deps_offset_(0u),
     vdex_quickening_info_offset_(0u),
     oat_size_(0u),
@@ -3363,6 +3364,54 @@
         return false;
       }
     }
+
+    // Write shared dex file data section and fix up the dex file headers.
+    vdex_dex_shared_data_offset_ = vdex_size_;
+    if (dex_container_ != nullptr) {
+      DexContainer::Section* const section = dex_container_->GetDataSection();
+      if (section->Size() > 0) {
+        const uint32_t shared_data_offset = vdex_size_;
+        const off_t existing_offset = out->Seek(0, kSeekCurrent);
+        if (static_cast<uint32_t>(existing_offset) != shared_data_offset) {
+          LOG(ERROR) << "Expected offset " << shared_data_offset << " but got " << existing_offset;
+          return false;
+        }
+        const uint32_t shared_data_size = section->Size();
+        if (!out->WriteFully(section->Begin(), shared_data_size)) {
+          LOG(ERROR) << "Failed to write shared data!";
+          return false;
+        }
+        // Fix up the dex headers to have correct offsets to the data section.
+        for (OatDexFile& oat_dex_file : oat_dex_files_) {
+          // Overwrite the header by reading it, updating the offset, and writing it back out.
+          DexFile::Header header;
+          if (!file->PreadFully(&header, sizeof(header), oat_dex_file.dex_file_offset_)) {
+            LOG(ERROR) << "Failed to read dex header for updating";
+            return false;
+          }
+          CHECK(CompactDexFile::IsMagicValid(header.magic_)) << "Must be compact dex";
+          CHECK_GT(shared_data_offset, oat_dex_file.dex_file_offset_);
+          // Offset is from the dex file base.
+          header.data_off_ = shared_data_offset - oat_dex_file.dex_file_offset_;
+          // The size should already be what part of the data buffer may be used by the dex.
+          CHECK_LE(header.data_size_, shared_data_size);
+          if (!file->PwriteFully(&header, sizeof(header), oat_dex_file.dex_file_offset_)) {
+            LOG(ERROR) << "Failed to write dex header for updating";
+            return false;
+          }
+        }
+        vdex_size_ += shared_data_size;
+        size_dex_file_ += shared_data_size;
+        section->Clear();
+        if (!out->Flush()) {
+          PLOG(ERROR) << "Failed to flush after writing shared dex section.";
+          return false;
+        }
+      }
+      dex_container_.reset();
+    }
+  } else {
+    vdex_dex_shared_data_offset_ =  vdex_size_;
   }
 
   return true;
@@ -3521,20 +3570,23 @@
   options.compact_dex_level_ = compact_dex_level_;
   options.update_checksum_ = true;
   DexLayout dex_layout(options, profile_compilation_info_, /*file*/ nullptr, /*header*/ nullptr);
-  std::unique_ptr<DexContainer> out_data;
-  dex_layout.ProcessDexFile(location.c_str(), dex_file.get(), 0, &out_data);
+  dex_layout.ProcessDexFile(location.c_str(), dex_file.get(), 0, &dex_container_);
   oat_dex_file->dex_sections_layout_ = dex_layout.GetSections();
   // Dex layout can affect the size of the dex file, so we update here what we have set
   // when adding the dex file as a source.
   const UnalignedDexFileHeader* header =
-      AsUnalignedDexFileHeader(out_data->GetMainSection()->Begin());
+      AsUnalignedDexFileHeader(dex_container_->GetMainSection()->Begin());
   oat_dex_file->dex_file_size_ = header->file_size_;
   if (!WriteDexFile(out,
                     oat_dex_file,
-                    out_data->GetMainSection()->Begin(),
+                    dex_container_->GetMainSection()->Begin(),
                     /* update_input_vdex */ false)) {
     return false;
   }
+  if (dex_container_ != nullptr) {
+    // Clear the main section in case we write more data into the container.
+    dex_container_->GetMainSection()->Clear();
+  }
   CHECK_EQ(oat_dex_file->dex_file_location_checksum_, dex_file->GetLocationChecksum());
   return true;
 }
@@ -3996,12 +4048,14 @@
   DCHECK_NE(vdex_verifier_deps_offset_, 0u);
   DCHECK_NE(vdex_quickening_info_offset_, 0u);
 
-  size_t dex_section_size = vdex_verifier_deps_offset_ - vdex_dex_files_offset_;
+  size_t dex_section_size = vdex_dex_shared_data_offset_ - vdex_dex_files_offset_;
+  size_t dex_shared_data_size = vdex_verifier_deps_offset_ - vdex_dex_shared_data_offset_;
   size_t verifier_deps_section_size = vdex_quickening_info_offset_ - vdex_verifier_deps_offset_;
   size_t quickening_info_section_size = vdex_size_ - vdex_quickening_info_offset_;
 
   VdexFile::Header vdex_header(oat_dex_files_.size(),
                                dex_section_size,
+                               dex_shared_data_size,
                                verifier_deps_section_size,
                                quickening_info_section_size);
   if (!vdex_out->WriteFully(&vdex_header, sizeof(VdexFile::Header))) {
diff --git a/dex2oat/linker/oat_writer.h b/dex2oat/linker/oat_writer.h
index c08c05a..dfcaafc 100644
--- a/dex2oat/linker/oat_writer.h
+++ b/dex2oat/linker/oat_writer.h
@@ -41,6 +41,7 @@
 class BitVector;
 class CompiledMethod;
 class CompilerDriver;
+class DexContainer;
 class ProfileCompilationInfo;
 class TimingLogger;
 class TypeLookupTable;
@@ -382,6 +383,9 @@
   // Offset of section holding Dex files inside Vdex.
   size_t vdex_dex_files_offset_;
 
+  // Offset of section holding shared dex data section in the Vdex.
+  size_t vdex_dex_shared_data_offset_;
+
   // Offset of section holding VerifierDeps inside Vdex.
   size_t vdex_verifier_deps_offset_;
 
@@ -518,6 +522,9 @@
   // This pointer is only non-null after InitOatCodeDexFiles succeeds.
   std::unique_ptr<OrderedMethodList> ordered_methods_;
 
+  // Container of shared dex data.
+  std::unique_ptr<DexContainer> dex_container_;
+
   DISALLOW_COPY_AND_ASSIGN(OatWriter);
 };
 
diff --git a/dexlayout/compact_dex_writer.cc b/dexlayout/compact_dex_writer.cc
index 2f601b6..ef31c3f 100644
--- a/dexlayout/compact_dex_writer.cc
+++ b/dexlayout/compact_dex_writer.cc
@@ -167,6 +167,7 @@
                                                               code_item->GetOffset());
     if (deduped_offset != Deduper::kDidNotDedupe) {
       code_item->SetOffset(deduped_offset);
+      stream->Clear(start_offset, stream->Tell() - start_offset);
       // Undo the offset for all that we wrote since we deduped.
       stream->Seek(start_offset);
     }
@@ -287,9 +288,16 @@
   CHECK(output->IsCompactDexContainer());
   Container* const container = down_cast<Container*>(output);
   // For now, use the same stream for both data and metadata.
-  Stream stream(output->GetMainSection());
-  Stream* main_stream = &stream;
-  Stream* data_stream = &stream;
+  Stream temp_main_stream(output->GetMainSection());
+  Stream temp_data_stream(output->GetDataSection());
+  Stream* main_stream = &temp_main_stream;
+  Stream* data_stream = &temp_data_stream;
+
+  // We want offset 0 to be reserved for null, seek to the data section alignment or the end of the
+  // section.
+  data_stream->Seek(std::max(
+      static_cast<uint32_t>(output->GetDataSection()->Size()),
+      kDataSectionAlignment));
   code_item_dedupe_ = &container->code_item_dedupe_;
 
   // Starting offset is right after the header.
@@ -312,11 +320,9 @@
   WriteCallSiteIds(main_stream, /*reserve_only*/ true);
   WriteMethodHandles(main_stream);
 
-  uint32_t data_offset_ = 0u;
   if (compute_offsets_) {
     // Data section.
     data_stream->AlignTo(kDataSectionAlignment);
-    data_offset_ = data_stream->Tell();
   }
 
   // Write code item first to minimize the space required for encoded methods.
@@ -362,19 +368,9 @@
   } else {
     data_stream->Seek(collection.MapListOffset());
   }
-  GenerateAndWriteMapItems(data_stream);
-  data_stream->AlignTo(kDataSectionAlignment);
 
   // Map items are included in the data section.
-  if (compute_offsets_) {
-    header_->SetDataSize(data_stream->Tell() - data_offset_);
-    if (header_->DataSize() != 0) {
-      // Offset must be zero when the size is zero.
-      header_->SetDataOffset(data_offset_);
-    } else {
-      header_->SetDataOffset(0u);
-    }
-  }
+  GenerateAndWriteMapItems(data_stream);
 
   // Write link data if it exists.
   const std::vector<uint8_t>& link_data = collection.LinkData();
@@ -391,19 +387,39 @@
   // Write debug info offset table last to make dex file verifier happy.
   WriteDebugInfoOffsetTable(data_stream);
 
+  data_stream->AlignTo(kDataSectionAlignment);
+  if (compute_offsets_) {
+    header_->SetDataSize(data_stream->Tell());
+    if (header_->DataSize() != 0) {
+      // Offset must be zero when the size is zero.
+      main_stream->AlignTo(kDataSectionAlignment);
+      // For now, default to saying the data is right after the main stream.
+      header_->SetDataOffset(main_stream->Tell());
+      header_->SetDataOffset(0u);
+    } else {
+      header_->SetDataOffset(0u);
+    }
+  }
+
   // Write header last.
   if (compute_offsets_) {
     header_->SetFileSize(main_stream->Tell());
   }
   WriteHeader(main_stream);
 
+  // Trim sections to make sure they are sized properly.
+  output->GetMainSection()->Resize(header_->FileSize());
+  output->GetDataSection()->Resize(data_stream->Tell());
+
   if (dex_layout_->GetOptions().update_checksum_) {
-    header_->SetChecksum(DexFile::CalculateChecksum(main_stream->Begin(), header_->FileSize()));
+    // Compute the cdex section (also covers the used part of the data section).
+    header_->SetChecksum(CompactDexFile::CalculateChecksum(output->GetMainSection()->Begin(),
+                                                           output->GetMainSection()->Size(),
+                                                           output->GetDataSection()->Begin(),
+                                                           output->GetDataSection()->Size()));
     // Rewrite the header with the calculated checksum.
     WriteHeader(main_stream);
   }
-  // Trim the map to make it sized as large as the dex file.
-  output->GetMainSection()->Resize(header_->FileSize());
 }
 
 std::unique_ptr<DexContainer> CompactDexWriter::CreateDexContainer() const {
diff --git a/dexlayout/dex_container.h b/dexlayout/dex_container.h
index 7c426cb..2b9a5f9 100644
--- a/dexlayout/dex_container.h
+++ b/dexlayout/dex_container.h
@@ -43,6 +43,9 @@
     // Resize the backing storage.
     virtual void Resize(size_t size) = 0;
 
+    // Clear the container.
+    virtual void Clear() = 0;
+
     // Returns the end of the memory region.
     uint8_t* End() {
       return Begin() + Size();
@@ -66,6 +69,10 @@
       data_.resize(size, 0u);
     }
 
+    void Clear() OVERRIDE {
+      data_.clear();
+    }
+
    private:
     std::vector<uint8_t> data_;
   };
diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc
index fb7dff6..1525d53 100644
--- a/dexlayout/dex_ir.cc
+++ b/dexlayout/dex_ir.cc
@@ -280,7 +280,7 @@
     }
     case DexFile::kDexAnnotationArray: {
       EncodedValueVector* values = new EncodedValueVector();
-      const uint32_t offset = *data - dex_file.Begin();
+      const uint32_t offset = *data - dex_file.DataBegin();
       const uint32_t size = DecodeUnsignedLeb128(data);
       // Decode all elements.
       for (uint32_t i = 0; i < size; i++) {
@@ -440,7 +440,7 @@
 AnnotationItem* Collections::CreateAnnotationItem(const DexFile& dex_file,
                                                   const DexFile::AnnotationItem* annotation) {
   const uint8_t* const start_data = reinterpret_cast<const uint8_t*>(annotation);
-  const uint32_t offset = start_data - dex_file.Begin();
+  const uint32_t offset = start_data - dex_file.DataBegin();
   AnnotationItem* annotation_item = annotation_items_map_.GetExistingObject(offset);
   if (annotation_item == nullptr) {
     uint8_t visibility = annotation->visibility_;
@@ -772,8 +772,7 @@
 
 void Collections::CreateCallSitesAndMethodHandles(const DexFile& dex_file) {
   // Iterate through the map list and set the offset of the CallSiteIds and MethodHandleItems.
-  const DexFile::MapList* map =
-      reinterpret_cast<const DexFile::MapList*>(dex_file.Begin() + MapListOffset());
+  const DexFile::MapList* map = dex_file.GetMapList();
   for (uint32_t i = 0; i < map->size_; ++i) {
     const DexFile::MapItem* item = map->list_ + i;
     switch (item->type_) {
@@ -799,7 +798,7 @@
 
 void Collections::CreateCallSiteId(const DexFile& dex_file, uint32_t i) {
   const DexFile::CallSiteIdItem& disk_call_site_id = dex_file.GetCallSiteId(i);
-  const uint8_t* disk_call_item_ptr = dex_file.Begin() + disk_call_site_id.data_off_;
+  const uint8_t* disk_call_item_ptr = dex_file.DataBegin() + disk_call_site_id.data_off_;
   EncodedArrayItem* call_site_item =
       CreateEncodedArrayItem(dex_file, disk_call_item_ptr, disk_call_site_id.data_off_);
 
diff --git a/dexlayout/dex_ir_builder.cc b/dexlayout/dex_ir_builder.cc
index 231826b..3ec163ce 100644
--- a/dexlayout/dex_ir_builder.cc
+++ b/dexlayout/dex_ir_builder.cc
@@ -83,8 +83,8 @@
 
   // Load the link data if it exists.
   collections.SetLinkData(std::vector<uint8_t>(
-      dex_file.Begin() + dex_file.GetHeader().link_off_,
-      dex_file.Begin() + dex_file.GetHeader().link_off_ + dex_file.GetHeader().link_size_));
+      dex_file.DataBegin() + dex_file.GetHeader().link_off_,
+      dex_file.DataBegin() + dex_file.GetHeader().link_off_ + dex_file.GetHeader().link_size_));
 
   return header;
 }
@@ -92,8 +92,7 @@
 static void CheckAndSetRemainingOffsets(const DexFile& dex_file, Collections* collections) {
   const DexFile::Header& disk_header = dex_file.GetHeader();
   // Read MapItems and validate/set remaining offsets.
-  const DexFile::MapList* map =
-      reinterpret_cast<const DexFile::MapList*>(dex_file.Begin() + disk_header.map_off_);
+  const DexFile::MapList* map = dex_file.GetMapList();
   const uint32_t count = map->size_;
   for (uint32_t i = 0; i < count; ++i) {
     const DexFile::MapItem* item = map->list_ + i;
diff --git a/dexlayout/dex_writer.cc b/dexlayout/dex_writer.cc
index eb038a0..67d0f9a 100644
--- a/dexlayout/dex_writer.cc
+++ b/dexlayout/dex_writer.cc
@@ -30,6 +30,8 @@
 
 namespace art {
 
+constexpr uint32_t DexWriter::kDataSectionAlignment;
+
 static size_t EncodeIntValue(int32_t value, uint8_t* buffer) {
   size_t length = 0;
   if (value >= 0) {
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index d33a0bd..1b32f7b 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -1838,13 +1838,17 @@
     }
   }
   DexWriter::Output(this, dex_container, compute_offsets);
-  DexContainer* const container = dex_container->get();
-  DexContainer::Section* const main_section = container->GetMainSection();
-  DexContainer::Section* const data_section = container->GetDataSection();
-  CHECK_EQ(data_section->Size(), 0u) << "Unsupported";
   if (new_file != nullptr) {
+    DexContainer* const container = dex_container->get();
+    DexContainer::Section* const main_section = container->GetMainSection();
     if (!new_file->WriteFully(main_section->Begin(), main_section->Size())) {
-      LOG(ERROR) << "Failed tow write dex file to " << dex_file_location;
+      LOG(ERROR) << "Failed to write main section for dex file " << dex_file_location;
+      new_file->Erase();
+      return;
+    }
+    DexContainer::Section* const data_section = container->GetDataSection();
+    if (!new_file->WriteFully(data_section->Begin(), data_section->Size())) {
+      LOG(ERROR) << "Failed to write data section for dex file " << dex_file_location;
       new_file->Erase();
       return;
     }
@@ -1919,17 +1923,22 @@
       // Dex file verifier cannot handle compact dex.
       bool verify = options_.compact_dex_level_ == CompactDexLevel::kCompactDexLevelNone;
       const ArtDexFileLoader dex_file_loader;
-      DexContainer::Section* section = (*dex_container)->GetMainSection();
-      DCHECK_EQ(file_size, section->Size());
+      DexContainer::Section* const main_section = (*dex_container)->GetMainSection();
+      DexContainer::Section* const data_section = (*dex_container)->GetDataSection();
+      DCHECK_EQ(file_size, main_section->Size())
+          << main_section->Size() << " " << data_section->Size();
       std::unique_ptr<const DexFile> output_dex_file(
-          dex_file_loader.Open(section->Begin(),
-                               file_size,
-                               location,
-                               /* checksum */ 0,
-                               /*oat_dex_file*/ nullptr,
-                               verify,
-                               /*verify_checksum*/ false,
-                               &error_msg));
+          dex_file_loader.OpenWithDataSection(
+              main_section->Begin(),
+              main_section->Size(),
+              data_section->Begin(),
+              data_section->Size(),
+              location,
+              /* checksum */ 0,
+              /*oat_dex_file*/ nullptr,
+              verify,
+              /*verify_checksum*/ false,
+              &error_msg));
       CHECK(output_dex_file != nullptr) << "Failed to re-open output file:" << error_msg;
 
       // Do IR-level comparison between input and output. This check ignores potential differences
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index f2a69f3..f7151b3 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -1156,6 +1156,7 @@
       // Vdex unquicken output should match original input bytecode
       uint32_t orig_checksum =
           reinterpret_cast<DexFile::Header*>(const_cast<uint8_t*>(dex_file->Begin()))->checksum_;
+      CHECK_EQ(orig_checksum, dex_file->CalculateChecksum());
       if (orig_checksum != dex_file->CalculateChecksum()) {
         os << "Unexpected checksum from unquicken dex file '" << dex_file_location << "'\n";
         return false;
@@ -1208,7 +1209,11 @@
       return false;
     }
 
-    if (!file->WriteFully(dex_file->Begin(), fsize)) {
+    bool success = false;
+      success = file->WriteFully(dex_file->Begin(), fsize);
+    // }
+
+    if (!success) {
       os << "Failed to write dex file";
       file->Erase();
       return false;
diff --git a/openjdkjvmti/fixed_up_dex_file.cc b/openjdkjvmti/fixed_up_dex_file.cc
index 323137a..cc56a7b 100644
--- a/openjdkjvmti/fixed_up_dex_file.cc
+++ b/openjdkjvmti/fixed_up_dex_file.cc
@@ -70,8 +70,21 @@
 std::unique_ptr<FixedUpDexFile> FixedUpDexFile::Create(const art::DexFile& original) {
   // Copy the data into mutable memory.
   std::vector<unsigned char> data;
-  data.resize(original.Size());
-  memcpy(data.data(), original.Begin(), original.Size());
+  if (original.IsCompactDexFile()) {
+    // Compact dex has a separate data section that is relative from the original dex.
+    // We need to copy the shared data section so that dequickening doesn't change anything.
+    data.resize(original.Size() + original.DataSize());
+    memcpy(data.data(), original.Begin(), original.Size());
+    memcpy(data.data() + original.Size(), original.DataBegin(), original.DataSize());
+    // Go patch up the header to point to the copied data section.
+    art::CompactDexFile::Header* const header =
+        const_cast<art::CompactDexFile::Header*>(art::CompactDexFile::Header::At(data.data()));
+    header->data_off_ = original.Size();
+    header->data_size_ = original.DataSize();
+  } else {
+    data.resize(original.Size());
+    memcpy(data.data(), original.Begin(), original.Size());
+  }
   std::string error;
   const art::ArtDexFileLoader dex_file_loader;
   std::unique_ptr<const art::DexFile> new_dex_file(dex_file_loader.Open(
@@ -105,6 +118,7 @@
                               0,
                               &dex_container);
     art::DexContainer::Section* main_section = dex_container->GetMainSection();
+    CHECK_EQ(dex_container->GetDataSection()->Size(), 0u);
     // Overwrite the dex file stored in data with the new result.
     data.clear();
     data.insert(data.end(), main_section->Begin(), main_section->End());
diff --git a/runtime/dex/art_dex_file_loader.cc b/runtime/dex/art_dex_file_loader.cc
index dee736e..08cf30d 100644
--- a/runtime/dex/art_dex_file_loader.cc
+++ b/runtime/dex/art_dex_file_loader.cc
@@ -154,6 +154,8 @@
   ScopedTrace trace(std::string("Open dex file from RAM ") + location);
   return OpenCommon(base,
                     size,
+                    /*data_base*/ nullptr,
+                    /*data_size*/ 0u,
                     location,
                     location_checksum,
                     oat_dex_file,
@@ -182,6 +184,8 @@
 
   std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
                                                  map->Size(),
+                                                 /*data_base*/ nullptr,
+                                                 /*data_size*/ 0u,
                                                  location,
                                                  location_checksum,
                                                  kNoOatDexFile,
@@ -303,6 +307,8 @@
 
   std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
                                                  map->Size(),
+                                                 /*data_base*/ nullptr,
+                                                 /*data_size*/ 0u,
                                                  location,
                                                  dex_header->checksum_,
                                                  kNoOatDexFile,
@@ -370,6 +376,8 @@
   VerifyResult verify_result;
   std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
                                                  map->Size(),
+                                                 /*data_base*/ nullptr,
+                                                 /*data_size*/ 0u,
                                                  location,
                                                  zip_entry->GetCrc32(),
                                                  kNoOatDexFile,
diff --git a/runtime/dex/code_item_accessors-no_art-inl.h b/runtime/dex/code_item_accessors-no_art-inl.h
index 6a99009..a243a4a 100644
--- a/runtime/dex/code_item_accessors-no_art-inl.h
+++ b/runtime/dex/code_item_accessors-no_art-inl.h
@@ -50,7 +50,7 @@
 inline void CodeItemInstructionAccessor::Init(const DexFile& dex_file,
                                               const DexFile::CodeItem* code_item) {
   if (code_item != nullptr) {
-    DCHECK(dex_file.HasAddress(code_item));
+    DCHECK(dex_file.IsInDataSection(code_item));
     if (dex_file.IsCompactDexFile()) {
       Init(down_cast<const CompactDexFile::CodeItem&>(*code_item));
     } else {
diff --git a/runtime/dex/code_item_accessors_test.cc b/runtime/dex/code_item_accessors_test.cc
index 3380be8..8e2548b 100644
--- a/runtime/dex/code_item_accessors_test.cc
+++ b/runtime/dex/code_item_accessors_test.cc
@@ -39,8 +39,12 @@
                            &error_msg));
   CHECK(map != nullptr) << error_msg;
   if (compact_dex) {
-    CompactDexFile::WriteMagic(map->Begin());
-    CompactDexFile::WriteCurrentVersion(map->Begin());
+    CompactDexFile::Header* header =
+        const_cast<CompactDexFile::Header*>(CompactDexFile::Header::At(map->Begin()));
+    CompactDexFile::WriteMagic(header->magic_);
+    CompactDexFile::WriteCurrentVersion(header->magic_);
+    header->data_off_ = 0;
+    header->data_size_ = map->Size();
   } else {
     StandardDexFile::WriteMagic(map->Begin());
     StandardDexFile::WriteCurrentVersion(map->Begin());
diff --git a/runtime/dex/compact_dex_file.cc b/runtime/dex/compact_dex_file.cc
index ff193ff..37f5d00 100644
--- a/runtime/dex/compact_dex_file.cc
+++ b/runtime/dex/compact_dex_file.cc
@@ -56,27 +56,52 @@
 }
 
 uint32_t CompactDexFile::GetCodeItemSize(const DexFile::CodeItem& item) const {
-  // TODO: Clean up this temporary code duplication with StandardDexFile. Eventually the
-  // implementations will differ.
-  DCHECK(HasAddress(&item));
+  DCHECK(IsInDataSection(&item));
   return reinterpret_cast<uintptr_t>(CodeItemDataAccessor(*this, &item).CodeItemDataEnd()) -
       reinterpret_cast<uintptr_t>(&item);
 }
 
+
+uint32_t CompactDexFile::CalculateChecksum(const uint8_t* base_begin,
+                                           size_t base_size,
+                                           const uint8_t* data_begin,
+                                           size_t data_size) {
+  Header temp_header(*Header::At(base_begin));
+  // Zero out fields that are not included in the sum.
+  temp_header.checksum_ = 0u;
+  temp_header.data_off_ = 0u;
+  temp_header.data_size_ = 0u;
+  uint32_t checksum = ChecksumMemoryRange(reinterpret_cast<const uint8_t*>(&temp_header),
+                                          sizeof(temp_header));
+  // Exclude the header since we already computed it's checksum.
+  checksum = (checksum * 31) ^ ChecksumMemoryRange(base_begin + sizeof(temp_header),
+                                                   base_size - sizeof(temp_header));
+  checksum = (checksum * 31) ^ ChecksumMemoryRange(data_begin, data_size);
+  return checksum;
+}
+
+uint32_t CompactDexFile::CalculateChecksum() const {
+  return CalculateChecksum(Begin(), Size(), DataBegin(), DataSize());
+}
+
 CompactDexFile::CompactDexFile(const uint8_t* base,
                                size_t size,
+                               const uint8_t* data_begin,
+                               size_t data_size,
                                const std::string& location,
                                uint32_t location_checksum,
                                const OatDexFile* oat_dex_file,
                                DexFileContainer* container)
     : DexFile(base,
               size,
+              data_begin,
+              data_size,
               location,
               location_checksum,
               oat_dex_file,
               container,
               /*is_compact_dex*/ true),
-      debug_info_offsets_(Begin() + GetHeader().debug_info_offsets_pos_,
+      debug_info_offsets_(DataBegin() + GetHeader().debug_info_offsets_pos_,
                           GetHeader().debug_info_base_,
                           GetHeader().debug_info_offsets_table_offset_) {}
 
diff --git a/runtime/dex/compact_dex_file.h b/runtime/dex/compact_dex_file.h
index 8dad84d..1ecff04 100644
--- a/runtime/dex/compact_dex_file.h
+++ b/runtime/dex/compact_dex_file.h
@@ -35,10 +35,22 @@
 
   class Header : public DexFile::Header {
    public:
+    static const Header* At(const void* at) {
+      return reinterpret_cast<const Header*>(at);
+    }
+
     uint32_t GetFeatureFlags() const {
       return feature_flags_;
     }
 
+    uint32_t GetDataOffset() const {
+      return data_off_;
+    }
+
+    uint32_t GetDataSize() const {
+      return data_size_;
+    }
+
    private:
     uint32_t feature_flags_ = 0u;
 
@@ -245,9 +257,17 @@
     return debug_info_offsets_.GetDebugInfoOffset(dex_method_index);
   }
 
+  static uint32_t CalculateChecksum(const uint8_t* base_begin,
+                                    size_t base_size,
+                                    const uint8_t* data_begin,
+                                    size_t data_size);
+  virtual uint32_t CalculateChecksum() const OVERRIDE;
+
  private:
   CompactDexFile(const uint8_t* base,
                  size_t size,
+                 const uint8_t* data_begin,
+                 size_t data_size,
                  const std::string& location,
                  uint32_t location_checksum,
                  const OatDexFile* oat_dex_file,
diff --git a/runtime/dex/dex_file-inl.h b/runtime/dex/dex_file-inl.h
index 9b14514..aa53daa 100644
--- a/runtime/dex/dex_file-inl.h
+++ b/runtime/dex/dex_file-inl.h
@@ -29,14 +29,14 @@
 namespace art {
 
 inline int32_t DexFile::GetStringLength(const StringId& string_id) const {
-  const uint8_t* ptr = begin_ + string_id.string_data_off_;
+  const uint8_t* ptr = DataBegin() + string_id.string_data_off_;
   return DecodeUnsignedLeb128(&ptr);
 }
 
 inline const char* DexFile::GetStringDataAndUtf16Length(const StringId& string_id,
                                                         uint32_t* utf16_length) const {
   DCHECK(utf16_length != nullptr) << GetLocation();
-  const uint8_t* ptr = begin_ + string_id.string_data_off_;
+  const uint8_t* ptr = DataBegin() + string_id.string_data_off_;
   *utf16_length = DecodeUnsignedLeb128(&ptr);
   return reinterpret_cast<const char*>(ptr);
 }
diff --git a/runtime/dex/dex_file.cc b/runtime/dex/dex_file.cc
index 16325b8..6ec997c 100644
--- a/runtime/dex/dex_file.cc
+++ b/runtime/dex/dex_file.cc
@@ -50,9 +50,12 @@
 }
 
 uint32_t DexFile::CalculateChecksum(const uint8_t* begin, size_t size) {
-  const uint32_t non_sum = OFFSETOF_MEMBER(DexFile::Header, signature_);
-  const uint8_t* non_sum_ptr = begin + non_sum;
-  return adler32(adler32(0L, Z_NULL, 0), non_sum_ptr, size - non_sum);
+  const uint32_t non_sum_bytes = OFFSETOF_MEMBER(DexFile::Header, signature_);
+  return ChecksumMemoryRange(begin + non_sum_bytes, size - non_sum_bytes);
+}
+
+uint32_t DexFile::ChecksumMemoryRange(const uint8_t* begin, size_t size) {
+  return adler32(adler32(0L, Z_NULL, 0), begin, size);
 }
 
 int DexFile::GetPermissions() const {
@@ -77,6 +80,8 @@
 
 DexFile::DexFile(const uint8_t* base,
                  size_t size,
+                 const uint8_t* data_begin,
+                 size_t data_size,
                  const std::string& location,
                  uint32_t location_checksum,
                  const OatDexFile* oat_dex_file,
@@ -84,6 +89,8 @@
                  bool is_compact_dex)
     : begin_(base),
       size_(size),
+      data_begin_(data_begin),
+      data_size_(data_size),
       location_(location),
       location_checksum_(location_checksum),
       header_(reinterpret_cast<const Header*>(base)),
@@ -149,7 +156,7 @@
 }
 
 void DexFile::InitializeSectionsFromMapList() {
-  const MapList* map_list = reinterpret_cast<const MapList*>(begin_ + header_->map_off_);
+  const MapList* map_list = reinterpret_cast<const MapList*>(DataBegin() + header_->map_off_);
   if (header_->map_off_ == 0 || header_->map_off_ > size_) {
     // Bad offset. The dex file verifier runs after this method and will reject the file.
     return;
@@ -166,10 +173,10 @@
   for (size_t i = 0; i < count; ++i) {
     const MapItem& map_item = map_list->list_[i];
     if (map_item.type_ == kDexTypeMethodHandleItem) {
-      method_handles_ = reinterpret_cast<const MethodHandleItem*>(begin_ + map_item.offset_);
+      method_handles_ = reinterpret_cast<const MethodHandleItem*>(DataBegin() + map_item.offset_);
       num_method_handles_ = map_item.size_;
     } else if (map_item.type_ == kDexTypeCallSiteIdItem) {
-      call_site_ids_ = reinterpret_cast<const CallSiteIdItem*>(begin_ + map_item.offset_);
+      call_site_ids_ = reinterpret_cast<const CallSiteIdItem*>(DataBegin() + map_item.offset_);
       num_call_site_ids_ = map_item.size_;
     }
   }
diff --git a/runtime/dex/dex_file.h b/runtime/dex/dex_file.h
index 511ce31..ef25797 100644
--- a/runtime/dex/dex_file.h
+++ b/runtime/dex/dex_file.h
@@ -646,11 +646,7 @@
   const ClassDef* FindClassDef(dex::TypeIndex type_idx) const;
 
   const TypeList* GetInterfacesList(const ClassDef& class_def) const {
-    if (class_def.interfaces_off_ == 0) {
-      return nullptr;
-    }
-    const uint8_t* addr = begin_ + class_def.interfaces_off_;
-    return reinterpret_cast<const TypeList*>(addr);
+    return DataPointer<TypeList>(class_def.interfaces_off_);
   }
 
   uint32_t NumMethodHandles() const {
@@ -673,17 +669,13 @@
 
   // Returns a pointer to the raw memory mapped class_data_item
   const uint8_t* GetClassData(const ClassDef& class_def) const {
-    return (class_def.class_data_off_ == 0) ? nullptr : begin_ + class_def.class_data_off_;
+    return DataPointer<uint8_t>(class_def.class_data_off_);
   }
 
-  //
+  // Return the code item for a provided offset.
   const CodeItem* GetCodeItem(const uint32_t code_off) const {
-    DCHECK_LT(code_off, size_) << "Code item offset larger then maximum allowed offset";
-    if (code_off == 0) {
-      return nullptr;  // native or abstract method
-    }
-    const uint8_t* addr = begin_ + code_off;
-    return reinterpret_cast<const CodeItem*>(addr);
+    // May be null for native or abstract methods.
+    return DataPointer<CodeItem>(code_off);
   }
 
   const char* GetReturnTypeDescriptor(const ProtoId& proto_id) const;
@@ -728,17 +720,15 @@
   const char* GetShorty(uint32_t proto_idx) const;
 
   const TypeList* GetProtoParameters(const ProtoId& proto_id) const {
-    return (proto_id.parameters_off_ == 0)
-        ? nullptr
-        : reinterpret_cast<const TypeList*>(begin_ + proto_id.parameters_off_);
+    return DataPointer<TypeList>(proto_id.parameters_off_);
   }
 
   const uint8_t* GetEncodedStaticFieldValuesArray(const ClassDef& class_def) const {
-    return (class_def.static_values_off_ == 0) ? 0 : begin_ + class_def.static_values_off_;
+    return DataPointer<uint8_t>(class_def.static_values_off_);
   }
 
   const uint8_t* GetCallSiteEncodedValuesArray(const CallSiteIdItem& call_site_id) const {
-    return begin_ + call_site_id.data_off_;
+    return DataBegin() + call_site_id.data_off_;
   }
 
   static const TryItem* GetTryItems(const DexInstructionIterator& code_item_end, uint32_t offset);
@@ -756,7 +746,9 @@
     // Check that the offset is in bounds.
     // Note that although the specification says that 0 should be used if there
     // is no debug information, some applications incorrectly use 0xFFFFFFFF.
-    return (debug_info_off == 0 || debug_info_off >= size_) ? nullptr : begin_ + debug_info_off;
+    return (debug_info_off == 0 || debug_info_off >= data_size_)
+        ? nullptr
+        : DataBegin() + debug_info_off;
   }
 
   struct PositionInfo {
@@ -787,21 +779,17 @@
   static bool LineNumForPcCb(void* context, const PositionInfo& entry);
 
   const AnnotationsDirectoryItem* GetAnnotationsDirectory(const ClassDef& class_def) const {
-    return (class_def.annotations_off_ == 0)
-        ? nullptr
-        : reinterpret_cast<const AnnotationsDirectoryItem*>(begin_ + class_def.annotations_off_);
+    return DataPointer<AnnotationsDirectoryItem>(class_def.annotations_off_);
   }
 
   const AnnotationSetItem* GetClassAnnotationSet(const AnnotationsDirectoryItem* anno_dir) const {
-    return (anno_dir->class_annotations_off_ == 0)
-        ? nullptr
-        : reinterpret_cast<const AnnotationSetItem*>(begin_ + anno_dir->class_annotations_off_);
+    return DataPointer<AnnotationSetItem>(anno_dir->class_annotations_off_);
   }
 
   const FieldAnnotationsItem* GetFieldAnnotations(const AnnotationsDirectoryItem* anno_dir) const {
     return (anno_dir->fields_size_ == 0)
-        ? nullptr
-        : reinterpret_cast<const FieldAnnotationsItem*>(&anno_dir[1]);
+         ? nullptr
+         : reinterpret_cast<const FieldAnnotationsItem*>(&anno_dir[1]);
   }
 
   const MethodAnnotationsItem* GetMethodAnnotations(const AnnotationsDirectoryItem* anno_dir)
@@ -828,33 +816,21 @@
   }
 
   const AnnotationSetItem* GetFieldAnnotationSetItem(const FieldAnnotationsItem& anno_item) const {
-    uint32_t offset = anno_item.annotations_off_;
-    return (offset == 0)
-        ? nullptr
-        : reinterpret_cast<const AnnotationSetItem*>(begin_ + offset);
+    return DataPointer<AnnotationSetItem>(anno_item.annotations_off_);
   }
 
   const AnnotationSetItem* GetMethodAnnotationSetItem(const MethodAnnotationsItem& anno_item)
       const {
-    uint32_t offset = anno_item.annotations_off_;
-    return (offset == 0)
-        ? nullptr
-        : reinterpret_cast<const AnnotationSetItem*>(begin_ + offset);
+    return DataPointer<AnnotationSetItem>(anno_item.annotations_off_);
   }
 
   const AnnotationSetRefList* GetParameterAnnotationSetRefList(
       const ParameterAnnotationsItem* anno_item) const {
-    uint32_t offset = anno_item->annotations_off_;
-    return (offset == 0)
-        ? nullptr
-        : reinterpret_cast<const AnnotationSetRefList*>(begin_ + offset);
+    return DataPointer<AnnotationSetRefList>(anno_item->annotations_off_);
   }
 
   ALWAYS_INLINE const AnnotationItem* GetAnnotationItemAtOffset(uint32_t offset) const {
-    DCHECK_LE(offset, Size());
-    return (offset == 0)
-        ? nullptr
-        : reinterpret_cast<const AnnotationItem*>(begin_ + offset);
+    return DataPointer<AnnotationItem>(offset);
   }
 
   const AnnotationItem* GetAnnotationItem(const AnnotationSetItem* set_item, uint32_t index) const {
@@ -863,10 +839,7 @@
   }
 
   const AnnotationSetItem* GetSetRefItemItem(const AnnotationSetRefItem* anno_item) const {
-    uint32_t offset = anno_item->annotations_off_;
-    return (offset == 0)
-        ? nullptr
-        : reinterpret_cast<const AnnotationSetItem*>(begin_ + offset);
+    return DataPointer<AnnotationSetItem>(anno_item->annotations_off_);
   }
 
   // Debug info opcodes and constants
@@ -955,6 +928,20 @@
     return size_;
   }
 
+  const uint8_t* DataBegin() const {
+    return data_begin_;
+  }
+
+  size_t DataSize() const {
+    return data_size_;
+  }
+
+  template <typename T>
+  const T* DataPointer(size_t offset) const {
+    DCHECK_LT(offset, DataSize()) << "Offset past end of data section";
+    return (offset != 0u) ? reinterpret_cast<const T*>(DataBegin() + offset) : nullptr;
+  }
+
   const OatDexFile* GetOatDexFile() const {
     return oat_dex_file_;
   }
@@ -964,6 +951,11 @@
     oat_dex_file_ = oat_dex_file;
   }
 
+  // Read MapItems and validate/set remaining offsets.
+  const DexFile::MapList* GetMapList() const {
+    return reinterpret_cast<const DexFile::MapList*>(DataBegin() + header_->map_off_);
+  }
+
   // Utility methods for reading integral values from a buffer.
   static int32_t ReadSignedInt(const uint8_t* ptr, int zwidth);
   static uint32_t ReadUnsignedInt(const uint8_t* ptr, int zwidth, bool fill_on_right);
@@ -971,8 +963,9 @@
   static uint64_t ReadUnsignedLong(const uint8_t* ptr, int zwidth, bool fill_on_right);
 
   // Recalculates the checksum of the dex file. Does not use the current value in the header.
-  uint32_t CalculateChecksum() const;
+  virtual uint32_t CalculateChecksum() const;
   static uint32_t CalculateChecksum(const uint8_t* begin, size_t size);
+  static uint32_t ChecksumMemoryRange(const uint8_t* begin, size_t size);
 
   // Returns a human-readable form of the method at an index.
   std::string PrettyMethod(uint32_t method_idx, bool with_signature = true) const;
@@ -991,10 +984,14 @@
   ALWAYS_INLINE const StandardDexFile* AsStandardDexFile() const;
   ALWAYS_INLINE const CompactDexFile* AsCompactDexFile() const;
 
-  bool HasAddress(const void* addr) const {
+  bool IsInMainSection(const void* addr) const {
     return Begin() <= addr && addr < Begin() + Size();
   }
 
+  bool IsInDataSection(const void* addr) const {
+    return DataBegin() <= addr && addr < DataBegin() + DataSize();
+  }
+
   DexFileContainer* GetContainer() const {
     return container_.get();
   }
@@ -1005,6 +1002,8 @@
 
   DexFile(const uint8_t* base,
           size_t size,
+          const uint8_t* data_begin,
+          size_t data_size,
           const std::string& location,
           uint32_t location_checksum,
           const OatDexFile* oat_dex_file,
@@ -1026,6 +1025,12 @@
   // The size of the underlying memory allocation in bytes.
   const size_t size_;
 
+  // The base address of the data section (same as Begin() for standard dex).
+  const uint8_t* const data_begin_;
+
+  // The size of the data section.
+  const size_t data_size_;
+
   // Typically the dex file name when available, alternatively some identifying string.
   //
   // The ClassLinker will use this to match DexFiles the boot class
diff --git a/runtime/dex/dex_file_loader.cc b/runtime/dex/dex_file_loader.cc
index ccad19f..7dde0a4 100644
--- a/runtime/dex/dex_file_loader.cc
+++ b/runtime/dex/dex_file_loader.cc
@@ -222,6 +222,33 @@
                                                    std::string* error_msg) const {
   return OpenCommon(base,
                     size,
+                    /*data_base*/ base,
+                    /*data_size*/ size,
+                    location,
+                    location_checksum,
+                    oat_dex_file,
+                    verify,
+                    verify_checksum,
+                    error_msg,
+                    /*container*/ nullptr,
+                    /*verify_result*/ nullptr);
+}
+
+std::unique_ptr<const DexFile> DexFileLoader::OpenWithDataSection(
+    const uint8_t* base,
+    size_t size,
+    const uint8_t* data_base,
+    size_t data_size,
+    const std::string& location,
+    uint32_t location_checksum,
+    const OatDexFile* oat_dex_file,
+    bool verify,
+    bool verify_checksum,
+    std::string* error_msg) const {
+  return OpenCommon(base,
+                    size,
+                    data_base,
+                    data_size,
                     location,
                     location_checksum,
                     oat_dex_file,
@@ -278,6 +305,8 @@
 
 std::unique_ptr<DexFile> DexFileLoader::OpenCommon(const uint8_t* base,
                                                    size_t size,
+                                                   const uint8_t* data_base,
+                                                   size_t data_size,
                                                    const std::string& location,
                                                    uint32_t location_checksum,
                                                    const OatDexFile* oat_dex_file,
@@ -291,11 +320,32 @@
   }
   std::unique_ptr<DexFile> dex_file;
   if (StandardDexFile::IsMagicValid(base)) {
-    dex_file.reset(
-        new StandardDexFile(base, size, location, location_checksum, oat_dex_file, container));
+    if (data_size != 0) {
+      CHECK_EQ(base, data_base) << "Unsupported for standard dex";
+    }
+    dex_file.reset(new StandardDexFile(base,
+                                       size,
+                                       location,
+                                       location_checksum,
+                                       oat_dex_file,
+                                       container));
   } else if (CompactDexFile::IsMagicValid(base)) {
-    dex_file.reset(
-        new CompactDexFile(base, size, location, location_checksum, oat_dex_file, container));
+    if (data_base == nullptr) {
+      // TODO: Is there a clean way to support both an explicit data section and reading the one
+      // from the header.
+      CHECK_EQ(data_size, 0u);
+      const CompactDexFile::Header* const header = CompactDexFile::Header::At(base);
+      data_base = base + header->data_off_;
+      data_size = header->data_size_;
+    }
+    dex_file.reset(new CompactDexFile(base,
+                                      size,
+                                      data_base,
+                                      data_size,
+                                      location,
+                                      location_checksum,
+                                      oat_dex_file,
+                                      container));
   }
   if (dex_file == nullptr) {
     *error_msg = StringPrintf("Failed to open dex file '%s' from memory: %s", location.c_str(),
@@ -353,6 +403,8 @@
   VerifyResult verify_result;
   std::unique_ptr<const DexFile> dex_file = OpenCommon(map.data(),
                                                        map.size(),
+                                                       /*data_base*/ nullptr,
+                                                       /*data_size*/ 0u,
                                                        location,
                                                        zip_entry->GetCrc32(),
                                                        /*oat_dex_file*/ nullptr,
diff --git a/runtime/dex/dex_file_loader.h b/runtime/dex/dex_file_loader.h
index 05a51d0..508397c 100644
--- a/runtime/dex/dex_file_loader.h
+++ b/runtime/dex/dex_file_loader.h
@@ -120,6 +120,20 @@
                                               bool verify_checksum,
                                               std::string* error_msg) const;
 
+  // Open a dex file with a separate data section.
+  virtual std::unique_ptr<const DexFile> OpenWithDataSection(
+      const uint8_t* base,
+      size_t size,
+      const uint8_t* data_base,
+      size_t data_size,
+      const std::string& location,
+      uint32_t location_checksum,
+      const OatDexFile* oat_dex_file,
+      bool verify,
+      bool verify_checksum,
+      std::string* error_msg) const;
+
+
   // Opens all .dex files found in the memory map, guessing the container format based on file
   // extension.
   virtual bool OpenAll(const uint8_t* base,
@@ -148,6 +162,8 @@
 
   static std::unique_ptr<DexFile> OpenCommon(const uint8_t* base,
                                              size_t size,
+                                             const uint8_t* data_base,
+                                             size_t data_size,
                                              const std::string& location,
                                              uint32_t location_checksum,
                                              const OatDexFile* oat_dex_file,
diff --git a/runtime/dex/standard_dex_file.cc b/runtime/dex/standard_dex_file.cc
index 52fdff3..024f73b 100644
--- a/runtime/dex/standard_dex_file.cc
+++ b/runtime/dex/standard_dex_file.cc
@@ -73,10 +73,7 @@
 }
 
 uint32_t StandardDexFile::GetCodeItemSize(const DexFile::CodeItem& item) const {
-  DCHECK(HasAddress(&item));
-  // TODO: Clean up this temporary code duplication with StandardDexFile. Eventually the
-  // implementations will differ.
-  DCHECK(HasAddress(&item));
+  DCHECK(IsInDataSection(&item));
   return reinterpret_cast<uintptr_t>(CodeItemDataAccessor(*this, &item).CodeItemDataEnd()) -
       reinterpret_cast<uintptr_t>(&item);
 }
diff --git a/runtime/dex/standard_dex_file.h b/runtime/dex/standard_dex_file.h
index 6437def..94ef1f2 100644
--- a/runtime/dex/standard_dex_file.h
+++ b/runtime/dex/standard_dex_file.h
@@ -92,6 +92,8 @@
                   DexFileContainer* container)
       : DexFile(base,
                 size,
+                /*data_begin*/ base,
+                /*data_size*/ size,
                 location,
                 location_checksum,
                 oat_dex_file,
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 9fd9905..307f7b9 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -1653,7 +1653,12 @@
     if (lookup_table_data_ + TypeLookupTable::RawDataLength(num_class_defs) > GetOatFile()->End()) {
       LOG(WARNING) << "found truncated lookup table in " << dex_file_location_;
     } else {
-      lookup_table_ = TypeLookupTable::Open(dex_file_pointer_, lookup_table_data_, num_class_defs);
+      const uint8_t* dex_data = dex_file_pointer_;
+      // TODO: Clean this up to create the type lookup table after the dex file has been created?
+      if (CompactDexFile::IsMagicValid(dex_header->magic_)) {
+        dex_data += dex_header->data_off_;
+      }
+      lookup_table_ = TypeLookupTable::Open(dex_data, lookup_table_data_, num_class_defs);
     }
   }
 }
@@ -1733,9 +1738,17 @@
                                                            size_t hash) {
   const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
   DCHECK_EQ(ComputeModifiedUtf8Hash(descriptor), hash);
+  bool used_lookup_table = false;
+  const DexFile::ClassDef* lookup_table_classdef = nullptr;
   if (LIKELY((oat_dex_file != nullptr) && (oat_dex_file->GetTypeLookupTable() != nullptr))) {
+    used_lookup_table = true;
     const uint32_t class_def_idx = oat_dex_file->GetTypeLookupTable()->Lookup(descriptor, hash);
-    return (class_def_idx != dex::kDexNoIndex) ? &dex_file.GetClassDef(class_def_idx) : nullptr;
+    lookup_table_classdef = (class_def_idx != dex::kDexNoIndex)
+        ? &dex_file.GetClassDef(class_def_idx)
+        : nullptr;
+    if (!kIsDebugBuild) {
+      return lookup_table_classdef;
+    }
   }
   // Fast path for rare no class defs case.
   const uint32_t num_class_defs = dex_file.NumClassDefs();
@@ -1745,7 +1758,11 @@
   const DexFile::TypeId* type_id = dex_file.FindTypeId(descriptor);
   if (type_id != nullptr) {
     dex::TypeIndex type_idx = dex_file.GetIndexForTypeId(*type_id);
-    return dex_file.FindClassDef(type_idx);
+    const DexFile::ClassDef* found_class_def = dex_file.FindClassDef(type_idx);
+    if (kIsDebugBuild && used_lookup_table) {
+      DCHECK_EQ(found_class_def, lookup_table_classdef);
+    }
+    return found_class_def;
   }
   return nullptr;
 }
diff --git a/runtime/type_lookup_table.cc b/runtime/type_lookup_table.cc
index 6eb3d83..649a4f9 100644
--- a/runtime/type_lookup_table.cc
+++ b/runtime/type_lookup_table.cc
@@ -66,7 +66,7 @@
 }
 
 TypeLookupTable::TypeLookupTable(const DexFile& dex_file, uint8_t* storage)
-    : dex_file_begin_(dex_file.Begin()),
+    : dex_data_begin_(dex_file.DataBegin()),
       raw_data_length_(RawDataLength(dex_file.NumClassDefs())),
       mask_(CalculateMask(dex_file.NumClassDefs())),
       entries_(storage != nullptr ? reinterpret_cast<Entry*>(storage) : new Entry[mask_ + 1]),
@@ -106,7 +106,7 @@
 TypeLookupTable::TypeLookupTable(const uint8_t* dex_file_pointer,
                                  const uint8_t* raw_data,
                                  uint32_t num_class_defs)
-    : dex_file_begin_(dex_file_pointer),
+    : dex_data_begin_(dex_file_pointer),
       raw_data_length_(RawDataLength(num_class_defs)),
       mask_(CalculateMask(num_class_defs)),
       entries_(reinterpret_cast<Entry*>(const_cast<uint8_t*>(raw_data))),
diff --git a/runtime/type_lookup_table.h b/runtime/type_lookup_table.h
index 6a6f47f..50c93ad 100644
--- a/runtime/type_lookup_table.h
+++ b/runtime/type_lookup_table.h
@@ -43,7 +43,7 @@
 
   // Method search class_def_idx by class descriptor and it's hash.
   // If no data found then the method returns dex::kDexNoIndex.
-  ALWAYS_INLINE uint32_t Lookup(const char* str, uint32_t hash) const {
+  uint32_t Lookup(const char* str, uint32_t hash) const {
     uint32_t pos = hash & GetSizeMask();
     // Thanks to special insertion algorithm, the element at position pos can be empty or start of
     // bucket.
@@ -127,8 +127,8 @@
                   uint32_t num_class_defs);
 
   bool IsStringsEquals(const char* str, uint32_t str_offset) const {
-    const uint8_t* ptr = dex_file_begin_ + str_offset;
-    CHECK(dex_file_begin_ != nullptr);
+    const uint8_t* ptr = dex_data_begin_ + str_offset;
+    CHECK(dex_data_begin_ != nullptr);
     // Skip string length.
     DecodeUnsignedLeb128(&ptr);
     return CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(
@@ -160,7 +160,7 @@
   // Find the last entry in a chain.
   uint32_t FindLastEntryInBucket(uint32_t cur_pos) const;
 
-  const uint8_t* dex_file_begin_;
+  const uint8_t* dex_data_begin_;
   const uint32_t raw_data_length_;
   const uint32_t mask_;
   std::unique_ptr<Entry[]> entries_;
diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc
index cab91df..36ebb17 100644
--- a/runtime/vdex_file.cc
+++ b/runtime/vdex_file.cc
@@ -48,10 +48,12 @@
 
 VdexFile::Header::Header(uint32_t number_of_dex_files,
                          uint32_t dex_size,
+                         uint32_t dex_shared_data_size,
                          uint32_t verifier_deps_size,
                          uint32_t quickening_info_size)
     : number_of_dex_files_(number_of_dex_files),
       dex_size_(dex_size),
+      dex_shared_data_size_(dex_shared_data_size),
       verifier_deps_size_(verifier_deps_size),
       quickening_info_size_(quickening_info_size) {
   memcpy(magic_, kVdexMagic, sizeof(kVdexMagic));
@@ -183,14 +185,17 @@
     // TODO: Supply the location information for a vdex file.
     static constexpr char kVdexLocation[] = "";
     std::string location = DexFileLoader::GetMultiDexLocation(i, kVdexLocation);
-    std::unique_ptr<const DexFile> dex(dex_file_loader.Open(dex_file_start,
-                                                            size,
-                                                            location,
-                                                            GetLocationChecksum(i),
-                                                            nullptr /*oat_dex_file*/,
-                                                            false /*verify*/,
-                                                            false /*verify_checksum*/,
-                                                            error_msg));
+    std::unique_ptr<const DexFile> dex(dex_file_loader.OpenWithDataSection(
+        dex_file_start,
+        size,
+        /*data_base*/ nullptr,
+        /*data_size*/ 0u,
+        location,
+        GetLocationChecksum(i),
+        nullptr /*oat_dex_file*/,
+        false /*verify*/,
+        false /*verify_checksum*/,
+        error_msg));
     if (dex == nullptr) {
       return false;
     }
diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h
index 4e45128..e8d66ac 100644
--- a/runtime/vdex_file.h
+++ b/runtime/vdex_file.h
@@ -54,6 +54,7 @@
    public:
     Header(uint32_t number_of_dex_files_,
            uint32_t dex_size,
+           uint32_t dex_shared_data_size,
            uint32_t verifier_deps_size,
            uint32_t quickening_info_size);
 
@@ -64,6 +65,7 @@
     bool IsValid() const { return IsMagicValid() && IsVersionValid(); }
 
     uint32_t GetDexSize() const { return dex_size_; }
+    uint32_t GetDexSharedDataSize() const { return dex_shared_data_size_; }
     uint32_t GetVerifierDepsSize() const { return verifier_deps_size_; }
     uint32_t GetQuickeningInfoSize() const { return quickening_info_size_; }
     uint32_t GetNumberOfDexFiles() const { return number_of_dex_files_; }
@@ -72,6 +74,7 @@
       return sizeof(Header) +
              GetSizeOfChecksumsSection() +
              GetDexSize() +
+             GetDexSharedDataSize() +
              GetVerifierDepsSize() +
              GetQuickeningInfoSize();
     }
@@ -84,13 +87,14 @@
 
    private:
     static constexpr uint8_t kVdexMagic[] = { 'v', 'd', 'e', 'x' };
-    // Last update: Use efficient encoding for compact dex code item fields
-    static constexpr uint8_t kVdexVersion[] = { '0', '1', '5', '\0' };
+    // Last update: Separate section for compact dex data.
+    static constexpr uint8_t kVdexVersion[] = { '0', '1', '6', '\0' };
 
     uint8_t magic_[4];
     uint8_t version_[4];
     uint32_t number_of_dex_files_;
     uint32_t dex_size_;
+    uint32_t dex_shared_data_size_;
     uint32_t verifier_deps_size_;
     uint32_t quickening_info_size_;
 
@@ -172,7 +176,8 @@
 
   ArrayRef<const uint8_t> GetVerifierDepsData() const {
     return ArrayRef<const uint8_t>(
-        DexBegin() + GetHeader().GetDexSize(), GetHeader().GetVerifierDepsSize());
+        DexBegin() + GetHeader().GetDexSize() + GetHeader().GetDexSharedDataSize(),
+        GetHeader().GetVerifierDepsSize());
   }
 
   ArrayRef<const uint8_t> GetQuickeningInfo() const {