oat_writer.cc revision 08f753d5859936f8d3524e9e4faa6cee353873ea
1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "oat_writer.h"
18
19#include <zlib.h>
20
21#include "class_linker.h"
22#include "class_loader.h"
23#include "file.h"
24#include "os.h"
25#include "safe_map.h"
26#include "scoped_thread_state_change.h"
27#include "space.h"
28#include "stl_util.h"
29
30namespace art {
31
32bool OatWriter::Create(File* file,
33                       jobject class_loader,
34                       const std::vector<const DexFile*>& dex_files,
35                       uint32_t image_file_location_checksum,
36                       const std::string& image_file_location,
37                       const Compiler& compiler) {
38  OatWriter oat_writer(dex_files,
39                       image_file_location_checksum,
40                       image_file_location,
41                       class_loader,
42                       compiler);
43  return oat_writer.Write(file);
44}
45
46OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files,
47                     uint32_t image_file_location_checksum,
48                     const std::string& image_file_location,
49                     jobject class_loader,
50                     const Compiler& compiler) {
51  compiler_ = &compiler;
52  class_loader_ = class_loader;
53  image_file_location_checksum_ = image_file_location_checksum;
54  image_file_location_ = image_file_location;
55  dex_files_ = &dex_files;
56  oat_header_ = NULL;
57  executable_offset_padding_length_ = 0;
58
59  size_t offset = InitOatHeader();
60  offset = InitOatDexFiles(offset);
61  offset = InitDexFiles(offset);
62  offset = InitOatClasses(offset);
63  offset = InitOatCode(offset);
64  offset = InitOatCodeDexFiles(offset);
65
66  CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
67}
68
69OatWriter::~OatWriter() {
70  delete oat_header_;
71  STLDeleteElements(&oat_dex_files_);
72  STLDeleteElements(&oat_classes_);
73}
74
75size_t OatWriter::InitOatHeader() {
76  // create the OatHeader
77  oat_header_ = new OatHeader(compiler_->GetInstructionSet(),
78                              dex_files_,
79                              image_file_location_checksum_,
80                              image_file_location_);
81  size_t offset = sizeof(*oat_header_);
82  offset += image_file_location_.size();
83  return offset;
84}
85
86size_t OatWriter::InitOatDexFiles(size_t offset) {
87  // create the OatDexFiles
88  for (size_t i = 0; i != dex_files_->size(); ++i) {
89    const DexFile* dex_file = (*dex_files_)[i];
90    CHECK(dex_file != NULL);
91    OatDexFile* oat_dex_file = new OatDexFile(*dex_file);
92    oat_dex_files_.push_back(oat_dex_file);
93    offset += oat_dex_file->SizeOf();
94  }
95  return offset;
96}
97
98size_t OatWriter::InitDexFiles(size_t offset) {
99  // calculate the offsets within OatDexFiles to the DexFiles
100  for (size_t i = 0; i != dex_files_->size(); ++i) {
101    // dex files are required to be 4 byte aligned
102    offset = RoundUp(offset, 4);
103
104    // set offset in OatDexFile to DexFile
105    oat_dex_files_[i]->dex_file_offset_ = offset;
106
107    const DexFile* dex_file = (*dex_files_)[i];
108    offset += dex_file->GetHeader().file_size_;
109  }
110  return offset;
111}
112
113size_t OatWriter::InitOatClasses(size_t offset) {
114  // create the OatClasses
115  // calculate the offsets within OatDexFiles to OatClasses
116  for (size_t i = 0; i != dex_files_->size(); ++i) {
117    const DexFile* dex_file = (*dex_files_)[i];
118    for (size_t class_def_index = 0;
119         class_def_index < dex_file->NumClassDefs();
120         class_def_index++) {
121      oat_dex_files_[i]->methods_offsets_[class_def_index] = offset;
122      const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
123      const byte* class_data = dex_file->GetClassData(class_def);
124      uint32_t num_methods = 0;
125      if (class_data != NULL) {  // ie not an empty class, such as a marker interface
126        ClassDataItemIterator it(*dex_file, class_data);
127        size_t num_direct_methods = it.NumDirectMethods();
128        size_t num_virtual_methods = it.NumVirtualMethods();
129        num_methods = num_direct_methods + num_virtual_methods;
130      }
131
132      CompiledClass* compiled_class =
133          compiler_->GetCompiledClass(Compiler::MethodReference(dex_file, class_def_index));
134      Class::Status status =
135          (compiled_class != NULL) ? compiled_class->GetStatus() : Class::kStatusNotReady;
136
137      OatClass* oat_class = new OatClass(status, num_methods);
138      oat_classes_.push_back(oat_class);
139      offset += oat_class->SizeOf();
140    }
141    oat_dex_files_[i]->UpdateChecksum(*oat_header_);
142  }
143  return offset;
144}
145
146size_t OatWriter::InitOatCode(size_t offset) {
147  // calculate the offsets within OatHeader to executable code
148  size_t old_offset = offset;
149  // required to be on a new page boundary
150  offset = RoundUp(offset, kPageSize);
151  oat_header_->SetExecutableOffset(offset);
152  executable_offset_padding_length_ = offset - old_offset;
153  return offset;
154}
155
156size_t OatWriter::InitOatCodeDexFiles(size_t offset) {
157  size_t oat_class_index = 0;
158  for (size_t i = 0; i != dex_files_->size(); ++i) {
159    const DexFile* dex_file = (*dex_files_)[i];
160    CHECK(dex_file != NULL);
161    offset = InitOatCodeDexFile(offset, oat_class_index, *dex_file);
162  }
163  return offset;
164}
165
166size_t OatWriter::InitOatCodeDexFile(size_t offset,
167                                     size_t& oat_class_index,
168                                     const DexFile& dex_file) {
169  for (size_t class_def_index = 0;
170       class_def_index < dex_file.NumClassDefs();
171       class_def_index++, oat_class_index++) {
172    const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
173    offset = InitOatCodeClassDef(offset, oat_class_index, class_def_index, dex_file, class_def);
174    oat_classes_[oat_class_index]->UpdateChecksum(*oat_header_);
175  }
176  return offset;
177}
178
179size_t OatWriter::InitOatCodeClassDef(size_t offset,
180                                      size_t oat_class_index, size_t class_def_index,
181                                      const DexFile& dex_file,
182                                      const DexFile::ClassDef& class_def) {
183  const byte* class_data = dex_file.GetClassData(class_def);
184  if (class_data == NULL) {
185    // empty class, such as a marker interface
186    return offset;
187  }
188  ClassDataItemIterator it(dex_file, class_data);
189  CHECK_EQ(oat_classes_[oat_class_index]->method_offsets_.size(),
190           it.NumDirectMethods() + it.NumVirtualMethods());
191  // Skip fields
192  while (it.HasNextStaticField()) {
193    it.Next();
194  }
195  while (it.HasNextInstanceField()) {
196    it.Next();
197  }
198  // Process methods
199  size_t class_def_method_index = 0;
200  while (it.HasNextDirectMethod()) {
201    bool is_native = (it.GetMemberAccessFlags() & kAccNative) != 0;
202    offset = InitOatCodeMethod(offset, oat_class_index, class_def_index, class_def_method_index,
203                               is_native, it.GetMethodInvokeType(class_def), it.GetMemberIndex(),
204                               &dex_file);
205    class_def_method_index++;
206    it.Next();
207  }
208  while (it.HasNextVirtualMethod()) {
209    bool is_native = (it.GetMemberAccessFlags() & kAccNative) != 0;
210    offset = InitOatCodeMethod(offset, oat_class_index, class_def_index, class_def_method_index,
211                               is_native, it.GetMethodInvokeType(class_def), it.GetMemberIndex(),
212                               &dex_file);
213    class_def_method_index++;
214    it.Next();
215  }
216  DCHECK(!it.HasNext());
217  return offset;
218}
219
220size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index,
221                                    size_t __attribute__((unused)) class_def_index,
222                                    size_t class_def_method_index,
223                                    bool __attribute__((unused)) is_native,
224                                    InvokeType type,
225                                    uint32_t method_idx, const DexFile* dex_file) {
226  // derived from CompiledMethod if available
227  uint32_t code_offset = 0;
228  uint32_t frame_size_in_bytes = kStackAlignment;
229  uint32_t core_spill_mask = 0;
230  uint32_t fp_spill_mask = 0;
231  uint32_t mapping_table_offset = 0;
232  uint32_t vmap_table_offset = 0;
233  uint32_t gc_map_offset = 0;
234  // derived from CompiledInvokeStub if available
235  uint32_t invoke_stub_offset = 0;
236#if defined(ART_USE_LLVM_COMPILER)
237  uint32_t proxy_stub_offset = 0;
238#endif
239
240  CompiledMethod* compiled_method =
241      compiler_->GetCompiledMethod(Compiler::MethodReference(dex_file, method_idx));
242  if (compiled_method != NULL) {
243    offset = compiled_method->AlignCode(offset);
244    DCHECK_ALIGNED(offset, kArmAlignment);
245    const std::vector<uint8_t>& code = compiled_method->GetCode();
246    uint32_t code_size = code.size() * sizeof(code[0]);
247    CHECK_NE(code_size, 0U);
248    uint32_t thumb_offset = compiled_method->CodeDelta();
249    code_offset = offset + sizeof(code_size) + thumb_offset;
250
251    // Deduplicate code arrays
252    SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = code_offsets_.find(&code);
253    if (code_iter != code_offsets_.end()) {
254      code_offset = code_iter->second;
255    } else {
256      code_offsets_.Put(&code, code_offset);
257      offset += sizeof(code_size);  // code size is prepended before code
258      offset += code_size;
259      oat_header_->UpdateChecksum(&code[0], code_size);
260    }
261    frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
262    core_spill_mask = compiled_method->GetCoreSpillMask();
263    fp_spill_mask = compiled_method->GetFpSpillMask();
264
265    const std::vector<uint32_t>& mapping_table = compiled_method->GetMappingTable();
266    size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]);
267    mapping_table_offset = (mapping_table_size == 0) ? 0 : offset;
268
269    // Deduplicate mapping tables
270    SafeMap<const std::vector<uint32_t>*, uint32_t>::iterator mapping_iter = mapping_table_offsets_.find(&mapping_table);
271    if (mapping_iter != mapping_table_offsets_.end()) {
272      mapping_table_offset = mapping_iter->second;
273    } else {
274      mapping_table_offsets_.Put(&mapping_table, mapping_table_offset);
275      offset += mapping_table_size;
276      oat_header_->UpdateChecksum(&mapping_table[0], mapping_table_size);
277    }
278
279    const std::vector<uint16_t>& vmap_table = compiled_method->GetVmapTable();
280    size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]);
281    vmap_table_offset = (vmap_table_size == 0) ? 0 : offset;
282
283    // Deduplicate vmap tables
284    SafeMap<const std::vector<uint16_t>*, uint32_t>::iterator vmap_iter = vmap_table_offsets_.find(&vmap_table);
285    if (vmap_iter != vmap_table_offsets_.end()) {
286      vmap_table_offset = vmap_iter->second;
287    } else {
288      vmap_table_offsets_.Put(&vmap_table, vmap_table_offset);
289      offset += vmap_table_size;
290      oat_header_->UpdateChecksum(&vmap_table[0], vmap_table_size);
291    }
292
293    const std::vector<uint8_t>& gc_map = compiled_method->GetGcMap();
294    size_t gc_map_size = gc_map.size() * sizeof(gc_map[0]);
295    gc_map_offset = (gc_map_size == 0) ? 0 : offset;
296
297#if !defined(NDEBUG) && !defined(ART_USE_LLVM_COMPILER)
298    // We expect GC maps except when the class hasn't been verified or the method is native
299    CompiledClass* compiled_class =
300        compiler_->GetCompiledClass(Compiler::MethodReference(dex_file, class_def_index));
301    Class::Status status =
302        (compiled_class != NULL) ? compiled_class->GetStatus() : Class::kStatusNotReady;
303    CHECK(gc_map_size != 0 || is_native || status < Class::kStatusVerified)
304        << &gc_map << " " << gc_map_size << " " << (is_native ? "true" : "false") << " " << (status < Class::kStatusVerified) << " " << status << " " << PrettyMethod(method_idx, *dex_file);
305#endif
306
307    // Deduplicate GC maps
308    SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator gc_map_iter = gc_map_offsets_.find(&gc_map);
309    if (gc_map_iter != gc_map_offsets_.end()) {
310      gc_map_offset = gc_map_iter->second;
311    } else {
312      gc_map_offsets_.Put(&gc_map, gc_map_offset);
313      offset += gc_map_size;
314      oat_header_->UpdateChecksum(&gc_map[0], gc_map_size);
315    }
316  }
317
318  const char* shorty = dex_file->GetMethodShorty(dex_file->GetMethodId(method_idx));
319  const CompiledInvokeStub* compiled_invoke_stub = compiler_->FindInvokeStub(type == kStatic,
320                                                                             shorty);
321  if (compiled_invoke_stub != NULL) {
322    offset = CompiledMethod::AlignCode(offset, compiler_->GetInstructionSet());
323    DCHECK_ALIGNED(offset, kArmAlignment);
324    const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode();
325    uint32_t invoke_stub_size = invoke_stub.size() * sizeof(invoke_stub[0]);
326    CHECK_NE(invoke_stub_size, 0U);
327    uint32_t thumb_offset = compiled_invoke_stub->CodeDelta();
328    invoke_stub_offset = offset + sizeof(invoke_stub_size) + thumb_offset;
329
330    // Deduplicate invoke stubs
331    SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator stub_iter = code_offsets_.find(&invoke_stub);
332    if (stub_iter != code_offsets_.end()) {
333      invoke_stub_offset = stub_iter->second;
334    } else {
335      code_offsets_.Put(&invoke_stub, invoke_stub_offset);
336      offset += sizeof(invoke_stub_size);  // invoke stub size is prepended before code
337      offset += invoke_stub_size;
338      oat_header_->UpdateChecksum(&invoke_stub[0], invoke_stub_size);
339    }
340  }
341
342#if defined(ART_USE_LLVM_COMPILER)
343  if (type == kStatic) {
344    const CompiledInvokeStub* compiled_proxy_stub = compiler_->FindProxyStub(shorty);
345    if (compiled_proxy_stub != NULL) {
346      offset = CompiledMethod::AlignCode(offset, compiler_->GetInstructionSet());
347      DCHECK_ALIGNED(offset, kArmAlignment);
348      const std::vector<uint8_t>& proxy_stub = compiled_proxy_stub->GetCode();
349      uint32_t proxy_stub_size = proxy_stub.size() * sizeof(proxy_stub[0]);
350      CHECK_NE(proxy_stub_size, 0U);
351      uint32_t thumb_offset = compiled_proxy_stub->CodeDelta();
352      proxy_stub_offset = offset + sizeof(proxy_stub_size) + thumb_offset;
353
354      // Deduplicate proxy stubs
355      SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator stub_iter = code_offsets_.find(&proxy_stub);
356      if (stub_iter != code_offsets_.end()) {
357        proxy_stub_offset = stub_iter->second;
358      } else {
359        code_offsets_.Put(&proxy_stub, proxy_stub_offset);
360        offset += sizeof(proxy_stub_size);  // proxy stub size is prepended before code
361        offset += proxy_stub_size;
362        oat_header_->UpdateChecksum(&proxy_stub[0], proxy_stub_size);
363      }
364    }
365  }
366#endif
367
368  oat_classes_[oat_class_index]->method_offsets_[class_def_method_index]
369      = OatMethodOffsets(code_offset,
370                         frame_size_in_bytes,
371                         core_spill_mask,
372                         fp_spill_mask,
373                         mapping_table_offset,
374                         vmap_table_offset,
375                         gc_map_offset,
376                         invoke_stub_offset
377#if defined(ART_USE_LLVM_COMPILER)
378                       , proxy_stub_offset
379#endif
380                         );
381
382  if (compiler_->IsImage()) {
383    ClassLinker* linker = Runtime::Current()->GetClassLinker();
384    DexCache* dex_cache = linker->FindDexCache(*dex_file);
385    // Unchecked as we hold mutator_lock_ on entry.
386    ScopedObjectAccessUnchecked soa(Thread::Current());
387    Method* method = linker->ResolveMethod(*dex_file, method_idx, dex_cache,
388                                           soa.Decode<ClassLoader*>(class_loader_), type);
389    CHECK(method != NULL);
390    method->SetFrameSizeInBytes(frame_size_in_bytes);
391    method->SetCoreSpillMask(core_spill_mask);
392    method->SetFpSpillMask(fp_spill_mask);
393    method->SetOatMappingTableOffset(mapping_table_offset);
394    // Don't overwrite static method trampoline
395    if (!method->IsStatic() || method->IsConstructor() ||
396        method->GetDeclaringClass()->IsInitialized()) {
397      method->SetOatCodeOffset(code_offset);
398    } else {
399      method->SetCode(Runtime::Current()->GetResolutionStubArray(Runtime::kStaticMethod)->GetData());
400    }
401    method->SetOatVmapTableOffset(vmap_table_offset);
402    method->SetOatGcMapOffset(gc_map_offset);
403    method->SetOatInvokeStubOffset(invoke_stub_offset);
404  }
405
406  return offset;
407}
408
409#define DCHECK_CODE_OFFSET() \
410  DCHECK_EQ(static_cast<off_t>(code_offset), lseek(file->Fd(), 0, SEEK_CUR))
411
412bool OatWriter::Write(File* file) {
413  if (!file->WriteFully(oat_header_, sizeof(*oat_header_))) {
414    PLOG(ERROR) << "Failed to write oat header to " << file->name();
415    return false;
416  }
417
418  if (!file->WriteFully(image_file_location_.data(),
419                        image_file_location_.size())) {
420    PLOG(ERROR) << "Failed to write oat header image file location to " << file->name();
421    return false;
422  }
423
424  if (!WriteTables(file)) {
425    LOG(ERROR) << "Failed to write oat tables to " << file->name();
426    return false;
427  }
428
429  size_t code_offset = WriteCode(file);
430  if (code_offset == 0) {
431    LOG(ERROR) << "Failed to write oat code to " << file->name();
432    return false;
433  }
434
435  code_offset = WriteCodeDexFiles(file, code_offset);
436  if (code_offset == 0) {
437    LOG(ERROR) << "Failed to write oat code for dex files to " << file->name();
438    return false;
439  }
440
441  return true;
442}
443
444bool OatWriter::WriteTables(File* file) {
445  for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
446    if (!oat_dex_files_[i]->Write(file)) {
447      PLOG(ERROR) << "Failed to write oat dex information to " << file->name();
448      return false;
449    }
450  }
451  for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
452    uint32_t expected_offset = oat_dex_files_[i]->dex_file_offset_;
453    off_t actual_offset = lseek(file->Fd(), expected_offset, SEEK_SET);
454    if (static_cast<uint32_t>(actual_offset) != expected_offset) {
455      const DexFile* dex_file = (*dex_files_)[i];
456      PLOG(ERROR) << "Failed to seek to dex file section. Actual: " << actual_offset
457                  << " Expected: " << expected_offset << " File: " << dex_file->GetLocation();
458      return false;
459    }
460    const DexFile* dex_file = (*dex_files_)[i];
461    if (!file->WriteFully(&dex_file->GetHeader(), dex_file->GetHeader().file_size_)) {
462      PLOG(ERROR) << "Failed to write dex file " << dex_file->GetLocation() << " to " << file->name();
463      return false;
464    }
465  }
466  for (size_t i = 0; i != oat_classes_.size(); ++i) {
467    if (!oat_classes_[i]->Write(file)) {
468      PLOG(ERROR) << "Failed to write oat methods information to " << file->name();
469      return false;
470    }
471  }
472  return true;
473}
474
475size_t OatWriter::WriteCode(File* file) {
476  uint32_t code_offset = oat_header_->GetExecutableOffset();
477  off_t new_offset = lseek(file->Fd(), executable_offset_padding_length_, SEEK_CUR);
478  if (static_cast<uint32_t>(new_offset) != code_offset) {
479    PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
480                << " Expected: " << code_offset << " File: " << file->name();
481    return 0;
482  }
483  DCHECK_CODE_OFFSET();
484  return code_offset;
485}
486
487size_t OatWriter::WriteCodeDexFiles(File* file, size_t code_offset) {
488  size_t oat_class_index = 0;
489  for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
490    const DexFile* dex_file = (*dex_files_)[i];
491    CHECK(dex_file != NULL);
492    code_offset = WriteCodeDexFile(file, code_offset, oat_class_index, *dex_file);
493    if (code_offset == 0) {
494      return 0;
495    }
496  }
497  return code_offset;
498}
499
500size_t OatWriter::WriteCodeDexFile(File* file, size_t code_offset, size_t& oat_class_index,
501                                   const DexFile& dex_file) {
502  for (size_t class_def_index = 0; class_def_index < dex_file.NumClassDefs();
503      class_def_index++, oat_class_index++) {
504    const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
505    code_offset = WriteCodeClassDef(file, code_offset, oat_class_index, dex_file, class_def);
506    if (code_offset == 0) {
507      return 0;
508    }
509  }
510  return code_offset;
511}
512
513void OatWriter::ReportWriteFailure(const char* what, uint32_t method_idx,
514                                   const DexFile& dex_file, File* f) const {
515  PLOG(ERROR) << "Failed to write " << what << " for " << PrettyMethod(method_idx, dex_file)
516      << " to " << f->name();
517}
518
519size_t OatWriter::WriteCodeClassDef(File* file,
520                                    size_t code_offset, size_t oat_class_index,
521                                    const DexFile& dex_file,
522                                    const DexFile::ClassDef& class_def) {
523  const byte* class_data = dex_file.GetClassData(class_def);
524  if (class_data == NULL) {
525    // ie. an empty class such as a marker interface
526    return code_offset;
527  }
528  ClassDataItemIterator it(dex_file, class_data);
529  // Skip fields
530  while (it.HasNextStaticField()) {
531    it.Next();
532  }
533  while (it.HasNextInstanceField()) {
534    it.Next();
535  }
536  // Process methods
537  size_t class_def_method_index = 0;
538  while (it.HasNextDirectMethod()) {
539    bool is_static = (it.GetMemberAccessFlags() & kAccStatic) != 0;
540    code_offset = WriteCodeMethod(file, code_offset, oat_class_index, class_def_method_index,
541                                  is_static, it.GetMemberIndex(), dex_file);
542    if (code_offset == 0) {
543      return 0;
544    }
545    class_def_method_index++;
546    it.Next();
547  }
548  while (it.HasNextVirtualMethod()) {
549    code_offset = WriteCodeMethod(file, code_offset, oat_class_index, class_def_method_index,
550                                  false, it.GetMemberIndex(), dex_file);
551    if (code_offset == 0) {
552      return 0;
553    }
554    class_def_method_index++;
555    it.Next();
556  }
557  return code_offset;
558}
559
560size_t OatWriter::WriteCodeMethod(File* file, size_t code_offset, size_t oat_class_index,
561                                  size_t class_def_method_index, bool is_static,
562                                  uint32_t method_idx, const DexFile& dex_file) {
563  const CompiledMethod* compiled_method =
564      compiler_->GetCompiledMethod(Compiler::MethodReference(&dex_file, method_idx));
565
566  OatMethodOffsets method_offsets =
567      oat_classes_[oat_class_index]->method_offsets_[class_def_method_index];
568
569
570  if (compiled_method != NULL) {  // ie. not an abstract method
571    uint32_t aligned_code_offset = compiled_method->AlignCode(code_offset);
572    uint32_t aligned_code_delta = aligned_code_offset - code_offset;
573    if (aligned_code_delta != 0) {
574      off_t new_offset = lseek(file->Fd(), aligned_code_delta, SEEK_CUR);
575      if (static_cast<uint32_t>(new_offset) != aligned_code_offset) {
576        PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset
577                    << " Expected: " << aligned_code_offset << " File: " << file->name();
578        return 0;
579      }
580      code_offset += aligned_code_delta;
581      DCHECK_CODE_OFFSET();
582    }
583    DCHECK_ALIGNED(code_offset, kArmAlignment);
584    const std::vector<uint8_t>& code = compiled_method->GetCode();
585    uint32_t code_size = code.size() * sizeof(code[0]);
586    CHECK_NE(code_size, 0U);
587
588    // Deduplicate code arrays
589    size_t offset = code_offset + sizeof(code_size) + compiled_method->CodeDelta();
590    SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = code_offsets_.find(&code);
591    if (code_iter != code_offsets_.end() && offset != method_offsets.code_offset_) {
592      DCHECK(code_iter->second == method_offsets.code_offset_) << PrettyMethod(method_idx, dex_file);
593    } else {
594      DCHECK(offset == method_offsets.code_offset_) << PrettyMethod(method_idx, dex_file);
595      if (!file->WriteFully(&code_size, sizeof(code_size))) {
596        ReportWriteFailure("method code size", method_idx, dex_file, file);
597        return 0;
598      }
599      code_offset += sizeof(code_size);
600      DCHECK_CODE_OFFSET();
601      if (!file->WriteFully(&code[0], code_size)) {
602        ReportWriteFailure("method code", method_idx, dex_file, file);
603        return 0;
604      }
605      code_offset += code_size;
606    }
607    DCHECK_CODE_OFFSET();
608
609    const std::vector<uint32_t>& mapping_table = compiled_method->GetMappingTable();
610    size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]);
611
612    // Deduplicate mapping tables
613    SafeMap<const std::vector<uint32_t>*, uint32_t>::iterator mapping_iter =
614        mapping_table_offsets_.find(&mapping_table);
615    if (mapping_iter != mapping_table_offsets_.end() &&
616        code_offset != method_offsets.mapping_table_offset_) {
617      DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0)
618          || mapping_iter->second == method_offsets.mapping_table_offset_)
619          << PrettyMethod(method_idx, dex_file);
620    } else {
621      DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0)
622          || code_offset == method_offsets.mapping_table_offset_)
623          << PrettyMethod(method_idx, dex_file);
624      if (!file->WriteFully(&mapping_table[0], mapping_table_size)) {
625        ReportWriteFailure("mapping table", method_idx, dex_file, file);
626        return 0;
627      }
628      code_offset += mapping_table_size;
629    }
630    DCHECK_CODE_OFFSET();
631
632    const std::vector<uint16_t>& vmap_table = compiled_method->GetVmapTable();
633    size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]);
634
635    // Deduplicate vmap tables
636    SafeMap<const std::vector<uint16_t>*, uint32_t>::iterator vmap_iter =
637        vmap_table_offsets_.find(&vmap_table);
638    if (vmap_iter != vmap_table_offsets_.end() &&
639        code_offset != method_offsets.vmap_table_offset_) {
640      DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0)
641          || vmap_iter->second == method_offsets.vmap_table_offset_)
642          << PrettyMethod(method_idx, dex_file);
643    } else {
644      DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0)
645          || code_offset == method_offsets.vmap_table_offset_)
646          << PrettyMethod(method_idx, dex_file);
647      if (!file->WriteFully(&vmap_table[0], vmap_table_size)) {
648        ReportWriteFailure("vmap table", method_idx, dex_file, file);
649        return 0;
650      }
651      code_offset += vmap_table_size;
652    }
653    DCHECK_CODE_OFFSET();
654
655    const std::vector<uint8_t>& gc_map = compiled_method->GetGcMap();
656    size_t gc_map_size = gc_map.size() * sizeof(gc_map[0]);
657
658    // Deduplicate GC maps
659    SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator gc_map_iter =
660        gc_map_offsets_.find(&gc_map);
661    if (gc_map_iter != gc_map_offsets_.end() &&
662        code_offset != method_offsets.gc_map_offset_) {
663      DCHECK((gc_map_size == 0 && method_offsets.gc_map_offset_ == 0)
664          || gc_map_iter->second == method_offsets.gc_map_offset_)
665          << PrettyMethod(method_idx, dex_file);
666    } else {
667      DCHECK((gc_map_size == 0 && method_offsets.gc_map_offset_ == 0)
668          || code_offset == method_offsets.gc_map_offset_)
669          << PrettyMethod(method_idx, dex_file);
670      if (!file->WriteFully(&gc_map[0], gc_map_size)) {
671        ReportWriteFailure("GC map", method_idx, dex_file, file);
672        return 0;
673      }
674      code_offset += gc_map_size;
675    }
676    DCHECK_CODE_OFFSET();
677  }
678  const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx));
679  const CompiledInvokeStub* compiled_invoke_stub = compiler_->FindInvokeStub(is_static, shorty);
680  if (compiled_invoke_stub != NULL) {
681    uint32_t aligned_code_offset = CompiledMethod::AlignCode(code_offset,
682                                                             compiler_->GetInstructionSet());
683    uint32_t aligned_code_delta = aligned_code_offset - code_offset;
684    if (aligned_code_delta != 0) {
685      off_t new_offset = lseek(file->Fd(), aligned_code_delta, SEEK_CUR);
686      if (static_cast<uint32_t>(new_offset) != aligned_code_offset) {
687        PLOG(ERROR) << "Failed to seek to align invoke stub code. Actual: " << new_offset
688                    << " Expected: " << aligned_code_offset;
689        return 0;
690      }
691      code_offset += aligned_code_delta;
692      DCHECK_CODE_OFFSET();
693    }
694    DCHECK_ALIGNED(code_offset, kArmAlignment);
695    const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode();
696    uint32_t invoke_stub_size = invoke_stub.size() * sizeof(invoke_stub[0]);
697    CHECK_NE(invoke_stub_size, 0U);
698
699    // Deduplicate invoke stubs
700    size_t offset = code_offset + sizeof(invoke_stub_size) + compiled_invoke_stub->CodeDelta();
701    SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator stub_iter =
702        code_offsets_.find(&invoke_stub);
703    if (stub_iter != code_offsets_.end() && offset != method_offsets.invoke_stub_offset_) {
704      DCHECK(stub_iter->second == method_offsets.invoke_stub_offset_) << PrettyMethod(method_idx, dex_file);
705    } else {
706      DCHECK(offset == method_offsets.invoke_stub_offset_) << PrettyMethod(method_idx, dex_file);
707      if (!file->WriteFully(&invoke_stub_size, sizeof(invoke_stub_size))) {
708        ReportWriteFailure("invoke stub code size", method_idx, dex_file, file);
709        return 0;
710      }
711      code_offset += sizeof(invoke_stub_size);
712      DCHECK_CODE_OFFSET();
713      if (!file->WriteFully(&invoke_stub[0], invoke_stub_size)) {
714        ReportWriteFailure("invoke stub code", method_idx, dex_file, file);
715        return 0;
716      }
717      code_offset += invoke_stub_size;
718      DCHECK_CODE_OFFSET();
719    }
720  }
721
722#if defined(ART_USE_LLVM_COMPILER)
723  if (is_static) {
724    const CompiledInvokeStub* compiled_proxy_stub = compiler_->FindProxyStub(shorty);
725    if (compiled_proxy_stub != NULL) {
726      uint32_t aligned_code_offset = CompiledMethod::AlignCode(code_offset,
727                                                               compiler_->GetInstructionSet());
728      uint32_t aligned_code_delta = aligned_code_offset - code_offset;
729      CHECK(aligned_code_delta < 48u);
730      if (aligned_code_delta != 0) {
731        off_t new_offset = lseek(file->Fd(), aligned_code_delta, SEEK_CUR);
732        if (static_cast<uint32_t>(new_offset) != aligned_code_offset) {
733          PLOG(ERROR) << "Failed to seek to align proxy stub code. Actual: " << new_offset
734                      << " Expected: " << aligned_code_offset;
735          return 0;
736        }
737        code_offset += aligned_code_delta;
738        DCHECK_CODE_OFFSET();
739      }
740      DCHECK_ALIGNED(code_offset, kArmAlignment);
741      const std::vector<uint8_t>& proxy_stub = compiled_proxy_stub->GetCode();
742      uint32_t proxy_stub_size = proxy_stub.size() * sizeof(proxy_stub[0]);
743      CHECK_NE(proxy_stub_size, 0U);
744
745      // Deduplicate proxy stubs
746      size_t offset = code_offset + sizeof(proxy_stub_size) + compiled_proxy_stub->CodeDelta();
747      SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator stub_iter =
748          code_offsets_.find(&proxy_stub);
749      if (stub_iter != code_offsets_.end() && offset != method_offsets.proxy_stub_offset_) {
750        DCHECK(stub_iter->second == method_offsets.proxy_stub_offset_) << PrettyMethod(method_idx, dex_file);
751      } else {
752        DCHECK(offset == method_offsets.proxy_stub_offset_) << PrettyMethod(method_idx, dex_file);
753        if (!file->WriteFully(&proxy_stub_size, sizeof(proxy_stub_size))) {
754          ReportWriteFailure("proxy stub code size", method_idx, dex_file, file);
755          return 0;
756        }
757        code_offset += sizeof(proxy_stub_size);
758        DCHECK_CODE_OFFSET();
759        if (!file->WriteFully(&proxy_stub[0], proxy_stub_size)) {
760          ReportWriteFailure("proxy stub code", method_idx, dex_file, file);
761          return 0;
762        }
763        code_offset += proxy_stub_size;
764        DCHECK_CODE_OFFSET();
765      }
766      DCHECK_CODE_OFFSET();
767    }
768  }
769#endif
770
771  return code_offset;
772}
773
774OatWriter::OatDexFile::OatDexFile(const DexFile& dex_file) {
775  const std::string& location(dex_file.GetLocation());
776  dex_file_location_size_ = location.size();
777  dex_file_location_data_ = reinterpret_cast<const uint8_t*>(location.data());
778  dex_file_location_checksum_ = dex_file.GetLocationChecksum();
779  dex_file_offset_ = 0;
780  methods_offsets_.resize(dex_file.NumClassDefs());
781}
782
783size_t OatWriter::OatDexFile::SizeOf() const {
784  return sizeof(dex_file_location_size_)
785          + dex_file_location_size_
786          + sizeof(dex_file_location_checksum_)
787          + sizeof(dex_file_offset_)
788          + (sizeof(methods_offsets_[0]) * methods_offsets_.size());
789}
790
791void OatWriter::OatDexFile::UpdateChecksum(OatHeader& oat_header) const {
792  oat_header.UpdateChecksum(&dex_file_location_size_, sizeof(dex_file_location_size_));
793  oat_header.UpdateChecksum(dex_file_location_data_, dex_file_location_size_);
794  oat_header.UpdateChecksum(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_));
795  oat_header.UpdateChecksum(&dex_file_offset_, sizeof(dex_file_offset_));
796  oat_header.UpdateChecksum(&methods_offsets_[0],
797                            sizeof(methods_offsets_[0]) * methods_offsets_.size());
798}
799
800bool OatWriter::OatDexFile::Write(File* file) const {
801  if (!file->WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
802    PLOG(ERROR) << "Failed to write dex file location length to " << file->name();
803    return false;
804  }
805  if (!file->WriteFully(dex_file_location_data_, dex_file_location_size_)) {
806    PLOG(ERROR) << "Failed to write dex file location data to " << file->name();
807    return false;
808  }
809  if (!file->WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) {
810    PLOG(ERROR) << "Failed to write dex file location checksum to " << file->name();
811    return false;
812  }
813  if (!file->WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
814    PLOG(ERROR) << "Failed to write dex file offset to " << file->name();
815    return false;
816  }
817  if (!file->WriteFully(&methods_offsets_[0],
818                        sizeof(methods_offsets_[0]) * methods_offsets_.size())) {
819    PLOG(ERROR) << "Failed to write methods offsets to " << file->name();
820    return false;
821  }
822  return true;
823}
824
825OatWriter::OatClass::OatClass(Class::Status status, uint32_t methods_count) {
826  status_ = status;
827  method_offsets_.resize(methods_count);
828}
829
830size_t OatWriter::OatClass::SizeOf() const {
831  return sizeof(status_)
832          + (sizeof(method_offsets_[0]) * method_offsets_.size());
833}
834
835void OatWriter::OatClass::UpdateChecksum(OatHeader& oat_header) const {
836  oat_header.UpdateChecksum(&status_, sizeof(status_));
837  oat_header.UpdateChecksum(&method_offsets_[0],
838                            sizeof(method_offsets_[0]) * method_offsets_.size());
839}
840
841bool OatWriter::OatClass::Write(File* file) const {
842  if (!file->WriteFully(&status_, sizeof(status_))) {
843    PLOG(ERROR) << "Failed to write class status to " << file->name();
844    return false;
845  }
846  if (!file->WriteFully(&method_offsets_[0],
847                        sizeof(method_offsets_[0]) * method_offsets_.size())) {
848    PLOG(ERROR) << "Failed to write method offsets to " << file->name();
849    return false;
850  }
851  return true;
852}
853
854}  // namespace art
855