Revamp dexlayout writing functions

Added some stream abstractions to make it easier to split apart
the main part of the dex file compared to the data one.

Moved to using a vector based stream instead of a mem_map one.

Motivations:
Make it easy to separate data into a separate stream for multidex data
deduping.
Remove upper bounds on dex expansion that would SIGSEGV if the writer
went over the limit.

Bug: 72051652
Bug: 63756964
Test: test-art-host

Change-Id: Ic622a4142b161566d149166a1767434ff4cc7fec
diff --git a/dexlayout/compact_dex_writer.cc b/dexlayout/compact_dex_writer.cc
index dd1eee7..2f601b6 100644
--- a/dexlayout/compact_dex_writer.cc
+++ b/dexlayout/compact_dex_writer.cc
@@ -24,20 +24,20 @@
 
 namespace art {
 
-CompactDexWriter::CompactDexWriter(dex_ir::Header* header,
-                                   MemMap* mem_map,
-                                   DexLayout* dex_layout,
-                                   CompactDexLevel compact_dex_level)
-    : DexWriter(header, mem_map, dex_layout, /*compute_offsets*/ true),
-      compact_dex_level_(compact_dex_level),
-      data_dedupe_(/*bucket_count*/ 32,
-                   HashedMemoryRange::HashEqual(mem_map->Begin()),
-                   HashedMemoryRange::HashEqual(mem_map->Begin())) {
-  CHECK(compact_dex_level_ != CompactDexLevel::kCompactDexLevelNone);
+CompactDexWriter::CompactDexWriter(DexLayout* dex_layout)
+    : DexWriter(dex_layout, /*compute_offsets*/ true) {
+  CHECK(GetCompactDexLevel() != CompactDexLevel::kCompactDexLevelNone);
 }
 
-uint32_t CompactDexWriter::WriteDebugInfoOffsetTable(uint32_t offset) {
-  const uint32_t start_offset = offset;
+CompactDexLevel CompactDexWriter::GetCompactDexLevel() const {
+  return dex_layout_->GetOptions().compact_dex_level_;
+}
+
+CompactDexWriter::Container::Container(bool dedupe_code_items)
+    : code_item_dedupe_(dedupe_code_items, &data_section_) {}
+
+uint32_t CompactDexWriter::WriteDebugInfoOffsetTable(Stream* stream) {
+  const uint32_t start_offset = stream->Tell();
   const dex_ir::Collections& collections = header_->GetCollections();
   // Debug offsets for method indexes. 0 means no debug info.
   std::vector<uint32_t> debug_info_offsets(collections.MethodIdsSize(), 0u);
@@ -79,15 +79,16 @@
                                         &debug_info_base_,
                                         &debug_info_offsets_table_offset_);
   // Align the table and write it out.
-  offset = RoundUp(offset, CompactDexDebugInfoOffsetTable::kAlignment);
-  debug_info_offsets_pos_ = offset;
-  offset += Write(data.data(), data.size(), offset);
+  stream->AlignTo(CompactDexDebugInfoOffsetTable::kAlignment);
+  debug_info_offsets_pos_ = stream->Tell();
+  stream->Write(data.data(), data.size());
 
   // Verify that the whole table decodes as expected and measure average performance.
   const bool kMeasureAndTestOutput = dex_layout_->GetOptions().verify_output_;
   if (kMeasureAndTestOutput && !debug_info_offsets.empty()) {
     uint64_t start_time = NanoTime();
-    CompactDexDebugInfoOffsetTable::Accessor accessor(mem_map_->Begin() + debug_info_offsets_pos_,
+    stream->Begin();
+    CompactDexDebugInfoOffsetTable::Accessor accessor(stream->Begin() + debug_info_offsets_pos_,
                                                       debug_info_base_,
                                                       debug_info_offsets_table_offset_);
 
@@ -99,19 +100,19 @@
               << (end_time - start_time) / debug_info_offsets.size();
   }
 
-  return offset - start_offset;
+  return stream->Tell() - start_offset;
 }
 
-uint32_t CompactDexWriter::WriteCodeItem(dex_ir::CodeItem* code_item,
-                                         uint32_t offset,
+uint32_t CompactDexWriter::WriteCodeItem(Stream* stream,
+                                         dex_ir::CodeItem* code_item,
                                          bool reserve_only) {
   DCHECK(code_item != nullptr);
   DCHECK(!reserve_only) << "Not supported because of deduping.";
-  const uint32_t start_offset = offset;
+  const uint32_t start_offset = stream->Tell();
 
   // Align to minimum requirements, additional alignment requirements are handled below after we
   // know the preheader size.
-  offset = RoundUp(offset, CompactDexFile::CodeItem::kAlignment);
+  stream->AlignTo(CompactDexFile::CodeItem::kAlignment);
 
   CompactDexFile::CodeItem disk_code_item;
 
@@ -127,7 +128,7 @@
   const size_t preheader_bytes = (preheader_end - preheader) * sizeof(preheader[0]);
 
   static constexpr size_t kPayloadInstructionRequiredAlignment = 4;
-  const uint32_t current_code_item_start = offset + preheader_bytes;
+  const uint32_t current_code_item_start = stream->Tell() + preheader_bytes;
   if (!IsAlignedParam(current_code_item_start, kPayloadInstructionRequiredAlignment)) {
     // If the preheader is going to make the code unaligned, consider adding 2 bytes of padding
     // before if required.
@@ -137,49 +138,60 @@
       if (opcode == Instruction::FILL_ARRAY_DATA ||
           opcode == Instruction::PACKED_SWITCH ||
           opcode == Instruction::SPARSE_SWITCH) {
-        offset += RoundUp(current_code_item_start, kPayloadInstructionRequiredAlignment) -
-            current_code_item_start;
+        stream->Skip(
+            RoundUp(current_code_item_start, kPayloadInstructionRequiredAlignment) -
+                current_code_item_start);
         break;
       }
     }
   }
 
-  const uint32_t data_start = offset;
+  const uint32_t data_start = stream->Tell();
 
   // Write preheader first.
-  offset += Write(reinterpret_cast<const uint8_t*>(preheader), preheader_bytes, offset);
+  stream->Write(reinterpret_cast<const uint8_t*>(preheader), preheader_bytes);
   // Registered offset is after the preheader.
-  ProcessOffset(&offset, code_item);
+  ProcessOffset(stream, code_item);
   // Avoid using sizeof so that we don't write the fake instruction array at the end of the code
   // item.
-  offset += Write(&disk_code_item,
-                  OFFSETOF_MEMBER(CompactDexFile::CodeItem, insns_),
-                  offset);
+  stream->Write(&disk_code_item, OFFSETOF_MEMBER(CompactDexFile::CodeItem, insns_));
   // Write the instructions.
-  offset += Write(code_item->Insns(), code_item->InsnsSize() * sizeof(uint16_t), offset);
+  stream->Write(code_item->Insns(), code_item->InsnsSize() * sizeof(uint16_t));
   // Write the post instruction data.
-  offset += WriteCodeItemPostInstructionData(code_item, offset, reserve_only);
+  WriteCodeItemPostInstructionData(stream, code_item, reserve_only);
 
-  if (dex_layout_->GetOptions().dedupe_code_items_ && compute_offsets_) {
-    // After having written, try to dedupe the whole code item (excluding padding).
-    uint32_t deduped_offset = DedupeData(data_start, offset, code_item->GetOffset());
-    if (deduped_offset != kDidNotDedupe) {
+  if (compute_offsets_) {
+    // After having written, maybe dedupe the whole code item (excluding padding).
+    const uint32_t deduped_offset = code_item_dedupe_->Dedupe(data_start,
+                                                              stream->Tell(),
+                                                              code_item->GetOffset());
+    if (deduped_offset != Deduper::kDidNotDedupe) {
       code_item->SetOffset(deduped_offset);
       // Undo the offset for all that we wrote since we deduped.
-      offset = start_offset;
+      stream->Seek(start_offset);
     }
   }
 
-  return offset - start_offset;
+  return stream->Tell() - start_offset;
 }
 
-uint32_t CompactDexWriter::DedupeData(uint32_t data_start,
-                                      uint32_t data_end,
-                                      uint32_t item_offset) {
+
+CompactDexWriter::Deduper::Deduper(bool enabled, DexContainer::Section* section)
+    : enabled_(enabled),
+      dedupe_map_(/*bucket_count*/ 32,
+                  HashedMemoryRange::HashEqual(section),
+                  HashedMemoryRange::HashEqual(section)) {}
+
+uint32_t CompactDexWriter::Deduper::Dedupe(uint32_t data_start,
+                                           uint32_t data_end,
+                                           uint32_t item_offset) {
+  if (!enabled_) {
+    return kDidNotDedupe;
+  }
   HashedMemoryRange range {data_start, data_end - data_start};
-  auto existing = data_dedupe_.emplace(range, item_offset);
+  auto existing = dedupe_map_.emplace(range, item_offset);
   if (!existing.second) {
-    // Failed to insert, item already existed in the map.
+    // Failed to insert means we deduped, return the existing item offset.
     return existing.first->second;
   }
   return kDidNotDedupe;
@@ -223,7 +235,7 @@
   });
 }
 
-void CompactDexWriter::WriteHeader() {
+void CompactDexWriter::WriteHeader(Stream* stream) {
   CompactDexFile::Header header;
   CompactDexFile::WriteMagic(&header.magic_[0]);
   CompactDexFile::WriteCurrentVersion(&header.magic_[0]);
@@ -263,78 +275,99 @@
   if (header_->SupportDefaultMethods()) {
     header.feature_flags_ |= static_cast<uint32_t>(CompactDexFile::FeatureFlags::kDefaultMethods);
   }
-  UNUSED(Write(reinterpret_cast<uint8_t*>(&header), sizeof(header), 0u));
+  stream->Seek(0);
+  stream->Overwrite(reinterpret_cast<uint8_t*>(&header), sizeof(header));
 }
 
 size_t CompactDexWriter::GetHeaderSize() const {
   return sizeof(CompactDexFile::Header);
 }
 
-void CompactDexWriter::WriteMemMap() {
+void CompactDexWriter::Write(DexContainer* output)  {
+  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;
+  code_item_dedupe_ = &container->code_item_dedupe_;
+
   // Starting offset is right after the header.
-  uint32_t offset = GetHeaderSize();
+  main_stream->Seek(GetHeaderSize());
 
   dex_ir::Collections& collection = header_->GetCollections();
 
   // Based on: https://source.android.com/devices/tech/dalvik/dex-format
   // Since the offsets may not be calculated already, the writing must be done in the correct order.
-  const uint32_t string_ids_offset = offset;
-  offset += WriteStringIds(offset, /*reserve_only*/ true);
-  offset += WriteTypeIds(offset);
-  const uint32_t proto_ids_offset = offset;
-  offset += WriteProtoIds(offset, /*reserve_only*/ true);
-  offset += WriteFieldIds(offset);
-  offset += WriteMethodIds(offset);
-  const uint32_t class_defs_offset = offset;
-  offset += WriteClassDefs(offset, /*reserve_only*/ true);
-  const uint32_t call_site_ids_offset = offset;
-  offset += WriteCallSiteIds(offset, /*reserve_only*/ true);
-  offset += WriteMethodHandles(offset);
+  const uint32_t string_ids_offset = main_stream->Tell();
+  WriteStringIds(main_stream, /*reserve_only*/ true);
+  WriteTypeIds(main_stream);
+  const uint32_t proto_ids_offset = main_stream->Tell();
+  WriteProtoIds(main_stream, /*reserve_only*/ true);
+  WriteFieldIds(main_stream);
+  WriteMethodIds(main_stream);
+  const uint32_t class_defs_offset = main_stream->Tell();
+  WriteClassDefs(main_stream, /*reserve_only*/ true);
+  const uint32_t call_site_ids_offset = main_stream->Tell();
+  WriteCallSiteIds(main_stream, /*reserve_only*/ true);
+  WriteMethodHandles(main_stream);
 
   uint32_t data_offset_ = 0u;
   if (compute_offsets_) {
     // Data section.
-    offset = RoundUp(offset, kDataSectionAlignment);
-    data_offset_ = offset;
+    data_stream->AlignTo(kDataSectionAlignment);
+    data_offset_ = data_stream->Tell();
   }
 
   // Write code item first to minimize the space required for encoded methods.
   // For cdex, the code items don't depend on the debug info.
-  offset += WriteCodeItems(offset, /*reserve_only*/ false);
+  WriteCodeItems(data_stream, /*reserve_only*/ false);
 
   // Sort the debug infos by method index order, this reduces size by ~0.1% by reducing the size of
   // the debug info offset table.
   SortDebugInfosByMethodIndex();
-  offset += WriteDebugInfoItems(offset);
+  WriteDebugInfoItems(data_stream);
 
-  offset += WriteEncodedArrays(offset);
-  offset += WriteAnnotations(offset);
-  offset += WriteAnnotationSets(offset);
-  offset += WriteAnnotationSetRefs(offset);
-  offset += WriteAnnotationsDirectories(offset);
-  offset += WriteTypeLists(offset);
-  offset += WriteClassDatas(offset);
-  offset += WriteStringDatas(offset);
+  WriteEncodedArrays(data_stream);
+  WriteAnnotations(data_stream);
+  WriteAnnotationSets(data_stream);
+  WriteAnnotationSetRefs(data_stream);
+  WriteAnnotationsDirectories(data_stream);
+  WriteTypeLists(data_stream);
+  WriteClassDatas(data_stream);
+  WriteStringDatas(data_stream);
 
   // Write delayed id sections that depend on data sections.
-  WriteStringIds(string_ids_offset, /*reserve_only*/ false);
-  WriteProtoIds(proto_ids_offset, /*reserve_only*/ false);
-  WriteClassDefs(class_defs_offset, /*reserve_only*/ false);
-  WriteCallSiteIds(call_site_ids_offset, /*reserve_only*/ false);
+  {
+    Stream::ScopedSeek seek(main_stream, string_ids_offset);
+    WriteStringIds(main_stream, /*reserve_only*/ false);
+  }
+  {
+    Stream::ScopedSeek seek(main_stream, proto_ids_offset);
+    WriteProtoIds(main_stream, /*reserve_only*/ false);
+  }
+  {
+    Stream::ScopedSeek seek(main_stream, class_defs_offset);
+    WriteClassDefs(main_stream, /*reserve_only*/ false);
+  }
+  {
+    Stream::ScopedSeek seek(main_stream, call_site_ids_offset);
+    WriteCallSiteIds(main_stream, /*reserve_only*/ false);
+  }
 
   // Write the map list.
   if (compute_offsets_) {
-    offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeMapList));
-    collection.SetMapListOffset(offset);
+    data_stream->AlignTo(SectionAlignment(DexFile::kDexTypeMapList));
+    collection.SetMapListOffset(data_stream->Tell());
   } else {
-    offset = collection.MapListOffset();
+    data_stream->Seek(collection.MapListOffset());
   }
-  offset += GenerateAndWriteMapItems(offset);
-  offset = RoundUp(offset, kDataSectionAlignment);
+  GenerateAndWriteMapItems(data_stream);
+  data_stream->AlignTo(kDataSectionAlignment);
 
   // Map items are included in the data section.
   if (compute_offsets_) {
-    header_->SetDataSize(offset - data_offset_);
+    header_->SetDataSize(data_stream->Tell() - data_offset_);
     if (header_->DataSize() != 0) {
       // Offset must be zero when the size is zero.
       header_->SetDataOffset(data_offset_);
@@ -348,25 +381,34 @@
   if (link_data.size() > 0) {
     CHECK_EQ(header_->LinkSize(), static_cast<uint32_t>(link_data.size()));
     if (compute_offsets_) {
-      header_->SetLinkOffset(offset);
+      header_->SetLinkOffset(data_stream->Tell());
+    } else {
+      data_stream->Seek(header_->LinkOffset());
     }
-    offset += Write(&link_data[0], link_data.size(), header_->LinkOffset());
+    data_stream->Write(&link_data[0], link_data.size());
   }
 
   // Write debug info offset table last to make dex file verifier happy.
-  offset += WriteDebugInfoOffsetTable(offset);
+  WriteDebugInfoOffsetTable(data_stream);
 
   // Write header last.
   if (compute_offsets_) {
-    header_->SetFileSize(offset);
+    header_->SetFileSize(main_stream->Tell());
   }
-  WriteHeader();
+  WriteHeader(main_stream);
 
   if (dex_layout_->GetOptions().update_checksum_) {
-    header_->SetChecksum(DexFile::CalculateChecksum(mem_map_->Begin(), offset));
+    header_->SetChecksum(DexFile::CalculateChecksum(main_stream->Begin(), header_->FileSize()));
     // Rewrite the header with the calculated checksum.
-    WriteHeader();
+    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 {
+  return std::unique_ptr<DexContainer>(
+      new CompactDexWriter::Container(dex_layout_->GetOptions().dedupe_code_items_));
 }
 
 }  // namespace art
diff --git a/dexlayout/compact_dex_writer.h b/dexlayout/compact_dex_writer.h
index cb53cae..626b85a 100644
--- a/dexlayout/compact_dex_writer.h
+++ b/dexlayout/compact_dex_writer.h
@@ -19,6 +19,7 @@
 #ifndef ART_DEXLAYOUT_COMPACT_DEX_WRITER_H_
 #define ART_DEXLAYOUT_COMPACT_DEX_WRITER_H_
 
+#include <memory>  // For unique_ptr
 #include <unordered_map>
 
 #include "dex_writer.h"
@@ -26,62 +27,108 @@
 
 namespace art {
 
-class HashedMemoryRange {
+// Compact dex writer for a single dex.
+class CompactDexWriter : public DexWriter {
  public:
-  uint32_t offset_;
-  uint32_t length_;
+  explicit CompactDexWriter(DexLayout* dex_layout);
 
-  class HashEqual {
+ protected:
+  class Deduper {
    public:
-    explicit HashEqual(const uint8_t* data) : data_(data) {}
+    static const uint32_t kDidNotDedupe = 0;
 
-    // Equal function.
-    bool operator()(const HashedMemoryRange& a, const HashedMemoryRange& b) const {
-      return a.length_ == b.length_ && std::equal(data_ + a.offset_,
-                                                  data_ + a.offset_ + a.length_,
-                                                  data_ + b.offset_);
+    // if not enabled, Dedupe will always return kDidNotDedupe.
+    explicit Deduper(bool enabled, DexContainer::Section* section);
+
+    // Deduplicate a blob of data that has been written to mem_map.
+    // Returns the offset of the deduplicated data or kDidNotDedupe did deduplication did not occur.
+    uint32_t Dedupe(uint32_t data_start, uint32_t data_end, uint32_t item_offset);
+
+   private:
+    class HashedMemoryRange {
+     public:
+      uint32_t offset_;
+      uint32_t length_;
+
+      class HashEqual {
+       public:
+        explicit HashEqual(DexContainer::Section* section) : section_(section) {}
+
+        // Equal function.
+        bool operator()(const HashedMemoryRange& a, const HashedMemoryRange& b) const {
+          if (a.length_ != b.length_) {
+            return false;
+          }
+          const uint8_t* data = Data();
+          return std::equal(data + a.offset_, data + a.offset_ + a.length_, data + b.offset_);
+        }
+
+        // Hash function.
+        size_t operator()(const HashedMemoryRange& range) const {
+          return HashBytes(Data() + range.offset_, range.length_);
+        }
+
+        ALWAYS_INLINE uint8_t* Data() const {
+          return section_->Begin();
+        }
+
+       private:
+        DexContainer::Section* const section_;
+      };
+    };
+
+    const bool enabled_;
+
+    // Dedupe map.
+    std::unordered_map<HashedMemoryRange,
+                       uint32_t,
+                       HashedMemoryRange::HashEqual,
+                       HashedMemoryRange::HashEqual> dedupe_map_;
+  };
+
+ public:
+  class Container : public DexContainer {
+   public:
+    Section* GetMainSection() OVERRIDE {
+      return &main_section_;
     }
 
-    // Hash function.
-    size_t operator()(const HashedMemoryRange& range) const {
-      return HashBytes(data_ + range.offset_, range.length_);
+    Section* GetDataSection() OVERRIDE {
+      return &data_section_;
+    }
+
+    bool IsCompactDexContainer() const OVERRIDE {
+      return true;
     }
 
    private:
-    const uint8_t* data_;
-  };
-};
+    explicit Container(bool dedupe_code_items);
 
-class CompactDexWriter : public DexWriter {
- public:
-  CompactDexWriter(dex_ir::Header* header,
-                   MemMap* mem_map,
-                   DexLayout* dex_layout,
-                   CompactDexLevel compact_dex_level);
+    VectorSection main_section_;
+    VectorSection data_section_;
+    Deduper code_item_dedupe_;
+
+    friend class CompactDexWriter;
+  };
 
  protected:
-  void WriteMemMap() OVERRIDE;
+  void Write(DexContainer* output) OVERRIDE;
 
-  void WriteHeader() OVERRIDE;
+  std::unique_ptr<DexContainer> CreateDexContainer() const OVERRIDE;
+
+  void WriteHeader(Stream* stream) OVERRIDE;
 
   size_t GetHeaderSize() const OVERRIDE;
 
-  uint32_t WriteDebugInfoOffsetTable(uint32_t offset);
+  uint32_t WriteDebugInfoOffsetTable(Stream* stream);
 
-  uint32_t WriteCodeItem(dex_ir::CodeItem* code_item, uint32_t offset, bool reserve_only) OVERRIDE;
+  uint32_t WriteCodeItem(Stream* stream, dex_ir::CodeItem* code_item, bool reserve_only) OVERRIDE;
 
   void SortDebugInfosByMethodIndex();
 
-  // Deduplicate a blob of data that has been written to mem_map. The backing storage is the actual
-  // mem_map contents to reduce RAM usage.
-  // Returns the offset of the deduplicated data or 0 if kDidNotDedupe did not occur.
-  uint32_t DedupeData(uint32_t data_start, uint32_t data_end, uint32_t item_offset);
+  CompactDexLevel GetCompactDexLevel() const;
 
  private:
-  const CompactDexLevel compact_dex_level_;
-
-  static const uint32_t kDidNotDedupe = 0;
-
   // Position in the compact dex file for the debug info table data starts.
   uint32_t debug_info_offsets_pos_ = 0u;
 
@@ -91,11 +138,8 @@
   // Base offset of where debug info starts in the dex file.
   uint32_t debug_info_base_ = 0u;
 
-  // Dedupe map.
-  std::unordered_map<HashedMemoryRange,
-                     uint32_t,
-                     HashedMemoryRange::HashEqual,
-                     HashedMemoryRange::HashEqual> data_dedupe_;
+  // State for where we are deduping.
+  Deduper* code_item_dedupe_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(CompactDexWriter);
 };
diff --git a/dexlayout/dex_container.h b/dexlayout/dex_container.h
new file mode 100644
index 0000000..7c426cb
--- /dev/null
+++ b/dexlayout/dex_container.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Header file of an in-memory representation of DEX files.
+ */
+
+#ifndef ART_DEXLAYOUT_DEX_CONTAINER_H_
+#define ART_DEXLAYOUT_DEX_CONTAINER_H_
+
+#include <vector>
+
+namespace art {
+
+// Dex container holds the artifacts produced by dexlayout and contains up to two sections: a main
+// section and a data section.
+// This container may also hold metadata used for multi dex deduplication in the future.
+class DexContainer {
+ public:
+  virtual ~DexContainer() {}
+
+  class Section {
+   public:
+    virtual ~Section() {}
+
+    // Returns the start of the memory region.
+    virtual uint8_t* Begin() = 0;
+
+    // Size in bytes.
+    virtual size_t Size() const = 0;
+
+    // Resize the backing storage.
+    virtual void Resize(size_t size) = 0;
+
+    // Returns the end of the memory region.
+    uint8_t* End() {
+      return Begin() + Size();
+    }
+  };
+
+  // Vector backed section.
+  class VectorSection : public Section {
+   public:
+    virtual ~VectorSection() {}
+
+    uint8_t* Begin() OVERRIDE {
+      return &data_[0];
+    }
+
+    size_t Size() const OVERRIDE {
+      return data_.size();
+    }
+
+    void Resize(size_t size) OVERRIDE {
+      data_.resize(size, 0u);
+    }
+
+   private:
+    std::vector<uint8_t> data_;
+  };
+
+  virtual Section* GetMainSection() = 0;
+  virtual Section* GetDataSection() = 0;
+  virtual bool IsCompactDexContainer() const = 0;
+};
+
+}  // namespace art
+
+#endif  // ART_DEXLAYOUT_DEX_CONTAINER_H_
diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h
index 3627717..1a84d23 100644
--- a/dexlayout/dex_ir.h
+++ b/dexlayout/dex_ir.h
@@ -486,11 +486,11 @@
   virtual ~Item() { }
 
   // Return the assigned offset.
-  uint32_t GetOffset() const {
+  uint32_t GetOffset() const WARN_UNUSED {
     CHECK(OffsetAssigned());
     return offset_;
   }
-  uint32_t GetSize() const { return size_; }
+  uint32_t GetSize() const WARN_UNUSED { return size_; }
   void SetOffset(uint32_t offset) { offset_ = offset; }
   void SetSize(uint32_t size) { size_ = size; }
   bool OffsetAssigned() const {
diff --git a/dexlayout/dex_writer.cc b/dexlayout/dex_writer.cc
index d26c948..eb038a0 100644
--- a/dexlayout/dex_writer.cc
+++ b/dexlayout/dex_writer.cc
@@ -30,7 +30,7 @@
 
 namespace art {
 
-size_t EncodeIntValue(int32_t value, uint8_t* buffer) {
+static size_t EncodeIntValue(int32_t value, uint8_t* buffer) {
   size_t length = 0;
   if (value >= 0) {
     while (value > 0x7f) {
@@ -47,7 +47,7 @@
   return length;
 }
 
-size_t EncodeUIntValue(uint32_t value, uint8_t* buffer) {
+static size_t EncodeUIntValue(uint32_t value, uint8_t* buffer) {
   size_t length = 0;
   do {
     buffer[length++] = static_cast<uint8_t>(value);
@@ -56,7 +56,7 @@
   return length;
 }
 
-size_t EncodeLongValue(int64_t value, uint8_t* buffer) {
+static size_t EncodeLongValue(int64_t value, uint8_t* buffer) {
   size_t length = 0;
   if (value >= 0) {
     while (value > 0x7f) {
@@ -78,7 +78,7 @@
   uint32_t i_;
 };
 
-size_t EncodeFloatValue(float value, uint8_t* buffer) {
+static size_t EncodeFloatValue(float value, uint8_t* buffer) {
   FloatUnion float_union;
   float_union.f_ = value;
   uint32_t int_value = float_union.i_;
@@ -95,7 +95,7 @@
   uint64_t l_;
 };
 
-size_t EncodeDoubleValue(double value, uint8_t* buffer) {
+static size_t EncodeDoubleValue(double value, uint8_t* buffer) {
   DoubleUnion double_union;
   double_union.d_ = value;
   uint64_t long_value = double_union.l_;
@@ -107,26 +107,13 @@
   return 7 - index;
 }
 
-size_t DexWriter::Write(const void* buffer, size_t length, size_t offset) {
-  DCHECK_LE(offset + length, mem_map_->Size());
-  memcpy(mem_map_->Begin() + offset, buffer, length);
-  return length;
-}
+DexWriter::DexWriter(DexLayout* dex_layout, bool compute_offsets)
+    : header_(dex_layout->GetHeader()),
+      dex_layout_(dex_layout),
+      compute_offsets_(compute_offsets) {}
 
-size_t DexWriter::WriteSleb128(uint32_t value, size_t offset) {
-  uint8_t buffer[8];
-  EncodeSignedLeb128(buffer, value);
-  return Write(buffer, SignedLeb128Size(value), offset);
-}
-
-size_t DexWriter::WriteUleb128(uint32_t value, size_t offset) {
-  uint8_t buffer[8];
-  EncodeUnsignedLeb128(buffer, value);
-  return Write(buffer, UnsignedLeb128Size(value), offset);
-}
-
-size_t DexWriter::WriteEncodedValue(dex_ir::EncodedValue* encoded_value, size_t offset) {
-  size_t original_offset = offset;
+size_t DexWriter::WriteEncodedValue(Stream* stream, dex_ir::EncodedValue* encoded_value) {
+  size_t original_offset = stream->Tell();
   size_t start = 0;
   size_t length;
   uint8_t buffer[8];
@@ -175,284 +162,285 @@
       length = EncodeUIntValue(encoded_value->GetMethodId()->GetIndex(), buffer);
       break;
     case DexFile::kDexAnnotationArray:
-      offset += WriteEncodedValueHeader(type, 0, offset);
-      offset += WriteEncodedArray(encoded_value->GetEncodedArray()->GetEncodedValues(), offset);
-      return offset - original_offset;
+      WriteEncodedValueHeader(stream, type, 0);
+      WriteEncodedArray(stream, encoded_value->GetEncodedArray()->GetEncodedValues());
+      return stream->Tell() - original_offset;
     case DexFile::kDexAnnotationAnnotation:
-      offset += WriteEncodedValueHeader(type, 0, offset);
-      offset += WriteEncodedAnnotation(encoded_value->GetEncodedAnnotation(), offset);
-      return offset - original_offset;
+      WriteEncodedValueHeader(stream, type, 0);
+      WriteEncodedAnnotation(stream, encoded_value->GetEncodedAnnotation());
+      return stream->Tell() - original_offset;
     case DexFile::kDexAnnotationNull:
-      return WriteEncodedValueHeader(type, 0, offset);
+      return WriteEncodedValueHeader(stream, type, 0);
     case DexFile::kDexAnnotationBoolean:
-      return WriteEncodedValueHeader(type, encoded_value->GetBoolean() ? 1 : 0, offset);
+      return WriteEncodedValueHeader(stream, type, encoded_value->GetBoolean() ? 1 : 0);
     default:
       return 0;
   }
-  offset += WriteEncodedValueHeader(type, length - 1, offset);
-  offset += Write(buffer + start, length, offset);
-  return offset - original_offset;
+  WriteEncodedValueHeader(stream, type, length - 1);
+  stream->Write(buffer + start, length);
+  return stream->Tell() - original_offset;
 }
 
-size_t DexWriter::WriteEncodedValueHeader(int8_t value_type, size_t value_arg, size_t offset) {
+size_t DexWriter::WriteEncodedValueHeader(Stream* stream, int8_t value_type, size_t value_arg) {
   uint8_t buffer[1] = { static_cast<uint8_t>((value_arg << 5) | value_type) };
-  return Write(buffer, sizeof(uint8_t), offset);
+  return stream->Write(buffer, sizeof(uint8_t));
 }
 
-size_t DexWriter::WriteEncodedArray(dex_ir::EncodedValueVector* values, size_t offset) {
-  size_t original_offset = offset;
-  offset += WriteUleb128(values->size(), offset);
+size_t DexWriter::WriteEncodedArray(Stream* stream, dex_ir::EncodedValueVector* values) {
+  size_t original_offset = stream->Tell();
+  stream->WriteUleb128(values->size());
   for (std::unique_ptr<dex_ir::EncodedValue>& value : *values) {
-    offset += WriteEncodedValue(value.get(), offset);
+    WriteEncodedValue(stream, value.get());
   }
-  return offset - original_offset;
+  return stream->Tell() - original_offset;
 }
 
-size_t DexWriter::WriteEncodedAnnotation(dex_ir::EncodedAnnotation* annotation, size_t offset) {
-  size_t original_offset = offset;
-  offset += WriteUleb128(annotation->GetType()->GetIndex(), offset);
-  offset += WriteUleb128(annotation->GetAnnotationElements()->size(), offset);
+size_t DexWriter::WriteEncodedAnnotation(Stream* stream, dex_ir::EncodedAnnotation* annotation) {
+  size_t original_offset = stream->Tell();
+  stream->WriteUleb128(annotation->GetType()->GetIndex());
+  stream->WriteUleb128(annotation->GetAnnotationElements()->size());
   for (std::unique_ptr<dex_ir::AnnotationElement>& annotation_element :
       *annotation->GetAnnotationElements()) {
-    offset += WriteUleb128(annotation_element->GetName()->GetIndex(), offset);
-    offset += WriteEncodedValue(annotation_element->GetValue(), offset);
+    stream->WriteUleb128(annotation_element->GetName()->GetIndex());
+    WriteEncodedValue(stream, annotation_element->GetValue());
   }
-  return offset - original_offset;
+  return stream->Tell() - original_offset;
 }
 
-size_t DexWriter::WriteEncodedFields(dex_ir::FieldItemVector* fields, size_t offset) {
-  size_t original_offset = offset;
+size_t DexWriter::WriteEncodedFields(Stream* stream, dex_ir::FieldItemVector* fields) {
+  size_t original_offset = stream->Tell();
   uint32_t prev_index = 0;
   for (std::unique_ptr<dex_ir::FieldItem>& field : *fields) {
     uint32_t index = field->GetFieldId()->GetIndex();
-    offset += WriteUleb128(index - prev_index, offset);
-    offset += WriteUleb128(field->GetAccessFlags(), offset);
+    stream->WriteUleb128(index - prev_index);
+    stream->WriteUleb128(field->GetAccessFlags());
     prev_index = index;
   }
-  return offset - original_offset;
+  return stream->Tell() - original_offset;
 }
 
-size_t DexWriter::WriteEncodedMethods(dex_ir::MethodItemVector* methods, size_t offset) {
-  size_t original_offset = offset;
+size_t DexWriter::WriteEncodedMethods(Stream* stream, dex_ir::MethodItemVector* methods) {
+  size_t original_offset = stream->Tell();
   uint32_t prev_index = 0;
   for (std::unique_ptr<dex_ir::MethodItem>& method : *methods) {
     uint32_t index = method->GetMethodId()->GetIndex();
     uint32_t code_off = method->GetCodeItem() == nullptr ? 0 : method->GetCodeItem()->GetOffset();
-    offset += WriteUleb128(index - prev_index, offset);
-    offset += WriteUleb128(method->GetAccessFlags(), offset);
-    offset += WriteUleb128(code_off, offset);
+    stream->WriteUleb128(index - prev_index);
+    stream->WriteUleb128(method->GetAccessFlags());
+    stream->WriteUleb128(code_off);
     prev_index = index;
   }
-  return offset - original_offset;
+  return stream->Tell() - original_offset;
 }
 
 // TODO: Refactor this to remove duplicated boiler plate. One way to do this is adding
 // function that takes a CollectionVector<T> and uses overloading.
-uint32_t DexWriter::WriteStringIds(uint32_t offset, bool reserve_only) {
-  const uint32_t start = offset;
+uint32_t DexWriter::WriteStringIds(Stream* stream, bool reserve_only) {
+  const uint32_t start = stream->Tell();
   for (std::unique_ptr<dex_ir::StringId>& string_id : header_->GetCollections().StringIds()) {
-    offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeStringIdItem));
+    stream->AlignTo(SectionAlignment(DexFile::kDexTypeStringIdItem));
     if (reserve_only) {
-      offset += string_id->GetSize();
+      stream->Skip(string_id->GetSize());
     } else {
       uint32_t string_data_off = string_id->DataItem()->GetOffset();
-      offset += Write(&string_data_off, string_id->GetSize(), offset);
+      stream->Write(&string_data_off, string_id->GetSize());
     }
   }
-  if (compute_offsets_ && start != offset) {
+  if (compute_offsets_ && start != stream->Tell()) {
     header_->GetCollections().SetStringIdsOffset(start);
   }
-  return offset - start;
+  return stream->Tell() - start;
 }
 
-uint32_t DexWriter::WriteStringDatas(uint32_t offset) {
-  const uint32_t start = offset;
+uint32_t DexWriter::WriteStringDatas(Stream* stream) {
+  const uint32_t start = stream->Tell();
   for (std::unique_ptr<dex_ir::StringData>& string_data : header_->GetCollections().StringDatas()) {
-    ProcessOffset(&offset, string_data.get());
-    offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeStringDataItem));
-    offset += WriteUleb128(CountModifiedUtf8Chars(string_data->Data()), offset);
+    ProcessOffset(stream, string_data.get());
+    stream->AlignTo(SectionAlignment(DexFile::kDexTypeStringDataItem));
+    stream->WriteUleb128(CountModifiedUtf8Chars(string_data->Data()));
+    stream->Write(string_data->Data(), strlen(string_data->Data()));
     // Skip null terminator (already zeroed out, no need to write).
-    offset += Write(string_data->Data(), strlen(string_data->Data()), offset) + 1u;
+    stream->Skip(1);
   }
-  if (compute_offsets_ && start != offset) {
+  if (compute_offsets_ && start != stream->Tell()) {
     header_->GetCollections().SetStringDatasOffset(start);
   }
-  return offset - start;
+  return stream->Tell() - start;
 }
 
-uint32_t DexWriter::WriteTypeIds(uint32_t offset) {
+uint32_t DexWriter::WriteTypeIds(Stream* stream) {
   uint32_t descriptor_idx[1];
-  const uint32_t start = offset;
+  const uint32_t start = stream->Tell();
   for (std::unique_ptr<dex_ir::TypeId>& type_id : header_->GetCollections().TypeIds()) {
-    offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeTypeIdItem));
-    ProcessOffset(&offset, type_id.get());
+    stream->AlignTo(SectionAlignment(DexFile::kDexTypeTypeIdItem));
+    ProcessOffset(stream, type_id.get());
     descriptor_idx[0] = type_id->GetStringId()->GetIndex();
-    offset += Write(descriptor_idx, type_id->GetSize(), offset);
+    stream->Write(descriptor_idx, type_id->GetSize());
   }
-  if (compute_offsets_ && start != offset) {
+  if (compute_offsets_ && start != stream->Tell()) {
     header_->GetCollections().SetTypeIdsOffset(start);
   }
-  return offset - start;
+  return stream->Tell() - start;
 }
 
-uint32_t DexWriter::WriteTypeLists(uint32_t offset) {
+uint32_t DexWriter::WriteTypeLists(Stream* stream) {
   uint32_t size[1];
   uint16_t list[1];
-  const uint32_t start = offset;
+  const uint32_t start = stream->Tell();
   for (std::unique_ptr<dex_ir::TypeList>& type_list : header_->GetCollections().TypeLists()) {
-    offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeTypeList));
+    stream->AlignTo(SectionAlignment(DexFile::kDexTypeTypeList));
     size[0] = type_list->GetTypeList()->size();
-    ProcessOffset(&offset, type_list.get());
-    offset += Write(size, sizeof(uint32_t), offset);
+    ProcessOffset(stream, type_list.get());
+    stream->Write(size, sizeof(uint32_t));
     for (const dex_ir::TypeId* type_id : *type_list->GetTypeList()) {
       list[0] = type_id->GetIndex();
-      offset += Write(list, sizeof(uint16_t), offset);
+      stream->Write(list, sizeof(uint16_t));
     }
   }
-  if (compute_offsets_ && start != offset) {
+  if (compute_offsets_ && start != stream->Tell()) {
     header_->GetCollections().SetTypeListsOffset(start);
   }
-  return offset - start;
+  return stream->Tell() - start;
 }
 
-uint32_t DexWriter::WriteProtoIds(uint32_t offset, bool reserve_only) {
+uint32_t DexWriter::WriteProtoIds(Stream* stream, bool reserve_only) {
   uint32_t buffer[3];
-  const uint32_t start = offset;
+  const uint32_t start = stream->Tell();
   for (std::unique_ptr<dex_ir::ProtoId>& proto_id : header_->GetCollections().ProtoIds()) {
-    offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeProtoIdItem));
-    ProcessOffset(&offset, proto_id.get());
+    stream->AlignTo(SectionAlignment(DexFile::kDexTypeProtoIdItem));
+    ProcessOffset(stream, proto_id.get());
     if (reserve_only) {
-      offset += proto_id->GetSize();
+      stream->Skip(proto_id->GetSize());
     } else {
       buffer[0] = proto_id->Shorty()->GetIndex();
       buffer[1] = proto_id->ReturnType()->GetIndex();
       buffer[2] = proto_id->Parameters() == nullptr ? 0 : proto_id->Parameters()->GetOffset();
-      offset += Write(buffer, proto_id->GetSize(), offset);
+      stream->Write(buffer, proto_id->GetSize());
     }
   }
-  if (compute_offsets_ && start != offset) {
+  if (compute_offsets_ && start != stream->Tell()) {
     header_->GetCollections().SetProtoIdsOffset(start);
   }
-  return offset - start;
+  return stream->Tell() - start;
 }
 
-uint32_t DexWriter::WriteFieldIds(uint32_t offset) {
+uint32_t DexWriter::WriteFieldIds(Stream* stream) {
   uint16_t buffer[4];
-  const uint32_t start = offset;
+  const uint32_t start = stream->Tell();
   for (std::unique_ptr<dex_ir::FieldId>& field_id : header_->GetCollections().FieldIds()) {
-    offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeFieldIdItem));
-    ProcessOffset(&offset, field_id.get());
+    stream->AlignTo(SectionAlignment(DexFile::kDexTypeFieldIdItem));
+    ProcessOffset(stream, field_id.get());
     buffer[0] = field_id->Class()->GetIndex();
     buffer[1] = field_id->Type()->GetIndex();
     buffer[2] = field_id->Name()->GetIndex();
     buffer[3] = field_id->Name()->GetIndex() >> 16;
-    offset += Write(buffer, field_id->GetSize(), offset);
+    stream->Write(buffer, field_id->GetSize());
   }
-  if (compute_offsets_ && start != offset) {
+  if (compute_offsets_ && start != stream->Tell()) {
     header_->GetCollections().SetFieldIdsOffset(start);
   }
-  return offset - start;
+  return stream->Tell() - start;
 }
 
-uint32_t DexWriter::WriteMethodIds(uint32_t offset) {
+uint32_t DexWriter::WriteMethodIds(Stream* stream) {
   uint16_t buffer[4];
-  const uint32_t start = offset;
+  const uint32_t start = stream->Tell();
   for (std::unique_ptr<dex_ir::MethodId>& method_id : header_->GetCollections().MethodIds()) {
-    offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeMethodIdItem));
-    ProcessOffset(&offset, method_id.get());
+    stream->AlignTo(SectionAlignment(DexFile::kDexTypeMethodIdItem));
+    ProcessOffset(stream, method_id.get());
     buffer[0] = method_id->Class()->GetIndex();
     buffer[1] = method_id->Proto()->GetIndex();
     buffer[2] = method_id->Name()->GetIndex();
     buffer[3] = method_id->Name()->GetIndex() >> 16;
-    offset += Write(buffer, method_id->GetSize(), offset);
+    stream->Write(buffer, method_id->GetSize());
   }
-  if (compute_offsets_ && start != offset) {
+  if (compute_offsets_ && start != stream->Tell()) {
     header_->GetCollections().SetMethodIdsOffset(start);
   }
-  return offset - start;
+  return stream->Tell() - start;
 }
 
-uint32_t DexWriter::WriteEncodedArrays(uint32_t offset) {
-  const uint32_t start = offset;
+uint32_t DexWriter::WriteEncodedArrays(Stream* stream) {
+  const uint32_t start = stream->Tell();
   for (std::unique_ptr<dex_ir::EncodedArrayItem>& encoded_array :
       header_->GetCollections().EncodedArrayItems()) {
-    offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeEncodedArrayItem));
-    ProcessOffset(&offset, encoded_array.get());
-    offset += WriteEncodedArray(encoded_array->GetEncodedValues(), offset);
+    stream->AlignTo(SectionAlignment(DexFile::kDexTypeEncodedArrayItem));
+    ProcessOffset(stream, encoded_array.get());
+    WriteEncodedArray(stream, encoded_array->GetEncodedValues());
   }
-  if (compute_offsets_ && start != offset) {
+  if (compute_offsets_ && start != stream->Tell()) {
     header_->GetCollections().SetEncodedArrayItemsOffset(start);
   }
-  return offset - start;
+  return stream->Tell() - start;
 }
 
-uint32_t DexWriter::WriteAnnotations(uint32_t offset) {
+uint32_t DexWriter::WriteAnnotations(Stream* stream) {
   uint8_t visibility[1];
-  const uint32_t start = offset;
+  const uint32_t start = stream->Tell();
   for (std::unique_ptr<dex_ir::AnnotationItem>& annotation :
       header_->GetCollections().AnnotationItems()) {
-    offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeAnnotationItem));
+    stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationItem));
     visibility[0] = annotation->GetVisibility();
-    ProcessOffset(&offset, annotation.get());
-    offset += Write(visibility, sizeof(uint8_t), offset);
-    offset += WriteEncodedAnnotation(annotation->GetAnnotation(), offset);
+    ProcessOffset(stream, annotation.get());
+    stream->Write(visibility, sizeof(uint8_t));
+    WriteEncodedAnnotation(stream, annotation->GetAnnotation());
   }
-  if (compute_offsets_ && start != offset) {
+  if (compute_offsets_ && start != stream->Tell()) {
     header_->GetCollections().SetAnnotationItemsOffset(start);
   }
-  return offset - start;
+  return stream->Tell() - start;
 }
 
-uint32_t DexWriter::WriteAnnotationSets(uint32_t offset) {
+uint32_t DexWriter::WriteAnnotationSets(Stream* stream) {
   uint32_t size[1];
   uint32_t annotation_off[1];
-  const uint32_t start = offset;
+  const uint32_t start = stream->Tell();
   for (std::unique_ptr<dex_ir::AnnotationSetItem>& annotation_set :
       header_->GetCollections().AnnotationSetItems()) {
-    offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeAnnotationSetItem));
+    stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationSetItem));
     size[0] = annotation_set->GetItems()->size();
-    ProcessOffset(&offset, annotation_set.get());
-    offset += Write(size, sizeof(uint32_t), offset);
+    ProcessOffset(stream, annotation_set.get());
+    stream->Write(size, sizeof(uint32_t));
     for (dex_ir::AnnotationItem* annotation : *annotation_set->GetItems()) {
       annotation_off[0] = annotation->GetOffset();
-      offset += Write(annotation_off, sizeof(uint32_t), offset);
+      stream->Write(annotation_off, sizeof(uint32_t));
     }
   }
-  if (compute_offsets_ && start != offset) {
+  if (compute_offsets_ && start != stream->Tell()) {
     header_->GetCollections().SetAnnotationSetItemsOffset(start);
   }
-  return offset - start;
+  return stream->Tell() - start;
 }
 
-uint32_t DexWriter::WriteAnnotationSetRefs(uint32_t offset) {
+uint32_t DexWriter::WriteAnnotationSetRefs(Stream* stream) {
   uint32_t size[1];
   uint32_t annotations_off[1];
-  const uint32_t start = offset;
+  const uint32_t start = stream->Tell();
   for (std::unique_ptr<dex_ir::AnnotationSetRefList>& annotation_set_ref :
       header_->GetCollections().AnnotationSetRefLists()) {
-    offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeAnnotationSetRefList));
+    stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationSetRefList));
     size[0] = annotation_set_ref->GetItems()->size();
-    ProcessOffset(&offset, annotation_set_ref.get());
-    offset += Write(size, sizeof(uint32_t), offset);
+    ProcessOffset(stream, annotation_set_ref.get());
+    stream->Write(size, sizeof(uint32_t));
     for (dex_ir::AnnotationSetItem* annotation_set : *annotation_set_ref->GetItems()) {
       annotations_off[0] = annotation_set == nullptr ? 0 : annotation_set->GetOffset();
-      offset += Write(annotations_off, sizeof(uint32_t), offset);
+      stream->Write(annotations_off, sizeof(uint32_t));
     }
   }
-  if (compute_offsets_ && start != offset) {
+  if (compute_offsets_ && start != stream->Tell()) {
     header_->GetCollections().SetAnnotationSetRefListsOffset(start);
   }
-  return offset - start;
+  return stream->Tell() - start;
 }
 
-uint32_t DexWriter::WriteAnnotationsDirectories(uint32_t offset) {
+uint32_t DexWriter::WriteAnnotationsDirectories(Stream* stream) {
   uint32_t directory_buffer[4];
   uint32_t annotation_buffer[2];
-  const uint32_t start = offset;
+  const uint32_t start = stream->Tell();
   for (std::unique_ptr<dex_ir::AnnotationsDirectoryItem>& annotations_directory :
       header_->GetCollections().AnnotationsDirectoryItems()) {
-    offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeAnnotationsDirectoryItem));
-    ProcessOffset(&offset, annotations_directory.get());
+    stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationsDirectoryItem));
+    ProcessOffset(stream, annotations_directory.get());
     directory_buffer[0] = annotations_directory->GetClassAnnotation() == nullptr ? 0 :
         annotations_directory->GetClassAnnotation()->GetOffset();
     directory_buffer[1] = annotations_directory->GetFieldAnnotations() == nullptr ? 0 :
@@ -461,13 +449,13 @@
         annotations_directory->GetMethodAnnotations()->size();
     directory_buffer[3] = annotations_directory->GetParameterAnnotations() == nullptr ? 0 :
         annotations_directory->GetParameterAnnotations()->size();
-    offset += Write(directory_buffer, 4 * sizeof(uint32_t), offset);
+    stream->Write(directory_buffer, 4 * sizeof(uint32_t));
     if (annotations_directory->GetFieldAnnotations() != nullptr) {
       for (std::unique_ptr<dex_ir::FieldAnnotation>& field :
           *annotations_directory->GetFieldAnnotations()) {
         annotation_buffer[0] = field->GetFieldId()->GetIndex();
         annotation_buffer[1] = field->GetAnnotationSetItem()->GetOffset();
-        offset += Write(annotation_buffer, 2 * sizeof(uint32_t), offset);
+        stream->Write(annotation_buffer, 2 * sizeof(uint32_t));
       }
     }
     if (annotations_directory->GetMethodAnnotations() != nullptr) {
@@ -475,7 +463,7 @@
           *annotations_directory->GetMethodAnnotations()) {
         annotation_buffer[0] = method->GetMethodId()->GetIndex();
         annotation_buffer[1] = method->GetAnnotationSetItem()->GetOffset();
-        offset += Write(annotation_buffer, 2 * sizeof(uint32_t), offset);
+        stream->Write(annotation_buffer, 2 * sizeof(uint32_t));
       }
     }
     if (annotations_directory->GetParameterAnnotations() != nullptr) {
@@ -483,37 +471,36 @@
           *annotations_directory->GetParameterAnnotations()) {
         annotation_buffer[0] = parameter->GetMethodId()->GetIndex();
         annotation_buffer[1] = parameter->GetAnnotations()->GetOffset();
-        offset += Write(annotation_buffer, 2 * sizeof(uint32_t), offset);
+        stream->Write(annotation_buffer, 2 * sizeof(uint32_t));
       }
     }
   }
-  if (compute_offsets_ && start != offset) {
+  if (compute_offsets_ && start != stream->Tell()) {
     header_->GetCollections().SetAnnotationsDirectoryItemsOffset(start);
   }
-  return offset - start;
+  return stream->Tell() - start;
 }
 
-uint32_t DexWriter::WriteDebugInfoItems(uint32_t offset) {
-  const uint32_t start = offset;
+uint32_t DexWriter::WriteDebugInfoItems(Stream* stream) {
+  const uint32_t start = stream->Tell();
   for (std::unique_ptr<dex_ir::DebugInfoItem>& debug_info :
       header_->GetCollections().DebugInfoItems()) {
-    offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeDebugInfoItem));
-    ProcessOffset(&offset, debug_info.get());
-    offset += Write(debug_info->GetDebugInfo(), debug_info->GetDebugInfoSize(), offset);
+    stream->AlignTo(SectionAlignment(DexFile::kDexTypeDebugInfoItem));
+    ProcessOffset(stream, debug_info.get());
+    stream->Write(debug_info->GetDebugInfo(), debug_info->GetDebugInfoSize());
   }
-  if (compute_offsets_ && start != offset) {
+  if (compute_offsets_ && start != stream->Tell()) {
     header_->GetCollections().SetDebugInfoItemsOffset(start);
   }
-  return offset - start;
+  return stream->Tell() - start;
 }
 
-uint32_t DexWriter::WriteCodeItemPostInstructionData(dex_ir::CodeItem* code_item,
-                                                     uint32_t offset,
+uint32_t DexWriter::WriteCodeItemPostInstructionData(Stream* stream,
+                                                     dex_ir::CodeItem* code_item,
                                                      bool reserve_only) {
-  const uint32_t start_offset = offset;
+  const uint32_t start_offset = stream->Tell();
   if (code_item->TriesSize() != 0) {
-    // Align for the try items.
-    offset = RoundUp(offset, DexFile::TryItem::kAlignment);
+    stream->AlignTo(DexFile::TryItem::kAlignment);
     // Write try items.
     for (std::unique_ptr<const dex_ir::TryItem>& try_item : *code_item->Tries()) {
       DexFile::TryItem disk_try_item;
@@ -522,38 +509,37 @@
         disk_try_item.insn_count_ = try_item->InsnCount();
         disk_try_item.handler_off_ = try_item->GetHandlers()->GetListOffset();
       }
-      offset += Write(&disk_try_item, sizeof(disk_try_item), offset);
+      stream->Write(&disk_try_item, sizeof(disk_try_item));
     }
-    size_t max_offset = offset;
     // Leave offset pointing to the end of the try items.
-    UNUSED(WriteUleb128(code_item->Handlers()->size(), offset));
+    const size_t offset = stream->Tell();
+    size_t max_offset = offset + stream->WriteUleb128(code_item->Handlers()->size());
     for (std::unique_ptr<const dex_ir::CatchHandler>& handlers : *code_item->Handlers()) {
-      size_t list_offset = offset + handlers->GetListOffset();
+      stream->Seek(offset + handlers->GetListOffset());
       uint32_t size = handlers->HasCatchAll() ? (handlers->GetHandlers()->size() - 1) * -1 :
           handlers->GetHandlers()->size();
-      list_offset += WriteSleb128(size, list_offset);
+      stream->WriteSleb128(size);
       for (std::unique_ptr<const dex_ir::TypeAddrPair>& handler : *handlers->GetHandlers()) {
         if (handler->GetTypeId() != nullptr) {
-          list_offset += WriteUleb128(handler->GetTypeId()->GetIndex(), list_offset);
+          stream->WriteUleb128(handler->GetTypeId()->GetIndex());
         }
-        list_offset += WriteUleb128(handler->GetAddress(), list_offset);
+        stream->WriteUleb128(handler->GetAddress());
       }
       // TODO: Clean this up to write the handlers in address order.
-      max_offset = std::max(max_offset, list_offset);
+      max_offset = std::max(max_offset, stream->Tell());
     }
-    offset = max_offset;
+    stream->Seek(max_offset);
   }
-
-  return offset - start_offset;
+  return stream->Tell() - start_offset;
 }
 
-uint32_t DexWriter::WriteCodeItem(dex_ir::CodeItem* code_item,
-                                  uint32_t offset,
+uint32_t DexWriter::WriteCodeItem(Stream* stream,
+                                  dex_ir::CodeItem* code_item,
                                   bool reserve_only) {
   DCHECK(code_item != nullptr);
-  const uint32_t start_offset = offset;
-  offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeCodeItem));
-  ProcessOffset(&offset, code_item);
+  const uint32_t start_offset = stream->Tell();
+  stream->AlignTo(SectionAlignment(DexFile::kDexTypeCodeItem));
+  ProcessOffset(stream, code_item);
 
   StandardDexFile::CodeItem disk_code_item;
   if (!reserve_only) {
@@ -568,50 +554,50 @@
   }
   // Avoid using sizeof so that we don't write the fake instruction array at the end of the code
   // item.
-  offset += Write(&disk_code_item,
-                  OFFSETOF_MEMBER(StandardDexFile::CodeItem, insns_),
-                  offset);
+  stream->Write(&disk_code_item, OFFSETOF_MEMBER(StandardDexFile::CodeItem, insns_));
   // Write the instructions.
-  offset += Write(code_item->Insns(), code_item->InsnsSize() * sizeof(uint16_t), offset);
+  stream->Write(code_item->Insns(), code_item->InsnsSize() * sizeof(uint16_t));
   // Write the post instruction data.
-  offset += WriteCodeItemPostInstructionData(code_item, offset, reserve_only);
-  return offset - start_offset;
+  WriteCodeItemPostInstructionData(stream, code_item, reserve_only);
+  if (reserve_only) {
+    stream->Clear(start_offset, stream->Tell() - start_offset);
+  }
+  return stream->Tell() - start_offset;
 }
 
-uint32_t DexWriter::WriteCodeItems(uint32_t offset, bool reserve_only) {
+uint32_t DexWriter::WriteCodeItems(Stream* stream, bool reserve_only) {
   DexLayoutSection* code_section = nullptr;
   if (!reserve_only && dex_layout_ != nullptr) {
     code_section = &dex_layout_->GetSections().sections_[static_cast<size_t>(
         DexLayoutSections::SectionType::kSectionTypeCode)];
   }
-  uint32_t start = offset;
+  const uint32_t start = stream->Tell();
   for (auto& code_item : header_->GetCollections().CodeItems()) {
-    const size_t code_item_size = WriteCodeItem(code_item.get(), offset, reserve_only);
+    const size_t code_item_size = WriteCodeItem(stream, code_item.get(), reserve_only);
     // Only add the section hotness info once.
     if (!reserve_only && code_section != nullptr) {
       auto it = dex_layout_->LayoutHotnessInfo().code_item_layout_.find(code_item.get());
       if (it != dex_layout_->LayoutHotnessInfo().code_item_layout_.end()) {
         code_section->parts_[static_cast<size_t>(it->second)].CombineSection(
-            offset,
-            offset + code_item_size);
+            stream->Tell() - code_item_size,
+            stream->Tell());
       }
     }
-    offset += code_item_size;
   }
 
-  if (compute_offsets_ && start != offset) {
+  if (compute_offsets_ && start != stream->Tell()) {
     header_->GetCollections().SetCodeItemsOffset(start);
   }
-  return offset - start;
+  return stream->Tell() - start;
 }
 
-uint32_t DexWriter::WriteClassDefs(uint32_t offset, bool reserve_only) {
-  const uint32_t start = offset;
+uint32_t DexWriter::WriteClassDefs(Stream* stream, bool reserve_only) {
+  const uint32_t start = stream->Tell();
   uint32_t class_def_buffer[8];
   for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
-    offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeClassDefItem));
+    stream->AlignTo(SectionAlignment(DexFile::kDexTypeClassDefItem));
     if (reserve_only) {
-      offset += class_def->GetSize();
+      stream->Skip(class_def->GetSize());
     } else {
       class_def_buffer[0] = class_def->ClassType()->GetIndex();
       class_def_buffer[1] = class_def->GetAccessFlags();
@@ -626,94 +612,94 @@
           class_def->GetClassData()->GetOffset();
       class_def_buffer[7] = class_def->StaticValues() == nullptr ? 0 :
           class_def->StaticValues()->GetOffset();
-      offset += Write(class_def_buffer, class_def->GetSize(), offset);
+      stream->Write(class_def_buffer, class_def->GetSize());
     }
   }
-  if (compute_offsets_ && start != offset) {
+  if (compute_offsets_ && start != stream->Tell()) {
     header_->GetCollections().SetClassDefsOffset(start);
   }
-  return offset - start;
+  return stream->Tell() - start;
 }
 
-uint32_t DexWriter::WriteClassDatas(uint32_t offset) {
-  const uint32_t start = offset;
+uint32_t DexWriter::WriteClassDatas(Stream* stream) {
+  const uint32_t start = stream->Tell();
   for (const std::unique_ptr<dex_ir::ClassData>& class_data :
       header_->GetCollections().ClassDatas()) {
-    offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeClassDataItem));
-    ProcessOffset(&offset, class_data.get());
-    offset += WriteUleb128(class_data->StaticFields()->size(), offset);
-    offset += WriteUleb128(class_data->InstanceFields()->size(), offset);
-    offset += WriteUleb128(class_data->DirectMethods()->size(), offset);
-    offset += WriteUleb128(class_data->VirtualMethods()->size(), offset);
-    offset += WriteEncodedFields(class_data->StaticFields(), offset);
-    offset += WriteEncodedFields(class_data->InstanceFields(), offset);
-    offset += WriteEncodedMethods(class_data->DirectMethods(), offset);
-    offset += WriteEncodedMethods(class_data->VirtualMethods(), offset);
+    stream->AlignTo(SectionAlignment(DexFile::kDexTypeClassDataItem));
+    ProcessOffset(stream, class_data.get());
+    stream->WriteUleb128(class_data->StaticFields()->size());
+    stream->WriteUleb128(class_data->InstanceFields()->size());
+    stream->WriteUleb128(class_data->DirectMethods()->size());
+    stream->WriteUleb128(class_data->VirtualMethods()->size());
+    WriteEncodedFields(stream, class_data->StaticFields());
+    WriteEncodedFields(stream, class_data->InstanceFields());
+    WriteEncodedMethods(stream, class_data->DirectMethods());
+    WriteEncodedMethods(stream, class_data->VirtualMethods());
   }
-  if (compute_offsets_ && start != offset) {
+  if (compute_offsets_ && start != stream->Tell()) {
     header_->GetCollections().SetClassDatasOffset(start);
   }
-  return offset - start;
+  return stream->Tell() - start;
 }
 
-uint32_t DexWriter::WriteCallSiteIds(uint32_t offset, bool reserve_only) {
-  const uint32_t start = offset;
+uint32_t DexWriter::WriteCallSiteIds(Stream* stream, bool reserve_only) {
+  const uint32_t start = stream->Tell();
   uint32_t call_site_off[1];
   for (std::unique_ptr<dex_ir::CallSiteId>& call_site_id :
       header_->GetCollections().CallSiteIds()) {
-    offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeCallSiteIdItem));
+    stream->AlignTo(SectionAlignment(DexFile::kDexTypeCallSiteIdItem));
     if (reserve_only) {
-      offset += call_site_id->GetSize();
+      stream->Skip(call_site_id->GetSize());
     } else {
       call_site_off[0] = call_site_id->CallSiteItem()->GetOffset();
-      offset += Write(call_site_off, call_site_id->GetSize(), offset);
+      stream->Write(call_site_off, call_site_id->GetSize());
     }
   }
-  if (compute_offsets_ && start != offset) {
+  if (compute_offsets_ && start != stream->Tell()) {
     header_->GetCollections().SetCallSiteIdsOffset(start);
   }
-  return offset - start;
+  return stream->Tell() - start;
 }
 
-uint32_t DexWriter::WriteMethodHandles(uint32_t offset) {
-  const uint32_t start = offset;
+uint32_t DexWriter::WriteMethodHandles(Stream* stream) {
+  const uint32_t start = stream->Tell();
   uint16_t method_handle_buff[4];
   for (std::unique_ptr<dex_ir::MethodHandleItem>& method_handle :
       header_->GetCollections().MethodHandleItems()) {
-    offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeMethodHandleItem));
+    stream->AlignTo(SectionAlignment(DexFile::kDexTypeMethodHandleItem));
     method_handle_buff[0] = static_cast<uint16_t>(method_handle->GetMethodHandleType());
     method_handle_buff[1] = 0;  // unused.
     method_handle_buff[2] = method_handle->GetFieldOrMethodId()->GetIndex();
     method_handle_buff[3] = 0;  // unused.
-    offset += Write(method_handle_buff, method_handle->GetSize(), offset);
+    stream->Write(method_handle_buff, method_handle->GetSize());
   }
-  if (compute_offsets_ && start != offset) {
+  if (compute_offsets_ && start != stream->Tell()) {
     header_->GetCollections().SetMethodHandleItemsOffset(start);
   }
-  return offset - start;
+  return stream->Tell() - start;
 }
 
-uint32_t DexWriter::WriteMapItems(uint32_t offset, MapItemQueue* queue) {
+uint32_t DexWriter::WriteMapItems(Stream* stream, MapItemQueue* queue) {
   // All the sections should already have been added.
   uint16_t uint16_buffer[2];
   uint32_t uint32_buffer[2];
   uint16_buffer[1] = 0;
   uint32_buffer[0] = queue->size();
-  const uint32_t start = offset;
-  offset += Write(uint32_buffer, sizeof(uint32_t), offset);
+  const uint32_t start = stream->Tell();
+  stream->Write(uint32_buffer, sizeof(uint32_t));
   while (!queue->empty()) {
     const MapItem& map_item = queue->top();
     uint16_buffer[0] = map_item.type_;
     uint32_buffer[0] = map_item.size_;
     uint32_buffer[1] = map_item.offset_;
-    offset += Write(uint16_buffer, 2 * sizeof(uint16_t), offset);
-    offset += Write(uint32_buffer, 2 * sizeof(uint32_t), offset);
+    stream->Write(uint16_buffer, 2 * sizeof(uint16_t));
+    stream->Write(uint32_buffer, 2 * sizeof(uint32_t));
     queue->pop();
   }
-  return offset - start;
+  return stream->Tell() - start;
 }
 
-uint32_t DexWriter::GenerateAndWriteMapItems(uint32_t offset) {
+uint32_t DexWriter::GenerateAndWriteMapItems(Stream* stream) {
   dex_ir::Collections& collection = header_->GetCollections();
   MapItemQueue queue;
 
@@ -777,10 +763,10 @@
                               collection.AnnotationsDirectoryItemsOffset()));
 
   // Write the map items.
-  return WriteMapItems(offset, &queue);
+  return WriteMapItems(stream, &queue);
 }
 
-void DexWriter::WriteHeader() {
+void DexWriter::WriteHeader(Stream* stream) {
   StandardDexFile::Header header;
   if (CompactDexFile::IsMagicValid(header_->Magic())) {
     StandardDexFile::WriteMagic(header.magic_);
@@ -818,78 +804,97 @@
 
   CHECK_EQ(sizeof(header), GetHeaderSize());
   static_assert(sizeof(header) == 0x70, "Size doesn't match dex spec");
-  UNUSED(Write(reinterpret_cast<uint8_t*>(&header), sizeof(header), 0u));
+  stream->Seek(0);
+  stream->Overwrite(reinterpret_cast<uint8_t*>(&header), sizeof(header));
 }
 
 size_t DexWriter::GetHeaderSize() const {
   return sizeof(StandardDexFile::Header);
 }
 
-void DexWriter::WriteMemMap() {
+void DexWriter::Write(DexContainer* output) {
+  Stream stream_storage(output->GetMainSection());
+  Stream* stream = &stream_storage;
+
   // Starting offset is right after the header.
-  uint32_t offset = GetHeaderSize();
+  stream->Seek(GetHeaderSize());
 
   dex_ir::Collections& collection = header_->GetCollections();
 
   // Based on: https://source.android.com/devices/tech/dalvik/dex-format
   // Since the offsets may not be calculated already, the writing must be done in the correct order.
-  const uint32_t string_ids_offset = offset;
-  offset += WriteStringIds(offset, /*reserve_only*/ true);
-  offset += WriteTypeIds(offset);
-  const uint32_t proto_ids_offset = offset;
-  offset += WriteProtoIds(offset, /*reserve_only*/ true);
-  offset += WriteFieldIds(offset);
-  offset += WriteMethodIds(offset);
-  const uint32_t class_defs_offset = offset;
-  offset += WriteClassDefs(offset, /*reserve_only*/ true);
-  const uint32_t call_site_ids_offset = offset;
-  offset += WriteCallSiteIds(offset, /*reserve_only*/ true);
-  offset += WriteMethodHandles(offset);
+  const uint32_t string_ids_offset = stream->Tell();
+  WriteStringIds(stream, /*reserve_only*/ true);
+  WriteTypeIds(stream);
+  const uint32_t proto_ids_offset = stream->Tell();
+  WriteProtoIds(stream, /*reserve_only*/ true);
+  WriteFieldIds(stream);
+  WriteMethodIds(stream);
+  const uint32_t class_defs_offset = stream->Tell();
+  WriteClassDefs(stream, /*reserve_only*/ true);
+  const uint32_t call_site_ids_offset = stream->Tell();
+  WriteCallSiteIds(stream, /*reserve_only*/ true);
+  WriteMethodHandles(stream);
 
   uint32_t data_offset_ = 0u;
   if (compute_offsets_) {
     // Data section.
-    offset = RoundUp(offset, kDataSectionAlignment);
-    data_offset_ = offset;
+    stream->AlignTo(kDataSectionAlignment);
+    data_offset_ = stream->Tell();
   }
 
   // Write code item first to minimize the space required for encoded methods.
   // Reserve code item space since we need the debug offsets to actually write them.
-  const uint32_t code_items_offset = offset;
-  offset += WriteCodeItems(offset, /*reserve_only*/ true);
+  const uint32_t code_items_offset = stream->Tell();
+  WriteCodeItems(stream, /*reserve_only*/ true);
   // Write debug info section.
-  offset += WriteDebugInfoItems(offset);
-  // Actually write code items since debug info offsets are calculated now.
-  WriteCodeItems(code_items_offset, /*reserve_only*/ false);
+  WriteDebugInfoItems(stream);
+  {
+    // Actually write code items since debug info offsets are calculated now.
+    Stream::ScopedSeek seek(stream, code_items_offset);
+    WriteCodeItems(stream, /*reserve_only*/ false);
+  }
 
-  offset += WriteEncodedArrays(offset);
-  offset += WriteAnnotations(offset);
-  offset += WriteAnnotationSets(offset);
-  offset += WriteAnnotationSetRefs(offset);
-  offset += WriteAnnotationsDirectories(offset);
-  offset += WriteTypeLists(offset);
-  offset += WriteClassDatas(offset);
-  offset += WriteStringDatas(offset);
+  WriteEncodedArrays(stream);
+  WriteAnnotations(stream);
+  WriteAnnotationSets(stream);
+  WriteAnnotationSetRefs(stream);
+  WriteAnnotationsDirectories(stream);
+  WriteTypeLists(stream);
+  WriteClassDatas(stream);
+  WriteStringDatas(stream);
 
   // Write delayed id sections that depend on data sections.
-  WriteStringIds(string_ids_offset, /*reserve_only*/ false);
-  WriteProtoIds(proto_ids_offset, /*reserve_only*/ false);
-  WriteClassDefs(class_defs_offset, /*reserve_only*/ false);
-  WriteCallSiteIds(call_site_ids_offset, /*reserve_only*/ false);
+  {
+    Stream::ScopedSeek seek(stream, string_ids_offset);
+    WriteStringIds(stream, /*reserve_only*/ false);
+  }
+  {
+    Stream::ScopedSeek seek(stream, proto_ids_offset);
+    WriteProtoIds(stream, /*reserve_only*/ false);
+  }
+  {
+    Stream::ScopedSeek seek(stream, class_defs_offset);
+    WriteClassDefs(stream, /*reserve_only*/ false);
+  }
+  {
+    Stream::ScopedSeek seek(stream, call_site_ids_offset);
+    WriteCallSiteIds(stream, /*reserve_only*/ false);
+  }
 
   // Write the map list.
   if (compute_offsets_) {
-    offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeMapList));
-    collection.SetMapListOffset(offset);
+    stream->AlignTo(SectionAlignment(DexFile::kDexTypeMapList));
+    collection.SetMapListOffset(stream->Tell());
   } else {
-    offset = collection.MapListOffset();
+    stream->Seek(collection.MapListOffset());
   }
-  offset += GenerateAndWriteMapItems(offset);
-  offset = RoundUp(offset, kDataSectionAlignment);
+  GenerateAndWriteMapItems(stream);
+  stream->AlignTo(kDataSectionAlignment);
 
   // Map items are included in the data section.
   if (compute_offsets_) {
-    header_->SetDataSize(offset - data_offset_);
+    header_->SetDataSize(stream->Tell() - data_offset_);
     if (header_->DataSize() != 0) {
       // Offset must be zero when the size is zero.
       header_->SetDataOffset(data_offset_);
@@ -903,37 +908,45 @@
   if (link_data.size() > 0) {
     CHECK_EQ(header_->LinkSize(), static_cast<uint32_t>(link_data.size()));
     if (compute_offsets_) {
-      header_->SetLinkOffset(offset);
+      header_->SetLinkOffset(stream->Tell());
+    } else {
+      stream->Seek(header_->LinkOffset());
     }
-    offset += Write(&link_data[0], link_data.size(), header_->LinkOffset());
+    stream->Write(&link_data[0], link_data.size());
   }
 
   // Write header last.
   if (compute_offsets_) {
-    header_->SetFileSize(offset);
+    header_->SetFileSize(stream->Tell());
   }
-  WriteHeader();
+  WriteHeader(stream);
 
   if (dex_layout_->GetOptions().update_checksum_) {
-    header_->SetChecksum(DexFile::CalculateChecksum(mem_map_->Begin(), offset));
+    header_->SetChecksum(DexFile::CalculateChecksum(stream->Begin(), header_->FileSize()));
     // Rewrite the header with the calculated checksum.
-    WriteHeader();
+    WriteHeader(stream);
   }
+
+  // Trim the map to make it sized as large as the dex file.
+  output->GetMainSection()->Resize(header_->FileSize());
 }
 
-void DexWriter::Output(dex_ir::Header* header,
-                       MemMap* mem_map,
-                       DexLayout* dex_layout,
-                       bool compute_offsets,
-                       CompactDexLevel compact_dex_level) {
+void DexWriter::Output(DexLayout* dex_layout,
+                       std::unique_ptr<DexContainer>* container,
+                       bool compute_offsets) {
   CHECK(dex_layout != nullptr);
   std::unique_ptr<DexWriter> writer;
-  if (compact_dex_level != CompactDexLevel::kCompactDexLevelNone) {
-    writer.reset(new CompactDexWriter(header, mem_map, dex_layout, compact_dex_level));
+  if (dex_layout->GetOptions().compact_dex_level_ != CompactDexLevel::kCompactDexLevelNone) {
+    CHECK(compute_offsets) << "Compact dex requires computing offsets";
+    writer.reset(new CompactDexWriter(dex_layout));
   } else {
-    writer.reset(new DexWriter(header, mem_map, dex_layout, compute_offsets));
+    writer.reset(new DexWriter(dex_layout, compute_offsets));
   }
-  writer->WriteMemMap();
+  DCHECK(container != nullptr);
+  if (*container == nullptr) {
+    *container = writer->CreateDexContainer();
+  }
+  writer->Write(container->get());
 }
 
 void MapItemQueue::AddIfNotEmpty(const MapItem& item) {
@@ -942,4 +955,17 @@
   }
 }
 
+void DexWriter::ProcessOffset(Stream* stream, dex_ir::Item* item) {
+  if (compute_offsets_) {
+    item->SetOffset(stream->Tell());
+  } else {
+    // Not computing offsets, just use the one in the item.
+    stream->Seek(item->GetOffset());
+  }
+}
+
+std::unique_ptr<DexContainer> DexWriter::CreateDexContainer() const {
+  return std::unique_ptr<DexContainer>(new DexWriter::Container);
+}
+
 }  // namespace art
diff --git a/dexlayout/dex_writer.h b/dexlayout/dex_writer.h
index 892ea74..e581a8b 100644
--- a/dexlayout/dex_writer.h
+++ b/dexlayout/dex_writer.h
@@ -20,9 +20,11 @@
 #define ART_DEXLAYOUT_DEX_WRITER_H_
 
 #include <functional>
+#include <memory>  // For unique_ptr
 
 #include "base/unix_file/fd_file.h"
 #include "dex/compact_dex_level.h"
+#include "dex_container.h"
 #include "dex/dex_file.h"
 #include "dex_ir.h"
 #include "mem_map.h"
@@ -39,7 +41,7 @@
   // Not using DexFile::MapItemType since compact dex and standard dex file may have different
   // sections.
   MapItem() = default;
-  MapItem(uint32_t type, uint32_t size, uint32_t offset)
+  MapItem(uint32_t type, uint32_t size, size_t offset)
       : type_(type), size_(size), offset_(offset) { }
 
   // Sort by decreasing order since the priority_queue puts largest elements first.
@@ -63,6 +65,114 @@
   static constexpr uint32_t kDataSectionAlignment = sizeof(uint32_t) * 2;
   static constexpr uint32_t kDexSectionWordAlignment = 4;
 
+  // Stream that writes into a dex container section. Do not have two streams pointing to the same
+  // backing storage as there may be invalidation of backing storage to resize the section.
+  // Random access stream (consider refactoring).
+  class Stream {
+   public:
+    explicit Stream(DexContainer::Section* section) : section_(section) {
+      SyncWithSection();
+    }
+
+    const uint8_t* Begin() const {
+      return data_;
+    }
+
+    // Functions are not virtual (yet) for speed.
+    size_t Tell() const {
+      return position_;
+    }
+
+    void Seek(size_t position) {
+      position_ = position;
+    }
+
+    // Does not allow overwriting for bug prevention purposes.
+    ALWAYS_INLINE size_t Write(const void* buffer, size_t length) {
+      EnsureStorage(length);
+      for (size_t i = 0; i < length; ++i) {
+        DCHECK_EQ(data_[position_ + i], 0u);
+      }
+      memcpy(&data_[position_], buffer, length);
+      position_ += length;
+      return length;
+    }
+
+    ALWAYS_INLINE size_t Overwrite(const void* buffer, size_t length) {
+      EnsureStorage(length);
+      memcpy(&data_[position_], buffer, length);
+      position_ += length;
+      return length;
+    }
+
+    ALWAYS_INLINE size_t Clear(size_t position, size_t length) {
+      EnsureStorage(length);
+      memset(&data_[position], 0, length);
+      return length;
+    }
+
+    ALWAYS_INLINE size_t WriteSleb128(int32_t value) {
+      EnsureStorage(8);
+      uint8_t* ptr = &data_[position_];
+      const size_t len = EncodeSignedLeb128(ptr, value) - ptr;
+      position_ += len;
+      return len;
+    }
+
+    ALWAYS_INLINE size_t WriteUleb128(uint32_t value) {
+      EnsureStorage(8);
+      uint8_t* ptr = &data_[position_];
+      const size_t len = EncodeUnsignedLeb128(ptr, value) - ptr;
+      position_ += len;
+      return len;
+    }
+
+    ALWAYS_INLINE void AlignTo(const size_t alignment) {
+      position_ = RoundUp(position_, alignment);
+    }
+
+    ALWAYS_INLINE void Skip(const size_t count) {
+      position_ += count;
+    }
+
+    class ScopedSeek {
+     public:
+      ScopedSeek(Stream* stream, uint32_t offset) : stream_(stream), offset_(stream->Tell()) {
+        stream->Seek(offset);
+      }
+
+      ~ScopedSeek() {
+        stream_->Seek(offset_);
+      }
+
+     private:
+      Stream* const stream_;
+      const uint32_t offset_;
+    };
+
+   private:
+    ALWAYS_INLINE void EnsureStorage(size_t length) {
+      size_t end = position_ + length;
+      while (UNLIKELY(end > data_size_)) {
+        section_->Resize(data_size_ * 3 / 2 + 1);
+        SyncWithSection();
+      }
+    }
+
+    void SyncWithSection() {
+      data_ = section_->Begin();
+      data_size_ = section_->Size();
+    }
+
+    // Current position of the stream.
+    size_t position_ = 0u;
+    DexContainer::Section* const section_ = nullptr;
+    // Cached Begin() from the container to provide faster accesses.
+    uint8_t* data_ = nullptr;
+    // Cached Size from the container to provide faster accesses.
+    size_t data_size_ = 0u;
+  };
+
   static inline constexpr uint32_t SectionAlignment(DexFile::MapItemType type) {
     switch (type) {
       case DexFile::kDexTypeClassDataItem:
@@ -78,83 +188,85 @@
     }
   }
 
-  DexWriter(dex_ir::Header* header,
-            MemMap* mem_map,
-            DexLayout* dex_layout,
-            bool compute_offsets)
-      : header_(header),
-        mem_map_(mem_map),
-        dex_layout_(dex_layout),
-        compute_offsets_(compute_offsets) {}
+  class Container : public DexContainer {
+   public:
+    Section* GetMainSection() OVERRIDE {
+      return &main_section_;
+    }
 
-  static void Output(dex_ir::Header* header,
-                     MemMap* mem_map,
-                     DexLayout* dex_layout,
-                     bool compute_offsets,
-                     CompactDexLevel compact_dex_level);
+    Section* GetDataSection() OVERRIDE {
+      return &data_section_;
+    }
+
+    bool IsCompactDexContainer() const OVERRIDE {
+      return false;
+    }
+
+   private:
+    VectorSection main_section_;
+    VectorSection data_section_;
+
+    friend class CompactDexWriter;
+  };
+
+  DexWriter(DexLayout* dex_layout, bool compute_offsets);
+
+  static void Output(DexLayout* dex_layout,
+                     std::unique_ptr<DexContainer>* container,
+                     bool compute_offsets);
 
   virtual ~DexWriter() {}
 
  protected:
-  virtual void WriteMemMap();
+  virtual void Write(DexContainer* output);
+  virtual std::unique_ptr<DexContainer> CreateDexContainer() const;
 
-  size_t Write(const void* buffer, size_t length, size_t offset) WARN_UNUSED;
-  size_t WriteSleb128(uint32_t value, size_t offset) WARN_UNUSED;
-  size_t WriteUleb128(uint32_t value, size_t offset) WARN_UNUSED;
-  size_t WriteEncodedValue(dex_ir::EncodedValue* encoded_value, size_t offset) WARN_UNUSED;
-  size_t WriteEncodedValueHeader(int8_t value_type, size_t value_arg, size_t offset) WARN_UNUSED;
-  size_t WriteEncodedArray(dex_ir::EncodedValueVector* values, size_t offset) WARN_UNUSED;
-  size_t WriteEncodedAnnotation(dex_ir::EncodedAnnotation* annotation, size_t offset) WARN_UNUSED;
-  size_t WriteEncodedFields(dex_ir::FieldItemVector* fields, size_t offset) WARN_UNUSED;
-  size_t WriteEncodedMethods(dex_ir::MethodItemVector* methods, size_t offset) WARN_UNUSED;
+  size_t WriteEncodedValue(Stream* stream, dex_ir::EncodedValue* encoded_value);
+  size_t WriteEncodedValueHeader(Stream* stream, int8_t value_type, size_t value_arg);
+  size_t WriteEncodedArray(Stream* stream, dex_ir::EncodedValueVector* values);
+  size_t WriteEncodedAnnotation(Stream* stream, dex_ir::EncodedAnnotation* annotation);
+  size_t WriteEncodedFields(Stream* stream, dex_ir::FieldItemVector* fields);
+  size_t WriteEncodedMethods(Stream* stream, dex_ir::MethodItemVector* methods);
 
   // Header and id section
-  virtual void WriteHeader();
+  virtual void WriteHeader(Stream* stream);
   virtual size_t GetHeaderSize() const;
   // reserve_only means don't write, only reserve space. This is required since the string data
   // offsets must be assigned.
-  uint32_t WriteStringIds(uint32_t offset, bool reserve_only);
-  uint32_t WriteTypeIds(uint32_t offset);
-  uint32_t WriteProtoIds(uint32_t offset, bool reserve_only);
-  uint32_t WriteFieldIds(uint32_t offset);
-  uint32_t WriteMethodIds(uint32_t offset);
-  uint32_t WriteClassDefs(uint32_t offset, bool reserve_only);
-  uint32_t WriteCallSiteIds(uint32_t offset, bool reserve_only);
+  uint32_t WriteStringIds(Stream* stream, bool reserve_only);
+  uint32_t WriteTypeIds(Stream* stream);
+  uint32_t WriteProtoIds(Stream* stream, bool reserve_only);
+  uint32_t WriteFieldIds(Stream* stream);
+  uint32_t WriteMethodIds(Stream* stream);
+  uint32_t WriteClassDefs(Stream* stream, bool reserve_only);
+  uint32_t WriteCallSiteIds(Stream* stream, bool reserve_only);
 
-  uint32_t WriteEncodedArrays(uint32_t offset);
-  uint32_t WriteAnnotations(uint32_t offset);
-  uint32_t WriteAnnotationSets(uint32_t offset);
-  uint32_t WriteAnnotationSetRefs(uint32_t offset);
-  uint32_t WriteAnnotationsDirectories(uint32_t offset);
+  uint32_t WriteEncodedArrays(Stream* stream);
+  uint32_t WriteAnnotations(Stream* stream);
+  uint32_t WriteAnnotationSets(Stream* stream);
+  uint32_t WriteAnnotationSetRefs(Stream* stream);
+  uint32_t WriteAnnotationsDirectories(Stream* stream);
 
   // Data section.
-  uint32_t WriteDebugInfoItems(uint32_t offset);
-  uint32_t WriteCodeItems(uint32_t offset, bool reserve_only);
-  uint32_t WriteTypeLists(uint32_t offset);
-  uint32_t WriteStringDatas(uint32_t offset);
-  uint32_t WriteClassDatas(uint32_t offset);
-  uint32_t WriteMethodHandles(uint32_t offset);
-  uint32_t WriteMapItems(uint32_t offset, MapItemQueue* queue);
-  uint32_t GenerateAndWriteMapItems(uint32_t offset);
+  uint32_t WriteDebugInfoItems(Stream* stream);
+  uint32_t WriteCodeItems(Stream* stream, bool reserve_only);
+  uint32_t WriteTypeLists(Stream* stream);
+  uint32_t WriteStringDatas(Stream* stream);
+  uint32_t WriteClassDatas(Stream* stream);
+  uint32_t WriteMethodHandles(Stream* stream);
+  uint32_t WriteMapItems(Stream* stream, MapItemQueue* queue);
+  uint32_t GenerateAndWriteMapItems(Stream* stream);
 
-  virtual uint32_t WriteCodeItemPostInstructionData(dex_ir::CodeItem* item,
-                                                    uint32_t offset,
+  virtual uint32_t WriteCodeItemPostInstructionData(Stream* stream,
+                                                    dex_ir::CodeItem* item,
                                                     bool reserve_only);
-  virtual uint32_t WriteCodeItem(dex_ir::CodeItem* item, uint32_t offset, bool reserve_only);
+  virtual uint32_t WriteCodeItem(Stream* stream, dex_ir::CodeItem* item, bool reserve_only);
 
   // Process an offset, if compute_offset is set, write into the dex ir item, otherwise read the
   // existing offset and use that for writing.
-  void ProcessOffset(uint32_t* const offset, dex_ir::Item* item) {
-    if (compute_offsets_) {
-      item->SetOffset(*offset);
-    } else {
-      // Not computing offsets, just use the one in the item.
-      *offset = item->GetOffset();
-    }
-  }
+  void ProcessOffset(Stream* stream, dex_ir::Item* item);
 
   dex_ir::Header* const header_;
-  MemMap* const mem_map_;
   DexLayout* const dex_layout_;
   bool compute_offsets_;
 
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index 3d3b121..d33a0bd 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -1813,21 +1813,14 @@
   LayoutCodeItems(dex_file);
 }
 
-void DexLayout::OutputDexFile(const DexFile* dex_file, bool compute_offsets) {
-  const std::string& dex_file_location = dex_file->GetLocation();
+void DexLayout::OutputDexFile(const DexFile* input_dex_file,
+                              bool compute_offsets,
+                              std::unique_ptr<DexContainer>* dex_container) {
+  const std::string& dex_file_location = input_dex_file->GetLocation();
   std::string error_msg;
   std::unique_ptr<File> new_file;
-  // Since we allow dex growth, we need to size the map larger than the original input to be safe.
-  // Reserve an extra 10% to add some buffer room. Note that this is probably more than
-  // necessary.
-  static constexpr size_t kReserveFraction = 10;
-  // Add an extra constant amount since the compact dex header and extra tables may cause more
-  // expansion than fits in the reserve fraction for small dex files.
-  // TODO: Move to using a resizable buffer like a vector.
-  static constexpr size_t kExtraReserve = 128 * KB;
-  const size_t max_size = header_->FileSize() + kExtraReserve +
-      header_->FileSize() / kReserveFraction;
-  if (!options_.output_to_memmap_) {
+  // If options_.output_dex_directory_ is non null, we are outputting to a file.
+  if (options_.output_dex_directory_ != nullptr) {
     std::string output_location(options_.output_dex_directory_);
     size_t last_slash = dex_file_location.rfind('/');
     std::string dex_file_directory = dex_file_location.substr(0, last_slash + 1);
@@ -1843,32 +1836,18 @@
       LOG(ERROR) << "Could not create dex writer output file: " << output_location;
       return;
     }
-    if (ftruncate(new_file->Fd(), max_size) != 0) {
-      LOG(ERROR) << "Could not grow dex writer output file: " << output_location;;
+  }
+  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) {
+    if (!new_file->WriteFully(main_section->Begin(), main_section->Size())) {
+      LOG(ERROR) << "Failed tow write dex file to " << dex_file_location;
       new_file->Erase();
       return;
     }
-    mem_map_.reset(MemMap::MapFile(max_size, PROT_READ | PROT_WRITE, MAP_SHARED,
-        new_file->Fd(), 0, /*low_4gb*/ false, output_location.c_str(), &error_msg));
-  } else {
-    mem_map_.reset(MemMap::MapAnonymous("layout dex", nullptr, max_size,
-        PROT_READ | PROT_WRITE, /* low_4gb */ false, /* reuse */ false, &error_msg));
-  }
-  if (mem_map_ == nullptr) {
-    LOG(ERROR) << "Could not create mem map for dex writer output: " << error_msg;
-    if (new_file != nullptr) {
-      new_file->Erase();
-    }
-    return;
-  }
-  DexWriter::Output(header_, mem_map_.get(), this, compute_offsets, options_.compact_dex_level_);
-  if (new_file != nullptr) {
-    // Since we make the memmap larger than needed, shrink the file back down to not leave extra
-    // padding.
-    int res = new_file->SetLength(header_->FileSize());
-    if (res != 0) {
-      LOG(ERROR) << "Truncating file resulted in " << res;
-    }
     UNUSED(new_file->FlushCloseOrErase());
   }
 }
@@ -1878,8 +1857,11 @@
  */
 void DexLayout::ProcessDexFile(const char* file_name,
                                const DexFile* dex_file,
-                               size_t dex_file_index) {
-  const bool output = options_.output_dex_directory_ != nullptr || options_.output_to_memmap_;
+                               size_t dex_file_index,
+                               std::unique_ptr<DexContainer>* dex_container) {
+  const bool has_output_container = dex_container != nullptr;
+  const bool output = options_.output_dex_directory_ != nullptr || has_output_container;
+
   // Try to avoid eagerly assigning offsets to find bugs since GetOffset will abort if the offset
   // is unassigned.
   bool eagerly_assign_offsets = false;
@@ -1918,22 +1900,29 @@
     if (do_layout) {
       LayoutOutputFile(dex_file);
     }
+    // The output needs a dex container, use a temporary one.
+    std::unique_ptr<DexContainer> temp_container;
+    if (dex_container == nullptr) {
+      dex_container = &temp_container;
+    }
     // If we didn't set the offsets eagerly, we definitely need to compute them here.
-    OutputDexFile(dex_file, do_layout || !eagerly_assign_offsets);
+    OutputDexFile(dex_file, do_layout || !eagerly_assign_offsets, dex_container);
 
     // Clear header before verifying to reduce peak RAM usage.
     const size_t file_size = header_->FileSize();
     header.reset();
 
     // Verify the output dex file's structure, only enabled by default for debug builds.
-    if (options_.verify_output_) {
+    if (options_.verify_output_ && has_output_container) {
       std::string error_msg;
       std::string location = "memory mapped file for " + std::string(file_name);
       // 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());
       std::unique_ptr<const DexFile> output_dex_file(
-          dex_file_loader.Open(mem_map_->Begin(),
+          dex_file_loader.Open(section->Begin(),
                                file_size,
                                location,
                                /* checksum */ 0,
@@ -1988,7 +1977,8 @@
     fprintf(out_file_, "Checksum verified\n");
   } else {
     for (size_t i = 0; i < dex_files.size(); i++) {
-      ProcessDexFile(file_name, dex_files[i].get(), i);
+      // Pass in a null container to avoid output by default.
+      ProcessDexFile(file_name, dex_files[i].get(), i, /*dex_container*/ nullptr);
     }
   }
   return 0;
diff --git a/dexlayout/dexlayout.h b/dexlayout/dexlayout.h
index cb0eabc..00d24db 100644
--- a/dexlayout/dexlayout.h
+++ b/dexlayout/dexlayout.h
@@ -28,6 +28,7 @@
 #include <unordered_map>
 
 #include "dex/compact_dex_level.h"
+#include "dex_container.h"
 #include "dex/dex_file_layout.h"
 #include "dex_ir.h"
 #include "mem_map.h"
@@ -55,7 +56,7 @@
   bool disassemble_ = false;
   bool exports_only_ = false;
   bool ignore_bad_checksum_ = false;
-  bool output_to_memmap_ = false;
+  bool output_to_container_ = false;
   bool show_annotations_ = false;
   bool show_file_headers_ = false;
   bool show_section_headers_ = false;
@@ -82,6 +83,18 @@
 
 class DexLayout {
  public:
+  class VectorOutputContainer {
+   public:
+    // Begin is not necessarily aligned (for now).
+    uint8_t* Begin() {
+      return &data_[0];
+    }
+
+   private:
+    std::vector<uint8_t> data_;
+  };
+
+
   // Setting this to false disables class def layout entirely, which is stronger than strictly
   // necessary to ensure the partial order w.r.t. class derivation. TODO: Re-enable (b/68317550).
   static constexpr bool kChangeClassDefOrder = false;
@@ -89,18 +102,21 @@
   DexLayout(Options& options,
             ProfileCompilationInfo* info,
             FILE* out_file,
-            dex_ir::Header*
-            header = nullptr)
-      : options_(options), info_(info), out_file_(out_file), header_(header) { }
+            dex_ir::Header* header)
+      : options_(options),
+        info_(info),
+        out_file_(out_file),
+        header_(header) { }
 
   int ProcessFile(const char* file_name);
-  void ProcessDexFile(const char* file_name, const DexFile* dex_file, size_t dex_file_index);
+  void ProcessDexFile(const char* file_name,
+                      const DexFile* dex_file,
+                      size_t dex_file_index,
+                      std::unique_ptr<DexContainer>* dex_container);
 
   dex_ir::Header* GetHeader() const { return header_; }
   void SetHeader(dex_ir::Header* header) { header_ = header; }
 
-  MemMap* GetAndReleaseMemMap() { return mem_map_.release(); }
-
   DexLayoutSections& GetSections() {
     return dex_sections_;
   }
@@ -150,7 +166,9 @@
   // Creates a new layout for the dex file based on profile info.
   // Currently reorders ClassDefs, ClassDataItems, and CodeItems.
   void LayoutOutputFile(const DexFile* dex_file);
-  void OutputDexFile(const DexFile* dex_file, bool compute_offsets);
+  void OutputDexFile(const DexFile* input_dex_file,
+                     bool compute_offsets,
+                     std::unique_ptr<DexContainer>* dex_container);
 
   void DumpCFG(const DexFile* dex_file, int idx);
   void DumpCFG(const DexFile* dex_file, uint32_t dex_method_idx, const DexFile::CodeItem* code);
@@ -159,7 +177,6 @@
   ProfileCompilationInfo* info_;
   FILE* out_file_;
   dex_ir::Header* header_;
-  std::unique_ptr<MemMap> mem_map_;
   DexLayoutSections dex_sections_;
   // Layout hotness information is only calculated when dexlayout is enabled.
   DexLayoutHotnessInfo layout_hotness_info_;
diff --git a/dexlayout/dexlayout_main.cc b/dexlayout/dexlayout_main.cc
index 83fb99a..ece0f93 100644
--- a/dexlayout/dexlayout_main.cc
+++ b/dexlayout/dexlayout_main.cc
@@ -80,7 +80,7 @@
 
   // Parse all arguments.
   while (1) {
-    const int ic = getopt(argc, argv, "abcdefghil:mo:p:stvw:x:");
+    const int ic = getopt(argc, argv, "abcdefghil:o:p:stvw:x:");
     if (ic < 0) {
       break;  // done
     }
@@ -119,9 +119,6 @@
           want_usage = true;
         }
         break;
-      case 'm':  // output dex files to a memmap
-        options.output_to_memmap_ = true;
-        break;
       case 'o':  // output file
         options.output_file_name_ = optarg;
         break;
@@ -197,7 +194,7 @@
   }
 
   // Create DexLayout instance.
-  DexLayout dex_layout(options, profile_info.get(), out_file);
+  DexLayout dex_layout(options, profile_info.get(), out_file, /*header*/ nullptr);
 
   // Process all files supplied on command line.
   int result = 0;