Created compiled stubs in image.

Saves class linker from having to set code pointers when loading
from an image. Added stubs for quick and portable resolution
trampolines, and interpreter-to-interpreter and interpreter-to-quick
entry points. Also added sizing stats output for oat writer.

Change-Id: I3905fae81047742c23d1cf0ca001db798db971b1
diff --git a/src/oat_writer.cc b/src/oat_writer.cc
index 8acbfe9..a4bd87d 100644
--- a/src/oat_writer.cc
+++ b/src/oat_writer.cc
@@ -54,13 +54,35 @@
                      uint32_t image_file_location_oat_begin,
                      const std::string& image_file_location,
                      const CompilerDriver* compiler)
-    : compiler_driver_(compiler) {
-  image_file_location_oat_checksum_ = image_file_location_oat_checksum;
-  image_file_location_oat_begin_ = image_file_location_oat_begin;
-  image_file_location_ = image_file_location;
-  dex_files_ = &dex_files;
-  oat_header_ = NULL;
-  executable_offset_padding_length_ = 0;
+  : compiler_driver_(compiler),
+    dex_files_(&dex_files),
+    image_file_location_oat_checksum_(image_file_location_oat_checksum),
+    image_file_location_oat_begin_(image_file_location_oat_begin),
+    image_file_location_(image_file_location),
+    oat_header_(NULL),
+    size_dex_file_alignment_(0),
+    size_executable_offset_alignment_(0),
+    size_oat_header_(0),
+    size_oat_header_image_file_location_(0),
+    size_dex_file_(0),
+    size_interpreter_to_interpreter_entry_(0),
+    size_interpreter_to_quick_entry_(0),
+    size_portable_resolution_trampoline_(0),
+    size_quick_resolution_trampoline_(0),
+    size_stubs_alignment_(0),
+    size_code_size_(0),
+    size_code_(0),
+    size_code_alignment_(0),
+    size_mapping_table_(0),
+    size_vmap_table_(0),
+    size_gc_map_(0),
+    size_oat_dex_file_location_size_(0),
+    size_oat_dex_file_location_data_(0),
+    size_oat_dex_file_location_checksum_(0),
+    size_oat_dex_file_offset_(0),
+    size_oat_dex_file_methods_offsets_(0),
+    size_oat_class_status_(0),
+    size_oat_class_method_offsets_(0) {
 
   size_t offset = InitOatHeader();
   offset = InitOatDexFiles(offset);
@@ -70,6 +92,7 @@
   offset = InitOatCodeDexFiles(offset);
 
   CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
+  CHECK(image_file_location.empty() == compiler->IsImage());
 }
 
 OatWriter::~OatWriter() {
@@ -106,7 +129,9 @@
   // calculate the offsets within OatDexFiles to the DexFiles
   for (size_t i = 0; i != dex_files_->size(); ++i) {
     // dex files are required to be 4 byte aligned
+    size_t original_offset = offset;
     offset = RoundUp(offset, 4);
+    size_dex_file_alignment_ += offset - original_offset;
 
     // set offset in OatDexFile to DexFile
     oat_dex_files_[i]->dex_file_offset_ = offset;
@@ -162,7 +187,33 @@
   // required to be on a new page boundary
   offset = RoundUp(offset, kPageSize);
   oat_header_->SetExecutableOffset(offset);
-  executable_offset_padding_length_ = offset - old_offset;
+  size_executable_offset_alignment_ = offset - old_offset;
+  if (compiler_driver_->IsImage()) {
+    InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
+    oat_header_->SetInterpreterToInterpreterEntryOffset(offset);
+    interpreter_to_interpreter_entry_.reset(compiler_driver_->CreateInterpreterToInterpreterEntry());
+    offset += interpreter_to_interpreter_entry_->size();
+
+    offset = CompiledCode::AlignCode(offset, instruction_set);
+    oat_header_->SetInterpreterToQuickEntryOffset(offset);
+    interpreter_to_quick_entry_.reset(compiler_driver_->CreateInterpreterToQuickEntry());
+    offset += interpreter_to_quick_entry_->size();
+
+    offset = CompiledCode::AlignCode(offset, instruction_set);
+    oat_header_->SetPortableResolutionTrampolineOffset(offset);
+    portable_resolution_trampoline_.reset(compiler_driver_->CreatePortableResolutionTrampoline());
+    offset += portable_resolution_trampoline_->size();
+
+    offset = CompiledCode::AlignCode(offset, instruction_set);
+    oat_header_->SetQuickResolutionTrampolineOffset(offset);
+    quick_resolution_trampoline_.reset(compiler_driver_->CreateQuickResolutionTrampoline());
+    offset += quick_resolution_trampoline_->size();
+  } else {
+    oat_header_->SetInterpreterToInterpreterEntryOffset(0);
+    oat_header_->SetInterpreterToQuickEntryOffset(0);
+    oat_header_->SetPortableResolutionTrampolineOffset(0);
+    oat_header_->SetQuickResolutionTrampolineOffset(0);
+  }
   return offset;
 }
 
@@ -389,11 +440,13 @@
     PLOG(ERROR) << "Failed to write oat header to " << out.GetLocation();
     return false;
   }
+  size_oat_header_ += sizeof(*oat_header_);
 
   if (!out.WriteFully(image_file_location_.data(), image_file_location_.size())) {
     PLOG(ERROR) << "Failed to write oat header image file location to " << out.GetLocation();
     return false;
   }
+  size_oat_header_image_file_location_ += image_file_location_.size();
 
   if (!WriteTables(out)) {
     LOG(ERROR) << "Failed to write oat tables to " << out.GetLocation();
@@ -412,12 +465,64 @@
     return false;
   }
 
+  LOG(INFO) << "size_dex_file_alignment_=" << size_dex_file_alignment_;
+  LOG(INFO) << "size_executable_offset_alignment_=" << size_executable_offset_alignment_;
+  LOG(INFO) << "size_oat_header_=" << size_oat_header_;
+  LOG(INFO) << "size_oat_header_image_file_location_=" << size_oat_header_image_file_location_;
+  LOG(INFO) << "size_dex_file_=" << size_dex_file_;
+  LOG(INFO) << "size_interpreter_to_interpreter_entry_=" << size_interpreter_to_interpreter_entry_;
+  LOG(INFO) << "size_interpreter_to_quick_entry_=" << size_interpreter_to_quick_entry_;
+  LOG(INFO) << "size_portable_resolution_trampoline_=" << size_portable_resolution_trampoline_;
+  LOG(INFO) << "size_quick_resolution_trampoline_=" << size_quick_resolution_trampoline_;
+  LOG(INFO) << "size_stubs_alignment_=" << size_stubs_alignment_;
+  LOG(INFO) << "size_code_size_=" << size_code_size_;
+  LOG(INFO) << "size_code_=" << size_code_;
+  LOG(INFO) << "size_code_alignment_=" << size_code_alignment_;
+  LOG(INFO) << "size_mapping_table_=" << size_mapping_table_;
+  LOG(INFO) << "size_vmap_table_=" << size_vmap_table_;
+  LOG(INFO) << "size_gc_map_=" << size_gc_map_;
+  LOG(INFO) << "size_oat_dex_file_location_size_=" << size_oat_dex_file_location_size_;
+  LOG(INFO) << "size_oat_dex_file_location_data=" << size_oat_dex_file_location_data_;
+  LOG(INFO) << "size_oat_dex_file_location_checksum_=" << size_oat_dex_file_location_checksum_;
+  LOG(INFO) << "size_oat_dex_file_offset_=" << size_oat_dex_file_offset_;
+  LOG(INFO) << "size_oat_dex_file_methods_offsets_=" << size_oat_dex_file_methods_offsets_;
+  LOG(INFO) << "size_oat_class_status_=" << size_oat_class_status_;
+  LOG(INFO) << "size_oat_class_method_offsets=" << size_oat_class_method_offsets_;
+
+  uint32_t size_total =
+      size_dex_file_alignment_ +
+      size_executable_offset_alignment_ +
+      size_oat_header_ +
+      size_oat_header_image_file_location_ +
+      size_dex_file_ +
+      size_interpreter_to_interpreter_entry_ +
+      size_interpreter_to_quick_entry_ +
+      size_portable_resolution_trampoline_ +
+      size_quick_resolution_trampoline_ +
+      size_stubs_alignment_ +
+      size_code_size_ +
+      size_code_ +
+      size_code_alignment_ +
+      size_mapping_table_ +
+      size_vmap_table_ +
+      size_gc_map_ +
+      size_oat_dex_file_location_size_ +
+      size_oat_dex_file_location_data_ +
+      size_oat_dex_file_location_checksum_ +
+      size_oat_dex_file_offset_ +
+      size_oat_dex_file_methods_offsets_ +
+      size_oat_class_status_ +
+      size_oat_class_method_offsets_;
+
+  LOG(INFO) << "size_total=" << size_total;
+  DCHECK_EQ(size_total, static_cast<uint32_t>(out.Seek(0, kSeekCurrent)));
+
   return true;
 }
 
 bool OatWriter::WriteTables(OutputStream& out) {
   for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
-    if (!oat_dex_files_[i]->Write(out)) {
+    if (!oat_dex_files_[i]->Write(this, out)) {
       PLOG(ERROR) << "Failed to write oat dex information to " << out.GetLocation();
       return false;
     }
@@ -436,9 +541,10 @@
       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(out)) {
+    if (!oat_classes_[i]->Write(this, out)) {
       PLOG(ERROR) << "Failed to write oat methods information to " << out.GetLocation();
       return false;
     }
@@ -448,13 +554,59 @@
 
 size_t OatWriter::WriteCode(OutputStream& out) {
   uint32_t offset = oat_header_->GetExecutableOffset();
-  off_t new_offset = out.Seek(executable_offset_padding_length_, kSeekCurrent);
+  off_t new_offset = out.Seek(size_executable_offset_alignment_, kSeekCurrent);
   if (static_cast<uint32_t>(new_offset) != offset) {
     PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
                 << " Expected: " << 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())) {
+      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();
+    DCHECK_OFFSET();
+
+    uint32_t aligned_offset = CompiledCode::AlignCode(offset, instruction_set);
+    uint32_t alignment_padding = aligned_offset - offset;
+    out.Seek(alignment_padding, kSeekCurrent);
+    size_stubs_alignment_ += alignment_padding;
+    if (!out.WriteFully(&(*interpreter_to_quick_entry_)[0], interpreter_to_quick_entry_->size())) {
+      PLOG(ERROR) << "Failed to write interpreter to quick entry to " << out.GetLocation();
+      return false;
+    }
+    size_interpreter_to_quick_entry_ += interpreter_to_quick_entry_->size();
+    offset += alignment_padding + interpreter_to_quick_entry_->size();
+    DCHECK_OFFSET();
+
+    aligned_offset = CompiledCode::AlignCode(offset, instruction_set);
+    alignment_padding = aligned_offset - offset;
+    out.Seek(alignment_padding, kSeekCurrent);
+    size_stubs_alignment_ += alignment_padding;
+    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();
+    DCHECK_OFFSET();
+
+    aligned_offset = CompiledCode::AlignCode(offset, instruction_set);
+    alignment_padding = aligned_offset - offset;
+    out.Seek(alignment_padding, kSeekCurrent);
+    size_stubs_alignment_ += alignment_padding;
+    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();
+    DCHECK_OFFSET();
+  }
   return offset;
 }
 
@@ -547,6 +699,7 @@
     uint32_t aligned_code_delta = aligned_offset - 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) {
         PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset
                     << " Expected: " << aligned_offset << " File: " << out.GetLocation();
@@ -572,12 +725,14 @@
         ReportWriteFailure("method code size", method_idx, dex_file, out);
         return 0;
       }
