Move rest of code related blobs from Method to oat

Change-Id: I55041b564ab65317c8b1f863005f20ba650a0322
diff --git a/src/oat_writer.cc b/src/oat_writer.cc
index b8232d9..0722520 100644
--- a/src/oat_writer.cc
+++ b/src/oat_writer.cc
@@ -10,13 +10,18 @@
 
 namespace art {
 
-bool OatWriter::Create(const std::string& filename, const ClassLoader* class_loader) {
+bool OatWriter::Create(const std::string& filename,
+                       const ClassLoader* class_loader,
+                       const Compiler& compiler) {
   const std::vector<const DexFile*>& dex_files = ClassLoader::GetClassPath(class_loader);
-  OatWriter oat_writer(dex_files, class_loader);
+  OatWriter oat_writer(dex_files, class_loader, compiler);
   return oat_writer.Write(filename);
 }
 
-OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files, const ClassLoader* class_loader) {
+OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files,
+                     const ClassLoader* class_loader,
+                     const Compiler& compiler) {
+  compiler_ = &compiler;
   class_loader_ = class_loader;
   dex_files_ = &dex_files;
 
@@ -141,7 +146,6 @@
   CHECK_EQ(klass->GetClassLoader(), class_loader_);
   CHECK_EQ(oat_methods_[oat_class_index]->method_offsets_.size(),
            klass->NumDirectMethods() + num_virtual_methods);
-  // Note that we leave the offset to the code in Method::code_
   size_t class_def_method_index = 0;
   for (size_t i = 0; i < klass->NumDirectMethods(); i++, class_def_method_index++) {
     Method* method = klass->GetDirectMethod(i);
@@ -161,27 +165,99 @@
                                     size_t oat_class_index,
                                     size_t class_def_method_index,
                                     Method* method) {
-  Runtime* runtime = Runtime::Current();
-  ByteArray* jni_stub_array = runtime->GetJniStubArray();
-  ByteArray* ame_stub_array = runtime->GetAbstractMethodErrorStubArray();
+  // derived from CompiledMethod if available
+  uint32_t code_offset = 0;
+  uint32_t frame_size_in_bytes = kStackAlignment;
+  uint32_t return_pc_offset_in_bytes = 0;
+  uint32_t core_spill_mask = 0;
+  uint32_t fp_spill_mask = 0;
+  uint32_t mapping_table_offset = 0;
+  uint32_t vmap_table_offset = 0;
+  // derived from CompiledInvokeStub if available
+  uint32_t invoke_stub_offset = 0;
 
-  const ByteArray* code_array = method->GetCodeArray();
-  if (code_array == NULL || code_array == jni_stub_array || code_array == ame_stub_array) {
-    oat_methods_[oat_class_index]->method_offsets_[class_def_method_index] = 0;
-    method->SetOatCodeOffset(0);
-  } else {
-    offset = RoundUp(offset, kArmAlignment);
-    uint32_t thumb_offset = (reinterpret_cast<const int8_t*>(method->GetCode())
-                             - code_array->GetData());
-    uint32_t code_offset = offset + thumb_offset;
-    oat_methods_[oat_class_index]->method_offsets_[class_def_method_index] = code_offset;
-    method->SetOatCodeOffset(code_offset);
-    offset += code_array->GetLength();
-    oat_header_->UpdateChecksum(code_array->GetData(), code_array->GetLength());
+  const CompiledMethod* compiled_method = compiler_->GetCompiledMethod(method);
+  if (compiled_method != NULL) {
+
+    offset = compiled_method->AlignCode(offset);
+    DCHECK(IsAligned(offset, kArmAlignment)) << std::hex << offset;
+    const std::vector<uint8_t>& code = compiled_method->GetCode();
+    size_t code_size = code.size() * sizeof(code[0]);
+    uint32_t thumb_offset = compiled_method->CodeDelta();
+    code_offset = (code_size == 0) ? 0 : offset + thumb_offset;
+    offset += code_size;
+    oat_header_->UpdateChecksum(&code[0], code_size);
+
+    frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
+    return_pc_offset_in_bytes = compiled_method->GetReturnPcOffsetInBytes();
+    core_spill_mask = compiled_method->GetCoreSpillMask();
+    fp_spill_mask = compiled_method->GetFpSpillMask();
   }
+
+  offset += sizeof(frame_size_in_bytes);
+  oat_header_->UpdateChecksum(&frame_size_in_bytes, sizeof(frame_size_in_bytes));
+
+  offset += sizeof(return_pc_offset_in_bytes);
+  oat_header_->UpdateChecksum(&return_pc_offset_in_bytes, sizeof(return_pc_offset_in_bytes));
+
+  offset += sizeof(core_spill_mask);
+  oat_header_->UpdateChecksum(&core_spill_mask, sizeof(core_spill_mask));
+
+  offset += sizeof(fp_spill_mask);
+  oat_header_->UpdateChecksum(&fp_spill_mask, sizeof(fp_spill_mask));
+
+  if (compiled_method != NULL) {
+
+    const std::vector<uint32_t>& mapping_table = compiled_method->GetMappingTable();
+    size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]);
+    mapping_table_offset = (mapping_table_size == 0) ? 0 : offset;
+    offset += mapping_table_size;
+    oat_header_->UpdateChecksum(&mapping_table[0], mapping_table_size);
+
+    const std::vector<uint16_t>& vmap_table = compiled_method->GetVmapTable();
+    size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]);
+    vmap_table_offset = (vmap_table_size == 0) ? 0 : offset;
+    offset += vmap_table_size;
+    oat_header_->UpdateChecksum(&vmap_table[0], vmap_table_size);
+  }
+
+  const CompiledInvokeStub* compiled_invoke_stub = compiler_->GetCompiledInvokeStub(method);
+  if (compiled_invoke_stub != NULL) {
+    offset = CompiledMethod::AlignCode(offset, compiler_->GetInstructionSet());
+    DCHECK(IsAligned(offset, kArmAlignment)) << std::hex << offset;
+    const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode();
+    size_t invoke_stub_size = invoke_stub.size() * sizeof(invoke_stub[0]);
+    invoke_stub_offset = (invoke_stub_size == 0) ? 0 : offset;
+    offset += invoke_stub_size;
+    oat_header_->UpdateChecksum(&invoke_stub[0], invoke_stub_size);
+  }
+
+  oat_methods_[oat_class_index]->method_offsets_[class_def_method_index]
+      = OatMethodOffsets(code_offset,
+                         frame_size_in_bytes,
+                         return_pc_offset_in_bytes,
+                         core_spill_mask,
+                         fp_spill_mask,
+                         mapping_table_offset,
+                         vmap_table_offset,
+                         invoke_stub_offset);
+
+  // Note that we leave the offset and values back in the Method where ImageWriter will find them
+  method->SetOatCodeOffset(code_offset);
+  method->SetFrameSizeInBytes(frame_size_in_bytes);
+  method->SetReturnPcOffsetInBytes(return_pc_offset_in_bytes);
+  method->SetCoreSpillMask(core_spill_mask);
+  method->SetFpSpillMask(fp_spill_mask);
+  method->SetOatMappingTableOffset(mapping_table_offset);
+  method->SetOatVmapTableOffset(vmap_table_offset);
+  method->SetOatInvokeStubOffset(invoke_stub_offset);
+
   return offset;
 }
 
