oat_writer.cc revision 387b699e3dc55309023ae2427a76a1ca1d51b0cd
1// Copyright 2011 Google Inc. All Rights Reserved.
2
3#include "oat_writer.h"
4
5#include "class_linker.h"
6#include "class_loader.h"
7#include "file.h"
8#include "os.h"
9#include "stl_util.h"
10
11namespace art {
12
13bool OatWriter::Create(const std::string& filename,
14                       const ClassLoader* class_loader,
15                       const Compiler& compiler) {
16  const std::vector<const DexFile*>& dex_files = ClassLoader::GetCompileTimeClassPath(class_loader);
17  OatWriter oat_writer(dex_files, class_loader, compiler);
18  return oat_writer.Write(filename);
19}
20
21OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files,
22                     const ClassLoader* class_loader,
23                     const Compiler& compiler) {
24  compiler_ = &compiler;
25  class_loader_ = class_loader;
26  dex_files_ = &dex_files;
27
28  size_t offset = InitOatHeader();
29  offset = InitOatDexFiles(offset);
30  offset = InitOatClasses(offset);
31  offset = InitOatMethods(offset);
32  offset = InitOatCode(offset);
33  offset = InitOatCodeDexFiles(offset);
34
35  CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
36  CHECK_EQ(dex_files_->size(), oat_classes_.size());
37}
38
39size_t OatWriter::InitOatHeader() {
40  // create the OatHeader
41  oat_header_ = new OatHeader(dex_files_);
42  size_t offset = sizeof(*oat_header_);
43  return offset;
44}
45
46size_t OatWriter::InitOatDexFiles(size_t offset) {
47  // create the OatDexFiles
48  for (size_t i = 0; i != dex_files_->size(); ++i) {
49    const DexFile* dex_file = (*dex_files_)[i];
50    CHECK(dex_file != NULL);
51    OatDexFile* oat_dex_file = new OatDexFile(*dex_file);
52    oat_dex_files_.push_back(oat_dex_file);
53    offset += oat_dex_file->SizeOf();
54  }
55  return offset;
56}
57
58size_t OatWriter::InitOatClasses(size_t offset) {
59  // create the OatClasses
60  // calculate the offsets within OatDexFiles to OatClasses
61  for (size_t i = 0; i != dex_files_->size(); ++i) {
62    // set offset in OatDexFile to OatClasses
63    oat_dex_files_[i]->classes_offset_ = offset;
64    oat_dex_files_[i]->UpdateChecksum(*oat_header_);
65
66    const DexFile* dex_file = (*dex_files_)[i];
67    OatClasses* oat_classes = new OatClasses(*dex_file);
68    oat_classes_.push_back(oat_classes);
69    offset += oat_classes->SizeOf();
70  }
71  return offset;
72}
73
74size_t OatWriter::InitOatMethods(size_t offset) {
75  // create the OatMethods
76  // calculate the offsets within OatClasses to OatMethods
77  size_t class_index = 0;
78  for (size_t i = 0; i != dex_files_->size(); ++i) {
79    const DexFile* dex_file = (*dex_files_)[i];
80    for (size_t class_def_index = 0;
81         class_def_index < dex_file->NumClassDefs();
82         class_def_index++, class_index++) {
83      oat_classes_[i]->methods_offsets_[class_def_index] = offset;
84      const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
85      const byte* class_data = dex_file->GetClassData(class_def);
86      DexFile::ClassDataHeader header = dex_file->ReadClassDataHeader(&class_data);
87      size_t num_direct_methods = header.direct_methods_size_;
88      size_t num_virtual_methods = header.virtual_methods_size_;
89      uint32_t num_methods = num_direct_methods + num_virtual_methods;
90      OatMethods* oat_methods = new OatMethods(num_methods);
91      oat_methods_.push_back(oat_methods);
92      offset += oat_methods->SizeOf();
93    }
94    oat_classes_[i]->UpdateChecksum(*oat_header_);
95  }
96  return offset;
97}
98
99size_t OatWriter::InitOatCode(size_t offset) {
100  // calculate the offsets within OatHeader to executable code
101  size_t old_offset = offset;
102  // required to be on a new page boundary
103  offset = RoundUp(offset, kPageSize);
104  oat_header_->SetExecutableOffset(offset);
105  executable_offset_padding_length_ = offset - old_offset;
106  return offset;
107}
108
109size_t OatWriter::InitOatCodeDexFiles(size_t offset) {
110  // calculate the offsets within OatMethods
111  size_t oat_class_index = 0;
112  for (size_t i = 0; i != dex_files_->size(); ++i) {
113    const DexFile* dex_file = (*dex_files_)[i];
114    CHECK(dex_file != NULL);
115    offset = InitOatCodeDexFile(offset, oat_class_index, *dex_file);
116  }
117  return offset;
118}
119
120size_t OatWriter::InitOatCodeDexFile(size_t offset,
121                                     size_t& oat_class_index,
122                                     const DexFile& dex_file) {
123  for (size_t class_def_index = 0;
124       class_def_index < dex_file.NumClassDefs();
125       class_def_index++, oat_class_index++) {
126    const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
127    offset = InitOatCodeClassDef(offset, oat_class_index, dex_file, class_def);
128    oat_methods_[oat_class_index]->UpdateChecksum(*oat_header_);
129  }
130  return offset;
131}
132
133size_t OatWriter::InitOatCodeClassDef(size_t offset,
134                                      size_t oat_class_index,
135                                      const DexFile& dex_file,
136                                      const DexFile::ClassDef& class_def) {
137  const byte* class_data = dex_file.GetClassData(class_def);
138  DexFile::ClassDataHeader header = dex_file.ReadClassDataHeader(&class_data);
139  size_t num_virtual_methods = header.virtual_methods_size_;
140  const char* descriptor = dex_file.GetClassDescriptor(class_def);
141
142  // TODO: remove code ByteArrays from Class/Method (and therefore ClassLoader)
143  // TODO: don't write code for shared stubs
144  Class* klass = Runtime::Current()->GetClassLinker()->FindClass(descriptor, class_loader_);
145  if (klass == NULL) {
146    LOG(WARNING) << "Didn't find class '" << descriptor << "' in dex file " << dex_file.GetLocation();
147    Thread* thread = Thread::Current();
148    DCHECK(thread->IsExceptionPending());
149    thread->ClearException();
150    return offset;
151  }
152  CHECK_EQ(klass->GetClassLoader(), class_loader_);
153  CHECK_EQ(oat_methods_[oat_class_index]->method_offsets_.size(),
154           klass->NumDirectMethods() + num_virtual_methods);
155  size_t class_def_method_index = 0;
156  for (size_t i = 0; i < klass->NumDirectMethods(); i++, class_def_method_index++) {
157    Method* method = klass->GetDirectMethod(i);
158    CHECK(method != NULL) << descriptor << " direct " << i;
159    offset = InitOatCodeMethod(offset, oat_class_index, class_def_method_index, method);
160  }
161  // note that num_virtual_methods != klass->NumVirtualMethods() because of miranda methods
162  for (size_t i = 0; i < num_virtual_methods; i++, class_def_method_index++) {
163    Method* method = klass->GetVirtualMethod(i);
164    CHECK(method != NULL) << descriptor << " virtual " << i;
165    offset = InitOatCodeMethod(offset, oat_class_index, class_def_method_index, method);
166  }
167  return offset;
168}
169
170size_t OatWriter::InitOatCodeMethod(size_t offset,
171                                    size_t oat_class_index,
172                                    size_t class_def_method_index,
173                                    Method* method) {
174  // derived from CompiledMethod if available
175  uint32_t code_offset = 0;
176  uint32_t frame_size_in_bytes = kStackAlignment;
177  uint32_t return_pc_offset_in_bytes = 0;
178  uint32_t core_spill_mask = 0;
179  uint32_t fp_spill_mask = 0;
180  uint32_t mapping_table_offset = 0;
181  uint32_t vmap_table_offset = 0;
182  // derived from CompiledInvokeStub if available
183  uint32_t invoke_stub_offset = 0;
184
185  const CompiledMethod* compiled_method = compiler_->GetCompiledMethod(method);
186  if (compiled_method != NULL) {
187    offset = compiled_method->AlignCode(offset);
188    DCHECK_ALIGNED(offset, kArmAlignment);
189    const std::vector<uint8_t>& code = compiled_method->GetCode();
190    size_t code_size = code.size() * sizeof(code[0]);
191    uint32_t thumb_offset = compiled_method->CodeDelta();
192    code_offset = (code_size == 0) ? 0 : offset + thumb_offset;
193    offset += code_size;
194    oat_header_->UpdateChecksum(&code[0], code_size);
195
196    frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
197    return_pc_offset_in_bytes = compiled_method->GetReturnPcOffsetInBytes();
198    core_spill_mask = compiled_method->GetCoreSpillMask();
199    fp_spill_mask = compiled_method->GetFpSpillMask();
200  }
201
202  offset += sizeof(frame_size_in_bytes);
203  oat_header_->UpdateChecksum(&frame_size_in_bytes, sizeof(frame_size_in_bytes));
204
205  offset += sizeof(return_pc_offset_in_bytes);
206  oat_header_->UpdateChecksum(&return_pc_offset_in_bytes, sizeof(return_pc_offset_in_bytes));
207
208  offset += sizeof(core_spill_mask);
209  oat_header_->UpdateChecksum(&core_spill_mask, sizeof(core_spill_mask));
210
211  offset += sizeof(fp_spill_mask);
212  oat_header_->UpdateChecksum(&fp_spill_mask, sizeof(fp_spill_mask));
213
214  if (compiled_method != NULL) {
215    const std::vector<uint32_t>& mapping_table = compiled_method->GetMappingTable();
216    size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]);
217    mapping_table_offset = (mapping_table_size == 0) ? 0 : offset;
218    offset += mapping_table_size;
219    oat_header_->UpdateChecksum(&mapping_table[0], mapping_table_size);
220
221    const std::vector<uint16_t>& vmap_table = compiled_method->GetVmapTable();
222    size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]);
223    vmap_table_offset = (vmap_table_size == 0) ? 0 : offset;
224    offset += vmap_table_size;
225    oat_header_->UpdateChecksum(&vmap_table[0], vmap_table_size);
226  }
227
228  const CompiledInvokeStub* compiled_invoke_stub = compiler_->GetCompiledInvokeStub(method);
229  if (compiled_invoke_stub != NULL) {
230    offset = CompiledMethod::AlignCode(offset, compiler_->GetInstructionSet());
231    DCHECK_ALIGNED(offset, kArmAlignment);
232    const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode();
233    size_t invoke_stub_size = invoke_stub.size() * sizeof(invoke_stub[0]);
234    invoke_stub_offset = (invoke_stub_size == 0) ? 0 : offset;
235    offset += invoke_stub_size;
236    oat_header_->UpdateChecksum(&invoke_stub[0], invoke_stub_size);
237  }
238
239  oat_methods_[oat_class_index]->method_offsets_[class_def_method_index]
240      = OatMethodOffsets(code_offset,
241                         frame_size_in_bytes,
242                         return_pc_offset_in_bytes,
243                         core_spill_mask,
244                         fp_spill_mask,
245                         mapping_table_offset,
246                         vmap_table_offset,
247                         invoke_stub_offset);
248
249  // Note that we leave the offset and values back in the Method where ImageWriter will find them
250  method->SetOatCodeOffset(code_offset);
251  method->SetFrameSizeInBytes(frame_size_in_bytes);
252  method->SetCoreSpillMask(core_spill_mask);
253  method->SetFpSpillMask(fp_spill_mask);
254  method->SetOatMappingTableOffset(mapping_table_offset);
255  method->SetOatVmapTableOffset(vmap_table_offset);
256  method->SetOatInvokeStubOffset(invoke_stub_offset);
257
258  return offset;
259}
260
261#define DCHECK_CODE_OFFSET() \
262  DCHECK_EQ(static_cast<off_t>(code_offset), lseek(file->Fd(), 0, SEEK_CUR))
263
264bool OatWriter::Write(const std::string& filename) {
265  UniquePtr<File> file(OS::OpenFile(filename.c_str(), true));
266  if (file.get() == NULL) {
267    return false;
268  }
269
270  if (!file->WriteFully(oat_header_, sizeof(*oat_header_))) {
271    PLOG(ERROR) << "Failed to write oat header to " << filename;
272    return false;
273  }
274
275  if (!WriteTables(file.get())) {
276    LOG(ERROR) << "Failed to write oat tables to " << filename;
277    return false;
278  }
279
280  size_t code_offset = WriteCode(file.get());
281  if (code_offset == 0) {
282    LOG(ERROR) << "Failed to write oat code to " << filename;
283    return false;
284  }
285
286  code_offset = WriteCodeDexFiles(file.get(), code_offset);
287  if (code_offset == 0) {
288    LOG(ERROR) << "Failed to write oat code for dex files to " << filename;
289    return false;
290  }
291
292  return true;
293}
294
295bool OatWriter::WriteTables(File* file) {
296  for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
297    if (!oat_dex_files_[i]->Write(file)) {
298      PLOG(ERROR) << "Failed to write oat dex information";
299      return false;
300    }
301  }
302  for (size_t i = 0; i != oat_classes_.size(); ++i) {
303    if (!oat_classes_[i]->Write(file)) {
304      PLOG(ERROR) << "Failed to write oat classes information";
305      return false;
306    }
307  }
308  for (size_t i = 0; i != oat_methods_.size(); ++i) {
309    if (!oat_methods_[i]->Write(file)) {
310      PLOG(ERROR) << "Failed to write oat methods information";
311      return false;
312    }
313  }
314  return true;
315}
316
317size_t OatWriter::WriteCode(File* file) {
318  uint32_t code_offset = oat_header_->GetExecutableOffset();
319  off_t new_offset = lseek(file->Fd(), executable_offset_padding_length_, SEEK_CUR);
320  if (static_cast<uint32_t>(new_offset) != code_offset) {
321    PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
322                << " Expected: " << code_offset;
323    return 0;
324  }
325  DCHECK_CODE_OFFSET();
326  return code_offset;
327}
328
329size_t OatWriter::WriteCodeDexFiles(File* file, size_t code_offset) {
330  for (size_t i = 0; i != oat_classes_.size(); ++i) {
331    const DexFile* dex_file = (*dex_files_)[i];
332    CHECK(dex_file != NULL);
333    code_offset = WriteCodeDexFile(file, code_offset, *dex_file);
334    if (code_offset == 0) {
335      return 0;
336    }
337  }
338  return code_offset;
339}
340
341size_t OatWriter::WriteCodeDexFile(File* file,
342                                   size_t code_offset,
343                                   const DexFile& dex_file) {
344  for (size_t class_def_index = 0;
345       class_def_index < dex_file.NumClassDefs();
346       class_def_index++) {
347    const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
348    code_offset = WriteCodeClassDef(file, code_offset, dex_file, class_def);
349    if (code_offset == 0) {
350      return 0;
351    }
352  }
353  return code_offset;
354}
355
356size_t OatWriter::WriteCodeClassDef(File* file,
357                                    size_t code_offset,
358                                    const DexFile& dex_file,
359                                    const DexFile::ClassDef& class_def) {
360  const byte* class_data = dex_file.GetClassData(class_def);
361  DexFile::ClassDataHeader header = dex_file.ReadClassDataHeader(&class_data);
362  size_t num_virtual_methods = header.virtual_methods_size_;
363  const char* descriptor = dex_file.GetClassDescriptor(class_def);
364  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
365  Class* klass = class_linker->FindClass(descriptor, class_loader_);
366  if (klass == NULL) {
367    LOG(WARNING) << "Didn't find class '" << descriptor << "' in dex file " << dex_file.GetLocation();
368    Thread* thread = Thread::Current();
369    DCHECK(thread->IsExceptionPending());
370    thread->ClearException();
371    return code_offset;
372  }
373
374  // TODO: deduplicate code arrays
375  // Note that we clear the code array here, image_writer will use GetCodeOffset to find it
376  for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
377    Method* method = klass->GetDirectMethod(i);
378    code_offset = WriteCodeMethod(file, code_offset, method);
379    if (code_offset == 0) {
380      return 0;
381    }
382  }
383  // note that num_virtual_methods != klass->NumVirtualMethods() because of miranda methods
384  for (size_t i = 0; i < num_virtual_methods; i++) {
385    Method* method = klass->GetVirtualMethod(i);
386    code_offset = WriteCodeMethod(file, code_offset, method);
387    if (code_offset == 0) {
388      return 0;
389    }
390  }
391  for (size_t i = num_virtual_methods; i < klass->NumVirtualMethods(); i++) {
392    Method* method = klass->GetVirtualMethod(i);
393    CHECK(compiler_->GetCompiledMethod(method) == NULL) << PrettyMethod(method);
394  }
395  return code_offset;
396}
397
398size_t OatWriter::WriteCodeMethod(File* file, size_t code_offset, Method* method) {
399  const CompiledMethod* compiled_method = compiler_->GetCompiledMethod(method);
400  if (compiled_method != NULL) {
401    uint32_t aligned_code_offset = compiled_method->AlignCode(code_offset);
402    uint32_t aligned_code_delta = aligned_code_offset - code_offset;
403    if (aligned_code_delta != 0) {
404      off_t new_offset = lseek(file->Fd(), aligned_code_delta, SEEK_CUR);
405      if (static_cast<uint32_t>(new_offset) != aligned_code_offset) {
406        PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset
407                    << " Expected: " << aligned_code_offset;
408        return false;
409      }
410      code_offset += aligned_code_delta;
411      DCHECK_CODE_OFFSET();
412    }
413    DCHECK_ALIGNED(code_offset, kArmAlignment);
414    const std::vector<uint8_t>& code = compiled_method->GetCode();
415    size_t code_size = code.size() * sizeof(code[0]);
416    DCHECK((code_size == 0 && method->GetOatCodeOffset() == 0)
417           || code_offset + compiled_method->CodeDelta() == method->GetOatCodeOffset());
418    if (!file->WriteFully(&code[0], code_size)) {
419      PLOG(ERROR) << "Failed to write method code for " << PrettyMethod(method);
420      return false;
421    }
422    code_offset += code_size;
423    DCHECK_CODE_OFFSET();
424  }
425
426  uint32_t frame_size_in_bytes = method->GetFrameSizeInBytes();
427  uint32_t return_pc_offset_in_bytes = method->GetReturnPcOffsetInBytes();
428  uint32_t core_spill_mask = method->GetCoreSpillMask();
429  uint32_t fp_spill_mask = method->GetFpSpillMask();
430  if (!file->WriteFully(&frame_size_in_bytes, sizeof(frame_size_in_bytes))) {
431    PLOG(ERROR) << "Failed to write method frame size for " << PrettyMethod(method);
432    return false;
433  }
434  code_offset += sizeof(frame_size_in_bytes);
435  if (!file->WriteFully(&return_pc_offset_in_bytes, sizeof(return_pc_offset_in_bytes))) {
436    PLOG(ERROR) << "Failed to write method return pc offset for " << PrettyMethod(method);
437    return false;
438  }
439  code_offset += sizeof(return_pc_offset_in_bytes);
440  if (!file->WriteFully(&core_spill_mask, sizeof(core_spill_mask))) {
441    PLOG(ERROR) << "Failed to write method core spill mask for " << PrettyMethod(method);
442    return false;
443  }
444  code_offset += sizeof(core_spill_mask);
445  if (!file->WriteFully(&fp_spill_mask, sizeof(fp_spill_mask))) {
446    PLOG(ERROR) << "Failed to write method fp spill mask for " << PrettyMethod(method);
447    return false;
448  }
449  code_offset += sizeof(fp_spill_mask);
450
451  if (compiled_method != NULL) {
452    const std::vector<uint32_t>& mapping_table = compiled_method->GetMappingTable();
453    size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]);
454    DCHECK((mapping_table_size == 0 && method->GetOatMappingTableOffset() == 0)
455           || code_offset == method->GetOatMappingTableOffset());
456    if (!file->WriteFully(&mapping_table[0], mapping_table_size)) {
457      PLOG(ERROR) << "Failed to write mapping table for " << PrettyMethod(method);
458      return false;
459    }
460    code_offset += mapping_table_size;
461    DCHECK_CODE_OFFSET();
462
463    const std::vector<uint16_t>& vmap_table = compiled_method->GetVmapTable();
464    size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]);
465    DCHECK((vmap_table_size == 0 && method->GetOatVmapTableOffset() == 0)
466           || code_offset == method->GetOatVmapTableOffset());
467    if (!file->WriteFully(&vmap_table[0], vmap_table_size)) {
468      PLOG(ERROR) << "Failed to write vmap table for " << PrettyMethod(method);
469      return false;
470    }
471    code_offset += vmap_table_size;
472    DCHECK_CODE_OFFSET();
473  }
474
475  const CompiledInvokeStub* compiled_invoke_stub = compiler_->GetCompiledInvokeStub(method);
476  if (compiled_invoke_stub != NULL) {
477    uint32_t aligned_code_offset = CompiledMethod::AlignCode(code_offset,
478                                                             compiler_->GetInstructionSet());
479    uint32_t aligned_code_delta = aligned_code_offset - code_offset;
480    if (aligned_code_delta != 0) {
481      off_t new_offset = lseek(file->Fd(), aligned_code_delta, SEEK_CUR);
482      if (static_cast<uint32_t>(new_offset) != aligned_code_offset) {
483        PLOG(ERROR) << "Failed to seek to align invoke stub code. Actual: " << new_offset
484                    << " Expected: " << aligned_code_offset;
485        return false;
486      }
487      code_offset += aligned_code_delta;
488      DCHECK_CODE_OFFSET();
489    }
490    DCHECK_ALIGNED(code_offset, kArmAlignment);
491    const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode();
492    size_t invoke_stub_size = invoke_stub.size() * sizeof(invoke_stub[0]);
493    DCHECK((invoke_stub_size == 0 && method->GetOatInvokeStubOffset() == 0)
494        || code_offset == method->GetOatInvokeStubOffset()) << PrettyMethod(method);
495    if (!file->WriteFully(&invoke_stub[0], invoke_stub_size)) {
496      PLOG(ERROR) << "Failed to write invoke stub code for " << PrettyMethod(method);
497      return false;
498    }
499    code_offset += invoke_stub_size;
500    DCHECK_CODE_OFFSET();
501  }
502
503  return code_offset;
504}
505
506OatWriter::~OatWriter() {
507  delete oat_header_;
508  STLDeleteElements(&oat_dex_files_);
509  STLDeleteElements(&oat_classes_);
510  STLDeleteElements(&oat_methods_);
511}
512
513OatWriter::OatDexFile::OatDexFile(const DexFile& dex_file) {
514  const std::string& location = dex_file.GetLocation();
515  dex_file_location_size_ = location.size();
516  dex_file_location_data_ = reinterpret_cast<const uint8_t*>(location.data());
517  dex_file_checksum_ = dex_file.GetHeader().checksum_;
518}
519
520size_t OatWriter::OatDexFile::SizeOf() const {
521  return sizeof(dex_file_location_size_)
522          + dex_file_location_size_
523          + sizeof(dex_file_checksum_)
524          + sizeof(classes_offset_);
525}
526
527void OatWriter::OatDexFile::UpdateChecksum(OatHeader& oat_header) const {
528  oat_header.UpdateChecksum(&dex_file_location_size_, sizeof(dex_file_location_size_));
529  oat_header.UpdateChecksum(dex_file_location_data_, dex_file_location_size_);
530  oat_header.UpdateChecksum(&dex_file_checksum_, sizeof(dex_file_checksum_));
531  oat_header.UpdateChecksum(&classes_offset_, sizeof(classes_offset_));
532}
533
534bool OatWriter::OatDexFile::Write(File* file) const {
535  if (!file->WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
536    PLOG(ERROR) << "Failed to write dex file location length";
537    return false;
538  }
539  if (!file->WriteFully(dex_file_location_data_, dex_file_location_size_)) {
540    PLOG(ERROR) << "Failed to write dex file location data";
541    return false;
542  }
543  if (!file->WriteFully(&dex_file_checksum_, sizeof(dex_file_checksum_))) {
544    PLOG(ERROR) << "Failed to write dex file checksum";
545    return false;
546  }
547  if (!file->WriteFully(&classes_offset_, sizeof(classes_offset_))) {
548    PLOG(ERROR) << "Failed to write classes offset";
549    return false;
550  }
551  return true;
552}
553
554OatWriter::OatClasses::OatClasses(const DexFile& dex_file) {
555  methods_offsets_.resize(dex_file.NumClassDefs());
556}
557
558size_t OatWriter::OatClasses::SizeOf() const {
559  return (sizeof(methods_offsets_[0]) * methods_offsets_.size());
560}
561
562void OatWriter::OatClasses::UpdateChecksum(OatHeader& oat_header) const {
563  oat_header.UpdateChecksum(&methods_offsets_[0], SizeOf());
564}
565
566bool OatWriter::OatClasses::Write(File* file) const {
567  if (!file->WriteFully(&methods_offsets_[0], SizeOf())) {
568    PLOG(ERROR) << "Failed to methods offsets";
569    return false;
570  }
571  return true;
572}
573
574OatWriter::OatMethods::OatMethods(uint32_t methods_count) {
575  method_offsets_.resize(methods_count);
576}
577
578size_t OatWriter::OatMethods::SizeOf() const {
579  return (sizeof(method_offsets_[0]) * method_offsets_.size());
580}
581
582void OatWriter::OatMethods::UpdateChecksum(OatHeader& oat_header) const {
583  oat_header.UpdateChecksum(&method_offsets_[0], SizeOf());
584}
585
586bool OatWriter::OatMethods::Write(File* file) const {
587  if (!file->WriteFully(&method_offsets_[0], SizeOf())) {
588    PLOG(ERROR) << "Failed to method offsets";
589    return false;
590  }
591  return true;
592}
593
594}  // namespace art
595