+      size_code_size_ += sizeof(code_size);
       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;
     }
     DCHECK_OFFSET();
@@ -602,6 +757,7 @@
         ReportWriteFailure("mapping table", method_idx, dex_file, out);
         return 0;
       }
+      size_mapping_table_ += mapping_table_size;
       offset += mapping_table_size;
     }
     DCHECK_OFFSET();
@@ -625,6 +781,7 @@
         ReportWriteFailure("vmap table", method_idx, dex_file, out);
         return 0;
       }
+      size_vmap_table_ += vmap_table_size;
       offset += vmap_table_size;
     }
     DCHECK_OFFSET();
@@ -648,6 +805,7 @@
         ReportWriteFailure("GC map", method_idx, dex_file, out);
         return 0;
       }
+      size_gc_map_ += gc_map_size;
       offset += gc_map_size;
     }
     DCHECK_OFFSET();
@@ -683,29 +841,35 @@
                             sizeof(methods_offsets_[0]) * methods_offsets_.size());
 }
 
-bool OatWriter::OatDexFile::Write(OutputStream& out) const {
+bool OatWriter::OatDexFile::Write(OatWriter* oat_writer, OutputStream& out) 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();
     return false;
   }
+  oat_writer->size_oat_dex_file_location_size_ += sizeof(dex_file_location_size_);
   if (!out.WriteFully(dex_file_location_data_, dex_file_location_size_)) {
     PLOG(ERROR) << "Failed to write dex file location data to " << out.GetLocation();
     return false;
   }