+#define DCHECK_CODE_OFFSET() \
+  DCHECK_EQ(static_cast<off_t>(code_offset), lseek(file->Fd(), 0, SEEK_CUR))
+
 bool OatWriter::Write(const std::string& filename) {
 
   UniquePtr<File> file(OS::OpenFile(filename.c_str(), true));
@@ -240,9 +316,11 @@
   uint32_t code_offset = oat_header_->GetExecutableOffset();
   off_t new_offset = lseek(file->Fd(), executable_offset_padding_length_, SEEK_CUR);
   if (static_cast<uint32_t>(new_offset) != code_offset) {
-    PLOG(ERROR) << "Failed to seek to oat code section";
+    PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
+                << " Expected: " << code_offset;
     return 0;
   }
+  DCHECK_CODE_OFFSET();
   return code_offset;
 }
 
@@ -277,14 +355,11 @@
                                     size_t code_offset,
                                     const DexFile& dex_file,
                                     const DexFile::ClassDef& class_def) {
-  const Runtime* runtime = Runtime::Current();
-  ClassLinker* class_linker = runtime->GetClassLinker();
-  ByteArray* ame_stub_array = runtime->GetAbstractMethodErrorStubArray();
-
   const byte* class_data = dex_file.GetClassData(class_def);
   DexFile::ClassDataHeader header = dex_file.ReadClassDataHeader(&class_data);
   size_t num_virtual_methods = header.virtual_methods_size_;
   const char* descriptor = dex_file.GetClassDescriptor(class_def);
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   Class* klass = class_linker->FindClass(descriptor, class_loader_);
 
   // TODO: deduplicate code arrays
@@ -306,11 +381,7 @@
   }
   for (size_t i = num_virtual_methods; i < klass->NumVirtualMethods(); i++) {
     Method* method = klass->GetVirtualMethod(i);
-    const ByteArray* code_array = method->GetCodeArray();
-    CHECK(code_array == NULL  // if compiler not run
-          || code_array == ame_stub_array)  // otherwise
-            << PrettyMethod(method) << " " << code_array;
-    method->SetCodeArray(NULL, kNone);
+    CHECK(compiler_->GetCompiledMethod(method) == NULL) << PrettyMethod(method);
   }
   return code_offset;
 }
