Dexlayout cleanup and refactoring.

Created option to output to a mem map in preparation of hooking
dexlayout into dex2oat.

Test: mm test-art-host-gtest-dexlayout_test
Bug: 29921113
Change-Id: Id42ef15cb8f83cc8d05b025b7647a4338e9b96b0
diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp
index b9266f7..9ee9ebd 100644
--- a/dexlayout/Android.bp
+++ b/dexlayout/Android.bp
@@ -12,28 +12,46 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-art_cc_binary {
-    name: "dexlayout",
+art_cc_defaults {
+    name: "libart-dexlayout-defaults",
     host_supported: true,
     srcs: [
-        "dexlayout_main.cc",
         "dexlayout.cc",
         "dex_ir.cc",
         "dex_ir_builder.cc",
         "dex_visualize.cc",
         "dex_writer.cc",
     ],
+    export_include_dirs: ["."],
+    shared_libs: ["libbase"],
+    static_libs: ["libz"],
+}
+
+art_cc_library {
+    name: "libart-dexlayout",
+    defaults: ["libart-dexlayout-defaults"],
+    shared_libs: ["libart"],
+}
+
+art_cc_library {
+    name: "libartd-dexlayout",
+    defaults: ["libart-dexlayout-defaults"],
+    shared_libs: ["libartd"],
+}
+
+art_cc_binary {
+    name: "dexlayout",
+    host_supported: true,
+    srcs: ["dexlayout_main.cc"],
     cflags: ["-Wall"],
     shared_libs: [
         "libart",
-        "libbase",
+        "libart-dexlayout",
     ],
 }
 
 art_cc_test {
     name: "art_dexlayout_tests",
-    defaults: [
-        "art_gtest_defaults",
-    ],
+    defaults: ["art_gtest_defaults"],
     srcs: ["dexlayout_test.cc"],
 }
diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc
index 67f3e09..fe2bcce 100644
--- a/dexlayout/dex_ir.cc
+++ b/dexlayout/dex_ir.cc
@@ -56,6 +56,36 @@
                     entry.end_address_, entry.reg_)));
 }
 