+  oat_writer->size_oat_dex_file_location_data_ += dex_file_location_size_;
   if (!out.WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) {
     PLOG(ERROR) << "Failed to write dex file location checksum to " << out.GetLocation();
     return false;
   }
+  oat_writer->size_oat_dex_file_location_checksum_ += sizeof(dex_file_location_checksum_);
   if (!out.WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
     PLOG(ERROR) << "Failed to write dex file offset to " << out.GetLocation();
     return false;
   }
+  oat_writer->size_oat_dex_file_offset_ += sizeof(dex_file_offset_);
   if (!out.WriteFully(&methods_offsets_[0],
                       sizeof(methods_offsets_[0]) * methods_offsets_.size())) {
     PLOG(ERROR) << "Failed to write methods offsets to " << out.GetLocation();
     return false;
   }
+  oat_writer->size_oat_dex_file_methods_offsets_ +=
+      sizeof(methods_offsets_[0]) * methods_offsets_.size();
   return true;
 }
 
@@ -736,12 +900,13 @@
                             sizeof(method_offsets_[0]) * method_offsets_.size());
 }
 
-bool OatWriter::OatClass::Write(OutputStream& out) const {
+bool OatWriter::OatClass::Write(OatWriter* oat_writer, OutputStream& out) 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)),
             out.Seek(0, kSeekCurrent));
   if (!out.WriteFully(&method_offsets_[0],
@@ -749,6 +914,7 @@
     PLOG(ERROR) << "Failed to write method offsets to " << out.GetLocation();
     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())),
             out.Seek(0, kSeekCurrent));
   return true;