@@ -318,32 +389,110 @@
 size_t OatWriter::WriteCodeMethod(File* file,
                                   size_t code_offset,
                                   Method* method) {
-  const Runtime* runtime = Runtime::Current();
-  ByteArray* jni_stub_array = runtime->GetJniStubArray();
-  ByteArray* ame_stub_array = runtime->GetAbstractMethodErrorStubArray();
-
-  const ByteArray* code_array = method->GetCodeArray();
-  if (code_array != NULL && code_array != jni_stub_array && code_array != ame_stub_array) {
-    uint32_t aligned_code_offset = RoundUp(code_offset, kArmAlignment);
+  const CompiledMethod* compiled_method = compiler_->GetCompiledMethod(method);
+  if (compiled_method != NULL) {
+    uint32_t aligned_code_offset = compiled_method->AlignCode(code_offset);
     uint32_t aligned_code_delta = aligned_code_offset - code_offset;
     if (aligned_code_delta != 0) {
       off_t new_offset = lseek(file->Fd(), aligned_code_delta, SEEK_CUR);
       if (static_cast<uint32_t>(new_offset) != aligned_code_offset) {
-        PLOG(ERROR) << "Failed to seek to align oat code";
+        PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset
+                    << " Expected: " << aligned_code_offset;
         return false;
       }
       code_offset += aligned_code_delta;
+      DCHECK_CODE_OFFSET();
     }
-    if (!file->WriteFully(code_array->GetData(), code_array->GetLength())) {
+    DCHECK(IsAligned(code_offset, kArmAlignment)) << std::hex << code_offset;
+    const std::vector<uint8_t>& code = compiled_method->GetCode();
+    size_t code_size = code.size() * sizeof(code[0]);
+    DCHECK((code_size == 0 && method->GetOatCodeOffset() == 0)
+           || code_offset + compiled_method->CodeDelta() == method->GetOatCodeOffset());
+    if (!file->WriteFully(&code[0], code_size)) {
       PLOG(ERROR) << "Failed to write method code for " << PrettyMethod(method);
       return false;
     }
-    code_offset += code_array->GetLength();
+    code_offset += code_size;
+    DCHECK_CODE_OFFSET();
   }
-  // preserve code offset around code clearing
-  uint32_t offset = method->GetOatCodeOffset();
-  method->SetCodeArray(NULL, kNone);
-  method->SetOatCodeOffset(offset);
+
+  uint32_t frame_size_in_bytes = method->GetFrameSizeInBytes();
+  uint32_t return_pc_offset_in_bytes = method->GetReturnPcOffsetInBytes();
+  uint32_t core_spill_mask = method->GetCoreSpillMask();
+  uint32_t fp_spill_mask = method->GetFpSpillMask();
+  if (!file->WriteFully(&frame_size_in_bytes, sizeof(frame_size_in_bytes))) {
+    PLOG(ERROR) << "Failed to write method frame size for " << PrettyMethod(method);
+    return false;
+  }
+  code_offset += sizeof(frame_size_in_bytes);
+  if (!file->WriteFully(&return_pc_offset_in_bytes, sizeof(return_pc_offset_in_bytes))) {
+    PLOG(ERROR) << "Failed to write method return pc offset for " << PrettyMethod(method);
+    return false;
+  }
+  code_offset += sizeof(return_pc_offset_in_bytes);
+  if (!file->WriteFully(&core_spill_mask, sizeof(core_spill_mask))) {
+    PLOG(ERROR) << "Failed to write method core spill mask for " << PrettyMethod(method);
+    return false;
+  }
+  code_offset += sizeof(core_spill_mask);
+  if (!file->WriteFully(&fp_spill_mask, sizeof(fp_spill_mask))) {
+    PLOG(ERROR) << "Failed to write method fp spill mask for " << PrettyMethod(method);
+    return false;
+  }
+  code_offset += sizeof(fp_spill_mask);
+
+  if (compiled_method != NULL) {
+    const std::vector<uint32_t>& mapping_table = compiled_method->GetMappingTable();
+    size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]);
+    DCHECK((mapping_table_size == 0 && method->GetOatMappingTableOffset() == 0)
+           || code_offset == method->GetOatMappingTableOffset());
+    if (!file->WriteFully(&mapping_table[0], mapping_table_size)) {
+      PLOG(ERROR) << "Failed to write mapping table for " << PrettyMethod(method);
+      return false;
+    }
+    code_offset += mapping_table_size;
+    DCHECK_CODE_OFFSET();
+
+    const std::vector<uint16_t>& vmap_table = compiled_method->GetVmapTable();
+    size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]);
+    DCHECK((vmap_table_size == 0 && method->GetOatVmapTableOffset() == 0)
+           || code_offset == method->GetOatVmapTableOffset());
+    if (!file->WriteFully(&vmap_table[0], vmap_table_size)) {
+      PLOG(ERROR) << "Failed to write vmap table for " << PrettyMethod(method);
+      return false;
+    }
+    code_offset += vmap_table_size;
+    DCHECK_CODE_OFFSET();
+  }
+
+  const CompiledInvokeStub* compiled_invoke_stub = compiler_->GetCompiledInvokeStub(method);
+  if (compiled_invoke_stub != NULL) {
+    uint32_t aligned_code_offset = CompiledMethod::AlignCode(code_offset,
+                                                             compiler_->GetInstructionSet());
+    uint32_t aligned_code_delta = aligned_code_offset - code_offset;
+    if (aligned_code_delta != 0) {
+      off_t new_offset = lseek(file->Fd(), aligned_code_delta, SEEK_CUR);
+      if (static_cast<uint32_t>(new_offset) != aligned_code_offset) {
+        PLOG(ERROR) << "Failed to seek to align invoke stub code. Actual: " << new_offset
+                    << " Expected: " << aligned_code_offset;
+        return false;
+      }
+      code_offset += aligned_code_delta;
+      DCHECK_CODE_OFFSET();
+    }
+    DCHECK(IsAligned(code_offset, kArmAlignment)) << std::hex << code_offset;
+    const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode();
+    size_t invoke_stub_size = invoke_stub.size() * sizeof(invoke_stub[0]);
+    DCHECK((invoke_stub_size == 0 && method->GetOatInvokeStubOffset() == 0)
+           || code_offset == method->GetOatInvokeStubOffset());
+    if (!file->WriteFully(&invoke_stub[0], invoke_stub_size)) {
+      PLOG(ERROR) << "Failed to write invoke stub code for " << PrettyMethod(method);
+      return false;
+    }
+    code_offset += invoke_stub_size;
+    DCHECK_CODE_OFFSET();
+  }
+
   return code_offset;
 }