• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "base/stl_util.h"
22 #include "base/unix_file/fd_file.h"
23 #include "class_linker.h"
24 #include "dex_file-inl.h"
25 #include "gc/space/space.h"
26 #include "mirror/art_method-inl.h"
27 #include "mirror/array.h"
28 #include "mirror/class_loader.h"
29 #include "mirror/object-inl.h"
30 #include "os.h"
31 #include "output_stream.h"
32 #include "safe_map.h"
33 #include "scoped_thread_state_change.h"
34 #include "verifier/method_verifier.h"
35 
36 namespace art {
37 
OatWriter(const std::vector<const DexFile * > & dex_files,uint32_t image_file_location_oat_checksum,uint32_t image_file_location_oat_begin,const std::string & image_file_location,const CompilerDriver * compiler)38 OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files,
39                      uint32_t image_file_location_oat_checksum,
40                      uint32_t image_file_location_oat_begin,
41                      const std::string& image_file_location,
42                      const CompilerDriver* compiler)
43   : compiler_driver_(compiler),
44     dex_files_(&dex_files),
45     image_file_location_oat_checksum_(image_file_location_oat_checksum),
46     image_file_location_oat_begin_(image_file_location_oat_begin),
47     image_file_location_(image_file_location),
48     oat_header_(NULL),
49     size_dex_file_alignment_(0),
50     size_executable_offset_alignment_(0),
51     size_oat_header_(0),
52     size_oat_header_image_file_location_(0),
53     size_dex_file_(0),
54     size_interpreter_to_interpreter_bridge_(0),
55     size_interpreter_to_compiled_code_bridge_(0),
56     size_jni_dlsym_lookup_(0),
57     size_portable_resolution_trampoline_(0),
58     size_portable_to_interpreter_bridge_(0),
59     size_quick_resolution_trampoline_(0),
60     size_quick_to_interpreter_bridge_(0),
61     size_trampoline_alignment_(0),
62     size_code_size_(0),
63     size_code_(0),
64     size_code_alignment_(0),
65     size_mapping_table_(0),
66     size_vmap_table_(0),
67     size_gc_map_(0),
68     size_oat_dex_file_location_size_(0),
69     size_oat_dex_file_location_data_(0),
70     size_oat_dex_file_location_checksum_(0),
71     size_oat_dex_file_offset_(0),
72     size_oat_dex_file_methods_offsets_(0),
73     size_oat_class_status_(0),
74     size_oat_class_method_offsets_(0) {
75   size_t offset = InitOatHeader();
76   offset = InitOatDexFiles(offset);
77   offset = InitDexFiles(offset);
78   offset = InitOatClasses(offset);
79   offset = InitOatCode(offset);
80   offset = InitOatCodeDexFiles(offset);
81   size_ = offset;
82 
83   CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
84   CHECK(image_file_location.empty() == compiler->IsImage());
85 }
86 
~OatWriter()87 OatWriter::~OatWriter() {
88   delete oat_header_;
89   STLDeleteElements(&oat_dex_files_);
90   STLDeleteElements(&oat_classes_);
91 }
92 
InitOatHeader()93 size_t OatWriter::InitOatHeader() {
94   // create the OatHeader
95   oat_header_ = new OatHeader(compiler_driver_->GetInstructionSet(),
96                               dex_files_,
97                               image_file_location_oat_checksum_,
98                               image_file_location_oat_begin_,
99                               image_file_location_);
100   size_t offset = sizeof(*oat_header_);
101   offset += image_file_location_.size();
102   return offset;
103 }
104 
InitOatDexFiles(size_t offset)105 size_t OatWriter::InitOatDexFiles(size_t offset) {
106   // create the OatDexFiles
107   for (size_t i = 0; i != dex_files_->size(); ++i) {
108     const DexFile* dex_file = (*dex_files_)[i];
109     CHECK(dex_file != NULL);
110     OatDexFile* oat_dex_file = new OatDexFile(offset, *dex_file);
111     oat_dex_files_.push_back(oat_dex_file);
112     offset += oat_dex_file->SizeOf();
113   }
114   return offset;
115 }
116 
InitDexFiles(size_t offset)117 size_t OatWriter::InitDexFiles(size_t offset) {
118   // calculate the offsets within OatDexFiles to the DexFiles
119   for (size_t i = 0; i != dex_files_->size(); ++i) {
120     // dex files are required to be 4 byte aligned
121     size_t original_offset = offset;
122     offset = RoundUp(offset, 4);
123     size_dex_file_alignment_ += offset - original_offset;
124 
125     // set offset in OatDexFile to DexFile
126     oat_dex_files_[i]->dex_file_offset_ = offset;
127 
128     const DexFile* dex_file = (*dex_files_)[i];
129     offset += dex_file->GetHeader().file_size_;
130   }
131   return offset;
132 }
133 
InitOatClasses(size_t offset)134 size_t OatWriter::InitOatClasses(size_t offset) {
135   // create the OatClasses
136   // calculate the offsets within OatDexFiles to OatClasses
137   for (size_t i = 0; i != dex_files_->size(); ++i) {
138     const DexFile* dex_file = (*dex_files_)[i];
139     for (size_t class_def_index = 0;
140          class_def_index < dex_file->NumClassDefs();
141          class_def_index++) {
142       oat_dex_files_[i]->methods_offsets_[class_def_index] = offset;
143       const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
144       const byte* class_data = dex_file->GetClassData(class_def);
145       uint32_t num_methods = 0;
146       if (class_data != NULL) {  // ie not an empty class, such as a marker interface
147         ClassDataItemIterator it(*dex_file, class_data);
148         size_t num_direct_methods = it.NumDirectMethods();
149         size_t num_virtual_methods = it.NumVirtualMethods();
150         num_methods = num_direct_methods + num_virtual_methods;
151       }
152 
153       ClassReference class_ref(dex_file, class_def_index);
154       CompiledClass* compiled_class = compiler_driver_->GetCompiledClass(class_ref);
155       mirror::Class::Status status;
156       if (compiled_class != NULL) {
157         status = compiled_class->GetStatus();
158       } else if (verifier::MethodVerifier::IsClassRejected(class_ref)) {
159         status = mirror::Class::kStatusError;
160       } else {
161         status = mirror::Class::kStatusNotReady;
162       }
163 
164       OatClass* oat_class = new OatClass(offset, status, num_methods);
165       oat_classes_.push_back(oat_class);
166       offset += oat_class->SizeOf();
167     }
168     oat_dex_files_[i]->UpdateChecksum(*oat_header_);
169   }
170   return offset;
171 }
172 
InitOatCode(size_t offset)173 size_t OatWriter::InitOatCode(size_t offset) {
174   // calculate the offsets within OatHeader to executable code
175   size_t old_offset = offset;
176   // required to be on a new page boundary
177   offset = RoundUp(offset, kPageSize);
178   oat_header_->SetExecutableOffset(offset);
179   size_executable_offset_alignment_ = offset - old_offset;
180   if (compiler_driver_->IsImage()) {
181     InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
182 
183     #define DO_TRAMPOLINE(field, fn_name) \
184       offset = CompiledCode::AlignCode(offset, instruction_set); \
185       oat_header_->Set ## fn_name ## Offset(offset); \
186       field.reset(compiler_driver_->Create ## fn_name()); \
187       offset += field->size();
188 
189     DO_TRAMPOLINE(interpreter_to_interpreter_bridge_, InterpreterToInterpreterBridge);
190     DO_TRAMPOLINE(interpreter_to_compiled_code_bridge_, InterpreterToCompiledCodeBridge);
191     DO_TRAMPOLINE(jni_dlsym_lookup_, JniDlsymLookup);
192     DO_TRAMPOLINE(portable_resolution_trampoline_, PortableResolutionTrampoline);
193     DO_TRAMPOLINE(portable_to_interpreter_bridge_, PortableToInterpreterBridge);
194     DO_TRAMPOLINE(quick_resolution_trampoline_, QuickResolutionTrampoline);
195     DO_TRAMPOLINE(quick_to_interpreter_bridge_, QuickToInterpreterBridge);
196 
197     #undef DO_TRAMPOLINE
198   } else {
199     oat_header_->SetInterpreterToInterpreterBridgeOffset(0);
200     oat_header_->SetInterpreterToCompiledCodeBridgeOffset(0);
201     oat_header_->SetJniDlsymLookupOffset(0);
202     oat_header_->SetPortableResolutionTrampolineOffset(0);
203     oat_header_->SetPortableToInterpreterBridgeOffset(0);
204     oat_header_->SetQuickResolutionTrampolineOffset(0);
205     oat_header_->SetQuickToInterpreterBridgeOffset(0);
206   }
207   return offset;
208 }
209 
InitOatCodeDexFiles(size_t offset)210 size_t OatWriter::InitOatCodeDexFiles(size_t offset) {
211   size_t oat_class_index = 0;
212   for (size_t i = 0; i != dex_files_->size(); ++i) {
213     const DexFile* dex_file = (*dex_files_)[i];
214     CHECK(dex_file != NULL);
215     offset = InitOatCodeDexFile(offset, oat_class_index, *dex_file);
216   }
217   return offset;
218 }
219 
InitOatCodeDexFile(size_t offset,size_t & oat_class_index,const DexFile & dex_file)220 size_t OatWriter::InitOatCodeDexFile(size_t offset,
221                                      size_t& oat_class_index,
222                                      const DexFile& dex_file) {
223   for (size_t class_def_index = 0;
224        class_def_index < dex_file.NumClassDefs();
225        class_def_index++, oat_class_index++) {
226     const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
227     offset = InitOatCodeClassDef(offset, oat_class_index, class_def_index, dex_file, class_def);
228     oat_classes_[oat_class_index]->UpdateChecksum(*oat_header_);
229   }
230   return offset;
231 }
232 
InitOatCodeClassDef(size_t offset,size_t oat_class_index,size_t class_def_index,const DexFile & dex_file,const DexFile::ClassDef & class_def)233 size_t OatWriter::InitOatCodeClassDef(size_t offset,
234                                       size_t oat_class_index, size_t class_def_index,
235                                       const DexFile& dex_file,
236                                       const DexFile::ClassDef& class_def) {
237   const byte* class_data = dex_file.GetClassData(class_def);
238   if (class_data == NULL) {
239     // empty class, such as a marker interface
240     return offset;
241   }
242   ClassDataItemIterator it(dex_file, class_data);
243   CHECK_EQ(oat_classes_[oat_class_index]->method_offsets_.size(),
244            it.NumDirectMethods() + it.NumVirtualMethods());
245   // Skip fields
246   while (it.HasNextStaticField()) {
247     it.Next();
248   }
249   while (it.HasNextInstanceField()) {
250     it.Next();
251   }
252   // Process methods
253   size_t class_def_method_index = 0;
254   while (it.HasNextDirectMethod()) {
255     bool is_native = (it.GetMemberAccessFlags() & kAccNative) != 0;
256     offset = InitOatCodeMethod(offset, oat_class_index, class_def_index, class_def_method_index,
257                                is_native, it.GetMethodInvokeType(class_def), it.GetMemberIndex(),
258                                &dex_file);
259     class_def_method_index++;
260     it.Next();
261   }
262   while (it.HasNextVirtualMethod()) {
263     bool is_native = (it.GetMemberAccessFlags() & kAccNative) != 0;
264     offset = InitOatCodeMethod(offset, oat_class_index, class_def_index, class_def_method_index,
265                                is_native, it.GetMethodInvokeType(class_def), it.GetMemberIndex(),
266                                &dex_file);
267     class_def_method_index++;
268     it.Next();
269   }
270   DCHECK(!it.HasNext());
271   return offset;
272 }
273 
InitOatCodeMethod(size_t offset,size_t oat_class_index,size_t class_def_index,size_t class_def_method_index,bool is_native,InvokeType invoke_type,uint32_t method_idx,const DexFile * dex_file)274 size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index,
275                                     size_t __attribute__((unused)) class_def_index,
276                                     size_t class_def_method_index,
277                                     bool __attribute__((unused)) is_native,
278                                     InvokeType invoke_type,
279                                     uint32_t method_idx, const DexFile* dex_file) {
280   // derived from CompiledMethod if available
281   uint32_t code_offset = 0;
282   uint32_t frame_size_in_bytes = kStackAlignment;
283   uint32_t core_spill_mask = 0;
284   uint32_t fp_spill_mask = 0;
285   uint32_t mapping_table_offset = 0;
286   uint32_t vmap_table_offset = 0;
287   uint32_t gc_map_offset = 0;
288 
289   OatClass* oat_class = oat_classes_[oat_class_index];
290 #if defined(ART_USE_PORTABLE_COMPILER)
291   size_t oat_method_offsets_offset =
292       oat_class->GetOatMethodOffsetsOffsetFromOatHeader(class_def_method_index);
293 #endif
294 
295   CompiledMethod* compiled_method =
296       compiler_driver_->GetCompiledMethod(MethodReference(dex_file, method_idx));
297   if (compiled_method != NULL) {
298 #if defined(ART_USE_PORTABLE_COMPILER)
299     compiled_method->AddOatdataOffsetToCompliledCodeOffset(
300         oat_method_offsets_offset + OFFSETOF_MEMBER(OatMethodOffsets, code_offset_));
301 #else
302     const std::vector<uint8_t>& code = compiled_method->GetCode();
303     offset = compiled_method->AlignCode(offset);
304     DCHECK_ALIGNED(offset, kArmAlignment);
305     uint32_t code_size = code.size() * sizeof(code[0]);
306     CHECK_NE(code_size, 0U);
307     uint32_t thumb_offset = compiled_method->CodeDelta();
308     code_offset = offset + sizeof(code_size) + thumb_offset;
309 
310     // Deduplicate code arrays
311     SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = code_offsets_.find(&code);
312     if (code_iter != code_offsets_.end()) {
313       code_offset = code_iter->second;
314     } else {
315       code_offsets_.Put(&code, code_offset);
316       offset += sizeof(code_size);  // code size is prepended before code
317       offset += code_size;
318       oat_header_->UpdateChecksum(&code[0], code_size);
319     }
320 #endif
321     frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
322     core_spill_mask = compiled_method->GetCoreSpillMask();
323     fp_spill_mask = compiled_method->GetFpSpillMask();
324 
325     const std::vector<uint8_t>& mapping_table = compiled_method->GetMappingTable();
326     size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]);
327     mapping_table_offset = (mapping_table_size == 0) ? 0 : offset;
328 
329     // Deduplicate mapping tables
330     SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator mapping_iter =
331         mapping_table_offsets_.find(&mapping_table);
332     if (mapping_iter != mapping_table_offsets_.end()) {
333       mapping_table_offset = mapping_iter->second;
334     } else {
335       mapping_table_offsets_.Put(&mapping_table, mapping_table_offset);
336       offset += mapping_table_size;
337       oat_header_->UpdateChecksum(&mapping_table[0], mapping_table_size);
338     }
339 
340     const std::vector<uint8_t>& vmap_table = compiled_method->GetVmapTable();
341     size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]);
342     vmap_table_offset = (vmap_table_size == 0) ? 0 : offset;
343 
344     // Deduplicate vmap tables
345     SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator vmap_iter =
346         vmap_table_offsets_.find(&vmap_table);
347     if (vmap_iter != vmap_table_offsets_.end()) {
348       vmap_table_offset = vmap_iter->second;
349     } else {
350       vmap_table_offsets_.Put(&vmap_table, vmap_table_offset);
351       offset += vmap_table_size;
352       oat_header_->UpdateChecksum(&vmap_table[0], vmap_table_size);
353     }
354 
355     const std::vector<uint8_t>& gc_map = compiled_method->GetGcMap();
356     size_t gc_map_size = gc_map.size() * sizeof(gc_map[0]);
357     gc_map_offset = (gc_map_size == 0) ? 0 : offset;
358 
359 #if !defined(NDEBUG)
360     // We expect GC maps except when the class hasn't been verified or the method is native
361     ClassReference class_ref(dex_file, class_def_index);
362     CompiledClass* compiled_class = compiler_driver_->GetCompiledClass(class_ref);
363     mirror::Class::Status status;
364     if (compiled_class != NULL) {
365       status = compiled_class->GetStatus();
366     } else if (verifier::MethodVerifier::IsClassRejected(class_ref)) {
367       status = mirror::Class::kStatusError;
368     } else {
369       status = mirror::Class::kStatusNotReady;
370     }
371     CHECK(gc_map_size != 0 || is_native || status < mirror::Class::kStatusVerified)
372         << &gc_map << " " << gc_map_size << " " << (is_native ? "true" : "false") << " "
373         << (status < mirror::Class::kStatusVerified) << " " << status << " "
374         << PrettyMethod(method_idx, *dex_file);
375 #endif
376 
377     // Deduplicate GC maps
378     SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator gc_map_iter =
379         gc_map_offsets_.find(&gc_map);
380     if (gc_map_iter != gc_map_offsets_.end()) {
381       gc_map_offset = gc_map_iter->second;
382     } else {
383       gc_map_offsets_.Put(&gc_map, gc_map_offset);
384       offset += gc_map_size;
385       oat_header_->UpdateChecksum(&gc_map[0], gc_map_size);
386     }
387   }
388 
389   oat_class->method_offsets_[class_def_method_index] =
390       OatMethodOffsets(code_offset,
391                        frame_size_in_bytes,
392                        core_spill_mask,
393                        fp_spill_mask,
394                        mapping_table_offset,
395                        vmap_table_offset,
396                        gc_map_offset);
397 
398   if (compiler_driver_->IsImage()) {
399     ClassLinker* linker = Runtime::Current()->GetClassLinker();
400     mirror::DexCache* dex_cache = linker->FindDexCache(*dex_file);
401     // Unchecked as we hold mutator_lock_ on entry.
402     ScopedObjectAccessUnchecked soa(Thread::Current());
403     mirror::ArtMethod* method = linker->ResolveMethod(*dex_file, method_idx, dex_cache,
404                                                            NULL, NULL, invoke_type);
405     CHECK(method != NULL);
406     method->SetFrameSizeInBytes(frame_size_in_bytes);
407     method->SetCoreSpillMask(core_spill_mask);
408     method->SetFpSpillMask(fp_spill_mask);
409     method->SetOatMappingTableOffset(mapping_table_offset);
410     // Don't overwrite static method trampoline
411     if (!method->IsStatic() || method->IsConstructor() ||
412         method->GetDeclaringClass()->IsInitialized()) {
413       method->SetOatCodeOffset(code_offset);
414     } else {
415       method->SetEntryPointFromCompiledCode(NULL);
416     }
417     method->SetOatVmapTableOffset(vmap_table_offset);
418     method->SetOatNativeGcMapOffset(gc_map_offset);
419   }
420 
421   return offset;
422 }
423 
424 #define DCHECK_OFFSET() \
425   DCHECK_EQ(static_cast<off_t>(file_offset + relative_offset), out.Seek(0, kSeekCurrent)) \
426     << "file_offset=" << file_offset << " relative_offset=" << relative_offset
427 
428 #define DCHECK_OFFSET_() \
429   DCHECK_EQ(static_cast<off_t>(file_offset + offset_), out.Seek(0, kSeekCurrent)) \
430     << "file_offset=" << file_offset << " offset_=" << offset_
431 
Write(OutputStream & out)432 bool OatWriter::Write(OutputStream& out) {
433   const size_t file_offset = out.Seek(0, kSeekCurrent);
434 
435   if (!out.WriteFully(oat_header_, sizeof(*oat_header_))) {
436     PLOG(ERROR) << "Failed to write oat header to " << out.GetLocation();
437     return false;
438   }
439   size_oat_header_ += sizeof(*oat_header_);
440 
441   if (!out.WriteFully(image_file_location_.data(), image_file_location_.size())) {
442     PLOG(ERROR) << "Failed to write oat header image file location to " << out.GetLocation();
443     return false;
444   }
445   size_oat_header_image_file_location_ += image_file_location_.size();
446 
447   if (!WriteTables(out, file_offset)) {
448     LOG(ERROR) << "Failed to write oat tables to " << out.GetLocation();
449     return false;
450   }
451 
452   size_t relative_offset = WriteCode(out, file_offset);
453   if (relative_offset == 0) {
454     LOG(ERROR) << "Failed to write oat code to " << out.GetLocation();
455     return false;
456   }
457 
458   relative_offset = WriteCodeDexFiles(out, file_offset, relative_offset);
459   if (relative_offset == 0) {
460     LOG(ERROR) << "Failed to write oat code for dex files to " << out.GetLocation();
461     return false;
462   }
463 
464   if (kIsDebugBuild) {
465     uint32_t size_total = 0;
466     #define DO_STAT(x) \
467       VLOG(compiler) << #x "=" << PrettySize(x) << " (" << x << "B)"; \
468       size_total += x;
469 
470     DO_STAT(size_dex_file_alignment_);
471     DO_STAT(size_executable_offset_alignment_);
472     DO_STAT(size_oat_header_);
473     DO_STAT(size_oat_header_image_file_location_);
474     DO_STAT(size_dex_file_);
475     DO_STAT(size_interpreter_to_interpreter_bridge_);
476     DO_STAT(size_interpreter_to_compiled_code_bridge_);
477     DO_STAT(size_jni_dlsym_lookup_);
478     DO_STAT(size_portable_resolution_trampoline_);
479     DO_STAT(size_portable_to_interpreter_bridge_);
480     DO_STAT(size_quick_resolution_trampoline_);
481     DO_STAT(size_quick_to_interpreter_bridge_);
482     DO_STAT(size_trampoline_alignment_);
483     DO_STAT(size_code_size_);
484     DO_STAT(size_code_);
485     DO_STAT(size_code_alignment_);
486     DO_STAT(size_mapping_table_);
487     DO_STAT(size_vmap_table_);
488     DO_STAT(size_gc_map_);
489     DO_STAT(size_oat_dex_file_location_size_);
490     DO_STAT(size_oat_dex_file_location_data_);
491     DO_STAT(size_oat_dex_file_location_checksum_);
492     DO_STAT(size_oat_dex_file_offset_);
493     DO_STAT(size_oat_dex_file_methods_offsets_);
494     DO_STAT(size_oat_class_status_);
495     DO_STAT(size_oat_class_method_offsets_);
496     #undef DO_STAT
497 
498     VLOG(compiler) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)"; \
499     CHECK_EQ(file_offset + size_total, static_cast<uint32_t>(out.Seek(0, kSeekCurrent)));
500     CHECK_EQ(size_, size_total);
501   }
502 
503   CHECK_EQ(file_offset + size_, static_cast<uint32_t>(out.Seek(0, kSeekCurrent)));
504   CHECK_EQ(size_, relative_offset);
505 
506   return true;
507 }
508 
WriteTables(OutputStream & out,const size_t file_offset)509 bool OatWriter::WriteTables(OutputStream& out, const size_t file_offset) {
510   for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
511     if (!oat_dex_files_[i]->Write(this, out, file_offset)) {
512       PLOG(ERROR) << "Failed to write oat dex information to " << out.GetLocation();
513       return false;
514     }
515   }
516   for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
517     uint32_t expected_offset = file_offset + oat_dex_files_[i]->dex_file_offset_;
518     off_t actual_offset = out.Seek(expected_offset, kSeekSet);
519     if (static_cast<uint32_t>(actual_offset) != expected_offset) {
520       const DexFile* dex_file = (*dex_files_)[i];
521       PLOG(ERROR) << "Failed to seek to dex file section. Actual: " << actual_offset
522                   << " Expected: " << expected_offset << " File: " << dex_file->GetLocation();
523       return false;
524     }
525     const DexFile* dex_file = (*dex_files_)[i];
526     if (!out.WriteFully(&dex_file->GetHeader(), dex_file->GetHeader().file_size_)) {
527       PLOG(ERROR) << "Failed to write dex file " << dex_file->GetLocation()
528                   << " to " << out.GetLocation();
529       return false;
530     }
531     size_dex_file_ += dex_file->GetHeader().file_size_;
532   }
533   for (size_t i = 0; i != oat_classes_.size(); ++i) {
534     if (!oat_classes_[i]->Write(this, out, file_offset)) {
535       PLOG(ERROR) << "Failed to write oat methods information to " << out.GetLocation();
536       return false;
537     }
538   }
539   return true;
540 }
541 
WriteCode(OutputStream & out,const size_t file_offset)542 size_t OatWriter::WriteCode(OutputStream& out, const size_t file_offset) {
543   size_t relative_offset = oat_header_->GetExecutableOffset();
544   off_t new_offset = out.Seek(size_executable_offset_alignment_, kSeekCurrent);
545   size_t expected_file_offset = file_offset + relative_offset;
546   if (static_cast<uint32_t>(new_offset) != expected_file_offset) {
547     PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
548                 << " Expected: " << expected_file_offset << " File: " << out.GetLocation();
549     return 0;
550   }
551   DCHECK_OFFSET();
552   if (compiler_driver_->IsImage()) {
553     InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
554 
555     #define DO_TRAMPOLINE(field) \
556       do { \
557         uint32_t aligned_offset = CompiledCode::AlignCode(relative_offset, instruction_set); \
558         uint32_t alignment_padding = aligned_offset - relative_offset; \
559         out.Seek(alignment_padding, kSeekCurrent); \
560         size_trampoline_alignment_ += alignment_padding; \
561         if (!out.WriteFully(&(*field)[0], field->size())) { \
562           PLOG(ERROR) << "Failed to write " # field " to " << out.GetLocation(); \
563           return false; \
564         } \
565         size_ ## field += field->size(); \
566         relative_offset += alignment_padding + field->size(); \
567         DCHECK_OFFSET(); \
568       } while (false)
569 
570     DO_TRAMPOLINE(interpreter_to_interpreter_bridge_);
571     DO_TRAMPOLINE(interpreter_to_compiled_code_bridge_);
572     DO_TRAMPOLINE(jni_dlsym_lookup_);
573     DO_TRAMPOLINE(portable_resolution_trampoline_);
574     DO_TRAMPOLINE(portable_to_interpreter_bridge_);
575     DO_TRAMPOLINE(quick_resolution_trampoline_);
576     DO_TRAMPOLINE(quick_to_interpreter_bridge_);
577     #undef DO_TRAMPOLINE
578   }
579   return relative_offset;
580 }
581 
WriteCodeDexFiles(OutputStream & out,const size_t file_offset,size_t relative_offset)582 size_t OatWriter::WriteCodeDexFiles(OutputStream& out,
583                                     const size_t file_offset,
584                                     size_t relative_offset) {
585   size_t oat_class_index = 0;
586   for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
587     const DexFile* dex_file = (*dex_files_)[i];
588     CHECK(dex_file != NULL);
589     relative_offset = WriteCodeDexFile(out, file_offset, relative_offset, oat_class_index,
590                                        *dex_file);
591     if (relative_offset == 0) {
592       return 0;
593     }
594   }
595   return relative_offset;
596 }
597 
WriteCodeDexFile(OutputStream & out,const size_t file_offset,size_t relative_offset,size_t & oat_class_index,const DexFile & dex_file)598 size_t OatWriter::WriteCodeDexFile(OutputStream& out, const size_t file_offset,
599                                    size_t relative_offset, size_t& oat_class_index,
600                                    const DexFile& dex_file) {
601   for (size_t class_def_index = 0; class_def_index < dex_file.NumClassDefs();
602       class_def_index++, oat_class_index++) {
603     const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
604     relative_offset = WriteCodeClassDef(out, file_offset, relative_offset, oat_class_index,
605                                         dex_file, class_def);
606     if (relative_offset == 0) {
607       return 0;
608     }
609   }
610   return relative_offset;
611 }
612 
ReportWriteFailure(const char * what,uint32_t method_idx,const DexFile & dex_file,OutputStream & out) const613 void OatWriter::ReportWriteFailure(const char* what, uint32_t method_idx,
614                                    const DexFile& dex_file, OutputStream& out) const {
615   PLOG(ERROR) << "Failed to write " << what << " for " << PrettyMethod(method_idx, dex_file)
616       << " to " << out.GetLocation();
617 }
618 
WriteCodeClassDef(OutputStream & out,const size_t file_offset,size_t relative_offset,size_t oat_class_index,const DexFile & dex_file,const DexFile::ClassDef & class_def)619 size_t OatWriter::WriteCodeClassDef(OutputStream& out,
620                                     const size_t file_offset,
621                                     size_t relative_offset,
622                                     size_t oat_class_index,
623                                     const DexFile& dex_file,
624                                     const DexFile::ClassDef& class_def) {
625   const byte* class_data = dex_file.GetClassData(class_def);
626   if (class_data == NULL) {
627     // ie. an empty class such as a marker interface
628     return relative_offset;
629   }
630   ClassDataItemIterator it(dex_file, class_data);
631   // Skip fields
632   while (it.HasNextStaticField()) {
633     it.Next();
634   }
635   while (it.HasNextInstanceField()) {
636     it.Next();
637   }
638   // Process methods
639   size_t class_def_method_index = 0;
640   while (it.HasNextDirectMethod()) {
641     bool is_static = (it.GetMemberAccessFlags() & kAccStatic) != 0;
642     relative_offset = WriteCodeMethod(out, file_offset, relative_offset, oat_class_index,
643                                       class_def_method_index, is_static, it.GetMemberIndex(),
644                                       dex_file);
645     if (relative_offset == 0) {
646       return 0;
647     }
648     class_def_method_index++;
649     it.Next();
650   }
651   while (it.HasNextVirtualMethod()) {
652     relative_offset = WriteCodeMethod(out, file_offset, relative_offset, oat_class_index,
653                                       class_def_method_index, false, it.GetMemberIndex(), dex_file);
654     if (relative_offset == 0) {
655       return 0;
656     }
657     class_def_method_index++;
658     it.Next();
659   }
660   return relative_offset;
661 }
662 
WriteCodeMethod(OutputStream & out,const size_t file_offset,size_t relative_offset,size_t oat_class_index,size_t class_def_method_index,bool is_static,uint32_t method_idx,const DexFile & dex_file)663 size_t OatWriter::WriteCodeMethod(OutputStream& out, const size_t file_offset,
664                                   size_t relative_offset, size_t oat_class_index,
665                                   size_t class_def_method_index, bool is_static,
666                                   uint32_t method_idx, const DexFile& dex_file) {
667   const CompiledMethod* compiled_method =
668       compiler_driver_->GetCompiledMethod(MethodReference(&dex_file, method_idx));
669 
670   OatMethodOffsets method_offsets =
671       oat_classes_[oat_class_index]->method_offsets_[class_def_method_index];
672 
673 
674   if (compiled_method != NULL) {  // ie. not an abstract method
675 #if !defined(ART_USE_PORTABLE_COMPILER)
676     uint32_t aligned_offset = compiled_method->AlignCode(relative_offset);
677     uint32_t aligned_code_delta = aligned_offset - relative_offset;
678     if (aligned_code_delta != 0) {
679       off_t new_offset = out.Seek(aligned_code_delta, kSeekCurrent);
680       size_code_alignment_ += aligned_code_delta;
681       uint32_t expected_offset = file_offset + aligned_offset;
682       if (static_cast<uint32_t>(new_offset) != expected_offset) {
683         PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset
684                     << " Expected: " << expected_offset << " File: " << out.GetLocation();
685         return 0;
686       }
687       relative_offset += aligned_code_delta;
688       DCHECK_OFFSET();
689     }
690     DCHECK_ALIGNED(relative_offset, kArmAlignment);
691     const std::vector<uint8_t>& code = compiled_method->GetCode();
692     uint32_t code_size = code.size() * sizeof(code[0]);
693     CHECK_NE(code_size, 0U);
694 
695     // Deduplicate code arrays
696     size_t code_offset = relative_offset + sizeof(code_size) + compiled_method->CodeDelta();
697     SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = code_offsets_.find(&code);
698     if (code_iter != code_offsets_.end() && code_offset != method_offsets.code_offset_) {
699       DCHECK(code_iter->second == method_offsets.code_offset_)
700           << PrettyMethod(method_idx, dex_file);
701     } else {
702       DCHECK(code_offset == method_offsets.code_offset_) << PrettyMethod(method_idx, dex_file);
703       if (!out.WriteFully(&code_size, sizeof(code_size))) {
704         ReportWriteFailure("method code size", method_idx, dex_file, out);
705         return 0;
706       }
707       size_code_size_ += sizeof(code_size);
708       relative_offset += sizeof(code_size);
709       DCHECK_OFFSET();
710       if (!out.WriteFully(&code[0], code_size)) {
711         ReportWriteFailure("method code", method_idx, dex_file, out);
712         return 0;
713       }
714       size_code_ += code_size;
715       relative_offset += code_size;
716     }
717     DCHECK_OFFSET();
718 #endif
719 
720     const std::vector<uint8_t>& mapping_table = compiled_method->GetMappingTable();
721     size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]);
722 
723     // Deduplicate mapping tables
724     SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator mapping_iter =
725         mapping_table_offsets_.find(&mapping_table);
726     if (mapping_iter != mapping_table_offsets_.end() &&
727         relative_offset != method_offsets.mapping_table_offset_) {
728       DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0)
729           || mapping_iter->second == method_offsets.mapping_table_offset_)
730           << PrettyMethod(method_idx, dex_file);
731     } else {
732       DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0)
733           || relative_offset == method_offsets.mapping_table_offset_)
734           << PrettyMethod(method_idx, dex_file);
735       if (!out.WriteFully(&mapping_table[0], mapping_table_size)) {
736         ReportWriteFailure("mapping table", method_idx, dex_file, out);
737         return 0;
738       }
739       size_mapping_table_ += mapping_table_size;
740       relative_offset += mapping_table_size;
741     }
742     DCHECK_OFFSET();
743 
744     const std::vector<uint8_t>& vmap_table = compiled_method->GetVmapTable();
745     size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]);
746 
747     // Deduplicate vmap tables
748     SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator vmap_iter =
749         vmap_table_offsets_.find(&vmap_table);
750     if (vmap_iter != vmap_table_offsets_.end() &&
751         relative_offset != method_offsets.vmap_table_offset_) {
752       DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0)
753           || vmap_iter->second == method_offsets.vmap_table_offset_)
754           << PrettyMethod(method_idx, dex_file);
755     } else {
756       DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0)
757           || relative_offset == method_offsets.vmap_table_offset_)
758           << PrettyMethod(method_idx, dex_file);
759       if (!out.WriteFully(&vmap_table[0], vmap_table_size)) {
760         ReportWriteFailure("vmap table", method_idx, dex_file, out);
761         return 0;
762       }
763       size_vmap_table_ += vmap_table_size;
764       relative_offset += vmap_table_size;
765     }
766     DCHECK_OFFSET();
767 
768     const std::vector<uint8_t>& gc_map = compiled_method->GetGcMap();
769     size_t gc_map_size = gc_map.size() * sizeof(gc_map[0]);
770 
771     // Deduplicate GC maps
772     SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator gc_map_iter =
773         gc_map_offsets_.find(&gc_map);
774     if (gc_map_iter != gc_map_offsets_.end() &&
775         relative_offset != method_offsets.gc_map_offset_) {
776       DCHECK((gc_map_size == 0 && method_offsets.gc_map_offset_ == 0)
777           || gc_map_iter->second == method_offsets.gc_map_offset_)
778           << PrettyMethod(method_idx, dex_file);
779     } else {
780       DCHECK((gc_map_size == 0 && method_offsets.gc_map_offset_ == 0)
781           || relative_offset == method_offsets.gc_map_offset_)
782           << PrettyMethod(method_idx, dex_file);
783       if (!out.WriteFully(&gc_map[0], gc_map_size)) {
784         ReportWriteFailure("GC map", method_idx, dex_file, out);
785         return 0;
786       }
787       size_gc_map_ += gc_map_size;
788       relative_offset += gc_map_size;
789     }
790     DCHECK_OFFSET();
791   }
792 
793   return relative_offset;
794 }
795 
OatDexFile(size_t offset,const DexFile & dex_file)796 OatWriter::OatDexFile::OatDexFile(size_t offset, const DexFile& dex_file) {
797   offset_ = offset;
798   const std::string& location(dex_file.GetLocation());
799   dex_file_location_size_ = location.size();
800   dex_file_location_data_ = reinterpret_cast<const uint8_t*>(location.data());
801   dex_file_location_checksum_ = dex_file.GetLocationChecksum();
802   dex_file_offset_ = 0;
803   methods_offsets_.resize(dex_file.NumClassDefs());
804 }
805 
SizeOf() const806 size_t OatWriter::OatDexFile::SizeOf() const {
807   return sizeof(dex_file_location_size_)
808           + dex_file_location_size_
809           + sizeof(dex_file_location_checksum_)
810           + sizeof(dex_file_offset_)
811           + (sizeof(methods_offsets_[0]) * methods_offsets_.size());
812 }
813 
UpdateChecksum(OatHeader & oat_header) const814 void OatWriter::OatDexFile::UpdateChecksum(OatHeader& oat_header) const {
815   oat_header.UpdateChecksum(&dex_file_location_size_, sizeof(dex_file_location_size_));
816   oat_header.UpdateChecksum(dex_file_location_data_, dex_file_location_size_);
817   oat_header.UpdateChecksum(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_));
818   oat_header.UpdateChecksum(&dex_file_offset_, sizeof(dex_file_offset_));
819   oat_header.UpdateChecksum(&methods_offsets_[0],
820                             sizeof(methods_offsets_[0]) * methods_offsets_.size());
821 }
822 
Write(OatWriter * oat_writer,OutputStream & out,const size_t file_offset) const823 bool OatWriter::OatDexFile::Write(OatWriter* oat_writer,
824                                   OutputStream& out,
825                                   const size_t file_offset) const {
826   DCHECK_OFFSET_();
827   if (!out.WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
828     PLOG(ERROR) << "Failed to write dex file location length to " << out.GetLocation();
829     return false;
830   }
831   oat_writer->size_oat_dex_file_location_size_ += sizeof(dex_file_location_size_);
832   if (!out.WriteFully(dex_file_location_data_, dex_file_location_size_)) {
833     PLOG(ERROR) << "Failed to write dex file location data to " << out.GetLocation();
834     return false;
835   }
836   oat_writer->size_oat_dex_file_location_data_ += dex_file_location_size_;
837   if (!out.WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) {
838     PLOG(ERROR) << "Failed to write dex file location checksum to " << out.GetLocation();
839     return false;
840   }
841   oat_writer->size_oat_dex_file_location_checksum_ += sizeof(dex_file_location_checksum_);
842   if (!out.WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
843     PLOG(ERROR) << "Failed to write dex file offset to " << out.GetLocation();
844     return false;
845   }
846   oat_writer->size_oat_dex_file_offset_ += sizeof(dex_file_offset_);
847   if (!out.WriteFully(&methods_offsets_[0],
848                       sizeof(methods_offsets_[0]) * methods_offsets_.size())) {
849     PLOG(ERROR) << "Failed to write methods offsets to " << out.GetLocation();
850     return false;
851   }
852   oat_writer->size_oat_dex_file_methods_offsets_ +=
853       sizeof(methods_offsets_[0]) * methods_offsets_.size();
854   return true;
855 }
856 
OatClass(size_t offset,mirror::Class::Status status,uint32_t methods_count)857 OatWriter::OatClass::OatClass(size_t offset, mirror::Class::Status status, uint32_t methods_count) {
858   offset_ = offset;
859   status_ = status;
860   method_offsets_.resize(methods_count);
861 }
862 
GetOatMethodOffsetsOffsetFromOatHeader(size_t class_def_method_index_) const863 size_t OatWriter::OatClass::GetOatMethodOffsetsOffsetFromOatHeader(
864     size_t class_def_method_index_) const {
865   return offset_ + GetOatMethodOffsetsOffsetFromOatClass(class_def_method_index_);
866 }
867 
GetOatMethodOffsetsOffsetFromOatClass(size_t class_def_method_index_) const868 size_t OatWriter::OatClass::GetOatMethodOffsetsOffsetFromOatClass(
869     size_t class_def_method_index_) const {
870   return sizeof(status_)
871           + (sizeof(method_offsets_[0]) * class_def_method_index_);
872 }
873 
SizeOf() const874 size_t OatWriter::OatClass::SizeOf() const {
875   return GetOatMethodOffsetsOffsetFromOatClass(method_offsets_.size());
876 }
877 
UpdateChecksum(OatHeader & oat_header) const878 void OatWriter::OatClass::UpdateChecksum(OatHeader& oat_header) const {
879   oat_header.UpdateChecksum(&status_, sizeof(status_));
880   oat_header.UpdateChecksum(&method_offsets_[0],
881                             sizeof(method_offsets_[0]) * method_offsets_.size());
882 }
883 
Write(OatWriter * oat_writer,OutputStream & out,const size_t file_offset) const884 bool OatWriter::OatClass::Write(OatWriter* oat_writer,
885                                 OutputStream& out,
886                                 const size_t file_offset) const {
887   DCHECK_OFFSET_();
888   if (!out.WriteFully(&status_, sizeof(status_))) {
889     PLOG(ERROR) << "Failed to write class status to " << out.GetLocation();
890     return false;
891   }
892   oat_writer->size_oat_class_status_ += sizeof(status_);
893   DCHECK_EQ(static_cast<off_t>(file_offset + GetOatMethodOffsetsOffsetFromOatHeader(0)),
894             out.Seek(0, kSeekCurrent));
895   if (!out.WriteFully(&method_offsets_[0],
896                       sizeof(method_offsets_[0]) * method_offsets_.size())) {
897     PLOG(ERROR) << "Failed to write method offsets to " << out.GetLocation();
898     return false;
899   }
900   oat_writer->size_oat_class_method_offsets_ += sizeof(method_offsets_[0]) * method_offsets_.size();
901   DCHECK_EQ(static_cast<off_t>(file_offset +
902                                GetOatMethodOffsetsOffsetFromOatHeader(method_offsets_.size())),
903             out.Seek(0, kSeekCurrent));
904   return true;
905 }
906 
907 }  // namespace art
908