+static uint32_t GetCodeItemSize(const DexFile& dex_file, const DexFile::CodeItem& disk_code_item) {
+  uintptr_t code_item_start = reinterpret_cast<uintptr_t>(&disk_code_item);
+  uint32_t insns_size = disk_code_item.insns_size_in_code_units_;
+  uint32_t tries_size = disk_code_item.tries_size_;
+  if (tries_size == 0) {
+    uintptr_t insns_end = reinterpret_cast<uintptr_t>(&disk_code_item.insns_[insns_size]);
+    return insns_end - code_item_start;
+  } else {
+    uint32_t last_handler_off = 0;
+    for (uint32_t i = 0; i < tries_size; ++i) {
+      // Iterate over the try items to find the last catch handler.
+      const DexFile::TryItem* disk_try_item = dex_file.GetTryItems(disk_code_item, i);
+      uint16_t handler_off = disk_try_item->handler_off_;
+      if (handler_off > last_handler_off) {
+        last_handler_off = handler_off;
+      }
+    }
+    // Decode the final handler to see where it ends.
+    const uint8_t* handler_data = DexFile::GetCatchHandlerData(disk_code_item, last_handler_off);
+    int32_t uleb128_count = DecodeSignedLeb128(&handler_data) * 2;
+    if (uleb128_count <= 0) {
+      uleb128_count = -uleb128_count + 1;
+    }
+    for (int32_t i = 0; i < uleb128_count; ++i) {
+      DecodeUnsignedLeb128(&handler_data);
+    }
+    return reinterpret_cast<uintptr_t>(handler_data) - code_item_start;
+  }
+}
+
 static uint32_t GetDebugInfoStreamSize(const uint8_t* debug_info_stream) {
   const uint8_t* stream = debug_info_stream;
   DecodeUnsignedLeb128(&stream);  // line_start
@@ -384,11 +414,9 @@
   if (dex_type_list == nullptr) {
     return nullptr;
   }
-  // TODO: Create more efficient lookup for existing type lists.
-  for (std::unique_ptr<TypeList>& type_list : TypeLists()) {
-    if (type_list->GetOffset() == offset) {
-      return type_list.get();
-    }
+  auto found_type_list = TypeLists().find(offset);
+  if (found_type_list != TypeLists().end()) {
+    return found_type_list->second.get();
   }
   TypeIdVector* type_vector = new TypeIdVector();
   uint32_t size = dex_type_list->Size();
@@ -404,10 +432,9 @@
   if (static_data == nullptr) {
     return nullptr;
   }
-  for (std::unique_ptr<EncodedArrayItem>& existing_array_item : EncodedArrayItems()) {
-    if (existing_array_item->GetOffset() == offset) {
-      return existing_array_item.get();
-    }
+  auto found_encoded_array_item = EncodedArrayItems().find(offset);
+  if (found_encoded_array_item != EncodedArrayItems().end()) {
+    return found_encoded_array_item->second.get();
   }
   uint32_t size = DecodeUnsignedLeb128(&static_data);
   EncodedValueVector* values = new EncodedValueVector();
@@ -422,10 +449,9 @@
 
 AnnotationItem* Collections::CreateAnnotationItem(const DexFile::AnnotationItem* annotation,
                                                   uint32_t offset) {
-  for (std::unique_ptr<AnnotationItem>& existing_annotation_item : AnnotationItems()) {
-    if (existing_annotation_item->GetOffset() == offset) {
-      return existing_annotation_item.get();
-    }
+  auto found_annotation_item = AnnotationItems().find(offset);
+  if (found_annotation_item != AnnotationItems().end()) {
+    return found_annotation_item->second.get();
   }
   uint8_t visibility = annotation->visibility_;
   const uint8_t* annotation_data = annotation->annotation_;
@@ -444,10 +470,9 @@
   if (disk_annotations_item.size_ == 0 && offset == 0) {
     return nullptr;
   }
-  for (std::unique_ptr<AnnotationSetItem>& existing_anno_set_item : AnnotationSetItems()) {
-    if (existing_anno_set_item->GetOffset() == offset) {
-      return existing_anno_set_item.get();
-    }
+  auto found_anno_set_item = AnnotationSetItems().find(offset);
+  if (found_anno_set_item != AnnotationSetItems().end()) {
+    return found_anno_set_item->second.get();
   }
   std::vector<AnnotationItem*>* items = new std::vector<AnnotationItem*>();
   for (uint32_t i = 0; i < disk_annotations_item.size_; ++i) {
@@ -467,10 +492,9 @@
 
 AnnotationsDirectoryItem* Collections::CreateAnnotationsDirectoryItem(const DexFile& dex_file,
     const DexFile::AnnotationsDirectoryItem* disk_annotations_item, uint32_t offset) {
-  for (std::unique_ptr<AnnotationsDirectoryItem>& anno_dir_item : AnnotationsDirectoryItems()) {
-    if (anno_dir_item->GetOffset() == offset) {
-      return anno_dir_item.get();
-    }
+  auto found_anno_dir_item = AnnotationsDirectoryItems().find(offset);
+  if (found_anno_dir_item != AnnotationsDirectoryItems().end()) {
+    return found_anno_dir_item->second.get();
   }
   const DexFile::AnnotationSetItem* class_set_item =
       dex_file.GetClassAnnotationSet(disk_annotations_item);
@@ -535,11 +559,9 @@
     const DexFile& dex_file, MethodId* method_id,
     const DexFile::AnnotationSetRefList* annotation_set_ref_list, uint32_t offset) {
   AnnotationSetRefList* set_ref_list = nullptr;
-  for (std::unique_ptr<AnnotationSetRefList>& existing_set_ref_list : AnnotationSetRefLists()) {
-    if (existing_set_ref_list->GetOffset() == offset) {
-      set_ref_list = existing_set_ref_list.get();
-      break;
-    }
+  auto found_set_ref_list = AnnotationSetRefLists().find(offset);
+  if (found_set_ref_list != AnnotationSetRefLists().end()) {
+    set_ref_list = found_set_ref_list->second.get();
   }
   if (set_ref_list == nullptr) {
     std::vector<AnnotationSetItem*>* annotations = new std::vector<AnnotationSetItem*>();
@@ -610,9 +632,10 @@
       tries->push_back(std::unique_ptr<const TryItem>(try_item));
     }
   }
-  // TODO: Calculate the size of the code item.
+  uint32_t size = GetCodeItemSize(dex_file, disk_code_item);
   CodeItem* code_item = new CodeItem(
       registers_size, ins_size, outs_size, debug_info, insns_size, insns, tries, handler_list);
+  code_item->SetSize(size);
   code_items_.AddItem(code_item, offset);
   // Add "fixup" references to types, strings, methods, and fields.
   // This is temporary, as we will probably want more detailed parsing of the
@@ -690,8 +713,8 @@
       virtual_methods->push_back(
           std::unique_ptr<MethodItem>(GenerateMethodItem(dex_file, cdii)));
     }
-    // TODO: Calculate the size of the class data.
     class_data = new ClassData(static_fields, instance_fields, direct_methods, virtual_methods);
+    class_data->SetSize(cdii.EndDataPointer() - encoded_data);
     class_datas_.AddItem(class_data, offset);
   }
   return class_data;
diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h
index 38eb0b1..a2d1190 100644
--- a/dexlayout/dex_ir.h
+++ b/dexlayout/dex_ir.h
@@ -19,6 +19,7 @@
 #ifndef ART_DEXLAYOUT_DEX_IR_H_
 #define ART_DEXLAYOUT_DEX_IR_H_
 
+#include <map>
 #include <vector>
 #include <stdint.h>
 
@@ -98,34 +99,52 @@
 };
 
 // Collections become owners of the objects added by moving them into unique pointers.
-template<class T> class CollectionWithOffset {
+template<class T> class CollectionBase {
  public:
-  CollectionWithOffset() = default;
-  std::vector<std::unique_ptr<T>>& Collection() { return collection_; }
-  // Read-time support methods
-  void AddItem(T* object, uint32_t offset) {
-    object->SetOffset(offset);
-    collection_.push_back(std::unique_ptr<T>(object));
-  }
+  CollectionBase() = default;
+
+  uint32_t GetOffset() const { return offset_; }
+  void SetOffset(uint32_t new_offset) { offset_ = new_offset; }
+
+ private:
+  uint32_t offset_ = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(CollectionBase);
+};
+
+template<class T> class CollectionVector : public CollectionBase<T> {
+ public:
+  CollectionVector() = default;
+
   void AddIndexedItem(T* object, uint32_t offset, uint32_t index) {
     object->SetOffset(offset);
     object->SetIndex(index);
     collection_.push_back(std::unique_ptr<T>(object));
   }
-  // Ordinary object insertion into collection.
-  void Insert(T object ATTRIBUTE_UNUSED) {
-    // TODO(sehr): add ordered insertion support.
-    UNIMPLEMENTED(FATAL) << "Insertion not ready";
-  }
-  uint32_t GetOffset() const { return offset_; }
-  void SetOffset(uint32_t new_offset) { offset_ = new_offset; }
   uint32_t Size() const { return collection_.size(); }
+  std::vector<std::unique_ptr<T>>& Collection() { return collection_; }
 
  private:
   std::vector<std::unique_ptr<T>> collection_;
-  uint32_t offset_ = 0;
 
-  DISALLOW_COPY_AND_ASSIGN(CollectionWithOffset);
+  DISALLOW_COPY_AND_ASSIGN(CollectionVector);
+};
+
+template<class T> class CollectionMap : public CollectionBase<T> {
+ public:
+  CollectionMap() = default;
+
+  void AddItem(T* object, uint32_t offset) {
+    object->SetOffset(offset);
+    collection_.emplace(offset, std::unique_ptr<T>(object));
+  }
+  uint32_t Size() const { return collection_.size(); }
+  std::map<uint32_t, std::unique_ptr<T>>& Collection() { return collection_; }
+
+ private:
+  std::map<uint32_t, std::unique_ptr<T>> collection_;
+
+  DISALLOW_COPY_AND_ASSIGN(CollectionMap);
 };
 
 class Collections {
@@ -138,22 +157,23 @@
   std::vector<std::unique_ptr<FieldId>>& FieldIds() { return field_ids_.Collection(); }
   std::vector<std::unique_ptr<MethodId>>& MethodIds() { return method_ids_.Collection(); }
   std::vector<std::unique_ptr<ClassDef>>& ClassDefs() { return class_defs_.Collection(); }
-  std::vector<std::unique_ptr<StringData>>& StringDatas() { return string_datas_.Collection(); }
-  std::vector<std::unique_ptr<TypeList>>& TypeLists() { return type_lists_.Collection(); }
-  std::vector<std::unique_ptr<EncodedArrayItem>>& EncodedArrayItems()
+  std::map<uint32_t, std::unique_ptr<StringData>>& StringDatas()
+      { return string_datas_.Collection(); }
+  std::map<uint32_t, std::unique_ptr<TypeList>>& TypeLists() { return type_lists_.Collection(); }
+  std::map<uint32_t, std::unique_ptr<EncodedArrayItem>>& EncodedArrayItems()
       { return encoded_array_items_.Collection(); }
-  std::vector<std::unique_ptr<AnnotationItem>>& AnnotationItems()
+  std::map<uint32_t, std::unique_ptr<AnnotationItem>>& AnnotationItems()
       { return annotation_items_.Collection(); }
-  std::vector<std::unique_ptr<AnnotationSetItem>>& AnnotationSetItems()
+  std::map<uint32_t, std::unique_ptr<AnnotationSetItem>>& AnnotationSetItems()
       { return annotation_set_items_.Collection(); }
-  std::vector<std::unique_ptr<AnnotationSetRefList>>& AnnotationSetRefLists()
+  std::map<uint32_t, std::unique_ptr<AnnotationSetRefList>>& AnnotationSetRefLists()
       { return annotation_set_ref_lists_.Collection(); }
-  std::vector<std::unique_ptr<AnnotationsDirectoryItem>>& AnnotationsDirectoryItems()
+  std::map<uint32_t, std::unique_ptr<AnnotationsDirectoryItem>>& AnnotationsDirectoryItems()
       { return annotations_directory_items_.Collection(); }
-  std::vector<std::unique_ptr<DebugInfoItem>>& DebugInfoItems()
+  std::map<uint32_t, std::unique_ptr<DebugInfoItem>>& DebugInfoItems()
       { return debug_info_items_.Collection(); }
-  std::vector<std::unique_ptr<CodeItem>>& CodeItems() { return code_items_.Collection(); }
-  std::vector<std::unique_ptr<ClassData>>& ClassDatas() { return class_datas_.Collection(); }
+  std::map<uint32_t, std::unique_ptr<CodeItem>>& CodeItems() { return code_items_.Collection(); }
+  std::map<uint32_t, std::unique_ptr<ClassData>>& ClassDatas() { return class_datas_.Collection(); }
 
   void CreateStringId(const DexFile& dex_file, uint32_t i);
   void CreateTypeId(const DexFile& dex_file, uint32_t i);
@@ -204,7 +224,7 @@
   uint32_t DebugInfoItemsOffset() const { return debug_info_items_.GetOffset(); }
   uint32_t CodeItemsOffset() const { return code_items_.GetOffset(); }
   uint32_t ClassDatasOffset() const { return class_datas_.GetOffset(); }
-  uint32_t MapItemOffset() const { return map_item_offset_; }
+  uint32_t MapListOffset() const { return map_list_offset_; }
 
   void SetStringIdsOffset(uint32_t new_offset) { string_ids_.SetOffset(new_offset); }
   void SetTypeIdsOffset(uint32_t new_offset) { type_ids_.SetOffset(new_offset); }
@@ -226,7 +246,7 @@
   void SetDebugInfoItemsOffset(uint32_t new_offset) { debug_info_items_.SetOffset(new_offset); }
   void SetCodeItemsOffset(uint32_t new_offset) { code_items_.SetOffset(new_offset); }
   void SetClassDatasOffset(uint32_t new_offset) { class_datas_.SetOffset(new_offset); }
-  void SetMapItemOffset(uint32_t new_offset) { map_item_offset_ = new_offset; }
+  void SetMapListOffset(uint32_t new_offset) { map_list_offset_ = new_offset; }
 
   uint32_t StringIdsSize() const { return string_ids_.Size(); }
   uint32_t TypeIdsSize() const { return type_ids_.Size(); }
@@ -254,25 +274,25 @@
       const DexFile::AnnotationSetRefList* annotation_set_ref_list, uint32_t offset);
   MethodItem* GenerateMethodItem(const DexFile& dex_file, ClassDataItemIterator& cdii);
 
-  CollectionWithOffset<StringId> string_ids_;
-  CollectionWithOffset<TypeId> type_ids_;
-  CollectionWithOffset<ProtoId> proto_ids_;
-  CollectionWithOffset<FieldId> field_ids_;
-  CollectionWithOffset<MethodId> method_ids_;
-  CollectionWithOffset<ClassDef> class_defs_;
+  CollectionVector<StringId> string_ids_;
+  CollectionVector<TypeId> type_ids_;
+  CollectionVector<ProtoId> proto_ids_;
+  CollectionVector<FieldId> field_ids_;
+  CollectionVector<MethodId> method_ids_;
+  CollectionVector<ClassDef> class_defs_;
 
-  CollectionWithOffset<StringData> string_datas_;
-  CollectionWithOffset<TypeList> type_lists_;
-  CollectionWithOffset<EncodedArrayItem> encoded_array_items_;
-  CollectionWithOffset<AnnotationItem> annotation_items_;
-  CollectionWithOffset<AnnotationSetItem> annotation_set_items_;
-  CollectionWithOffset<AnnotationSetRefList> annotation_set_ref_lists_;
-  CollectionWithOffset<AnnotationsDirectoryItem> annotations_directory_items_;
-  CollectionWithOffset<DebugInfoItem> debug_info_items_;
-  CollectionWithOffset<CodeItem> code_items_;
-  CollectionWithOffset<ClassData> class_datas_;
+  CollectionMap<StringData> string_datas_;
+  CollectionMap<TypeList> type_lists_;
+  CollectionMap<EncodedArrayItem> encoded_array_items_;
+  CollectionMap<AnnotationItem> annotation_items_;
+  CollectionMap<AnnotationSetItem> annotation_set_items_;
+  CollectionMap<AnnotationSetRefList> annotation_set_ref_lists_;
+  CollectionMap<AnnotationsDirectoryItem> annotations_directory_items_;
+  CollectionMap<DebugInfoItem> debug_info_items_;
+  CollectionMap<CodeItem> code_items_;
+  CollectionMap<ClassData> class_datas_;
 
-  uint32_t map_item_offset_ = 0;
+  uint32_t map_list_offset_ = 0;
 
   DISALLOW_COPY_AND_ASSIGN(Collections);
 };
@@ -539,20 +559,20 @@
 
 class MethodItem : public Item {
  public:
-  MethodItem(uint32_t access_flags, const MethodId* method_id, const CodeItem* code)
+  MethodItem(uint32_t access_flags, const MethodId* method_id, CodeItem* code)
       : access_flags_(access_flags), method_id_(method_id), code_(code) { }
   ~MethodItem() OVERRIDE { }
 
   uint32_t GetAccessFlags() const { return access_flags_; }
   const MethodId* GetMethodId() const { return method_id_; }
-  const CodeItem* GetCodeItem() const { return code_; }
+  CodeItem* GetCodeItem() { return code_; }
 
   void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); }
 
  private:
   uint32_t access_flags_;
   const MethodId* method_id_;
-  const CodeItem* code_;  // This can be nullptr.
+  CodeItem* code_;  // This can be nullptr.
 
   DISALLOW_COPY_AND_ASSIGN(MethodItem);
 };
diff --git a/dexlayout/dex_ir_builder.cc b/dexlayout/dex_ir_builder.cc
index 68ff2a2..d0c5bf9 100644
--- a/dexlayout/dex_ir_builder.cc
+++ b/dexlayout/dex_ir_builder.cc
@@ -71,7 +71,7 @@
     collections.CreateClassDef(dex_file, i);
   }
   // MapItem.
-  collections.SetMapItemOffset(disk_header.map_off_);
+  collections.SetMapListOffset(disk_header.map_off_);
 
   CheckAndSetRemainingOffsets(dex_file, &collections);
 
diff --git a/dexlayout/dex_visualize.cc b/dexlayout/dex_visualize.cc
index 05ad98f..02274b2 100644
--- a/dexlayout/dex_visualize.cc
+++ b/dexlayout/dex_visualize.cc
@@ -263,11 +263,13 @@
     DumpStringId(method_id->Name(), class_index);
   }
 
-  void DumpMethodItem(const dex_ir::MethodItem* method, const DexFile* dex_file, int class_index) {
-    if (profile_info_ != nullptr) {
+  void DumpMethodItem(dex_ir::MethodItem* method,
+                      const DexFile* dex_file,
+                      int class_index,
+                      ProfileCompilationInfo* profile_info) {
+    if (profile_info != nullptr) {
       uint32_t method_idx = method->GetMethodId()->GetIndex();
-      MethodReference mr(dex_file, method_idx);
-      if (!profile_info_->ContainsMethod(mr)) {
+      if (!profile_info->ContainsMethod(MethodReference(dex_file, method_idx))) {
         return;
       }
     }
@@ -344,14 +346,17 @@
  * Dumps a gnuplot data file showing the parts of the dex_file that belong to each class.
  * If profiling information is present, it dumps only those classes that are marked as hot.
  */
-void VisualizeDexLayout(dex_ir::Header* header, const DexFile* dex_file, size_t dex_file_index) {
+void VisualizeDexLayout(dex_ir::Header* header,
+                        const DexFile* dex_file,
+                        size_t dex_file_index,
+                        ProfileCompilationInfo* profile_info) {
   std::unique_ptr<Dumper> dumper(new Dumper(header->GetCollections(), dex_file_index));
 
   const uint32_t class_defs_size = header->GetCollections().ClassDefsSize();
   for (uint32_t class_index = 0; class_index < class_defs_size; class_index++) {
     dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(class_index);
     dex::TypeIndex type_idx(class_def->ClassType()->GetIndex());
-    if (profile_info_ != nullptr && !profile_info_->ContainsClass(*dex_file, type_idx)) {
+    if (profile_info != nullptr && !profile_info->ContainsClass(*dex_file, type_idx)) {
       continue;
     }
     dumper->DumpAddressRange(class_def, class_index);
@@ -384,12 +389,12 @@
       }
       if (class_data->DirectMethods()) {
         for (auto& method_item : *class_data->DirectMethods()) {
-          dumper->DumpMethodItem(method_item.get(), dex_file, class_index);
+          dumper->DumpMethodItem(method_item.get(), dex_file, class_index, profile_info);
         }
       }
       if (class_data->VirtualMethods()) {
         for (auto& method_item : *class_data->VirtualMethods()) {
-          dumper->DumpMethodItem(method_item.get(), dex_file, class_index);
+          dumper->DumpMethodItem(method_item.get(), dex_file, class_index, profile_info);
         }
       }
     }
diff --git a/dexlayout/dex_visualize.h b/dexlayout/dex_visualize.h
index b1d2ed7..09f8306 100644
--- a/dexlayout/dex_visualize.h
+++ b/dexlayout/dex_visualize.h
@@ -28,11 +28,15 @@
 namespace art {
 
 class DexFile;
+class ProfileCompilationInfo;
 namespace dex_ir {
 class Header;
 }  // namespace dex_ir
 
-void VisualizeDexLayout(dex_ir::Header* header, const DexFile* dex_file, size_t dex_file_index);
+void VisualizeDexLayout(dex_ir::Header* header,
+                        const DexFile* dex_file,
+                        size_t dex_file_index,
+                        ProfileCompilationInfo* profile_info);
 
 }  // namespace art
 
diff --git a/dexlayout/dex_writer.cc b/dexlayout/dex_writer.cc
index dba5da0..7ffa38b 100644
--- a/dexlayout/dex_writer.cc
+++ b/dexlayout/dex_writer.cc
@@ -104,7 +104,9 @@
 }
 
 size_t DexWriter::Write(const void* buffer, size_t length, size_t offset) {
-  return dex_file_->PwriteFully(buffer, length, offset) ? length : 0;
+  DCHECK_LE(offset + length, mem_map_->Size());
+  memcpy(mem_map_->Begin() + offset, buffer, length);
+  return length;
 }
 
 size_t DexWriter::WriteSleb128(uint32_t value, size_t offset) {
@@ -236,12 +238,13 @@
 
 void DexWriter::WriteStrings() {
   uint32_t string_data_off[1];
-  for (std::unique_ptr<dex_ir::StringId>& string_id : header_.GetCollections().StringIds()) {
+  for (std::unique_ptr<dex_ir::StringId>& string_id : header_->GetCollections().StringIds()) {
     string_data_off[0] = string_id->DataItem()->GetOffset();
     Write(string_data_off, string_id->GetSize(), string_id->GetOffset());
   }
 
-  for (std::unique_ptr<dex_ir::StringData>& string_data : header_.GetCollections().StringDatas()) {
+  for (auto& string_data_pair : header_->GetCollections().StringDatas()) {
+    std::unique_ptr<dex_ir::StringData>& string_data = string_data_pair.second;
     uint32_t offset = string_data->GetOffset();
     offset += WriteUleb128(CountModifiedUtf8Chars(string_data->Data()), offset);
     Write(string_data->Data(), strlen(string_data->Data()), offset);
@@ -250,7 +253,7 @@
 
 void DexWriter::WriteTypes() {
   uint32_t descriptor_idx[1];
-  for (std::unique_ptr<dex_ir::TypeId>& type_id : header_.GetCollections().TypeIds()) {
+  for (std::unique_ptr<dex_ir::TypeId>& type_id : header_->GetCollections().TypeIds()) {
     descriptor_idx[0] = type_id->GetStringId()->GetIndex();
     Write(descriptor_idx, type_id->GetSize(), type_id->GetOffset());
   }
@@ -259,7 +262,8 @@
 void DexWriter::WriteTypeLists() {
   uint32_t size[1];
   uint16_t list[1];
-  for (std::unique_ptr<dex_ir::TypeList>& type_list : header_.GetCollections().TypeLists()) {
+  for (auto& type_list_pair : header_->GetCollections().TypeLists()) {
+    std::unique_ptr<dex_ir::TypeList>& type_list = type_list_pair.second;
     size[0] = type_list->GetTypeList()->size();
     uint32_t offset = type_list->GetOffset();
     offset += Write(size, sizeof(uint32_t), offset);
@@ -272,7 +276,7 @@
 
 void DexWriter::WriteProtos() {
   uint32_t buffer[3];
-  for (std::unique_ptr<dex_ir::ProtoId>& proto_id : header_.GetCollections().ProtoIds()) {
+  for (std::unique_ptr<dex_ir::ProtoId>& proto_id : header_->GetCollections().ProtoIds()) {
     buffer[0] = proto_id->Shorty()->GetIndex();
     buffer[1] = proto_id->ReturnType()->GetIndex();
     buffer[2] = proto_id->Parameters() == nullptr ? 0 : proto_id->Parameters()->GetOffset();
@@ -282,7 +286,7 @@
 
 void DexWriter::WriteFields() {
   uint16_t buffer[4];
-  for (std::unique_ptr<dex_ir::FieldId>& field_id : header_.GetCollections().FieldIds()) {
+  for (std::unique_ptr<dex_ir::FieldId>& field_id : header_->GetCollections().FieldIds()) {
     buffer[0] = field_id->Class()->GetIndex();
     buffer[1] = field_id->Type()->GetIndex();
     buffer[2] = field_id->Name()->GetIndex();
@@ -293,7 +297,7 @@
 
 void DexWriter::WriteMethods() {
   uint16_t buffer[4];
-  for (std::unique_ptr<dex_ir::MethodId>& method_id : header_.GetCollections().MethodIds()) {
+  for (std::unique_ptr<dex_ir::MethodId>& method_id : header_->GetCollections().MethodIds()) {
     buffer[0] = method_id->Class()->GetIndex();
     buffer[1] = method_id->Proto()->GetIndex();
     buffer[2] = method_id->Name()->GetIndex();
@@ -303,16 +307,16 @@
 }
 
 void DexWriter::WriteEncodedArrays() {
-  for (std::unique_ptr<dex_ir::EncodedArrayItem>& encoded_array :
-      header_.GetCollections().EncodedArrayItems()) {
+  for (auto& encoded_array_pair : header_->GetCollections().EncodedArrayItems()) {
+    std::unique_ptr<dex_ir::EncodedArrayItem>& encoded_array = encoded_array_pair.second;
     WriteEncodedArray(encoded_array->GetEncodedValues(), encoded_array->GetOffset());
   }
 }
 
 void DexWriter::WriteAnnotations() {
   uint8_t visibility[1];
-  for (std::unique_ptr<dex_ir::AnnotationItem>& annotation :
-      header_.GetCollections().AnnotationItems()) {
+  for (auto& annotation_pair : header_->GetCollections().AnnotationItems()) {
+    std::unique_ptr<dex_ir::AnnotationItem>& annotation = annotation_pair.second;
     visibility[0] = annotation->GetVisibility();
     size_t offset = annotation->GetOffset();
     offset += Write(visibility, sizeof(uint8_t), offset);
@@ -323,8 +327,8 @@
 void DexWriter::WriteAnnotationSets() {
   uint32_t size[1];
   uint32_t annotation_off[1];
-  for (std::unique_ptr<dex_ir::AnnotationSetItem>& annotation_set :
-      header_.GetCollections().AnnotationSetItems()) {
+  for (auto& annotation_set_pair : header_->GetCollections().AnnotationSetItems()) {
+    std::unique_ptr<dex_ir::AnnotationSetItem>& annotation_set = annotation_set_pair.second;
     size[0] = annotation_set->GetItems()->size();
     size_t offset = annotation_set->GetOffset();
     offset += Write(size, sizeof(uint32_t), offset);
@@ -338,8 +342,8 @@
 void DexWriter::WriteAnnotationSetRefs() {
   uint32_t size[1];
   uint32_t annotations_off[1];
-  for (std::unique_ptr<dex_ir::AnnotationSetRefList>& annotation_set_ref :
-        header_.GetCollections().AnnotationSetRefLists()) {
+  for (auto& anno_set_ref_pair : header_->GetCollections().AnnotationSetRefLists()) {
+    std::unique_ptr<dex_ir::AnnotationSetRefList>& annotation_set_ref = anno_set_ref_pair.second;
     size[0] = annotation_set_ref->GetItems()->size();
     size_t offset = annotation_set_ref->GetOffset();
     offset += Write(size, sizeof(uint32_t), offset);
@@ -353,8 +357,9 @@
 void DexWriter::WriteAnnotationsDirectories() {
   uint32_t directory_buffer[4];
   uint32_t annotation_buffer[2];
-  for (std::unique_ptr<dex_ir::AnnotationsDirectoryItem>& annotations_directory :
-          header_.GetCollections().AnnotationsDirectoryItems()) {
+  for (auto& annotations_directory_pair : header_->GetCollections().AnnotationsDirectoryItems()) {
+    std::unique_ptr<dex_ir::AnnotationsDirectoryItem>& annotations_directory =
+        annotations_directory_pair.second;
     directory_buffer[0] = annotations_directory->GetClassAnnotation() == nullptr ? 0 :
         annotations_directory->GetClassAnnotation()->GetOffset();
     directory_buffer[1] = annotations_directory->GetFieldAnnotations() == nullptr ? 0 :
@@ -393,15 +398,17 @@
 }
 
 void DexWriter::WriteDebugInfoItems() {
-  for (std::unique_ptr<dex_ir::DebugInfoItem>& info : header_.GetCollections().DebugInfoItems()) {
-    Write(info->GetDebugInfo(), info->GetDebugInfoSize(), info->GetOffset());
+  for (auto& debug_info_pair : header_->GetCollections().DebugInfoItems()) {
+    std::unique_ptr<dex_ir::DebugInfoItem>& debug_info = debug_info_pair.second;
+    Write(debug_info->GetDebugInfo(), debug_info->GetDebugInfoSize(), debug_info->GetOffset());
   }
 }
 
 void DexWriter::WriteCodeItems() {
   uint16_t uint16_buffer[4];
   uint32_t uint32_buffer[2];
-  for (std::unique_ptr<dex_ir::CodeItem>& code_item : header_.GetCollections().CodeItems()) {
+  for (auto& code_item_pair : header_->GetCollections().CodeItems()) {
+    std::unique_ptr<dex_ir::CodeItem>& code_item = code_item_pair.second;
     uint16_buffer[0] = code_item->RegistersSize();
     uint16_buffer[1] = code_item->InsSize();
     uint16_buffer[2] = code_item->OutsSize();
@@ -446,7 +453,7 @@
 
 void DexWriter::WriteClasses() {
   uint32_t class_def_buffer[8];
-  for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_.GetCollections().ClassDefs()) {
+  for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
     class_def_buffer[0] = class_def->ClassType()->GetIndex();
     class_def_buffer[1] = class_def->GetAccessFlags();
     class_def_buffer[2] = class_def->Superclass() == nullptr ? DexFile::kDexNoIndex :
@@ -464,7 +471,8 @@
     Write(class_def_buffer, class_def->GetSize(), offset);
   }
 
-  for (std::unique_ptr<dex_ir::ClassData>& class_data : header_.GetCollections().ClassDatas()) {
+  for (auto& class_data_pair : header_->GetCollections().ClassDatas()) {
+    std::unique_ptr<dex_ir::ClassData>& class_data = class_data_pair.second;
     size_t offset = class_data->GetOffset();
     offset += WriteUleb128(class_data->StaticFields()->size(), offset);
     offset += WriteUleb128(class_data->InstanceFields()->size(), offset);
@@ -491,7 +499,7 @@
 };
 
 void DexWriter::WriteMapItem() {
-  dex_ir::Collections& collection = header_.GetCollections();
+  dex_ir::Collections& collection = header_->GetCollections();
   std::priority_queue<MapItemContainer> queue;
 
   // Header and index section.
@@ -522,7 +530,7 @@
   }
 
   // Data section.
-  queue.push(MapItemContainer(DexFile::kDexTypeMapList, 1, collection.MapItemOffset()));
+  queue.push(MapItemContainer(DexFile::kDexTypeMapList, 1, collection.MapListOffset()));
   if (collection.TypeListsSize() != 0) {
     queue.push(MapItemContainer(DexFile::kDexTypeTypeList, collection.TypeListsSize(),
         collection.TypeListsOffset()));
@@ -564,7 +572,7 @@
         collection.AnnotationsDirectoryItemsSize(), collection.AnnotationsDirectoryItemsOffset()));
   }
 
-  uint32_t offset = collection.MapItemOffset();
+  uint32_t offset = collection.MapListOffset();
   uint16_t uint16_buffer[2];
   uint32_t uint32_buffer[2];
   uint16_buffer[1] = 0;
@@ -583,19 +591,19 @@
 
 void DexWriter::WriteHeader() {
   uint32_t buffer[20];
-  dex_ir::Collections& collections = header_.GetCollections();
+  dex_ir::Collections& collections = header_->GetCollections();
   size_t offset = 0;
-  offset += Write(header_.Magic(), 8 * sizeof(uint8_t), offset);
-  buffer[0] = header_.Checksum();
+  offset += Write(header_->Magic(), 8 * sizeof(uint8_t), offset);
+  buffer[0] = header_->Checksum();
   offset += Write(buffer, sizeof(uint32_t), offset);
-  offset += Write(header_.Signature(), 20 * sizeof(uint8_t), offset);
-  uint32_t file_size = header_.FileSize();
+  offset += Write(header_->Signature(), 20 * sizeof(uint8_t), offset);
+  uint32_t file_size = header_->FileSize();
   buffer[0] = file_size;
-  buffer[1] = header_.GetSize();
-  buffer[2] = header_.EndianTag();
-  buffer[3] = header_.LinkSize();
-  buffer[4] = header_.LinkOffset();
-  buffer[5] = collections.MapItemOffset();
+  buffer[1] = header_->GetSize();
+  buffer[2] = header_->EndianTag();
+  buffer[3] = header_->LinkSize();
+  buffer[4] = header_->LinkOffset();
+  buffer[5] = collections.MapListOffset();
   buffer[6] = collections.StringIdsSize();
   buffer[7] = collections.StringIdsOffset();
   buffer[8] = collections.TypeIdsSize();
@@ -617,12 +625,7 @@
   Write(buffer, 20 * sizeof(uint32_t), offset);
 }
 
-void DexWriter::WriteFile() {
-  if (dex_file_.get() == nullptr) {
-    fprintf(stderr, "Can't open output dex file\n");
-    return;
-  }
-
+void DexWriter::WriteMemMap() {
   WriteStrings();
   WriteTypes();
   WriteTypeLists();
@@ -641,8 +644,9 @@
   WriteHeader();
 }
 
-void DexWriter::OutputDexFile(dex_ir::Header& header, const char* file_name) {
-  (new DexWriter(header, file_name))->WriteFile();
+void DexWriter::Output(dex_ir::Header* header, MemMap* mem_map) {
+  DexWriter dex_writer(header, mem_map);
+  dex_writer.WriteMemMap();
 }
 
 }  // namespace art
diff --git a/dexlayout/dex_writer.h b/dexlayout/dex_writer.h
index 9104295..fb76e5c 100644
--- a/dexlayout/dex_writer.h
+++ b/dexlayout/dex_writer.h
@@ -21,19 +21,19 @@
 
 #include "base/unix_file/fd_file.h"
 #include "dex_ir.h"
+#include "mem_map.h"
 #include "os.h"
 
 namespace art {
 
 class DexWriter {
  public:
-  DexWriter(dex_ir::Header& header, const char* file_name) : header_(header),
-      dex_file_(OS::CreateEmptyFileWriteOnly(file_name)) { }
+  DexWriter(dex_ir::Header* header, MemMap* mem_map) : header_(header), mem_map_(mem_map) { }
 
-  static void OutputDexFile(dex_ir::Header& header, const char* file_name);
+  static void Output(dex_ir::Header* header, MemMap* mem_map);
 
  private:
-  void WriteFile();
+  void WriteMemMap();
 
   size_t Write(const void* buffer, size_t length, size_t offset);
   size_t WriteSleb128(uint32_t value, size_t offset);
@@ -62,13 +62,12 @@
   void WriteMapItem();
   void WriteHeader();
 
-  dex_ir::Header& header_;
-  std::unique_ptr<File> dex_file_;
+  dex_ir::Header* const header_;
+  MemMap* const mem_map_;
 
   DISALLOW_COPY_AND_ASSIGN(DexWriter);
 };
 
-
 }  // namespace art
 
 #endif  // ART_DEXLAYOUT_DEX_WRITER_H_
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index aa80655..634bb63 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -37,27 +37,13 @@
 #include "dex_visualize.h"
 #include "dex_writer.h"
 #include "jit/offline_profiling_info.h"
+#include "mem_map.h"
 #include "os.h"
 #include "utils.h"
 
 namespace art {
 
 /*
- * Options parsed in main driver.
- */
-struct Options options_;
-
-/*
- * Output file. Defaults to stdout.
- */
-FILE* out_file_ = stdout;
-
-/*
- * Profile information file.
- */
-ProfileCompilationInfo* profile_info_ = nullptr;
-
-/*
  * Flags for use with createAccessFlagStr().
  */
 enum AccessFor {
@@ -301,420 +287,65 @@
 /*
  * Dumps a string value with some escape characters.
  */
-static void DumpEscapedString(const char* p) {
-  fputs("\"", out_file_);
+static void DumpEscapedString(const char* p, FILE* out_file) {
+  fputs("\"", out_file);
   for (; *p; p++) {
     switch (*p) {
       case '\\':
-        fputs("\\\\", out_file_);
+        fputs("\\\\", out_file);
         break;
       case '\"':
-        fputs("\\\"", out_file_);
+        fputs("\\\"", out_file);
         break;
       case '\t':
-        fputs("\\t", out_file_);
+        fputs("\\t", out_file);
         break;
       case '\n':
-        fputs("\\n", out_file_);
+        fputs("\\n", out_file);
         break;
       case '\r':
-        fputs("\\r", out_file_);
+        fputs("\\r", out_file);
         break;
       default:
-        putc(*p, out_file_);
+        putc(*p, out_file);
     }  // switch
   }  // for
-  fputs("\"", out_file_);
+  fputs("\"", out_file);
 }
 
 /*
  * Dumps a string as an XML attribute value.
  */
-static void DumpXmlAttribute(const char* p) {
+static void DumpXmlAttribute(const char* p, FILE* out_file) {
   for (; *p; p++) {
     switch (*p) {
       case '&':
-        fputs("&amp;", out_file_);
+        fputs("&amp;", out_file);
         break;
       case '<':
-        fputs("&lt;", out_file_);
+        fputs("&lt;", out_file);
         break;
       case '>':
-        fputs("&gt;", out_file_);
+        fputs("&gt;", out_file);
         break;
       case '"':
-        fputs("&quot;", out_file_);
+        fputs("&quot;", out_file);
         break;
       case '\t':
-        fputs("&#x9;", out_file_);
+        fputs("&#x9;", out_file);
         break;
       case '\n':
-        fputs("&#xA;", out_file_);
+        fputs("&#xA;", out_file);
         break;
       case '\r':
-        fputs("&#xD;", out_file_);
+        fputs("&#xD;", out_file);
         break;
       default:
-        putc(*p, out_file_);
+        putc(*p, out_file);
     }  // switch
   }  // for
 }
 
-// Forward declare to resolve circular dependence.
-static void DumpEncodedValue(const dex_ir::EncodedValue* data);
-
-/*
- * Dumps encoded annotation.
- */
-static void DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation) {
-  fputs(annotation->GetType()->GetStringId()->Data(), out_file_);
-  // Display all name=value pairs.
-  for (auto& subannotation : *annotation->GetAnnotationElements()) {
-    fputc(' ', out_file_);
-    fputs(subannotation->GetName()->Data(), out_file_);
-    fputc('=', out_file_);
-    DumpEncodedValue(subannotation->GetValue());
-  }
-}
-/*
- * Dumps encoded value.
- */
-static void DumpEncodedValue(const dex_ir::EncodedValue* data) {
-  switch (data->Type()) {
-    case DexFile::kDexAnnotationByte:
-      fprintf(out_file_, "%" PRId8, data->GetByte());
-      break;
-    case DexFile::kDexAnnotationShort:
-      fprintf(out_file_, "%" PRId16, data->GetShort());
-      break;
-    case DexFile::kDexAnnotationChar:
-      fprintf(out_file_, "%" PRIu16, data->GetChar());
-      break;
-    case DexFile::kDexAnnotationInt:
-      fprintf(out_file_, "%" PRId32, data->GetInt());
-      break;
-    case DexFile::kDexAnnotationLong:
-      fprintf(out_file_, "%" PRId64, data->GetLong());
-      break;
-    case DexFile::kDexAnnotationFloat: {
-      fprintf(out_file_, "%g", data->GetFloat());
-      break;
-    }
-    case DexFile::kDexAnnotationDouble: {
-      fprintf(out_file_, "%g", data->GetDouble());
-      break;
-    }
-    case DexFile::kDexAnnotationString: {
-      dex_ir::StringId* string_id = data->GetStringId();
-      if (options_.output_format_ == kOutputPlain) {
-        DumpEscapedString(string_id->Data());
-      } else {
-        DumpXmlAttribute(string_id->Data());
-      }
-      break;
-    }
-    case DexFile::kDexAnnotationType: {
-      dex_ir::TypeId* type_id = data->GetTypeId();
-      fputs(type_id->GetStringId()->Data(), out_file_);
-      break;
-    }
-    case DexFile::kDexAnnotationField:
-    case DexFile::kDexAnnotationEnum: {
-      dex_ir::FieldId* field_id = data->GetFieldId();
-      fputs(field_id->Name()->Data(), out_file_);
-      break;
-    }
-    case DexFile::kDexAnnotationMethod: {
-      dex_ir::MethodId* method_id = data->GetMethodId();
-      fputs(method_id->Name()->Data(), out_file_);
-      break;
-    }
-    case DexFile::kDexAnnotationArray: {
-      fputc('{', out_file_);
-      // Display all elements.
-      for (auto& value : *data->GetEncodedArray()->GetEncodedValues()) {
-        fputc(' ', out_file_);
-        DumpEncodedValue(value.get());
-      }
-      fputs(" }", out_file_);
-      break;
-    }
-    case DexFile::kDexAnnotationAnnotation: {
-      DumpEncodedAnnotation(data->GetEncodedAnnotation());
-      break;
-    }
-    case DexFile::kDexAnnotationNull:
-      fputs("null", out_file_);
-      break;
-    case DexFile::kDexAnnotationBoolean:
-      fputs(StrBool(data->GetBoolean()), out_file_);
-      break;
-    default:
-      fputs("????", out_file_);
-      break;
-  }  // switch
-}
-
-/*
- * Dumps the file header.
- */
-static void DumpFileHeader(dex_ir::Header* header) {
-  char sanitized[8 * 2 + 1];
-  dex_ir::Collections& collections = header->GetCollections();
-  fprintf(out_file_, "DEX file header:\n");
-  Asciify(sanitized, header->Magic(), 8);
-  fprintf(out_file_, "magic               : '%s'\n", sanitized);
-  fprintf(out_file_, "checksum            : %08x\n", header->Checksum());
-  fprintf(out_file_, "signature           : %02x%02x...%02x%02x\n",
-          header->Signature()[0], header->Signature()[1],
-          header->Signature()[DexFile::kSha1DigestSize - 2],
-          header->Signature()[DexFile::kSha1DigestSize - 1]);
-  fprintf(out_file_, "file_size           : %d\n", header->FileSize());
-  fprintf(out_file_, "header_size         : %d\n", header->HeaderSize());
-  fprintf(out_file_, "link_size           : %d\n", header->LinkSize());
-  fprintf(out_file_, "link_off            : %d (0x%06x)\n",
-          header->LinkOffset(), header->LinkOffset());
-  fprintf(out_file_, "string_ids_size     : %d\n", collections.StringIdsSize());
-  fprintf(out_file_, "string_ids_off      : %d (0x%06x)\n",
-          collections.StringIdsOffset(), collections.StringIdsOffset());
-  fprintf(out_file_, "type_ids_size       : %d\n", collections.TypeIdsSize());
-  fprintf(out_file_, "type_ids_off        : %d (0x%06x)\n",
-          collections.TypeIdsOffset(), collections.TypeIdsOffset());
-  fprintf(out_file_, "proto_ids_size      : %d\n", collections.ProtoIdsSize());
-  fprintf(out_file_, "proto_ids_off       : %d (0x%06x)\n",
-          collections.ProtoIdsOffset(), collections.ProtoIdsOffset());
-  fprintf(out_file_, "field_ids_size      : %d\n", collections.FieldIdsSize());
-  fprintf(out_file_, "field_ids_off       : %d (0x%06x)\n",
-          collections.FieldIdsOffset(), collections.FieldIdsOffset());
-  fprintf(out_file_, "method_ids_size     : %d\n", collections.MethodIdsSize());
-  fprintf(out_file_, "method_ids_off      : %d (0x%06x)\n",
-          collections.MethodIdsOffset(), collections.MethodIdsOffset());
-  fprintf(out_file_, "class_defs_size     : %d\n", collections.ClassDefsSize());
-  fprintf(out_file_, "class_defs_off      : %d (0x%06x)\n",
-          collections.ClassDefsOffset(), collections.ClassDefsOffset());
-  fprintf(out_file_, "data_size           : %d\n", header->DataSize());
-  fprintf(out_file_, "data_off            : %d (0x%06x)\n\n",
-          header->DataOffset(), header->DataOffset());
-}
-
-/*
- * Dumps a class_def_item.
- */
-static void DumpClassDef(dex_ir::Header* header, int idx) {
-  // General class information.
-  dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx);
-  fprintf(out_file_, "Class #%d header:\n", idx);
-  fprintf(out_file_, "class_idx           : %d\n", class_def->ClassType()->GetIndex());
-  fprintf(out_file_, "access_flags        : %d (0x%04x)\n",
-          class_def->GetAccessFlags(), class_def->GetAccessFlags());
-  uint32_t superclass_idx =  class_def->Superclass() == nullptr ?
-      DexFile::kDexNoIndex16 : class_def->Superclass()->GetIndex();
-  fprintf(out_file_, "superclass_idx      : %d\n", superclass_idx);
-  fprintf(out_file_, "interfaces_off      : %d (0x%06x)\n",
-          class_def->InterfacesOffset(), class_def->InterfacesOffset());
-  uint32_t source_file_offset = 0xffffffffU;
-  if (class_def->SourceFile() != nullptr) {
-    source_file_offset = class_def->SourceFile()->GetIndex();
-  }
-  fprintf(out_file_, "source_file_idx     : %d\n", source_file_offset);
-  uint32_t annotations_offset = 0;
-  if (class_def->Annotations() != nullptr) {
-    annotations_offset = class_def->Annotations()->GetOffset();
-  }
-  fprintf(out_file_, "annotations_off     : %d (0x%06x)\n",
-          annotations_offset, annotations_offset);
-  if (class_def->GetClassData() == nullptr) {
-    fprintf(out_file_, "class_data_off      : %d (0x%06x)\n", 0, 0);
-  } else {
-    fprintf(out_file_, "class_data_off      : %d (0x%06x)\n",
-            class_def->GetClassData()->GetOffset(), class_def->GetClassData()->GetOffset());
-  }
-
-  // Fields and methods.
-  dex_ir::ClassData* class_data = class_def->GetClassData();
-  if (class_data != nullptr && class_data->StaticFields() != nullptr) {
-    fprintf(out_file_, "static_fields_size  : %zu\n", class_data->StaticFields()->size());
-  } else {
-    fprintf(out_file_, "static_fields_size  : 0\n");
-  }
-  if (class_data != nullptr && class_data->InstanceFields() != nullptr) {
-    fprintf(out_file_, "instance_fields_size: %zu\n", class_data->InstanceFields()->size());
-  } else {
-    fprintf(out_file_, "instance_fields_size: 0\n");
-  }
-  if (class_data != nullptr && class_data->DirectMethods() != nullptr) {
-    fprintf(out_file_, "direct_methods_size : %zu\n", class_data->DirectMethods()->size());
-  } else {
-    fprintf(out_file_, "direct_methods_size : 0\n");
-  }
-  if (class_data != nullptr && class_data->VirtualMethods() != nullptr) {
-    fprintf(out_file_, "virtual_methods_size: %zu\n", class_data->VirtualMethods()->size());
-  } else {
-    fprintf(out_file_, "virtual_methods_size: 0\n");
-  }
-  fprintf(out_file_, "\n");
-}
-
-/**
- * Dumps an annotation set item.
- */
-static void DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item) {
-  if (set_item == nullptr || set_item->GetItems()->size() == 0) {
-    fputs("  empty-annotation-set\n", out_file_);
-    return;
-  }
-  for (dex_ir::AnnotationItem* annotation : *set_item->GetItems()) {
-    if (annotation == nullptr) {
-      continue;
-    }
-    fputs("  ", out_file_);
-    switch (annotation->GetVisibility()) {
-      case DexFile::kDexVisibilityBuild:   fputs("VISIBILITY_BUILD ",   out_file_); break;
-      case DexFile::kDexVisibilityRuntime: fputs("VISIBILITY_RUNTIME ", out_file_); break;
-      case DexFile::kDexVisibilitySystem:  fputs("VISIBILITY_SYSTEM ",  out_file_); break;
-      default:                             fputs("VISIBILITY_UNKNOWN ", out_file_); break;
-    }  // switch
-    DumpEncodedAnnotation(annotation->GetAnnotation());
-    fputc('\n', out_file_);
-  }
-}
-
-/*
- * Dumps class annotations.
- */
-static void DumpClassAnnotations(dex_ir::Header* header, int idx) {
-  dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx);
-  dex_ir::AnnotationsDirectoryItem* annotations_directory = class_def->Annotations();
-  if (annotations_directory == nullptr) {
-    return;  // none
-  }
-
-  fprintf(out_file_, "Class #%d annotations:\n", idx);
-
-  dex_ir::AnnotationSetItem* class_set_item = annotations_directory->GetClassAnnotation();
-  dex_ir::FieldAnnotationVector* fields = annotations_directory->GetFieldAnnotations();
-  dex_ir::MethodAnnotationVector* methods = annotations_directory->GetMethodAnnotations();
-  dex_ir::ParameterAnnotationVector* parameters = annotations_directory->GetParameterAnnotations();
-
-  // Annotations on the class itself.
-  if (class_set_item != nullptr) {
-    fprintf(out_file_, "Annotations on class\n");
-    DumpAnnotationSetItem(class_set_item);
-  }
-
-  // Annotations on fields.
-  if (fields != nullptr) {
-    for (auto& field : *fields) {
-      const dex_ir::FieldId* field_id = field->GetFieldId();
-      const uint32_t field_idx = field_id->GetIndex();
-      const char* field_name = field_id->Name()->Data();
-      fprintf(out_file_, "Annotations on field #%u '%s'\n", field_idx, field_name);
-      DumpAnnotationSetItem(field->GetAnnotationSetItem());
-    }
-  }
-
-  // Annotations on methods.
-  if (methods != nullptr) {
-    for (auto& method : *methods) {
-      const dex_ir::MethodId* method_id = method->GetMethodId();
-      const uint32_t method_idx = method_id->GetIndex();
-      const char* method_name = method_id->Name()->Data();
-      fprintf(out_file_, "Annotations on method #%u '%s'\n", method_idx, method_name);
-      DumpAnnotationSetItem(method->GetAnnotationSetItem());
-    }
-  }
-
-  // Annotations on method parameters.
-  if (parameters != nullptr) {
-    for (auto& parameter : *parameters) {
-      const dex_ir::MethodId* method_id = parameter->GetMethodId();
-      const uint32_t method_idx = method_id->GetIndex();
-      const char* method_name = method_id->Name()->Data();
-      fprintf(out_file_, "Annotations on method #%u '%s' parameters\n", method_idx, method_name);
-      uint32_t j = 0;
-      for (dex_ir::AnnotationSetItem* annotation : *parameter->GetAnnotations()->GetItems()) {
-        fprintf(out_file_, "#%u\n", j);
-        DumpAnnotationSetItem(annotation);
-        ++j;
-      }
-    }
-  }
-
-  fputc('\n', out_file_);
-}
-
-/*
- * Dumps an interface that a class declares to implement.
- */
-static void DumpInterface(const dex_ir::TypeId* type_item, int i) {
-  const char* interface_name = type_item->GetStringId()->Data();
-  if (options_.output_format_ == kOutputPlain) {
-    fprintf(out_file_, "    #%d              : '%s'\n", i, interface_name);
-  } else {
-    std::string dot(DescriptorToDotWrapper(interface_name));
-    fprintf(out_file_, "<implements name=\"%s\">\n</implements>\n", dot.c_str());
-  }
-}
-
-/*
- * Dumps the catches table associated with the code.
- */
-static void DumpCatches(const dex_ir::CodeItem* code) {
-  const uint16_t tries_size = code->TriesSize();
-
-  // No catch table.
-  if (tries_size == 0) {
-    fprintf(out_file_, "      catches       : (none)\n");
-    return;
-  }
-
-  // Dump all table entries.
-  fprintf(out_file_, "      catches       : %d\n", tries_size);
-  std::vector<std::unique_ptr<const dex_ir::TryItem>>* tries = code->Tries();
-  for (uint32_t i = 0; i < tries_size; i++) {
-    const dex_ir::TryItem* try_item = (*tries)[i].get();
-    const uint32_t start = try_item->StartAddr();
-    const uint32_t end = start + try_item->InsnCount();
-    fprintf(out_file_, "        0x%04x - 0x%04x\n", start, end);
-    for (auto& handler : *try_item->GetHandlers()->GetHandlers()) {
-      const dex_ir::TypeId* type_id = handler->GetTypeId();
-      const char* descriptor = (type_id == nullptr) ? "<any>" : type_id->GetStringId()->Data();
-      fprintf(out_file_, "          %s -> 0x%04x\n", descriptor, handler->GetAddress());
-    }  // for
-  }  // for
-}
-
-/*
- * Dumps all positions table entries associated with the code.
- */
-static void DumpPositionInfo(const dex_ir::CodeItem* code) {
-  dex_ir::DebugInfoItem* debug_info = code->DebugInfo();
-  if (debug_info == nullptr) {
-    return;
-  }
-  std::vector<std::unique_ptr<dex_ir::PositionInfo>>& positions = debug_info->GetPositionInfo();
-  for (size_t i = 0; i < positions.size(); ++i) {
-    fprintf(out_file_, "        0x%04x line=%d\n", positions[i]->address_, positions[i]->line_);
-  }
-}
-
-/*
- * Dumps all locals table entries associated with the code.
- */
-static void DumpLocalInfo(const dex_ir::CodeItem* code) {
-  dex_ir::DebugInfoItem* debug_info = code->DebugInfo();
-  if (debug_info == nullptr) {
-    return;
-  }
-  std::vector<std::unique_ptr<dex_ir::LocalInfo>>& locals = debug_info->GetLocalInfo();
-  for (size_t i = 0; i < locals.size(); ++i) {
-    dex_ir::LocalInfo* entry = locals[i].get();
-    fprintf(out_file_, "        0x%04x - 0x%04x reg=%d %s %s %s\n",
-            entry->start_address_, entry->end_address_, entry->reg_,
-            entry->name_.c_str(), entry->descriptor_.c_str(), entry->signature_.c_str());
-  }
-}
-
 /*
  * Helper for dumpInstruction(), which builds the string
  * representation for the index in the given instruction.
@@ -723,11 +354,10 @@
 static std::unique_ptr<char[]> IndexString(dex_ir::Header* header,
                                            const Instruction* dec_insn,
                                            size_t buf_size) {
-  static const uint32_t kInvalidIndex = std::numeric_limits<uint32_t>::max();
   std::unique_ptr<char[]> buf(new char[buf_size]);
   // Determine index and width of the string.
   uint32_t index = 0;
-  uint32_t secondary_index = kInvalidIndex;
+  uint32_t secondary_index = DexFile::kDexNoIndex;
   uint32_t width = 4;
   switch (Instruction::FormatOf(dec_insn->Opcode())) {
     // SOME NOT SUPPORTED:
@@ -756,7 +386,6 @@
       index = dec_insn->VRegB();
       secondary_index = dec_insn->VRegH();
       width = 4;
-      break;
     default:
       break;
   }  // switch
@@ -821,9 +450,6 @@
     case Instruction::kIndexFieldOffset:
       outSize = snprintf(buf.get(), buf_size, "[obj+%0*x]", width, index);
       break;
-    // SOME NOT SUPPORTED:
-    // case Instruction::kIndexVaries:
-    // case Instruction::kIndexInlineMethod:
     case Instruction::kIndexMethodAndProtoRef: {
       std::string method("<method?>");
       std::string proto("<proto?>");
@@ -840,8 +466,11 @@
       }
       outSize = snprintf(buf.get(), buf_size, "%s, %s // method@%0*x, proto@%0*x",
                          method.c_str(), proto.c_str(), width, index, width, secondary_index);
-      }
-      break;
+    }
+    break;
+    // SOME NOT SUPPORTED:
+    // case Instruction::kIndexVaries:
+    // case Instruction::kIndexInlineMethod:
     default:
       outSize = snprintf(buf.get(), buf_size, "<?>");
       break;
@@ -858,11 +487,365 @@
 }
 
 /*
+ * Dumps encoded annotation.
+ */
+void DexLayout::DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation) {
+  fputs(annotation->GetType()->GetStringId()->Data(), out_file_);
+  // Display all name=value pairs.
+  for (auto& subannotation : *annotation->GetAnnotationElements()) {
+    fputc(' ', out_file_);
+    fputs(subannotation->GetName()->Data(), out_file_);
+    fputc('=', out_file_);
+    DumpEncodedValue(subannotation->GetValue());
+  }
+}
+/*
+ * Dumps encoded value.
+ */
+void DexLayout::DumpEncodedValue(const dex_ir::EncodedValue* data) {
+  switch (data->Type()) {
+    case DexFile::kDexAnnotationByte:
+      fprintf(out_file_, "%" PRId8, data->GetByte());
+      break;
+    case DexFile::kDexAnnotationShort:
+      fprintf(out_file_, "%" PRId16, data->GetShort());
+      break;
+    case DexFile::kDexAnnotationChar:
+      fprintf(out_file_, "%" PRIu16, data->GetChar());
+      break;
+    case DexFile::kDexAnnotationInt:
+      fprintf(out_file_, "%" PRId32, data->GetInt());
+      break;
+    case DexFile::kDexAnnotationLong:
+      fprintf(out_file_, "%" PRId64, data->GetLong());
+      break;
+    case DexFile::kDexAnnotationFloat: {
+      fprintf(out_file_, "%g", data->GetFloat());
+      break;
+    }
+    case DexFile::kDexAnnotationDouble: {
+      fprintf(out_file_, "%g", data->GetDouble());
+      break;
+    }
+    case DexFile::kDexAnnotationString: {
+      dex_ir::StringId* string_id = data->GetStringId();
+      if (options_.output_format_ == kOutputPlain) {
+        DumpEscapedString(string_id->Data(), out_file_);
+      } else {
+        DumpXmlAttribute(string_id->Data(), out_file_);
+      }
+      break;
+    }
+    case DexFile::kDexAnnotationType: {
+      dex_ir::TypeId* type_id = data->GetTypeId();
+      fputs(type_id->GetStringId()->Data(), out_file_);
+      break;
+    }
+    case DexFile::kDexAnnotationField:
+    case DexFile::kDexAnnotationEnum: {
+      dex_ir::FieldId* field_id = data->GetFieldId();
+      fputs(field_id->Name()->Data(), out_file_);
+      break;
+    }
+    case DexFile::kDexAnnotationMethod: {
+      dex_ir::MethodId* method_id = data->GetMethodId();
+      fputs(method_id->Name()->Data(), out_file_);
+      break;
+    }
+    case DexFile::kDexAnnotationArray: {
+      fputc('{', out_file_);
+      // Display all elements.
+      for (auto& value : *data->GetEncodedArray()->GetEncodedValues()) {
+        fputc(' ', out_file_);
+        DumpEncodedValue(value.get());
+      }
+      fputs(" }", out_file_);
+      break;
+    }
+    case DexFile::kDexAnnotationAnnotation: {
+      DumpEncodedAnnotation(data->GetEncodedAnnotation());
+      break;
+    }
+    case DexFile::kDexAnnotationNull:
+      fputs("null", out_file_);
+      break;
+    case DexFile::kDexAnnotationBoolean:
+      fputs(StrBool(data->GetBoolean()), out_file_);
+      break;
+    default:
+      fputs("????", out_file_);
+      break;
+  }  // switch
+}
+
+/*
+ * Dumps the file header.
+ */
+void DexLayout::DumpFileHeader() {
+  char sanitized[8 * 2 + 1];
+  dex_ir::Collections& collections = header_->GetCollections();
+  fprintf(out_file_, "DEX file header:\n");
+  Asciify(sanitized, header_->Magic(), 8);
+  fprintf(out_file_, "magic               : '%s'\n", sanitized);
+  fprintf(out_file_, "checksum            : %08x\n", header_->Checksum());
+  fprintf(out_file_, "signature           : %02x%02x...%02x%02x\n",
+          header_->Signature()[0], header_->Signature()[1],
+          header_->Signature()[DexFile::kSha1DigestSize - 2],
+          header_->Signature()[DexFile::kSha1DigestSize - 1]);
+  fprintf(out_file_, "file_size           : %d\n", header_->FileSize());
+  fprintf(out_file_, "header_size         : %d\n", header_->HeaderSize());
+  fprintf(out_file_, "link_size           : %d\n", header_->LinkSize());
+  fprintf(out_file_, "link_off            : %d (0x%06x)\n",
+          header_->LinkOffset(), header_->LinkOffset());
+  fprintf(out_file_, "string_ids_size     : %d\n", collections.StringIdsSize());
+  fprintf(out_file_, "string_ids_off      : %d (0x%06x)\n",
+          collections.StringIdsOffset(), collections.StringIdsOffset());
+  fprintf(out_file_, "type_ids_size       : %d\n", collections.TypeIdsSize());
+  fprintf(out_file_, "type_ids_off        : %d (0x%06x)\n",
+          collections.TypeIdsOffset(), collections.TypeIdsOffset());
+  fprintf(out_file_, "proto_ids_size      : %d\n", collections.ProtoIdsSize());
+  fprintf(out_file_, "proto_ids_off       : %d (0x%06x)\n",
+          collections.ProtoIdsOffset(), collections.ProtoIdsOffset());
+  fprintf(out_file_, "field_ids_size      : %d\n", collections.FieldIdsSize());
+  fprintf(out_file_, "field_ids_off       : %d (0x%06x)\n",
+          collections.FieldIdsOffset(), collections.FieldIdsOffset());
+  fprintf(out_file_, "method_ids_size     : %d\n", collections.MethodIdsSize());
+  fprintf(out_file_, "method_ids_off      : %d (0x%06x)\n",
+          collections.MethodIdsOffset(), collections.MethodIdsOffset());
+  fprintf(out_file_, "class_defs_size     : %d\n", collections.ClassDefsSize());
+  fprintf(out_file_, "class_defs_off      : %d (0x%06x)\n",
+          collections.ClassDefsOffset(), collections.ClassDefsOffset());
+  fprintf(out_file_, "data_size           : %d\n", header_->DataSize());
+  fprintf(out_file_, "data_off            : %d (0x%06x)\n\n",
+          header_->DataOffset(), header_->DataOffset());
+}
+
+/*
+ * Dumps a class_def_item.
+ */
+void DexLayout::DumpClassDef(int idx) {
+  // General class information.
+  dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
+  fprintf(out_file_, "Class #%d header:\n", idx);
+  fprintf(out_file_, "class_idx           : %d\n", class_def->ClassType()->GetIndex());
+  fprintf(out_file_, "access_flags        : %d (0x%04x)\n",
+          class_def->GetAccessFlags(), class_def->GetAccessFlags());
+  uint32_t superclass_idx =  class_def->Superclass() == nullptr ?
+      DexFile::kDexNoIndex16 : class_def->Superclass()->GetIndex();
+  fprintf(out_file_, "superclass_idx      : %d\n", superclass_idx);
+  fprintf(out_file_, "interfaces_off      : %d (0x%06x)\n",
+          class_def->InterfacesOffset(), class_def->InterfacesOffset());
+  uint32_t source_file_offset = 0xffffffffU;
+  if (class_def->SourceFile() != nullptr) {
+    source_file_offset = class_def->SourceFile()->GetIndex();
+  }
+  fprintf(out_file_, "source_file_idx     : %d\n", source_file_offset);
+  uint32_t annotations_offset = 0;
+  if (class_def->Annotations() != nullptr) {
+    annotations_offset = class_def->Annotations()->GetOffset();
+  }
+  fprintf(out_file_, "annotations_off     : %d (0x%06x)\n",
+          annotations_offset, annotations_offset);
+  if (class_def->GetClassData() == nullptr) {
+    fprintf(out_file_, "class_data_off      : %d (0x%06x)\n", 0, 0);
+  } else {
+    fprintf(out_file_, "class_data_off      : %d (0x%06x)\n",
+            class_def->GetClassData()->GetOffset(), class_def->GetClassData()->GetOffset());
+  }
+
+  // Fields and methods.
+  dex_ir::ClassData* class_data = class_def->GetClassData();
+  if (class_data != nullptr && class_data->StaticFields() != nullptr) {
+    fprintf(out_file_, "static_fields_size  : %zu\n", class_data->StaticFields()->size());
+  } else {
+    fprintf(out_file_, "static_fields_size  : 0\n");
+  }
+  if (class_data != nullptr && class_data->InstanceFields() != nullptr) {
+    fprintf(out_file_, "instance_fields_size: %zu\n", class_data->InstanceFields()->size());
+  } else {
+    fprintf(out_file_, "instance_fields_size: 0\n");
+  }
+  if (class_data != nullptr && class_data->DirectMethods() != nullptr) {
+    fprintf(out_file_, "direct_methods_size : %zu\n", class_data->DirectMethods()->size());
+  } else {
+    fprintf(out_file_, "direct_methods_size : 0\n");
+  }
+  if (class_data != nullptr && class_data->VirtualMethods() != nullptr) {
+    fprintf(out_file_, "virtual_methods_size: %zu\n", class_data->VirtualMethods()->size());
+  } else {
+    fprintf(out_file_, "virtual_methods_size: 0\n");
+  }
+  fprintf(out_file_, "\n");
+}
+
+/**
+ * Dumps an annotation set item.
+ */
+void DexLayout::DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item) {
+  if (set_item == nullptr || set_item->GetItems()->size() == 0) {
+    fputs("  empty-annotation-set\n", out_file_);
+    return;
+  }
+  for (dex_ir::AnnotationItem* annotation : *set_item->GetItems()) {
+    if (annotation == nullptr) {
+      continue;
+    }
+    fputs("  ", out_file_);
+    switch (annotation->GetVisibility()) {
+      case DexFile::kDexVisibilityBuild:   fputs("VISIBILITY_BUILD ",   out_file_); break;
+      case DexFile::kDexVisibilityRuntime: fputs("VISIBILITY_RUNTIME ", out_file_); break;
+      case DexFile::kDexVisibilitySystem:  fputs("VISIBILITY_SYSTEM ",  out_file_); break;
+      default:                             fputs("VISIBILITY_UNKNOWN ", out_file_); break;
+    }  // switch
+    DumpEncodedAnnotation(annotation->GetAnnotation());
+    fputc('\n', out_file_);
+  }
+}
+
+/*
+ * Dumps class annotations.
+ */
+void DexLayout::DumpClassAnnotations(int idx) {
+  dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
+  dex_ir::AnnotationsDirectoryItem* annotations_directory = class_def->Annotations();
+  if (annotations_directory == nullptr) {
+    return;  // none
+  }
+
+  fprintf(out_file_, "Class #%d annotations:\n", idx);
+
+  dex_ir::AnnotationSetItem* class_set_item = annotations_directory->GetClassAnnotation();
+  dex_ir::FieldAnnotationVector* fields = annotations_directory->GetFieldAnnotations();
+  dex_ir::MethodAnnotationVector* methods = annotations_directory->GetMethodAnnotations();
+  dex_ir::ParameterAnnotationVector* parameters = annotations_directory->GetParameterAnnotations();
+
+  // Annotations on the class itself.
+  if (class_set_item != nullptr) {
+    fprintf(out_file_, "Annotations on class\n");
+    DumpAnnotationSetItem(class_set_item);
+  }
+
+  // Annotations on fields.
+  if (fields != nullptr) {
+    for (auto& field : *fields) {
+      const dex_ir::FieldId* field_id = field->GetFieldId();
+      const uint32_t field_idx = field_id->GetIndex();
+      const char* field_name = field_id->Name()->Data();
+      fprintf(out_file_, "Annotations on field #%u '%s'\n", field_idx, field_name);
+      DumpAnnotationSetItem(field->GetAnnotationSetItem());
+    }
+  }
+
+  // Annotations on methods.
+  if (methods != nullptr) {
+    for (auto& method : *methods) {
+      const dex_ir::MethodId* method_id = method->GetMethodId();
+      const uint32_t method_idx = method_id->GetIndex();
+      const char* method_name = method_id->Name()->Data();
+      fprintf(out_file_, "Annotations on method #%u '%s'\n", method_idx, method_name);
+      DumpAnnotationSetItem(method->GetAnnotationSetItem());
+    }
+  }
+
+  // Annotations on method parameters.
+  if (parameters != nullptr) {
+    for (auto& parameter : *parameters) {
+      const dex_ir::MethodId* method_id = parameter->GetMethodId();
+      const uint32_t method_idx = method_id->GetIndex();
+      const char* method_name = method_id->Name()->Data();
+      fprintf(out_file_, "Annotations on method #%u '%s' parameters\n", method_idx, method_name);
+      uint32_t j = 0;
+      for (dex_ir::AnnotationSetItem* annotation : *parameter->GetAnnotations()->GetItems()) {
+        fprintf(out_file_, "#%u\n", j);
+        DumpAnnotationSetItem(annotation);
+        ++j;
+      }
+    }
+  }
+
+  fputc('\n', out_file_);
+}
+
+/*
+ * Dumps an interface that a class declares to implement.
+ */
+void DexLayout::DumpInterface(const dex_ir::TypeId* type_item, int i) {
+  const char* interface_name = type_item->GetStringId()->Data();
+  if (options_.output_format_ == kOutputPlain) {
+    fprintf(out_file_, "    #%d              : '%s'\n", i, interface_name);
+  } else {
+    std::string dot(DescriptorToDotWrapper(interface_name));
+    fprintf(out_file_, "<implements name=\"%s\">\n</implements>\n", dot.c_str());
+  }
+}
+
+/*
+ * Dumps the catches table associated with the code.
+ */
+void DexLayout::DumpCatches(const dex_ir::CodeItem* code) {
+  const uint16_t tries_size = code->TriesSize();
+
+  // No catch table.
+  if (tries_size == 0) {
+    fprintf(out_file_, "      catches       : (none)\n");
+    return;
+  }
+
+  // Dump all table entries.
+  fprintf(out_file_, "      catches       : %d\n", tries_size);
+  std::vector<std::unique_ptr<const dex_ir::TryItem>>* tries = code->Tries();
+  for (uint32_t i = 0; i < tries_size; i++) {
+    const dex_ir::TryItem* try_item = (*tries)[i].get();
+    const uint32_t start = try_item->StartAddr();
+    const uint32_t end = start + try_item->InsnCount();
+    fprintf(out_file_, "        0x%04x - 0x%04x\n", start, end);
+    for (auto& handler : *try_item->GetHandlers()->GetHandlers()) {
+      const dex_ir::TypeId* type_id = handler->GetTypeId();
+      const char* descriptor = (type_id == nullptr) ? "<any>" : type_id->GetStringId()->Data();
+      fprintf(out_file_, "          %s -> 0x%04x\n", descriptor, handler->GetAddress());
+    }  // for
+  }  // for
+}
+
+/*
+ * Dumps all positions table entries associated with the code.
+ */
+void DexLayout::DumpPositionInfo(const dex_ir::CodeItem* code) {
+  dex_ir::DebugInfoItem* debug_info = code->DebugInfo();
+  if (debug_info == nullptr) {
+    return;
+  }
+  std::vector<std::unique_ptr<dex_ir::PositionInfo>>& positions = debug_info->GetPositionInfo();
+  for (size_t i = 0; i < positions.size(); ++i) {
+    fprintf(out_file_, "        0x%04x line=%d\n", positions[i]->address_, positions[i]->line_);
+  }
+}
+
+/*
+ * Dumps all locals table entries associated with the code.
+ */
+void DexLayout::DumpLocalInfo(const dex_ir::CodeItem* code) {
+  dex_ir::DebugInfoItem* debug_info = code->DebugInfo();
+  if (debug_info == nullptr) {
+    return;
+  }
+  std::vector<std::unique_ptr<dex_ir::LocalInfo>>& locals = debug_info->GetLocalInfo();
+  for (size_t i = 0; i < locals.size(); ++i) {
+    dex_ir::LocalInfo* entry = locals[i].get();
+    fprintf(out_file_, "        0x%04x - 0x%04x reg=%d %s %s %s\n",
+            entry->start_address_, entry->end_address_, entry->reg_,
+            entry->name_.c_str(), entry->descriptor_.c_str(), entry->signature_.c_str());
+  }
+}
+
+/*
  * Dumps a single instruction.
  */
-static void DumpInstruction(dex_ir::Header* header, const dex_ir::CodeItem* code,
-                            uint32_t code_offset, uint32_t insn_idx, uint32_t insn_width,
-                            const Instruction* dec_insn) {
+void DexLayout::DumpInstruction(const dex_ir::CodeItem* code,
+                                uint32_t code_offset,
+                                uint32_t insn_idx,
+                                uint32_t insn_width,
+                                const Instruction* dec_insn) {
   // Address of instruction (expressed as byte offset).
   fprintf(out_file_, "%06x:", code_offset + 0x10 + insn_idx * 2);
 
@@ -901,7 +884,7 @@
   // Set up additional argument.
   std::unique_ptr<char[]> index_buf;
   if (Instruction::IndexTypeOf(dec_insn->Opcode()) != Instruction::kIndexNone) {
-    index_buf = IndexString(header, dec_insn, 200);
+    index_buf = IndexString(header_, dec_insn, 200);
   }
 
   // Dump the instruction.
@@ -1073,9 +1056,8 @@
 /*
  * Dumps a bytecode disassembly.
  */
-static void DumpBytecodes(dex_ir::Header* header, uint32_t idx,
-                          const dex_ir::CodeItem* code, uint32_t code_offset) {
-  dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(idx);
+void DexLayout::DumpBytecodes(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset) {
+  dex_ir::MethodId* method_id = header_->GetCollections().GetMethodId(idx);
   const char* name = method_id->Name()->Data();
   std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
   const char* back_descriptor = method_id->Class()->GetStringId()->Data();
@@ -1094,7 +1076,7 @@
       fprintf(stderr, "GLITCH: zero-width instruction at idx=0x%04x\n", insn_idx);
       break;
     }
-    DumpInstruction(header, code, code_offset, insn_idx, insn_width, instruction);
+    DumpInstruction(code, code_offset, insn_idx, insn_width, instruction);
     insn_idx += insn_width;
   }  // for
 }
@@ -1102,8 +1084,7 @@
 /*
  * Dumps code of a method.
  */
-static void DumpCode(dex_ir::Header* header, uint32_t idx, const dex_ir::CodeItem* code,
-                     uint32_t code_offset) {
+void DexLayout::DumpCode(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset) {
   fprintf(out_file_, "      registers     : %d\n", code->RegistersSize());
   fprintf(out_file_, "      ins           : %d\n", code->InsSize());
   fprintf(out_file_, "      outs          : %d\n", code->OutsSize());
@@ -1112,7 +1093,7 @@
 
   // Bytecode disassembly, if requested.
   if (options_.disassemble_) {
-    DumpBytecodes(header, idx, code, code_offset);
+    DumpBytecodes(idx, code, code_offset);
   }
 
   // Try-catch blocks.
@@ -1128,14 +1109,13 @@
 /*
  * Dumps a method.
  */
-static void DumpMethod(dex_ir::Header* header, uint32_t idx, uint32_t flags,
-                       const dex_ir::CodeItem* code, int i) {
+void DexLayout::DumpMethod(uint32_t idx, uint32_t flags, const dex_ir::CodeItem* code, int i) {
   // Bail for anything private if export only requested.
   if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) {
     return;
   }
 
-  dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(idx);
+  dex_ir::MethodId* method_id = header_->GetCollections().GetMethodId(idx);
   const char* name = method_id->Name()->Data();
   char* type_descriptor = strdup(GetSignatureForProtoId(method_id->Proto()).c_str());
   const char* back_descriptor = method_id->Class()->GetStringId()->Data();
@@ -1150,7 +1130,7 @@
       fprintf(out_file_, "      code          : (none)\n");
     } else {
       fprintf(out_file_, "      code          -\n");
-      DumpCode(header, idx, code, code->GetOffset());
+      DumpCode(idx, code, code->GetOffset());
     }
     if (options_.disassemble_) {
       fputc('\n', out_file_);
@@ -1233,14 +1213,13 @@
 /*
  * Dumps a static (class) field.
  */
-static void DumpSField(dex_ir::Header* header, uint32_t idx, uint32_t flags,
-                       int i, dex_ir::EncodedValue* init) {
+void DexLayout::DumpSField(uint32_t idx, uint32_t flags, int i, dex_ir::EncodedValue* init) {
   // Bail for anything private if export only requested.
   if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) {
     return;
   }
 
-  dex_ir::FieldId* field_id = header->GetCollections().GetFieldId(idx);
+  dex_ir::FieldId* field_id = header_->GetCollections().GetFieldId(idx);
   const char* name = field_id->Name()->Data();
   const char* type_descriptor = field_id->Type()->GetStringId()->Data();
   const char* back_descriptor = field_id->Class()->GetStringId()->Data();
@@ -1281,8 +1260,8 @@
 /*
  * Dumps an instance field.
  */
-static void DumpIField(dex_ir::Header* header, uint32_t idx, uint32_t flags, int i) {
-  DumpSField(header, idx, flags, i, nullptr);
+void DexLayout::DumpIField(uint32_t idx, uint32_t flags, int i) {
+  DumpSField(idx, flags, i, nullptr);
 }
 
 /*
@@ -1293,19 +1272,19 @@
  * If "*last_package" is nullptr or does not match the current class' package,
  * the value will be replaced with a newly-allocated string.
  */
-static void DumpClass(dex_ir::Header* header, int idx, char** last_package) {
-  dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx);
+void DexLayout::DumpClass(int idx, char** last_package) {
+  dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
   // Omitting non-public class.
   if (options_.exports_only_ && (class_def->GetAccessFlags() & kAccPublic) == 0) {
     return;
   }
 
   if (options_.show_section_headers_) {
-    DumpClassDef(header, idx);
+    DumpClassDef(idx);
   }
 
   if (options_.show_annotations_) {
-    DumpClassAnnotations(header, idx);
+    DumpClassAnnotations(idx);
   }
 
   // For the XML output, show the package name.  Ideally we'd gather
@@ -1313,7 +1292,7 @@
   // package name wouldn't jump around, but that's not a great plan
   // for something that needs to run on the device.
   const char* class_descriptor =
-      header->GetCollections().GetClassDef(idx)->ClassType()->GetStringId()->Data();
+      header_->GetCollections().GetClassDef(idx)->ClassType()->GetStringId()->Data();
   if (!(class_descriptor[0] == 'L' &&
         class_descriptor[strlen(class_descriptor)-1] == ';')) {
     // Arrays and primitives should not be defined explicitly. Keep going?
@@ -1406,8 +1385,7 @@
     dex_ir::FieldItemVector* static_fields = class_data->StaticFields();
     if (static_fields != nullptr) {
       for (uint32_t i = 0; i < static_fields->size(); i++) {
-        DumpSField(header,
-                   (*static_fields)[i]->GetFieldId()->GetIndex(),
+        DumpSField((*static_fields)[i]->GetFieldId()->GetIndex(),
                    (*static_fields)[i]->GetAccessFlags(),
                    i,
                    i < encoded_values_size ? (*encoded_values)[i].get() : nullptr);
@@ -1423,8 +1401,7 @@
     dex_ir::FieldItemVector* instance_fields = class_data->InstanceFields();
     if (instance_fields != nullptr) {
       for (uint32_t i = 0; i < instance_fields->size(); i++) {
-        DumpIField(header,
-                   (*instance_fields)[i]->GetFieldId()->GetIndex(),
+        DumpIField((*instance_fields)[i]->GetFieldId()->GetIndex(),
                    (*instance_fields)[i]->GetAccessFlags(),
                    i);
       }  // for
@@ -1439,8 +1416,7 @@
     dex_ir::MethodItemVector* direct_methods = class_data->DirectMethods();
     if (direct_methods != nullptr) {
       for (uint32_t i = 0; i < direct_methods->size(); i++) {
-        DumpMethod(header,
-                   (*direct_methods)[i]->GetMethodId()->GetIndex(),
+        DumpMethod((*direct_methods)[i]->GetMethodId()->GetIndex(),
                    (*direct_methods)[i]->GetAccessFlags(),
                    (*direct_methods)[i]->GetCodeItem(),
                  i);
@@ -1456,8 +1432,7 @@
     dex_ir::MethodItemVector* virtual_methods = class_data->VirtualMethods();
     if (virtual_methods != nullptr) {
       for (uint32_t i = 0; i < virtual_methods->size(); i++) {
-        DumpMethod(header,
-                   (*virtual_methods)[i]->GetMethodId()->GetIndex(),
+        DumpMethod((*virtual_methods)[i]->GetMethodId()->GetIndex(),
                    (*virtual_methods)[i]->GetAccessFlags(),
                    (*virtual_methods)[i]->GetCodeItem(),
                    i);
@@ -1481,24 +1456,10 @@
   free(access_str);
 }
 
-/*
- * Dumps the requested sections of the file.
- */
-static void ProcessDexFile(const char* file_name, const DexFile* dex_file, size_t dex_file_index) {
-  if (options_.verbose_) {
-    fprintf(out_file_, "Opened '%s', DEX version '%.3s'\n",
-            file_name, dex_file->GetHeader().magic_ + 4);
-  }
-  std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file));
-
-  if (options_.visualize_pattern_) {
-    VisualizeDexLayout(header.get(), dex_file, dex_file_index);
-    return;
-  }
-
+void DexLayout::DumpDexFile() {
   // Headers.
   if (options_.show_file_headers_) {
-    DumpFileHeader(header.get());
+    DumpFileHeader();
   }
 
   // Open XML context.
@@ -1508,9 +1469,9 @@
 
   // Iterate over all classes.
   char* package = nullptr;
-  const uint32_t class_defs_size = header->GetCollections().ClassDefsSize();
+  const uint32_t class_defs_size = header_->GetCollections().ClassDefsSize();
   for (uint32_t i = 0; i < class_defs_size; i++) {
-    DumpClass(header.get(), i, &package);
+    DumpClass(i, &package);
   }  // for
 
   // Free the last package allocated.
@@ -1523,20 +1484,77 @@
   if (options_.output_format_ == kOutputXml) {
     fprintf(out_file_, "</api>\n");
   }
+}
 
-  // Output dex file.
-  if (options_.output_dex_directory_ != nullptr) {
+void DexLayout::OutputDexFile(const std::string& dex_file_location) {
+  std::string error_msg;
+  std::unique_ptr<File> new_file;
+  if (!options_.output_to_memmap_) {
     std::string output_location(options_.output_dex_directory_);
-    size_t last_slash = dex_file->GetLocation().rfind('/');
-    output_location.append(dex_file->GetLocation().substr(last_slash));
-    DexWriter::OutputDexFile(*header, output_location.c_str());
+    size_t last_slash = dex_file_location.rfind("/");
+    std::string dex_file_directory = dex_file_location.substr(0, last_slash + 1);
+    if (output_location == dex_file_directory) {
+      output_location = dex_file_location + ".new";
+    } else if (last_slash != std::string::npos) {
+      output_location += dex_file_location.substr(last_slash);
+    } else {
+      output_location += "/" + dex_file_location + ".new";
+    }
+    new_file.reset(OS::CreateEmptyFile(output_location.c_str()));
+    ftruncate(new_file->Fd(), header_->FileSize());
+    mem_map_.reset(MemMap::MapFile(header_->FileSize(), 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, header_->FileSize(),
+        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.get() != nullptr) {
+      new_file->Erase();
+    }
+    return;
+  }
+  DexWriter::Output(header_, mem_map_.get());
+  if (new_file != nullptr) {
+    UNUSED(new_file->FlushCloseOrErase());
+  }
+}
+
+/*
+ * Dumps the requested sections of the file.
+ */
+void DexLayout::ProcessDexFile(const char* file_name,
+                               const DexFile* dex_file,
+                               size_t dex_file_index) {
+  std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file));
+  SetHeader(header.get());
+
+  if (options_.verbose_) {
+    fprintf(out_file_, "Opened '%s', DEX version '%.3s'\n",
+            file_name, dex_file->GetHeader().magic_ + 4);
+  }
+
+  if (options_.visualize_pattern_) {
+    VisualizeDexLayout(header_, dex_file, dex_file_index, info_);
+    return;
+  }
+
+  // Dump dex file.
+  if (options_.dump_) {
+    DumpDexFile();
+  }
+
+  // Output dex file as file or memmap.
+  if (options_.output_dex_directory_ != nullptr || options_.output_to_memmap_) {
+    OutputDexFile(dex_file->GetLocation());
   }
 }
 
 /*
  * Processes a single file (either direct .dex or indirect .zip/.jar/.apk).
  */
-int ProcessFile(const char* file_name) {
+int DexLayout::ProcessFile(const char* file_name) {
   if (options_.verbose_) {
     fprintf(out_file_, "Processing '%s'...\n", file_name);
   }
diff --git a/dexlayout/dexlayout.h b/dexlayout/dexlayout.h
index a5bd992..179e90e 100644
--- a/dexlayout/dexlayout.h
+++ b/dexlayout/dexlayout.h
@@ -26,8 +26,13 @@
 #include <stdint.h>
 #include <stdio.h>
 
+#include "dex_ir.h"
+#include "mem_map.h"
+
 namespace art {
 
+class DexFile;
+class Instruction;
 class ProfileCompilationInfo;
 
 /* Supported output formats. */
@@ -37,28 +42,87 @@
 };
 
 /* Command-line options. */
-struct Options {
-  bool build_dex_ir_;
-  bool checksum_only_;
-  bool disassemble_;
-  bool exports_only_;
-  bool ignore_bad_checksum_;
-  bool show_annotations_;
-  bool show_file_headers_;
-  bool show_section_headers_;
-  bool verbose_;
-  bool visualize_pattern_;
-  OutputFormat output_format_;
-  const char* output_dex_directory_;
-  const char* output_file_name_;
-  const char* profile_file_name_;
+class Options {
+ public:
+  Options() = default;
+
+  bool dump_ = false;
+  bool build_dex_ir_ = false;
+  bool checksum_only_ = false;
+  bool disassemble_ = false;
+  bool exports_only_ = false;
+  bool ignore_bad_checksum_ = false;
+  bool output_to_memmap_ = false;
+  bool show_annotations_ = false;
+  bool show_file_headers_ = false;
+  bool show_section_headers_ = false;
+  bool verbose_ = false;
+  bool visualize_pattern_ = false;
+  OutputFormat output_format_ = kOutputPlain;
+  const char* output_dex_directory_ = nullptr;
+  const char* output_file_name_ = nullptr;
+  const char* profile_file_name_ = nullptr;
 };
 
-/* Prototypes. */
-extern struct Options options_;
-extern FILE* out_file_;
-extern ProfileCompilationInfo* profile_info_;
-int ProcessFile(const char* file_name);
+class DexLayout {
+ public:
+  DexLayout(Options& options,
+            ProfileCompilationInfo* info,
+            FILE* out_file,
+            dex_ir::Header*
+            header = nullptr)
+      : 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);
+
+  dex_ir::Header* GetHeader() const { return header_; }
+  void SetHeader(dex_ir::Header* header) { header_ = header; }
+
+  MemMap* GetAndReleaseMemMap() { return mem_map_.release(); }
+
+ private:
+  void DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item);
+  void DumpBytecodes(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset);
+  void DumpCatches(const dex_ir::CodeItem* code);
+  void DumpClass(int idx, char** last_package);
+  void DumpClassAnnotations(int idx);
+  void DumpClassDef(int idx);
+  void DumpCode(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset);
+  void DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation);
+  void DumpEncodedValue(const dex_ir::EncodedValue* data);
+  void DumpFileHeader();
+  void DumpIField(uint32_t idx, uint32_t flags, int i);
+  void DumpInstruction(const dex_ir::CodeItem* code,
+                       uint32_t code_offset,
+                       uint32_t insn_idx,
+                       uint32_t insn_width,
+                       const Instruction* dec_insn);
+  void DumpInterface(const dex_ir::TypeId* type_item, int i);
+  void DumpLocalInfo(const dex_ir::CodeItem* code);
+  void DumpMethod(uint32_t idx, uint32_t flags, const dex_ir::CodeItem* code, int i);
+  void DumpPositionInfo(const dex_ir::CodeItem* code);
+  void DumpSField(uint32_t idx, uint32_t flags, int i, dex_ir::EncodedValue* init);
+
+  void DumpDexFile();
+  std::vector<dex_ir::ClassDef*> LayoutClassDefsAndClassData(const DexFile* dex_file);
+  int32_t LayoutCodeItems(std::vector<dex_ir::ClassDef*> new_class_def_order);
+  template<class T> void FixupSection(std::map<uint32_t, std::unique_ptr<T>>& map, uint32_t diff);
+  void FixupSections(uint32_t offset, uint32_t diff);
+  void LayoutOutputFile(const DexFile* dex_file);
+  void OutputDexFile(const std::string& dex_file_location);
+
+  void DumpCFG(const DexFile* dex_file, int idx);
+  void DumpCFG(const DexFile* dex_file, uint32_t dex_method_idx, const DexFile::CodeItem* code);
+
+  Options& options_;
+  ProfileCompilationInfo* info_;
+  FILE* out_file_;
+  dex_ir::Header* header_;
+  std::unique_ptr<MemMap> mem_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(DexLayout);
+};
 
 }  // namespace art
 
diff --git a/dexlayout/dexlayout_main.cc b/dexlayout/dexlayout_main.cc
index 825dd50..5f8a118 100644
--- a/dexlayout/dexlayout_main.cc
+++ b/dexlayout/dexlayout_main.cc
@@ -68,64 +68,67 @@
   InitLogging(argv, Runtime::Aborter);
   MemMap::Init();
 
-  // Reset options.
+  Options options;
+  options.dump_ = true;
+  options.verbose_ = true;
   bool want_usage = false;
-  memset(&options_, 0, sizeof(options_));
-  options_.verbose_ = true;
 
   // Parse all arguments.
   while (1) {
-    const int ic = getopt(argc, argv, "abcdefghil:o:p:sw:");
+    const int ic = getopt(argc, argv, "abcdefghil:mo:p:sw:");
     if (ic < 0) {
       break;  // done
     }
     switch (ic) {
       case 'a':  // display annotations
-        options_.show_annotations_ = true;
+        options.show_annotations_ = true;
         break;
       case 'b':  // build dex_ir
-        options_.build_dex_ir_ = true;
+        options.build_dex_ir_ = true;
         break;
       case 'c':  // verify the checksum then exit
-        options_.checksum_only_ = true;
+        options.checksum_only_ = true;
         break;
       case 'd':  // disassemble Dalvik instructions
-        options_.disassemble_ = true;
+        options.disassemble_ = true;
         break;
       case 'e':  // exported items only
-        options_.exports_only_ = true;
+        options.exports_only_ = true;
         break;
       case 'f':  // display outer file header
-        options_.show_file_headers_ = true;
+        options.show_file_headers_ = true;
         break;
       case 'h':  // display section headers, i.e. all meta-data
-        options_.show_section_headers_ = true;
+        options.show_section_headers_ = true;
         break;
       case 'i':  // continue even if checksum is bad
-        options_.ignore_bad_checksum_ = true;
+        options.ignore_bad_checksum_ = true;
         break;
       case 'l':  // layout
         if (strcmp(optarg, "plain") == 0) {
-          options_.output_format_ = kOutputPlain;
+          options.output_format_ = kOutputPlain;
         } else if (strcmp(optarg, "xml") == 0) {
-          options_.output_format_ = kOutputXml;
-          options_.verbose_ = false;
+          options.output_format_ = kOutputXml;
+          options.verbose_ = false;
         } else {
           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;
+        options.output_file_name_ = optarg;
         break;
       case 'p':  // profile file
-        options_.profile_file_name_ = optarg;
+        options.profile_file_name_ = optarg;
         break;
       case 's':  // visualize access pattern
-        options_.visualize_pattern_ = true;
-        options_.verbose_ = false;
+        options.visualize_pattern_ = true;
+        options.verbose_ = false;
         break;
       case 'w':  // output dex files directory
-        options_.output_dex_directory_ = optarg;
+        options.output_dex_directory_ = optarg;
         break;
       default:
         want_usage = true;
@@ -138,7 +141,7 @@
     fprintf(stderr, "%s: no file specified\n", kProgramName);
     want_usage = true;
   }
-  if (options_.checksum_only_ && options_.ignore_bad_checksum_) {
+  if (options.checksum_only_ && options.ignore_bad_checksum_) {
     fprintf(stderr, "Can't specify both -c and -i\n");
     want_usage = true;
   }
@@ -148,32 +151,37 @@
   }
 
   // Open alternative output file.
-  if (options_.output_file_name_) {
-    out_file_ = fopen(options_.output_file_name_, "w");
-    if (!out_file_) {
-      fprintf(stderr, "Can't open %s\n", options_.output_file_name_);
+  FILE* out_file = stdout;
+  if (options.output_file_name_) {
+    out_file = fopen(options.output_file_name_, "w");
+    if (!out_file) {
+      fprintf(stderr, "Can't open %s\n", options.output_file_name_);
       return 1;
     }
   }
 
   // Open profile file.
-  if (options_.profile_file_name_) {
-    int profile_fd = open(options_.profile_file_name_, O_RDONLY);
+  ProfileCompilationInfo* profile_info = nullptr;
+  if (options.profile_file_name_) {
+    int profile_fd = open(options.profile_file_name_, O_RDONLY);
     if (profile_fd < 0) {
-      fprintf(stderr, "Can't open %s\n", options_.profile_file_name_);
+      fprintf(stderr, "Can't open %s\n", options.profile_file_name_);
       return 1;
     }
-    profile_info_ = new ProfileCompilationInfo();
-    if (!profile_info_->Load(profile_fd)) {
-      fprintf(stderr, "Can't read profile info from %s\n", options_.profile_file_name_);
+    profile_info = new ProfileCompilationInfo();
+    if (!profile_info->Load(profile_fd)) {
+      fprintf(stderr, "Can't read profile info from %s\n", options.profile_file_name_);
       return 1;
     }
   }
 
+  // Create DexLayout instance.
+  DexLayout dex_layout(options, profile_info, out_file);
+
   // Process all files supplied on command line.
   int result = 0;
   while (optind < argc) {
-    result |= ProcessFile(argv[optind++]);
+    result |= dex_layout.ProcessFile(argv[optind++]);
   }  // while
   return result != 0;
 }