Remove OatWriter buffering to memory for ElfWriterQuick

This allows the oat contents to be directly written to the file.

Change-Id: Ibc7ddf57477b152f07784b52f7334be73fd22833
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 1f66730..ea2291c 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -2343,13 +2343,13 @@
 bool CompilerDriver::WriteElf(const std::string& android_root,
                               bool is_host,
                               const std::vector<const art::DexFile*>& dex_files,
-                              std::vector<uint8_t>& oat_contents,
+                              OatWriter& oat_writer,
                               art::File* file)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
 #if defined(ART_USE_PORTABLE_COMPILER)
-  return art::ElfWriterMclinker::Create(file, oat_contents, dex_files, android_root, is_host, *this);
+  return art::ElfWriterMclinker::Create(file, oat_writer, dex_files, android_root, is_host, *this);
 #else
-  return art::ElfWriterQuick::Create(file, oat_contents, dex_files, android_root, is_host, *this);
+  return art::ElfWriterQuick::Create(file, oat_writer, dex_files, android_root, is_host, *this);
 #endif
 }
 void CompilerDriver::InstructionSetToLLVMTarget(InstructionSet instruction_set,
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 1799057..f3f72dd 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -39,6 +39,7 @@
 class AOTCompilationStats;
 class ParallelCompilationManager;
 class DexCompilationUnit;
+class OatWriter;
 class TimingLogger;
 
 enum CompilerBackend {
@@ -192,7 +193,7 @@
   bool WriteElf(const std::string& android_root,
                 bool is_host,
                 const std::vector<const DexFile*>& dex_files,
-                std::vector<uint8_t>& oat_contents,
+                OatWriter& oat_writer,
                 File* file);
 
   // TODO: move to a common home for llvm helpers once quick/portable are merged
diff --git a/compiler/elf_writer.h b/compiler/elf_writer.h
index 0dfce6e..0ef4185 100644
--- a/compiler/elf_writer.h
+++ b/compiler/elf_writer.h
@@ -33,6 +33,7 @@
 class CompilerDriver;
 class DexFile;
 class ElfFile;
+class OatWriter;
 
 class ElfWriter {
  public:
@@ -49,7 +50,7 @@
   ElfWriter(const CompilerDriver& driver, File* elf_file);
   virtual ~ElfWriter();
 
-  virtual bool Write(std::vector<uint8_t>& oat_contents,
+  virtual bool Write(OatWriter& oat_writer,
                      const std::vector<const DexFile*>& dex_files,
                      const std::string& android_root,
                      bool is_host)
diff --git a/compiler/elf_writer_mclinker.cc b/compiler/elf_writer_mclinker.cc
index 05f3b02..2a9bc35 100644
--- a/compiler/elf_writer_mclinker.cc
+++ b/compiler/elf_writer_mclinker.cc
@@ -36,7 +36,9 @@
 #include "mirror/abstract_method.h"
 #include "mirror/abstract_method-inl.h"
 #include "mirror/object-inl.h"
+#include "oat_writer.h"
 #include "scoped_thread_state_change.h"
+#include "vector_output_stream.h"
 
 namespace art {
 
@@ -46,19 +48,25 @@
 ElfWriterMclinker::~ElfWriterMclinker() {}
 
 bool ElfWriterMclinker::Create(File* elf_file,
-                               std::vector<uint8_t>& oat_contents,
+                               OatWriter& oat_writer,
                                const std::vector<const DexFile*>& dex_files,
                                const std::string& android_root,
                                bool is_host,
                                const CompilerDriver& driver) {
   ElfWriterMclinker elf_writer(driver, elf_file);
-  return elf_writer.Write(oat_contents, dex_files, android_root, is_host);
+  return elf_writer.Write(oat_writer, dex_files, android_root, is_host);
 }
 
-bool ElfWriterMclinker::Write(std::vector<uint8_t>& oat_contents,
+bool ElfWriterMclinker::Write(OatWriter& oat_writer,
                               const std::vector<const DexFile*>& dex_files,
                               const std::string& android_root,
                               bool is_host) {
+  std::vector<uint8_t> oat_contents;
+  oat_contents.reserve(oat_writer.GetSize());
+  VectorOutputStream output_stream("oat contents", oat_contents);
+  CHECK(oat_writer.Write(output_stream));
+  CHECK_EQ(oat_writer.GetSize(), oat_contents.size());
+
   Init();
   AddOatInput(oat_contents);
 #if defined(ART_USE_PORTABLE_COMPILER)
@@ -68,6 +76,7 @@
   if (!Link()) {
     return false;
   }
+  oat_contents.clear();
 #if defined(ART_USE_PORTABLE_COMPILER)
   FixupOatMethodOffsets(dex_files);
 #endif
diff --git a/compiler/elf_writer_mclinker.h b/compiler/elf_writer_mclinker.h
index 3b33bc4..bdadf8f 100644
--- a/compiler/elf_writer_mclinker.h
+++ b/compiler/elf_writer_mclinker.h
@@ -40,7 +40,7 @@
  public:
   // Write an ELF file. Returns true on success, false on failure.
   static bool Create(File* file,
-                     std::vector<uint8_t>& oat_contents,
+                     OatWriter& oat_writer,
                      const std::vector<const DexFile*>& dex_files,
                      const std::string& android_root,
                      bool is_host,
@@ -48,7 +48,7 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
  protected:
-  virtual bool Write(std::vector<uint8_t>& oat_contents,
+  virtual bool Write(OatWriter& oat_writer,
                      const std::vector<const DexFile*>& dex_files,
                      const std::string& android_root,
                      bool is_host)
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index 9de96d2..f2db5d8 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -19,8 +19,10 @@
 #include "base/logging.h"
 #include "base/unix_file/fd_file.h"
 #include "driver/compiler_driver.h"
+#include "file_output_stream.h"
 #include "globals.h"
 #include "oat.h"
+#include "oat_writer.h"
 #include "utils.h"
 
 namespace art {
@@ -31,16 +33,16 @@
 ElfWriterQuick::~ElfWriterQuick() {}
 
 bool ElfWriterQuick::Create(File* elf_file,
-                            std::vector<uint8_t>& oat_contents,
+                            OatWriter& oat_writer,
                             const std::vector<const DexFile*>& dex_files,
                             const std::string& android_root,
                             bool is_host,
                             const CompilerDriver& driver) {
   ElfWriterQuick elf_writer(driver, elf_file);
-  return elf_writer.Write(oat_contents, dex_files, android_root, is_host);
+  return elf_writer.Write(oat_writer, dex_files, android_root, is_host);
 }
 
-bool ElfWriterQuick::Write(std::vector<uint8_t>& oat_contents,
+bool ElfWriterQuick::Write(OatWriter& oat_writer,
                            const std::vector<const DexFile*>& dex_files_unused,
                            const std::string& android_root_unused,
                            bool is_host_unused) {
@@ -193,9 +195,9 @@
   // .rodata
   uint32_t oat_data_alignment = kPageSize;
   uint32_t oat_data_offset = expected_offset = RoundUp(expected_offset, oat_data_alignment);
-  const OatHeader* oat_header = reinterpret_cast<OatHeader*>(&oat_contents[0]);
-  CHECK(oat_header->IsValid());
-  uint32_t oat_data_size = oat_header->GetExecutableOffset();
+  const OatHeader& oat_header = oat_writer.GetOatHeader();
+  CHECK(oat_header.IsValid());
+  uint32_t oat_data_size = oat_header.GetExecutableOffset();
   expected_offset += oat_data_size;
   if (debug) {
     LOG(INFO) << "oat_data_offset=" << oat_data_offset << std::hex << " " << oat_data_offset;
@@ -206,9 +208,9 @@
   uint32_t oat_exec_alignment = kPageSize;
   CHECK_ALIGNED(expected_offset, kPageSize);
   uint32_t oat_exec_offset = expected_offset = RoundUp(expected_offset, oat_exec_alignment);
-  uint32_t oat_exec_size = oat_contents.size() - oat_data_size;
+  uint32_t oat_exec_size = oat_writer.GetSize() - oat_data_size;
   expected_offset += oat_exec_size;
-  CHECK_EQ(oat_data_offset + oat_contents.size(), expected_offset);
+  CHECK_EQ(oat_data_offset + oat_writer.GetSize(), expected_offset);
   if (debug) {
     LOG(INFO) << "oat_exec_offset=" << oat_exec_offset << std::hex << " " << oat_exec_offset;
     LOG(INFO) << "oat_exec_size=" << oat_exec_size << std::hex << " " << oat_exec_size;
@@ -617,13 +619,14 @@
                 << " for " << elf_file_->GetPath();
     return false;
   }
-  if (!elf_file_->WriteFully(&oat_contents[0], oat_contents.size())) {
+  FileOutputStream output_stream(elf_file_);
+  if (!oat_writer.Write(output_stream)) {
     PLOG(ERROR) << "Failed to write .rodata and .text for " << elf_file_->GetPath();
     return false;
   }
 
   // .dynamic
-  DCHECK_LE(oat_data_offset + oat_contents.size(), dynamic_offset);
+  DCHECK_LE(oat_data_offset + oat_writer.GetSize(), dynamic_offset);
   if (static_cast<off_t>(dynamic_offset) != lseek(elf_file_->Fd(), dynamic_offset, SEEK_SET)) {
     PLOG(ERROR) << "Failed to seek to .dynamic offset " << dynamic_offset
                 << " for " << elf_file_->GetPath();
diff --git a/compiler/elf_writer_quick.h b/compiler/elf_writer_quick.h
index a15c239..f36d06f 100644
--- a/compiler/elf_writer_quick.h
+++ b/compiler/elf_writer_quick.h
@@ -25,7 +25,7 @@
  public:
   // Write an ELF file. Returns true on success, false on failure.
   static bool Create(File* file,
-                     std::vector<uint8_t>& oat_contents,
+                     OatWriter& oat_writer,
                      const std::vector<const DexFile*>& dex_files,
                      const std::string& android_root,
                      bool is_host,
@@ -33,7 +33,7 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
  protected:
-  virtual bool Write(std::vector<uint8_t>& oat_contents,
+  virtual bool Write(OatWriter& oat_writer,
                      const std::vector<const DexFile*>& dex_files,
                      const std::string& android_root,
                      bool is_host)
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index f395428..1612f7e 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -85,6 +85,10 @@
     return false;
   }
   oat_file_ = OatFile::OpenWritable(oat_file.get(), oat_location);
+  if (oat_file_ == NULL) {
+    LOG(ERROR) << "Failed to open writable oat file " << oat_filename << " for " << oat_location;
+    return false;
+  }
   class_linker->RegisterOatFile(*oat_file_);
   interpreter_to_interpreter_entry_offset_ = oat_file_->GetOatHeader().GetInterpreterToInterpreterEntryOffset();
   interpreter_to_quick_entry_offset_ = oat_file_->GetOatHeader().GetInterpreterToQuickEntryOffset();
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index da05c49..5eb837b 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -35,20 +35,6 @@
 
 namespace art {
 
-bool OatWriter::Create(OutputStream& output_stream,
-                       const std::vector<const DexFile*>& dex_files,
-                       uint32_t image_file_location_oat_checksum,
-                       uint32_t image_file_location_oat_begin,
-                       const std::string& image_file_location,
-                       const CompilerDriver& driver) {
-  OatWriter oat_writer(dex_files,
-                       image_file_location_oat_checksum,
-                       image_file_location_oat_begin,
-                       image_file_location,
-                       &driver);
-  return oat_writer.Write(output_stream);
-}
-
 OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files,
                      uint32_t image_file_location_oat_checksum,
                      uint32_t image_file_location_oat_begin,
@@ -89,6 +75,7 @@
   offset = InitOatClasses(offset);
   offset = InitOatCode(offset);
   offset = InitOatCodeDexFiles(offset);
+  size_ = offset;
 
   CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
   CHECK(image_file_location.empty() == compiler->IsImage());
@@ -190,7 +177,8 @@
   if (compiler_driver_->IsImage()) {
     InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
     oat_header_->SetInterpreterToInterpreterEntryOffset(offset);
-    interpreter_to_interpreter_entry_.reset(compiler_driver_->CreateInterpreterToInterpreterEntry());
+    interpreter_to_interpreter_entry_.reset(
+        compiler_driver_->CreateInterpreterToInterpreterEntry());
     offset += interpreter_to_interpreter_entry_->size();
 
     offset = CompiledCode::AlignCode(offset, instruction_set);
@@ -336,7 +324,8 @@
     mapping_table_offset = (mapping_table_size == 0) ? 0 : offset;
 
     // Deduplicate mapping tables
-    SafeMap<const std::vector<uint32_t>*, uint32_t>::iterator mapping_iter = mapping_table_offsets_.find(&mapping_table);
+    SafeMap<const std::vector<uint32_t>*, uint32_t>::iterator mapping_iter =
+        mapping_table_offsets_.find(&mapping_table);
     if (mapping_iter != mapping_table_offsets_.end()) {
       mapping_table_offset = mapping_iter->second;
     } else {
@@ -350,7 +339,8 @@
     vmap_table_offset = (vmap_table_size == 0) ? 0 : offset;
 
     // Deduplicate vmap tables
-    SafeMap<const std::vector<uint16_t>*, uint32_t>::iterator vmap_iter = vmap_table_offsets_.find(&vmap_table);
+    SafeMap<const std::vector<uint16_t>*, uint32_t>::iterator vmap_iter =
+        vmap_table_offsets_.find(&vmap_table);
     if (vmap_iter != vmap_table_offsets_.end()) {
       vmap_table_offset = vmap_iter->second;
     } else {
@@ -382,7 +372,8 @@
 #endif
 
     // Deduplicate GC maps
-    SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator gc_map_iter = gc_map_offsets_.find(&gc_map);
+    SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator gc_map_iter =
+        gc_map_offsets_.find(&gc_map);
     if (gc_map_iter != gc_map_offsets_.end()) {
       gc_map_offset = gc_map_iter->second;
     } else {
@@ -392,14 +383,14 @@
     }
   }
 
-  oat_class->method_offsets_[class_def_method_index]
-      = OatMethodOffsets(code_offset,
-                         frame_size_in_bytes,
-                         core_spill_mask,
-                         fp_spill_mask,
-                         mapping_table_offset,
-                         vmap_table_offset,
-                         gc_map_offset);
+  oat_class->method_offsets_[class_def_method_index] =
+      OatMethodOffsets(code_offset,
+                       frame_size_in_bytes,
+                       core_spill_mask,
+                       fp_spill_mask,
+                       mapping_table_offset,
+                       vmap_table_offset,
+                       gc_map_offset);
 
   if (compiler_driver_->IsImage()) {
     ClassLinker* linker = Runtime::Current()->GetClassLinker();
@@ -428,12 +419,16 @@
 }
 
 #define DCHECK_OFFSET() \
-  DCHECK_EQ(static_cast<off_t>(offset), out.Seek(0, kSeekCurrent))
+  DCHECK_EQ(static_cast<off_t>(file_offset + relative_offset), out.Seek(0, kSeekCurrent)) \
+    << "file_offset=" << file_offset << " relative_offset=" << relative_offset
 
 #define DCHECK_OFFSET_() \
-  DCHECK_EQ(static_cast<off_t>(offset_), out.Seek(0, kSeekCurrent))
+  DCHECK_EQ(static_cast<off_t>(file_offset + offset_), out.Seek(0, kSeekCurrent)) \
+    << "file_offset=" << file_offset << " offset_=" << offset_
 
 bool OatWriter::Write(OutputStream& out) {
+  const size_t file_offset = out.Seek(0, kSeekCurrent);
+
   if (!out.WriteFully(oat_header_, sizeof(*oat_header_))) {
     PLOG(ERROR) << "Failed to write oat header to " << out.GetLocation();
     return false;
@@ -446,19 +441,19 @@
   }
   size_oat_header_image_file_location_ += image_file_location_.size();
 
-  if (!WriteTables(out)) {
+  if (!WriteTables(out, file_offset)) {
     LOG(ERROR) << "Failed to write oat tables to " << out.GetLocation();
     return false;
   }
 
-  size_t code_offset = WriteCode(out);
-  if (code_offset == 0) {
+  size_t relative_offset = WriteCode(out, file_offset);
+  if (relative_offset == 0) {
     LOG(ERROR) << "Failed to write oat code to " << out.GetLocation();
     return false;
   }
 
-  code_offset = WriteCodeDexFiles(out, code_offset);
-  if (code_offset == 0) {
+  relative_offset = WriteCodeDexFiles(out, file_offset, relative_offset);
+  if (relative_offset == 0) {
     LOG(ERROR) << "Failed to write oat code for dex files to " << out.GetLocation();
     return false;
   }
@@ -495,21 +490,25 @@
     #undef DO_STAT
 
     LOG(INFO) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)"; \
-    CHECK_EQ(size_total, static_cast<uint32_t>(out.Seek(0, kSeekCurrent)));
+    CHECK_EQ(file_offset + size_total, static_cast<uint32_t>(out.Seek(0, kSeekCurrent)));
+    CHECK_EQ(size_, size_total);
   }
 
+  CHECK_EQ(file_offset + size_, static_cast<uint32_t>(out.Seek(0, kSeekCurrent)));
+  CHECK_EQ(size_, relative_offset);
+
   return true;
 }
 
-bool OatWriter::WriteTables(OutputStream& out) {
+bool OatWriter::WriteTables(OutputStream& out, const size_t file_offset) {
   for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
-    if (!oat_dex_files_[i]->Write(this, out)) {
+    if (!oat_dex_files_[i]->Write(this, out, file_offset)) {
       PLOG(ERROR) << "Failed to write oat dex information to " << out.GetLocation();
       return false;
     }
   }
   for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
-    uint32_t expected_offset = oat_dex_files_[i]->dex_file_offset_;
+    uint32_t expected_offset = file_offset + oat_dex_files_[i]->dex_file_offset_;
     off_t actual_offset = out.Seek(expected_offset, kSeekSet);
     if (static_cast<uint32_t>(actual_offset) != expected_offset) {
       const DexFile* dex_file = (*dex_files_)[i];
@@ -519,13 +518,14 @@
     }
     const DexFile* dex_file = (*dex_files_)[i];
     if (!out.WriteFully(&dex_file->GetHeader(), dex_file->GetHeader().file_size_)) {
-      PLOG(ERROR) << "Failed to write dex file " << dex_file->GetLocation() << " to " << out.GetLocation();
+      PLOG(ERROR) << "Failed to write dex file " << dex_file->GetLocation()
+                  << " to " << out.GetLocation();
       return false;
     }
     size_dex_file_ += dex_file->GetHeader().file_size_;
   }
   for (size_t i = 0; i != oat_classes_.size(); ++i) {
-    if (!oat_classes_[i]->Write(this, out)) {
+    if (!oat_classes_[i]->Write(this, out, file_offset)) {
       PLOG(ERROR) << "Failed to write oat methods information to " << out.GetLocation();
       return false;
     }
@@ -533,27 +533,29 @@
   return true;
 }
 
-size_t OatWriter::WriteCode(OutputStream& out) {
-  uint32_t offset = oat_header_->GetExecutableOffset();
+size_t OatWriter::WriteCode(OutputStream& out, const size_t file_offset) {
+  size_t relative_offset = oat_header_->GetExecutableOffset();
   off_t new_offset = out.Seek(size_executable_offset_alignment_, kSeekCurrent);
-  if (static_cast<uint32_t>(new_offset) != offset) {
+  size_t expected_file_offset = file_offset + relative_offset;
+  if (static_cast<uint32_t>(new_offset) != expected_file_offset) {
     PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
-                << " Expected: " << offset << " File: " << out.GetLocation();
+                << " Expected: " << expected_file_offset << " File: " << out.GetLocation();
     return 0;
   }
   DCHECK_OFFSET();
   if (compiler_driver_->IsImage()) {
     InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
-    if (!out.WriteFully(&(*interpreter_to_interpreter_entry_)[0], interpreter_to_interpreter_entry_->size())) {
+    if (!out.WriteFully(&(*interpreter_to_interpreter_entry_)[0],
+                        interpreter_to_interpreter_entry_->size())) {
       PLOG(ERROR) << "Failed to write interpreter to interpreter entry to " << out.GetLocation();
       return false;
     }
     size_interpreter_to_interpreter_entry_ += interpreter_to_interpreter_entry_->size();
-    offset += interpreter_to_interpreter_entry_->size();
+    relative_offset += interpreter_to_interpreter_entry_->size();
     DCHECK_OFFSET();
 
-    uint32_t aligned_offset = CompiledCode::AlignCode(offset, instruction_set);
-    uint32_t alignment_padding = aligned_offset - offset;
+    uint32_t aligned_offset = CompiledCode::AlignCode(relative_offset, instruction_set);
+    uint32_t alignment_padding = aligned_offset - relative_offset;
     out.Seek(alignment_padding, kSeekCurrent);
     size_stubs_alignment_ += alignment_padding;
     if (!out.WriteFully(&(*interpreter_to_quick_entry_)[0], interpreter_to_quick_entry_->size())) {
@@ -561,60 +563,67 @@
       return false;
     }
     size_interpreter_to_quick_entry_ += interpreter_to_quick_entry_->size();
-    offset += alignment_padding + interpreter_to_quick_entry_->size();
+    relative_offset += alignment_padding + interpreter_to_quick_entry_->size();
     DCHECK_OFFSET();
 
-    aligned_offset = CompiledCode::AlignCode(offset, instruction_set);
-    alignment_padding = aligned_offset - offset;
+    aligned_offset = CompiledCode::AlignCode(relative_offset, instruction_set);
+    alignment_padding = aligned_offset - relative_offset;
     out.Seek(alignment_padding, kSeekCurrent);
     size_stubs_alignment_ += alignment_padding;
-    if (!out.WriteFully(&(*portable_resolution_trampoline_)[0], portable_resolution_trampoline_->size())) {
+    if (!out.WriteFully(&(*portable_resolution_trampoline_)[0],
+                        portable_resolution_trampoline_->size())) {
       PLOG(ERROR) << "Failed to write portable resolution trampoline to " << out.GetLocation();
       return false;
     }
     size_portable_resolution_trampoline_ += portable_resolution_trampoline_->size();
-    offset += alignment_padding + portable_resolution_trampoline_->size();
+    relative_offset += alignment_padding + portable_resolution_trampoline_->size();
     DCHECK_OFFSET();
 
-    aligned_offset = CompiledCode::AlignCode(offset, instruction_set);
-    alignment_padding = aligned_offset - offset;
+    aligned_offset = CompiledCode::AlignCode(relative_offset, instruction_set);
+    alignment_padding = aligned_offset - relative_offset;
     out.Seek(alignment_padding, kSeekCurrent);
     size_stubs_alignment_ += alignment_padding;
-    if (!out.WriteFully(&(*quick_resolution_trampoline_)[0], quick_resolution_trampoline_->size())) {
+    if (!out.WriteFully(&(*quick_resolution_trampoline_)[0],
+                        quick_resolution_trampoline_->size())) {
       PLOG(ERROR) << "Failed to write quick resolution trampoline to " << out.GetLocation();
       return false;
     }
     size_quick_resolution_trampoline_ += quick_resolution_trampoline_->size();
-    offset += alignment_padding + quick_resolution_trampoline_->size();
+    relative_offset += alignment_padding + quick_resolution_trampoline_->size();
     DCHECK_OFFSET();
   }
-  return offset;
+  return relative_offset;
 }
 
-size_t OatWriter::WriteCodeDexFiles(OutputStream& out, size_t code_offset) {
+size_t OatWriter::WriteCodeDexFiles(OutputStream& out,
+                                    const size_t file_offset,
+                                    size_t relative_offset) {
   size_t oat_class_index = 0;
   for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
     const DexFile* dex_file = (*dex_files_)[i];
     CHECK(dex_file != NULL);
-    code_offset = WriteCodeDexFile(out, code_offset, oat_class_index, *dex_file);
-    if (code_offset == 0) {
+    relative_offset = WriteCodeDexFile(out, file_offset, relative_offset, oat_class_index,
+                                       *dex_file);
+    if (relative_offset == 0) {
       return 0;
     }
   }
-  return code_offset;
+  return relative_offset;
 }
 
-size_t OatWriter::WriteCodeDexFile(OutputStream& out, size_t code_offset, size_t& oat_class_index,
+size_t OatWriter::WriteCodeDexFile(OutputStream& out, const size_t file_offset,
+                                   size_t relative_offset, size_t& oat_class_index,
                                    const DexFile& dex_file) {
   for (size_t class_def_index = 0; class_def_index < dex_file.NumClassDefs();
       class_def_index++, oat_class_index++) {
     const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
-    code_offset = WriteCodeClassDef(out, code_offset, oat_class_index, dex_file, class_def);
-    if (code_offset == 0) {
+    relative_offset = WriteCodeClassDef(out, file_offset, relative_offset, oat_class_index,
+                                        dex_file, class_def);
+    if (relative_offset == 0) {
       return 0;
     }
   }
-  return code_offset;
+  return relative_offset;
 }
 
 void OatWriter::ReportWriteFailure(const char* what, uint32_t method_idx,
@@ -624,13 +633,15 @@
 }
 
 size_t OatWriter::WriteCodeClassDef(OutputStream& out,
-                                    size_t code_offset, size_t oat_class_index,
+                                    const size_t file_offset,
+                                    size_t relative_offset,
+                                    size_t oat_class_index,
                                     const DexFile& dex_file,
                                     const DexFile::ClassDef& class_def) {
   const byte* class_data = dex_file.GetClassData(class_def);
   if (class_data == NULL) {
     // ie. an empty class such as a marker interface
-    return code_offset;
+    return relative_offset;
   }
   ClassDataItemIterator it(dex_file, class_data);
   // Skip fields
@@ -644,27 +655,29 @@
   size_t class_def_method_index = 0;
   while (it.HasNextDirectMethod()) {
     bool is_static = (it.GetMemberAccessFlags() & kAccStatic) != 0;
-    code_offset = WriteCodeMethod(out, code_offset, oat_class_index, class_def_method_index,
-                                  is_static, it.GetMemberIndex(), dex_file);
-    if (code_offset == 0) {
+    relative_offset = WriteCodeMethod(out, file_offset, relative_offset, oat_class_index,
+                                      class_def_method_index, is_static, it.GetMemberIndex(),
+                                      dex_file);
+    if (relative_offset == 0) {
       return 0;
     }
     class_def_method_index++;
     it.Next();
   }
   while (it.HasNextVirtualMethod()) {
-    code_offset = WriteCodeMethod(out, code_offset, oat_class_index, class_def_method_index,
-                                  false, it.GetMemberIndex(), dex_file);
-    if (code_offset == 0) {
+    relative_offset = WriteCodeMethod(out, file_offset, relative_offset, oat_class_index,
+                                      class_def_method_index, false, it.GetMemberIndex(), dex_file);
+    if (relative_offset == 0) {
       return 0;
     }
     class_def_method_index++;
     it.Next();
   }
-  return code_offset;
+  return relative_offset;
 }
 
-size_t OatWriter::WriteCodeMethod(OutputStream& out, size_t offset, size_t oat_class_index,
+size_t OatWriter::WriteCodeMethod(OutputStream& out, const size_t file_offset,
+                                  size_t relative_offset, size_t oat_class_index,
                                   size_t class_def_method_index, bool is_static,
                                   uint32_t method_idx, const DexFile& dex_file) {
   const CompiledMethod* compiled_method =
@@ -676,26 +689,27 @@
 
   if (compiled_method != NULL) {  // ie. not an abstract method
 #if !defined(ART_USE_PORTABLE_COMPILER)
-    uint32_t aligned_offset = compiled_method->AlignCode(offset);
-    uint32_t aligned_code_delta = aligned_offset - offset;
+    uint32_t aligned_offset = compiled_method->AlignCode(relative_offset);
+    uint32_t aligned_code_delta = aligned_offset - relative_offset;
     if (aligned_code_delta != 0) {
       off_t new_offset = out.Seek(aligned_code_delta, kSeekCurrent);
       size_code_alignment_ += aligned_code_delta;
-      if (static_cast<uint32_t>(new_offset) != aligned_offset) {
+      uint32_t expected_offset = file_offset + aligned_offset;
+      if (static_cast<uint32_t>(new_offset) != expected_offset) {
         PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset
-                    << " Expected: " << aligned_offset << " File: " << out.GetLocation();
+                    << " Expected: " << expected_offset << " File: " << out.GetLocation();
         return 0;
       }
-      offset += aligned_code_delta;
+      relative_offset += aligned_code_delta;
       DCHECK_OFFSET();
     }
-    DCHECK_ALIGNED(offset, kArmAlignment);
+    DCHECK_ALIGNED(relative_offset, kArmAlignment);
     const std::vector<uint8_t>& code = compiled_method->GetCode();
     uint32_t code_size = code.size() * sizeof(code[0]);
     CHECK_NE(code_size, 0U);
 
     // Deduplicate code arrays
-    size_t code_offset = offset + sizeof(code_size) + compiled_method->CodeDelta();
+    size_t code_offset = relative_offset + sizeof(code_size) + compiled_method->CodeDelta();
     SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = code_offsets_.find(&code);
     if (code_iter != code_offsets_.end() && code_offset != method_offsets.code_offset_) {
       DCHECK(code_iter->second == method_offsets.code_offset_)
@@ -707,14 +721,14 @@
         return 0;
       }
       size_code_size_ += sizeof(code_size);
-      offset += sizeof(code_size);
+      relative_offset += sizeof(code_size);
       DCHECK_OFFSET();
       if (!out.WriteFully(&code[0], code_size)) {
         ReportWriteFailure("method code", method_idx, dex_file, out);
         return 0;
       }
       size_code_ += code_size;
-      offset += code_size;
+      relative_offset += code_size;
     }
     DCHECK_OFFSET();
 #endif
@@ -726,20 +740,20 @@
     SafeMap<const std::vector<uint32_t>*, uint32_t>::iterator mapping_iter =
         mapping_table_offsets_.find(&mapping_table);
     if (mapping_iter != mapping_table_offsets_.end() &&
-        offset != method_offsets.mapping_table_offset_) {
+        relative_offset != method_offsets.mapping_table_offset_) {
       DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0)
           || mapping_iter->second == method_offsets.mapping_table_offset_)
           << PrettyMethod(method_idx, dex_file);
     } else {
       DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0)
-          || offset == method_offsets.mapping_table_offset_)
+          || relative_offset == method_offsets.mapping_table_offset_)
           << PrettyMethod(method_idx, dex_file);
       if (!out.WriteFully(&mapping_table[0], mapping_table_size)) {
         ReportWriteFailure("mapping table", method_idx, dex_file, out);
         return 0;
       }
       size_mapping_table_ += mapping_table_size;
-      offset += mapping_table_size;
+      relative_offset += mapping_table_size;
     }
     DCHECK_OFFSET();
 
@@ -750,20 +764,20 @@
     SafeMap<const std::vector<uint16_t>*, uint32_t>::iterator vmap_iter =
         vmap_table_offsets_.find(&vmap_table);
     if (vmap_iter != vmap_table_offsets_.end() &&
-        offset != method_offsets.vmap_table_offset_) {
+        relative_offset != method_offsets.vmap_table_offset_) {
       DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0)
           || vmap_iter->second == method_offsets.vmap_table_offset_)
           << PrettyMethod(method_idx, dex_file);
     } else {
       DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0)
-          || offset == method_offsets.vmap_table_offset_)
+          || relative_offset == method_offsets.vmap_table_offset_)
           << PrettyMethod(method_idx, dex_file);
       if (!out.WriteFully(&vmap_table[0], vmap_table_size)) {
         ReportWriteFailure("vmap table", method_idx, dex_file, out);
         return 0;
       }
       size_vmap_table_ += vmap_table_size;
-      offset += vmap_table_size;
+      relative_offset += vmap_table_size;
     }
     DCHECK_OFFSET();
 
@@ -774,25 +788,25 @@
     SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator gc_map_iter =
         gc_map_offsets_.find(&gc_map);
     if (gc_map_iter != gc_map_offsets_.end() &&
-        offset != method_offsets.gc_map_offset_) {
+        relative_offset != method_offsets.gc_map_offset_) {
       DCHECK((gc_map_size == 0 && method_offsets.gc_map_offset_ == 0)
           || gc_map_iter->second == method_offsets.gc_map_offset_)
           << PrettyMethod(method_idx, dex_file);
     } else {
       DCHECK((gc_map_size == 0 && method_offsets.gc_map_offset_ == 0)
-          || offset == method_offsets.gc_map_offset_)
+          || relative_offset == method_offsets.gc_map_offset_)
           << PrettyMethod(method_idx, dex_file);
       if (!out.WriteFully(&gc_map[0], gc_map_size)) {
         ReportWriteFailure("GC map", method_idx, dex_file, out);
         return 0;
       }
       size_gc_map_ += gc_map_size;
-      offset += gc_map_size;
+      relative_offset += gc_map_size;
     }
     DCHECK_OFFSET();
   }
 
-  return offset;
+  return relative_offset;
 }
 
 OatWriter::OatDexFile::OatDexFile(size_t offset, const DexFile& dex_file) {
@@ -822,7 +836,9 @@
                             sizeof(methods_offsets_[0]) * methods_offsets_.size());
 }
 
-bool OatWriter::OatDexFile::Write(OatWriter* oat_writer, OutputStream& out) const {
+bool OatWriter::OatDexFile::Write(OatWriter* oat_writer,
+                                  OutputStream& out,
+                                  const size_t file_offset) const {
   DCHECK_OFFSET_();
   if (!out.WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
     PLOG(ERROR) << "Failed to write dex file location length to " << out.GetLocation();
@@ -881,14 +897,16 @@
                             sizeof(method_offsets_[0]) * method_offsets_.size());
 }
 
-bool OatWriter::OatClass::Write(OatWriter* oat_writer, OutputStream& out) const {
+bool OatWriter::OatClass::Write(OatWriter* oat_writer,
+                                OutputStream& out,
+                                const size_t file_offset) const {
   DCHECK_OFFSET_();
   if (!out.WriteFully(&status_, sizeof(status_))) {
     PLOG(ERROR) << "Failed to write class status to " << out.GetLocation();
     return false;
   }
   oat_writer->size_oat_class_status_ += sizeof(status_);
-  DCHECK_EQ(static_cast<off_t>(GetOatMethodOffsetsOffsetFromOatHeader(0)),
+  DCHECK_EQ(static_cast<off_t>(file_offset + GetOatMethodOffsetsOffsetFromOatHeader(0)),
             out.Seek(0, kSeekCurrent));
   if (!out.WriteFully(&method_offsets_[0],
                       sizeof(method_offsets_[0]) * method_offsets_.size())) {
@@ -896,7 +914,8 @@
     return false;
   }
   oat_writer->size_oat_class_method_offsets_ += sizeof(method_offsets_[0]) * method_offsets_.size();
-  DCHECK_EQ(static_cast<off_t>(GetOatMethodOffsetsOffsetFromOatHeader(method_offsets_.size())),
+  DCHECK_EQ(static_cast<off_t>(file_offset +
+                               GetOatMethodOffsetsOffsetFromOatHeader(method_offsets_.size())),
             out.Seek(0, kSeekCurrent));
   return true;
 }
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index ea7156e..f2c5626 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -62,23 +62,25 @@
 //
 class OatWriter {
  public:
-  // Write an oat file. Returns true on success, false on failure.
-  static bool Create(OutputStream& out,
-                     const std::vector<const DexFile*>& dex_files,
-                     uint32_t image_file_location_oat_checksum,
-                     uint32_t image_file_location_oat_begin,
-                     const std::string& image_file_location,
-                     const CompilerDriver& compiler)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
- private:
   OatWriter(const std::vector<const DexFile*>& dex_files,
             uint32_t image_file_location_oat_checksum,
             uint32_t image_file_location_oat_begin,
             const std::string& image_file_location,
             const CompilerDriver* compiler) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  const OatHeader& GetOatHeader() const {
+    return *oat_header_;
+  }
+
+  size_t GetSize() const {
+    return size_;
+  }
+
+  bool Write(OutputStream& out);
+
   ~OatWriter();
 
+ private:
   size_t InitOatHeader();
   size_t InitOatDexFiles(size_t offset);
   size_t InitDexFiles(size_t offset);
@@ -101,17 +103,17 @@
                            uint32_t method_idx, const DexFile*)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool Write(OutputStream& out);
-  bool WriteTables(OutputStream& out);
-  size_t WriteCode(OutputStream& out);
-  size_t WriteCodeDexFiles(OutputStream& out, size_t offset);
-  size_t WriteCodeDexFile(OutputStream& out, size_t offset, size_t& oat_class_index,
-                          const DexFile& dex_file);
-  size_t WriteCodeClassDef(OutputStream& out, size_t offset, size_t oat_class_index,
-                           const DexFile& dex_file, const DexFile::ClassDef& class_def);
-  size_t WriteCodeMethod(OutputStream& out, size_t offset, size_t oat_class_index,
-                         size_t class_def_method_index, bool is_static, uint32_t method_idx,
-                         const DexFile& dex_file);
+  bool WriteTables(OutputStream& out, const size_t file_offset);
+  size_t WriteCode(OutputStream& out, const size_t file_offset);
+  size_t WriteCodeDexFiles(OutputStream& out, const size_t file_offset, size_t relative_offset);
+  size_t WriteCodeDexFile(OutputStream& out, const size_t file_offset, size_t relative_offset,
+                          size_t& oat_class_index, const DexFile& dex_file);
+  size_t WriteCodeClassDef(OutputStream& out, const size_t file_offset, size_t relative_offset,
+                           size_t oat_class_index, const DexFile& dex_file,
+                           const DexFile::ClassDef& class_def);
+  size_t WriteCodeMethod(OutputStream& out, const size_t file_offset, size_t relative_offset,
+                         size_t oat_class_index, size_t class_def_method_index, bool is_static,
+                         uint32_t method_idx, const DexFile& dex_file);
 
   void ReportWriteFailure(const char* what, uint32_t method_idx, const DexFile& dex_file,
                           OutputStream& out) const;
@@ -121,7 +123,7 @@
     explicit OatDexFile(size_t offset, const DexFile& dex_file);
     size_t SizeOf() const;
     void UpdateChecksum(OatHeader& oat_header) const;
-    bool Write(OatWriter* oat_writer, OutputStream& out) const;
+    bool Write(OatWriter* oat_writer, OutputStream& out, const size_t file_offset) const;
 
     // Offset of start of OatDexFile from beginning of OatHeader. It is
     // used to validate file position when writing.
@@ -145,7 +147,7 @@
     size_t GetOatMethodOffsetsOffsetFromOatClass(size_t class_def_method_index_) const;
     size_t SizeOf() const;
     void UpdateChecksum(OatHeader& oat_header) const;
-    bool Write(OatWriter* oat_writer, OutputStream& out) const;
+    bool Write(OatWriter* oat_writer, OutputStream& out, const size_t file_offset) const;
 
     // Offset of start of OatClass from beginning of OatHeader. It is
     // used to validate file position when writing. For Portable, it
@@ -167,6 +169,9 @@
   // note OatFile does not take ownership of the DexFiles
   const std::vector<const DexFile*>* dex_files_;
 
+  // Size required for Oat data structures.
+  size_t size_;
+
   // dependencies on the image.
   uint32_t image_file_location_oat_checksum_;
   uint32_t image_file_location_oat_begin_;