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 <unistd.h>
20 #include <zlib.h>
21
22 #include "arch/arm64/instruction_set_features_arm64.h"
23 #include "art_method-inl.h"
24 #include "base/allocator.h"
25 #include "base/bit_vector-inl.h"
26 #include "base/enums.h"
27 #include "base/file_magic.h"
28 #include "base/stl_util.h"
29 #include "base/unix_file/fd_file.h"
30 #include "class_linker.h"
31 #include "compiled_method.h"
32 #include "debug/method_debug_info.h"
33 #include "dex/verification_results.h"
34 #include "dex_file-inl.h"
35 #include "dexlayout.h"
36 #include "driver/compiler_driver-inl.h"
37 #include "driver/compiler_options.h"
38 #include "gc/space/image_space.h"
39 #include "gc/space/space.h"
40 #include "handle_scope-inl.h"
41 #include "image_writer.h"
42 #include "linker/buffered_output_stream.h"
43 #include "linker/file_output_stream.h"
44 #include "linker/method_bss_mapping_encoder.h"
45 #include "linker/multi_oat_relative_patcher.h"
46 #include "linker/output_stream.h"
47 #include "mirror/array.h"
48 #include "mirror/class_loader.h"
49 #include "mirror/dex_cache-inl.h"
50 #include "mirror/object-inl.h"
51 #include "oat_quick_method_header.h"
52 #include "os.h"
53 #include "safe_map.h"
54 #include "scoped_thread_state_change-inl.h"
55 #include "type_lookup_table.h"
56 #include "utils/dex_cache_arrays_layout-inl.h"
57 #include "vdex_file.h"
58 #include "verifier/verifier_deps.h"
59 #include "zip_archive.h"
60
61 namespace art {
62
63 namespace { // anonymous namespace
64
65 // If we write dex layout info in the oat file.
66 static constexpr bool kWriteDexLayoutInfo = true;
67
68 typedef DexFile::Header __attribute__((aligned(1))) UnalignedDexFileHeader;
69
AsUnalignedDexFileHeader(const uint8_t * raw_data)70 const UnalignedDexFileHeader* AsUnalignedDexFileHeader(const uint8_t* raw_data) {
71 return reinterpret_cast<const UnalignedDexFileHeader*>(raw_data);
72 }
73
74 class ChecksumUpdatingOutputStream : public OutputStream {
75 public:
ChecksumUpdatingOutputStream(OutputStream * out,OatHeader * oat_header)76 ChecksumUpdatingOutputStream(OutputStream* out, OatHeader* oat_header)
77 : OutputStream(out->GetLocation()), out_(out), oat_header_(oat_header) { }
78
WriteFully(const void * buffer,size_t byte_count)79 bool WriteFully(const void* buffer, size_t byte_count) OVERRIDE {
80 oat_header_->UpdateChecksum(buffer, byte_count);
81 return out_->WriteFully(buffer, byte_count);
82 }
83
Seek(off_t offset,Whence whence)84 off_t Seek(off_t offset, Whence whence) OVERRIDE {
85 return out_->Seek(offset, whence);
86 }
87
Flush()88 bool Flush() OVERRIDE {
89 return out_->Flush();
90 }
91
92 private:
93 OutputStream* const out_;
94 OatHeader* const oat_header_;
95 };
96
CodeAlignmentSize(uint32_t header_offset,const CompiledMethod & compiled_method)97 inline uint32_t CodeAlignmentSize(uint32_t header_offset, const CompiledMethod& compiled_method) {
98 // We want to align the code rather than the preheader.
99 uint32_t unaligned_code_offset = header_offset + sizeof(OatQuickMethodHeader);
100 uint32_t aligned_code_offset = compiled_method.AlignCode(unaligned_code_offset);
101 return aligned_code_offset - unaligned_code_offset;
102 }
103
104 } // anonymous namespace
105
106 // Defines the location of the raw dex file to write.
107 class OatWriter::DexFileSource {
108 public:
109 enum Type {
110 kNone,
111 kZipEntry,
112 kRawFile,
113 kRawData,
114 };
115
DexFileSource(ZipEntry * zip_entry)116 explicit DexFileSource(ZipEntry* zip_entry)
117 : type_(kZipEntry), source_(zip_entry) {
118 DCHECK(source_ != nullptr);
119 }
120
DexFileSource(File * raw_file)121 explicit DexFileSource(File* raw_file)
122 : type_(kRawFile), source_(raw_file) {
123 DCHECK(source_ != nullptr);
124 }
125
DexFileSource(const uint8_t * dex_file)126 explicit DexFileSource(const uint8_t* dex_file)
127 : type_(kRawData), source_(dex_file) {
128 DCHECK(source_ != nullptr);
129 }
130
GetType() const131 Type GetType() const { return type_; }
IsZipEntry() const132 bool IsZipEntry() const { return type_ == kZipEntry; }
IsRawFile() const133 bool IsRawFile() const { return type_ == kRawFile; }
IsRawData() const134 bool IsRawData() const { return type_ == kRawData; }
135
GetZipEntry() const136 ZipEntry* GetZipEntry() const {
137 DCHECK(IsZipEntry());
138 DCHECK(source_ != nullptr);
139 return static_cast<ZipEntry*>(const_cast<void*>(source_));
140 }
141
GetRawFile() const142 File* GetRawFile() const {
143 DCHECK(IsRawFile());
144 DCHECK(source_ != nullptr);
145 return static_cast<File*>(const_cast<void*>(source_));
146 }
147
GetRawData() const148 const uint8_t* GetRawData() const {
149 DCHECK(IsRawData());
150 DCHECK(source_ != nullptr);
151 return static_cast<const uint8_t*>(source_);
152 }
153
Clear()154 void Clear() {
155 type_ = kNone;
156 source_ = nullptr;
157 }
158
159 private:
160 Type type_;
161 const void* source_;
162 };
163
164 // OatClassHeader is the header only part of the oat class that is required even when compilation
165 // is not enabled.
166 class OatWriter::OatClassHeader {
167 public:
OatClassHeader(uint32_t offset,uint32_t num_non_null_compiled_methods,uint32_t num_methods,mirror::Class::Status status)168 OatClassHeader(uint32_t offset,
169 uint32_t num_non_null_compiled_methods,
170 uint32_t num_methods,
171 mirror::Class::Status status)
172 : status_(status),
173 offset_(offset) {
174 // We just arbitrarily say that 0 methods means kOatClassNoneCompiled and that we won't use
175 // kOatClassAllCompiled unless there is at least one compiled method. This means in an
176 // interpreter only system, we can assert that all classes are kOatClassNoneCompiled.
177 if (num_non_null_compiled_methods == 0) {
178 type_ = kOatClassNoneCompiled;
179 } else if (num_non_null_compiled_methods == num_methods) {
180 type_ = kOatClassAllCompiled;
181 } else {
182 type_ = kOatClassSomeCompiled;
183 }
184 }
185
186 bool Write(OatWriter* oat_writer, OutputStream* out, const size_t file_offset) const;
187
SizeOf()188 static size_t SizeOf() {
189 return sizeof(status_) + sizeof(type_);
190 }
191
192 // Data to write.
193 static_assert(mirror::Class::Status::kStatusMax < (1 << 16), "class status won't fit in 16bits");
194 int16_t status_;
195
196 static_assert(OatClassType::kOatClassMax < (1 << 16), "oat_class type won't fit in 16bits");
197 uint16_t type_;
198
199 // Offset of start of OatClass from beginning of OatHeader. It is
200 // used to validate file position when writing.
201 uint32_t offset_;
202 };
203
204 // The actual oat class body contains the information about compiled methods. It is only required
205 // for compiler filters that have any compilation.
206 class OatWriter::OatClass {
207 public:
208 OatClass(const dchecked_vector<CompiledMethod*>& compiled_methods,
209 uint32_t compiled_methods_with_code,
210 uint16_t oat_class_type);
211 OatClass(OatClass&& src) = default;
212 size_t SizeOf() const;
213 bool Write(OatWriter* oat_writer, OutputStream* out) const;
214
GetCompiledMethod(size_t class_def_method_index) const215 CompiledMethod* GetCompiledMethod(size_t class_def_method_index) const {
216 return compiled_methods_[class_def_method_index];
217 }
218
219 // CompiledMethods for each class_def_method_index, or null if no method is available.
220 dchecked_vector<CompiledMethod*> compiled_methods_;
221
222 // Offset from OatClass::offset_ to the OatMethodOffsets for the
223 // class_def_method_index. If 0, it means the corresponding
224 // CompiledMethod entry in OatClass::compiled_methods_ should be
225 // null and that the OatClass::type_ should be kOatClassBitmap.
226 dchecked_vector<uint32_t> oat_method_offsets_offsets_from_oat_class_;
227
228 // Data to write.
229 uint32_t method_bitmap_size_;
230
231 // bit vector indexed by ClassDef method index. When
232 // OatClassType::type_ is kOatClassBitmap, a set bit indicates the
233 // method has an OatMethodOffsets in methods_offsets_, otherwise
234 // the entry was ommited to save space. If OatClassType::type_ is
235 // not is kOatClassBitmap, the bitmap will be null.
236 std::unique_ptr<BitVector> method_bitmap_;
237
238 // OatMethodOffsets and OatMethodHeaders for each CompiledMethod
239 // present in the OatClass. Note that some may be missing if
240 // OatClass::compiled_methods_ contains null values (and
241 // oat_method_offsets_offsets_from_oat_class_ should contain 0
242 // values in this case).
243 dchecked_vector<OatMethodOffsets> method_offsets_;
244 dchecked_vector<OatQuickMethodHeader> method_headers_;
245
246 private:
GetMethodOffsetsRawSize() const247 size_t GetMethodOffsetsRawSize() const {
248 return method_offsets_.size() * sizeof(method_offsets_[0]);
249 }
250
251 DISALLOW_COPY_AND_ASSIGN(OatClass);
252 };
253
254 class OatWriter::OatDexFile {
255 public:
256 OatDexFile(const char* dex_file_location,
257 DexFileSource source,
258 CreateTypeLookupTable create_type_lookup_table);
259 OatDexFile(OatDexFile&& src) = default;
260
GetLocation() const261 const char* GetLocation() const {
262 return dex_file_location_data_;
263 }
264
265 size_t SizeOf() const;
266 bool Write(OatWriter* oat_writer, OutputStream* out) const;
267 bool WriteClassOffsets(OatWriter* oat_writer, OutputStream* out);
268
GetClassOffsetsRawSize() const269 size_t GetClassOffsetsRawSize() const {
270 return class_offsets_.size() * sizeof(class_offsets_[0]);
271 }
272
273 // The source of the dex file.
274 DexFileSource source_;
275
276 // Whether to create the type lookup table.
277 CreateTypeLookupTable create_type_lookup_table_;
278
279 // Dex file size. Initialized when writing the dex file.
280 size_t dex_file_size_;
281
282 // Offset of start of OatDexFile from beginning of OatHeader. It is
283 // used to validate file position when writing.
284 size_t offset_;
285
286 // Data to write.
287 uint32_t dex_file_location_size_;
288 const char* dex_file_location_data_;
289 uint32_t dex_file_location_checksum_;
290 uint32_t dex_file_offset_;
291 uint32_t class_offsets_offset_;
292 uint32_t lookup_table_offset_;
293 uint32_t method_bss_mapping_offset_;
294 uint32_t dex_sections_layout_offset_;
295
296 // Data to write to a separate section.
297 dchecked_vector<uint32_t> class_offsets_;
298
299 // Dex section layout info to serialize.
300 DexLayoutSections dex_sections_layout_;
301
302 private:
303 DISALLOW_COPY_AND_ASSIGN(OatDexFile);
304 };
305
306 #define DCHECK_OFFSET() \
307 DCHECK_EQ(static_cast<off_t>(file_offset + relative_offset), out->Seek(0, kSeekCurrent)) \
308 << "file_offset=" << file_offset << " relative_offset=" << relative_offset
309
310 #define DCHECK_OFFSET_() \
311 DCHECK_EQ(static_cast<off_t>(file_offset + offset_), out->Seek(0, kSeekCurrent)) \
312 << "file_offset=" << file_offset << " offset_=" << offset_
313
OatWriter(bool compiling_boot_image,TimingLogger * timings,ProfileCompilationInfo * info)314 OatWriter::OatWriter(bool compiling_boot_image, TimingLogger* timings, ProfileCompilationInfo* info)
315 : write_state_(WriteState::kAddingDexFileSources),
316 timings_(timings),
317 raw_dex_files_(),
318 zip_archives_(),
319 zipped_dex_files_(),
320 zipped_dex_file_locations_(),
321 compiler_driver_(nullptr),
322 image_writer_(nullptr),
323 compiling_boot_image_(compiling_boot_image),
324 dex_files_(nullptr),
325 vdex_size_(0u),
326 vdex_dex_files_offset_(0u),
327 vdex_verifier_deps_offset_(0u),
328 vdex_quickening_info_offset_(0u),
329 oat_size_(0u),
330 bss_start_(0u),
331 bss_size_(0u),
332 bss_methods_offset_(0u),
333 bss_roots_offset_(0u),
334 bss_method_entry_references_(),
335 bss_method_entries_(),
336 bss_type_entries_(),
337 bss_string_entries_(),
338 oat_data_offset_(0u),
339 oat_header_(nullptr),
340 size_vdex_header_(0),
341 size_vdex_checksums_(0),
342 size_dex_file_alignment_(0),
343 size_executable_offset_alignment_(0),
344 size_oat_header_(0),
345 size_oat_header_key_value_store_(0),
346 size_dex_file_(0),
347 size_verifier_deps_(0),
348 size_verifier_deps_alignment_(0),
349 size_quickening_info_(0),
350 size_quickening_info_alignment_(0),
351 size_interpreter_to_interpreter_bridge_(0),
352 size_interpreter_to_compiled_code_bridge_(0),
353 size_jni_dlsym_lookup_(0),
354 size_quick_generic_jni_trampoline_(0),
355 size_quick_imt_conflict_trampoline_(0),
356 size_quick_resolution_trampoline_(0),
357 size_quick_to_interpreter_bridge_(0),
358 size_trampoline_alignment_(0),
359 size_method_header_(0),
360 size_code_(0),
361 size_code_alignment_(0),
362 size_relative_call_thunks_(0),
363 size_misc_thunks_(0),
364 size_vmap_table_(0),
365 size_method_info_(0),
366 size_oat_dex_file_location_size_(0),
367 size_oat_dex_file_location_data_(0),
368 size_oat_dex_file_location_checksum_(0),
369 size_oat_dex_file_offset_(0),
370 size_oat_dex_file_class_offsets_offset_(0),
371 size_oat_dex_file_lookup_table_offset_(0),
372 size_oat_dex_file_dex_layout_sections_offset_(0),
373 size_oat_dex_file_dex_layout_sections_(0),
374 size_oat_dex_file_dex_layout_sections_alignment_(0),
375 size_oat_dex_file_method_bss_mapping_offset_(0),
376 size_oat_lookup_table_alignment_(0),
377 size_oat_lookup_table_(0),
378 size_oat_class_offsets_alignment_(0),
379 size_oat_class_offsets_(0),
380 size_oat_class_type_(0),
381 size_oat_class_status_(0),
382 size_oat_class_method_bitmaps_(0),
383 size_oat_class_method_offsets_(0),
384 size_method_bss_mappings_(0u),
385 relative_patcher_(nullptr),
386 absolute_patch_locations_(),
387 profile_compilation_info_(info) {
388 }
389
AddDexFileSource(const char * filename,const char * location,CreateTypeLookupTable create_type_lookup_table)390 bool OatWriter::AddDexFileSource(const char* filename,
391 const char* location,
392 CreateTypeLookupTable create_type_lookup_table) {
393 DCHECK(write_state_ == WriteState::kAddingDexFileSources);
394 uint32_t magic;
395 std::string error_msg;
396 File fd = OpenAndReadMagic(filename, &magic, &error_msg);
397 if (fd.Fd() == -1) {
398 PLOG(ERROR) << "Failed to read magic number from dex file: '" << filename << "'";
399 return false;
400 } else if (IsDexMagic(magic)) {
401 // The file is open for reading, not writing, so it's OK to let the File destructor
402 // close it without checking for explicit Close(), so pass checkUsage = false.
403 raw_dex_files_.emplace_back(new File(fd.Release(), location, /* checkUsage */ false));
404 oat_dex_files_.emplace_back(location,
405 DexFileSource(raw_dex_files_.back().get()),
406 create_type_lookup_table);
407 } else if (IsZipMagic(magic)) {
408 if (!AddZippedDexFilesSource(std::move(fd), location, create_type_lookup_table)) {
409 return false;
410 }
411 } else {
412 LOG(ERROR) << "Expected valid zip or dex file: '" << filename << "'";
413 return false;
414 }
415 return true;
416 }
417
418 // Add dex file source(s) from a zip file specified by a file handle.
AddZippedDexFilesSource(File && zip_fd,const char * location,CreateTypeLookupTable create_type_lookup_table)419 bool OatWriter::AddZippedDexFilesSource(File&& zip_fd,
420 const char* location,
421 CreateTypeLookupTable create_type_lookup_table) {
422 DCHECK(write_state_ == WriteState::kAddingDexFileSources);
423 std::string error_msg;
424 zip_archives_.emplace_back(ZipArchive::OpenFromFd(zip_fd.Release(), location, &error_msg));
425 ZipArchive* zip_archive = zip_archives_.back().get();
426 if (zip_archive == nullptr) {
427 LOG(ERROR) << "Failed to open zip from file descriptor for '" << location << "': "
428 << error_msg;
429 return false;
430 }
431 for (size_t i = 0; ; ++i) {
432 std::string entry_name = DexFile::GetMultiDexClassesDexName(i);
433 std::unique_ptr<ZipEntry> entry(zip_archive->Find(entry_name.c_str(), &error_msg));
434 if (entry == nullptr) {
435 break;
436 }
437 zipped_dex_files_.push_back(std::move(entry));
438 zipped_dex_file_locations_.push_back(DexFile::GetMultiDexLocation(i, location));
439 const char* full_location = zipped_dex_file_locations_.back().c_str();
440 oat_dex_files_.emplace_back(full_location,
441 DexFileSource(zipped_dex_files_.back().get()),
442 create_type_lookup_table);
443 }
444 if (zipped_dex_file_locations_.empty()) {
445 LOG(ERROR) << "No dex files in zip file '" << location << "': " << error_msg;
446 return false;
447 }
448 return true;
449 }
450
451 // Add dex file source(s) from a vdex file specified by a file handle.
AddVdexDexFilesSource(const VdexFile & vdex_file,const char * location,CreateTypeLookupTable create_type_lookup_table)452 bool OatWriter::AddVdexDexFilesSource(const VdexFile& vdex_file,
453 const char* location,
454 CreateTypeLookupTable create_type_lookup_table) {
455 DCHECK(write_state_ == WriteState::kAddingDexFileSources);
456 const uint8_t* current_dex_data = nullptr;
457 for (size_t i = 0; i < vdex_file.GetHeader().GetNumberOfDexFiles(); ++i) {
458 current_dex_data = vdex_file.GetNextDexFileData(current_dex_data);
459 if (current_dex_data == nullptr) {
460 LOG(ERROR) << "Unexpected number of dex files in vdex " << location;
461 return false;
462 }
463 if (!DexFile::IsMagicValid(current_dex_data)) {
464 LOG(ERROR) << "Invalid magic in vdex file created from " << location;
465 return false;
466 }
467 // We used `zipped_dex_file_locations_` to keep the strings in memory.
468 zipped_dex_file_locations_.push_back(DexFile::GetMultiDexLocation(i, location));
469 const char* full_location = zipped_dex_file_locations_.back().c_str();
470 oat_dex_files_.emplace_back(full_location,
471 DexFileSource(current_dex_data),
472 create_type_lookup_table);
473 oat_dex_files_.back().dex_file_location_checksum_ = vdex_file.GetLocationChecksum(i);
474 }
475
476 if (vdex_file.GetNextDexFileData(current_dex_data) != nullptr) {
477 LOG(ERROR) << "Unexpected number of dex files in vdex " << location;
478 return false;
479 }
480
481 if (oat_dex_files_.empty()) {
482 LOG(ERROR) << "No dex files in vdex file created from " << location;
483 return false;
484 }
485 return true;
486 }
487
488 // Add dex file source from raw memory.
AddRawDexFileSource(const ArrayRef<const uint8_t> & data,const char * location,uint32_t location_checksum,CreateTypeLookupTable create_type_lookup_table)489 bool OatWriter::AddRawDexFileSource(const ArrayRef<const uint8_t>& data,
490 const char* location,
491 uint32_t location_checksum,
492 CreateTypeLookupTable create_type_lookup_table) {
493 DCHECK(write_state_ == WriteState::kAddingDexFileSources);
494 if (data.size() < sizeof(DexFile::Header)) {
495 LOG(ERROR) << "Provided data is shorter than dex file header. size: "
496 << data.size() << " File: " << location;
497 return false;
498 }
499 if (!ValidateDexFileHeader(data.data(), location)) {
500 return false;
501 }
502 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(data.data());
503 if (data.size() < header->file_size_) {
504 LOG(ERROR) << "Truncated dex file data. Data size: " << data.size()
505 << " file size from header: " << header->file_size_ << " File: " << location;
506 return false;
507 }
508
509 oat_dex_files_.emplace_back(location, DexFileSource(data.data()), create_type_lookup_table);
510 oat_dex_files_.back().dex_file_location_checksum_ = location_checksum;
511 return true;
512 }
513
GetSourceLocations() const514 dchecked_vector<std::string> OatWriter::GetSourceLocations() const {
515 dchecked_vector<std::string> locations;
516 locations.reserve(oat_dex_files_.size());
517 for (const OatDexFile& oat_dex_file : oat_dex_files_) {
518 locations.push_back(oat_dex_file.GetLocation());
519 }
520 return locations;
521 }
522
MayHaveCompiledMethods() const523 bool OatWriter::MayHaveCompiledMethods() const {
524 return CompilerFilter::IsAnyCompilationEnabled(
525 GetCompilerDriver()->GetCompilerOptions().GetCompilerFilter());
526 }
527
WriteAndOpenDexFiles(File * vdex_file,OutputStream * oat_rodata,InstructionSet instruction_set,const InstructionSetFeatures * instruction_set_features,SafeMap<std::string,std::string> * key_value_store,bool verify,bool update_input_vdex,std::unique_ptr<MemMap> * opened_dex_files_map,std::vector<std::unique_ptr<const DexFile>> * opened_dex_files)528 bool OatWriter::WriteAndOpenDexFiles(
529 File* vdex_file,
530 OutputStream* oat_rodata,
531 InstructionSet instruction_set,
532 const InstructionSetFeatures* instruction_set_features,
533 SafeMap<std::string, std::string>* key_value_store,
534 bool verify,
535 bool update_input_vdex,
536 /*out*/ std::unique_ptr<MemMap>* opened_dex_files_map,
537 /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) {
538 CHECK(write_state_ == WriteState::kAddingDexFileSources);
539
540 // Record the ELF rodata section offset, i.e. the beginning of the OAT data.
541 if (!RecordOatDataOffset(oat_rodata)) {
542 return false;
543 }
544
545 std::unique_ptr<MemMap> dex_files_map;
546 std::vector<std::unique_ptr<const DexFile>> dex_files;
547
548 // Initialize VDEX and OAT headers.
549 if (kIsVdexEnabled) {
550 // Reserve space for Vdex header and checksums.
551 vdex_size_ = sizeof(VdexFile::Header) + oat_dex_files_.size() * sizeof(VdexFile::VdexChecksum);
552 }
553 oat_size_ = InitOatHeader(instruction_set,
554 instruction_set_features,
555 dchecked_integral_cast<uint32_t>(oat_dex_files_.size()),
556 key_value_store);
557
558 ChecksumUpdatingOutputStream checksum_updating_rodata(oat_rodata, oat_header_.get());
559
560 if (kIsVdexEnabled) {
561 std::unique_ptr<BufferedOutputStream> vdex_out =
562 std::make_unique<BufferedOutputStream>(std::make_unique<FileOutputStream>(vdex_file));
563 // Write DEX files into VDEX, mmap and open them.
564 if (!WriteDexFiles(vdex_out.get(), vdex_file, update_input_vdex) ||
565 !OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) {
566 return false;
567 }
568 } else {
569 DCHECK(!update_input_vdex);
570 // Write DEX files into OAT, mmap and open them.
571 if (!WriteDexFiles(oat_rodata, vdex_file, update_input_vdex) ||
572 !OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) {
573 return false;
574 }
575
576 // Do a bulk checksum update for Dex[]. Doing it piece by piece would be
577 // difficult because we're not using the OutputStream directly.
578 if (!oat_dex_files_.empty()) {
579 size_t size = oat_size_ - oat_dex_files_[0].dex_file_offset_;
580 oat_header_->UpdateChecksum(dex_files_map->Begin(), size);
581 }
582 }
583
584 // Write type lookup tables into the oat file.
585 if (!WriteTypeLookupTables(&checksum_updating_rodata, dex_files)) {
586 return false;
587 }
588
589 // Write dex layout sections into the oat file.
590 if (!WriteDexLayoutSections(&checksum_updating_rodata, dex_files)) {
591 return false;
592 }
593
594 *opened_dex_files_map = std::move(dex_files_map);
595 *opened_dex_files = std::move(dex_files);
596 write_state_ = WriteState::kPrepareLayout;
597 return true;
598 }
599
PrepareLayout(linker::MultiOatRelativePatcher * relative_patcher)600 void OatWriter::PrepareLayout(linker::MultiOatRelativePatcher* relative_patcher) {
601 CHECK(write_state_ == WriteState::kPrepareLayout);
602
603 relative_patcher_ = relative_patcher;
604 SetMultiOatRelativePatcherAdjustment();
605
606 if (compiling_boot_image_) {
607 CHECK(image_writer_ != nullptr);
608 }
609 InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
610 CHECK_EQ(instruction_set, oat_header_->GetInstructionSet());
611
612 {
613 TimingLogger::ScopedTiming split("InitBssLayout", timings_);
614 InitBssLayout(instruction_set);
615 }
616
617 uint32_t offset = oat_size_;
618 {
619 TimingLogger::ScopedTiming split("InitClassOffsets", timings_);
620 offset = InitClassOffsets(offset);
621 }
622 {
623 TimingLogger::ScopedTiming split("InitOatClasses", timings_);
624 offset = InitOatClasses(offset);
625 }
626 {
627 TimingLogger::ScopedTiming split("InitMethodBssMappings", timings_);
628 offset = InitMethodBssMappings(offset);
629 }
630 {
631 TimingLogger::ScopedTiming split("InitOatMaps", timings_);
632 offset = InitOatMaps(offset);
633 }
634 {
635 TimingLogger::ScopedTiming split("InitOatDexFiles", timings_);
636 oat_header_->SetOatDexFilesOffset(offset);
637 offset = InitOatDexFiles(offset);
638 }
639 {
640 TimingLogger::ScopedTiming split("InitOatCode", timings_);
641 offset = InitOatCode(offset);
642 }
643 {
644 TimingLogger::ScopedTiming split("InitOatCodeDexFiles", timings_);
645 offset = InitOatCodeDexFiles(offset);
646 }
647 oat_size_ = offset;
648 bss_start_ = (bss_size_ != 0u) ? RoundUp(oat_size_, kPageSize) : 0u;
649
650 CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
651 if (compiling_boot_image_) {
652 CHECK_EQ(image_writer_ != nullptr,
653 oat_header_->GetStoreValueByKey(OatHeader::kImageLocationKey) == nullptr);
654 }
655
656 write_state_ = WriteState::kWriteRoData;
657 }
658
~OatWriter()659 OatWriter::~OatWriter() {
660 }
661
662 class OatWriter::DexMethodVisitor {
663 public:
DexMethodVisitor(OatWriter * writer,size_t offset)664 DexMethodVisitor(OatWriter* writer, size_t offset)
665 : writer_(writer),
666 offset_(offset),
667 dex_file_(nullptr),
668 class_def_index_(DexFile::kDexNoIndex) {}
669
StartClass(const DexFile * dex_file,size_t class_def_index)670 virtual bool StartClass(const DexFile* dex_file, size_t class_def_index) {
671 DCHECK(dex_file_ == nullptr);
672 DCHECK_EQ(class_def_index_, DexFile::kDexNoIndex);
673 dex_file_ = dex_file;
674 class_def_index_ = class_def_index;
675 return true;
676 }
677
678 virtual bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) = 0;
679
EndClass()680 virtual bool EndClass() {
681 if (kIsDebugBuild) {
682 dex_file_ = nullptr;
683 class_def_index_ = DexFile::kDexNoIndex;
684 }
685 return true;
686 }
687
GetOffset() const688 size_t GetOffset() const {
689 return offset_;
690 }
691
692 protected:
~DexMethodVisitor()693 virtual ~DexMethodVisitor() { }
694
695 OatWriter* const writer_;
696
697 // The offset is usually advanced for each visited method by the derived class.
698 size_t offset_;
699
700 // The dex file and class def index are set in StartClass().
701 const DexFile* dex_file_;
702 size_t class_def_index_;
703 };
704
705 class OatWriter::OatDexMethodVisitor : public DexMethodVisitor {
706 public:
OatDexMethodVisitor(OatWriter * writer,size_t offset)707 OatDexMethodVisitor(OatWriter* writer, size_t offset)
708 : DexMethodVisitor(writer, offset),
709 oat_class_index_(0u),
710 method_offsets_index_(0u) {}
711
StartClass(const DexFile * dex_file,size_t class_def_index)712 bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE {
713 DexMethodVisitor::StartClass(dex_file, class_def_index);
714 if (kIsDebugBuild && writer_->MayHaveCompiledMethods()) {
715 // There are no oat classes if there aren't any compiled methods.
716 CHECK_LT(oat_class_index_, writer_->oat_classes_.size());
717 }
718 method_offsets_index_ = 0u;
719 return true;
720 }
721
EndClass()722 bool EndClass() OVERRIDE {
723 ++oat_class_index_;
724 return DexMethodVisitor::EndClass();
725 }
726
727 protected:
728 size_t oat_class_index_;
729 size_t method_offsets_index_;
730 };
731
HasCompiledCode(const CompiledMethod * method)732 static bool HasCompiledCode(const CompiledMethod* method) {
733 // The dextodexcompiler puts the quickening info table into the CompiledMethod
734 // for simplicity. For such methods, we will emit an OatQuickMethodHeader
735 // only when vdex is disabled.
736 return method != nullptr && (!method->GetQuickCode().empty() || !kIsVdexEnabled);
737 }
738
HasQuickeningInfo(const CompiledMethod * method)739 static bool HasQuickeningInfo(const CompiledMethod* method) {
740 return method != nullptr && method->GetQuickCode().empty() && !method->GetVmapTable().empty();
741 }
742
743 class OatWriter::InitBssLayoutMethodVisitor : public DexMethodVisitor {
744 public:
InitBssLayoutMethodVisitor(OatWriter * writer)745 explicit InitBssLayoutMethodVisitor(OatWriter* writer)
746 : DexMethodVisitor(writer, /* offset */ 0u) {}
747
VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED,const ClassDataItemIterator & it)748 bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED,
749 const ClassDataItemIterator& it) OVERRIDE {
750 // Look for patches with .bss references and prepare maps with placeholders for their offsets.
751 CompiledMethod* compiled_method = writer_->compiler_driver_->GetCompiledMethod(
752 MethodReference(dex_file_, it.GetMemberIndex()));
753 if (HasCompiledCode(compiled_method)) {
754 for (const LinkerPatch& patch : compiled_method->GetPatches()) {
755 if (patch.GetType() == LinkerPatch::Type::kMethodBssEntry) {
756 MethodReference target_method = patch.TargetMethod();
757 auto refs_it = writer_->bss_method_entry_references_.find(target_method.dex_file);
758 if (refs_it == writer_->bss_method_entry_references_.end()) {
759 refs_it = writer_->bss_method_entry_references_.Put(
760 target_method.dex_file,
761 BitVector(target_method.dex_file->NumMethodIds(),
762 /* expandable */ false,
763 Allocator::GetMallocAllocator()));
764 refs_it->second.ClearAllBits();
765 }
766 refs_it->second.SetBit(target_method.dex_method_index);
767 writer_->bss_method_entries_.Overwrite(target_method, /* placeholder */ 0u);
768 } else if (patch.GetType() == LinkerPatch::Type::kTypeBssEntry) {
769 TypeReference ref(patch.TargetTypeDexFile(), patch.TargetTypeIndex());
770 writer_->bss_type_entries_.Overwrite(ref, /* placeholder */ 0u);
771 } else if (patch.GetType() == LinkerPatch::Type::kStringBssEntry) {
772 StringReference ref(patch.TargetStringDexFile(), patch.TargetStringIndex());
773 writer_->bss_string_entries_.Overwrite(ref, /* placeholder */ 0u);
774 }
775 }
776 } else {
777 DCHECK(compiled_method == nullptr || compiled_method->GetPatches().empty());
778 }
779 return true;
780 }
781 };
782
783 class OatWriter::InitOatClassesMethodVisitor : public DexMethodVisitor {
784 public:
InitOatClassesMethodVisitor(OatWriter * writer,size_t offset)785 InitOatClassesMethodVisitor(OatWriter* writer, size_t offset)
786 : DexMethodVisitor(writer, offset),
787 compiled_methods_(),
788 compiled_methods_with_code_(0u) {
789 size_t num_classes = 0u;
790 for (const OatDexFile& oat_dex_file : writer_->oat_dex_files_) {
791 num_classes += oat_dex_file.class_offsets_.size();
792 }
793 // If we aren't compiling only reserve headers.
794 writer_->oat_class_headers_.reserve(num_classes);
795 if (writer->MayHaveCompiledMethods()) {
796 writer->oat_classes_.reserve(num_classes);
797 }
798 compiled_methods_.reserve(256u);
799 // If there are any classes, the class offsets allocation aligns the offset.
800 DCHECK(num_classes == 0u || IsAligned<4u>(offset));
801 }
802
StartClass(const DexFile * dex_file,size_t class_def_index)803 bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE {
804 DexMethodVisitor::StartClass(dex_file, class_def_index);
805 compiled_methods_.clear();
806 compiled_methods_with_code_ = 0u;
807 return true;
808 }
809
VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED,const ClassDataItemIterator & it)810 bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED,
811 const ClassDataItemIterator& it) OVERRIDE {
812 // Fill in the compiled_methods_ array for methods that have a
813 // CompiledMethod. We track the number of non-null entries in
814 // compiled_methods_with_code_ since we only want to allocate
815 // OatMethodOffsets for the compiled methods.
816 uint32_t method_idx = it.GetMemberIndex();
817 CompiledMethod* compiled_method =
818 writer_->compiler_driver_->GetCompiledMethod(MethodReference(dex_file_, method_idx));
819 compiled_methods_.push_back(compiled_method);
820 if (HasCompiledCode(compiled_method)) {
821 ++compiled_methods_with_code_;
822 }
823 return true;
824 }
825
EndClass()826 bool EndClass() OVERRIDE {
827 ClassReference class_ref(dex_file_, class_def_index_);
828 mirror::Class::Status status;
829 bool found = writer_->compiler_driver_->GetCompiledClass(class_ref, &status);
830 if (!found) {
831 VerificationResults* results = writer_->compiler_driver_->GetVerificationResults();
832 if (results != nullptr && results->IsClassRejected(class_ref)) {
833 // The oat class status is used only for verification of resolved classes,
834 // so use kStatusErrorResolved whether the class was resolved or unresolved
835 // during compile-time verification.
836 status = mirror::Class::kStatusErrorResolved;
837 } else {
838 status = mirror::Class::kStatusNotReady;
839 }
840 }
841
842 writer_->oat_class_headers_.emplace_back(offset_,
843 compiled_methods_with_code_,
844 compiled_methods_.size(),
845 status);
846 OatClassHeader& header = writer_->oat_class_headers_.back();
847 offset_ += header.SizeOf();
848 if (writer_->MayHaveCompiledMethods()) {
849 writer_->oat_classes_.emplace_back(compiled_methods_,
850 compiled_methods_with_code_,
851 header.type_);
852 offset_ += writer_->oat_classes_.back().SizeOf();
853 }
854 return DexMethodVisitor::EndClass();
855 }
856
857 private:
858 dchecked_vector<CompiledMethod*> compiled_methods_;
859 size_t compiled_methods_with_code_;
860 };
861
862 class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor {
863 public:
InitCodeMethodVisitor(OatWriter * writer,size_t offset)864 InitCodeMethodVisitor(OatWriter* writer, size_t offset)
865 : OatDexMethodVisitor(writer, offset),
866 debuggable_(writer->GetCompilerDriver()->GetCompilerOptions().GetDebuggable()) {
867 writer_->absolute_patch_locations_.reserve(
868 writer_->compiler_driver_->GetNonRelativeLinkerPatchCount());
869 }
870
EndClass()871 bool EndClass() OVERRIDE {
872 OatDexMethodVisitor::EndClass();
873 if (oat_class_index_ == writer_->oat_classes_.size()) {
874 offset_ = writer_->relative_patcher_->ReserveSpaceEnd(offset_);
875 }
876 return true;
877 }
878
VisitMethod(size_t class_def_method_index,const ClassDataItemIterator & it)879 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE
880 REQUIRES_SHARED(Locks::mutator_lock_) {
881 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
882 CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
883
884 if (HasCompiledCode(compiled_method)) {
885 // Derived from CompiledMethod.
886 uint32_t quick_code_offset = 0;
887
888 ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
889 uint32_t code_size = quick_code.size() * sizeof(uint8_t);
890 uint32_t thumb_offset = compiled_method->CodeDelta();
891
892 // Deduplicate code arrays if we are not producing debuggable code.
893 bool deduped = true;
894 MethodReference method_ref(dex_file_, it.GetMemberIndex());
895 if (debuggable_) {
896 quick_code_offset = writer_->relative_patcher_->GetOffset(method_ref);
897 if (quick_code_offset != 0u) {
898 // Duplicate methods, we want the same code for both of them so that the oat writer puts
899 // the same code in both ArtMethods so that we do not get different oat code at runtime.
900 } else {
901 quick_code_offset = NewQuickCodeOffset(compiled_method, it, thumb_offset);
902 deduped = false;
903 }
904 } else {
905 quick_code_offset = dedupe_map_.GetOrCreate(
906 compiled_method,
907 [this, &deduped, compiled_method, &it, thumb_offset]() {
908 deduped = false;
909 return NewQuickCodeOffset(compiled_method, it, thumb_offset);
910 });
911 }
912
913 if (code_size != 0) {
914 if (writer_->relative_patcher_->GetOffset(method_ref) != 0u) {
915 // TODO: Should this be a hard failure?
916 LOG(WARNING) << "Multiple definitions of "
917 << method_ref.dex_file->PrettyMethod(method_ref.dex_method_index)
918 << " offsets " << writer_->relative_patcher_->GetOffset(method_ref)
919 << " " << quick_code_offset;
920 } else {
921 writer_->relative_patcher_->SetOffset(method_ref, quick_code_offset);
922 }
923 }
924
925 // Update quick method header.
926 DCHECK_LT(method_offsets_index_, oat_class->method_headers_.size());
927 OatQuickMethodHeader* method_header = &oat_class->method_headers_[method_offsets_index_];
928 uint32_t vmap_table_offset = method_header->GetVmapTableOffset();
929 uint32_t method_info_offset = method_header->GetMethodInfoOffset();
930 // The code offset was 0 when the mapping/vmap table offset was set, so it's set
931 // to 0-offset and we need to adjust it by code_offset.
932 uint32_t code_offset = quick_code_offset - thumb_offset;
933 if (!compiled_method->GetQuickCode().empty()) {
934 // If the code is compiled, we write the offset of the stack map relative
935 // to the code,
936 if (vmap_table_offset != 0u) {
937 vmap_table_offset += code_offset;
938 DCHECK_LT(vmap_table_offset, code_offset);
939 }
940 if (method_info_offset != 0u) {
941 method_info_offset += code_offset;
942 DCHECK_LT(method_info_offset, code_offset);
943 }
944 } else {
945 CHECK(!kIsVdexEnabled);
946 // We write the offset of the quickening info relative to the code.
947 vmap_table_offset += code_offset;
948 DCHECK_LT(vmap_table_offset, code_offset);
949 }
950 uint32_t frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
951 uint32_t core_spill_mask = compiled_method->GetCoreSpillMask();
952 uint32_t fp_spill_mask = compiled_method->GetFpSpillMask();
953 *method_header = OatQuickMethodHeader(vmap_table_offset,
954 method_info_offset,
955 frame_size_in_bytes,
956 core_spill_mask,
957 fp_spill_mask,
958 code_size);
959
960 if (!deduped) {
961 // Update offsets. (Checksum is updated when writing.)
962 offset_ += sizeof(*method_header); // Method header is prepended before code.
963 offset_ += code_size;
964 // Record absolute patch locations.
965 if (!compiled_method->GetPatches().empty()) {
966 uintptr_t base_loc = offset_ - code_size - writer_->oat_header_->GetExecutableOffset();
967 for (const LinkerPatch& patch : compiled_method->GetPatches()) {
968 if (!patch.IsPcRelative()) {
969 writer_->absolute_patch_locations_.push_back(base_loc + patch.LiteralOffset());
970 }
971 }
972 }
973 }
974
975 const CompilerOptions& compiler_options = writer_->compiler_driver_->GetCompilerOptions();
976 // Exclude quickened dex methods (code_size == 0) since they have no native code.
977 if (compiler_options.GenerateAnyDebugInfo() && code_size != 0) {
978 bool has_code_info = method_header->IsOptimized();
979 // Record debug information for this function if we are doing that.
980 debug::MethodDebugInfo info = debug::MethodDebugInfo();
981 info.trampoline_name = nullptr;
982 info.dex_file = dex_file_;
983 info.class_def_index = class_def_index_;
984 info.dex_method_index = it.GetMemberIndex();
985 info.access_flags = it.GetMethodAccessFlags();
986 info.code_item = it.GetMethodCodeItem();
987 info.isa = compiled_method->GetInstructionSet();
988 info.deduped = deduped;
989 info.is_native_debuggable = compiler_options.GetNativeDebuggable();
990 info.is_optimized = method_header->IsOptimized();
991 info.is_code_address_text_relative = true;
992 info.code_address = code_offset - writer_->oat_header_->GetExecutableOffset();
993 info.code_size = code_size;
994 info.frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
995 info.code_info = has_code_info ? compiled_method->GetVmapTable().data() : nullptr;
996 info.cfi = compiled_method->GetCFIInfo();
997 writer_->method_info_.push_back(info);
998 }
999
1000 DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
1001 OatMethodOffsets* offsets = &oat_class->method_offsets_[method_offsets_index_];
1002 offsets->code_offset_ = quick_code_offset;
1003 ++method_offsets_index_;
1004 }
1005
1006 return true;
1007 }
1008
1009 private:
1010 struct CodeOffsetsKeyComparator {
operator ()art::OatWriter::InitCodeMethodVisitor::CodeOffsetsKeyComparator1011 bool operator()(const CompiledMethod* lhs, const CompiledMethod* rhs) const {
1012 // Code is deduplicated by CompilerDriver, compare only data pointers.
1013 if (lhs->GetQuickCode().data() != rhs->GetQuickCode().data()) {
1014 return lhs->GetQuickCode().data() < rhs->GetQuickCode().data();
1015 }
1016 // If the code is the same, all other fields are likely to be the same as well.
1017 if (UNLIKELY(lhs->GetVmapTable().data() != rhs->GetVmapTable().data())) {
1018 return lhs->GetVmapTable().data() < rhs->GetVmapTable().data();
1019 }
1020 if (UNLIKELY(lhs->GetMethodInfo().data() != rhs->GetMethodInfo().data())) {
1021 return lhs->GetMethodInfo().data() < rhs->GetMethodInfo().data();
1022 }
1023 if (UNLIKELY(lhs->GetPatches().data() != rhs->GetPatches().data())) {
1024 return lhs->GetPatches().data() < rhs->GetPatches().data();
1025 }
1026 return false;
1027 }
1028 };
1029
NewQuickCodeOffset(CompiledMethod * compiled_method,const ClassDataItemIterator & it,uint32_t thumb_offset)1030 uint32_t NewQuickCodeOffset(CompiledMethod* compiled_method,
1031 const ClassDataItemIterator& it,
1032 uint32_t thumb_offset) {
1033 offset_ = writer_->relative_patcher_->ReserveSpace(
1034 offset_, compiled_method, MethodReference(dex_file_, it.GetMemberIndex()));
1035 offset_ += CodeAlignmentSize(offset_, *compiled_method);
1036 DCHECK_ALIGNED_PARAM(offset_ + sizeof(OatQuickMethodHeader),
1037 GetInstructionSetAlignment(compiled_method->GetInstructionSet()));
1038 return offset_ + sizeof(OatQuickMethodHeader) + thumb_offset;
1039 }
1040
1041 // Deduplication is already done on a pointer basis by the compiler driver,
1042 // so we can simply compare the pointers to find out if things are duplicated.
1043 SafeMap<const CompiledMethod*, uint32_t, CodeOffsetsKeyComparator> dedupe_map_;
1044
1045 // Cache of compiler's --debuggable option.
1046 const bool debuggable_;
1047 };
1048
1049 class OatWriter::InitMapMethodVisitor : public OatDexMethodVisitor {
1050 public:
InitMapMethodVisitor(OatWriter * writer,size_t offset)1051 InitMapMethodVisitor(OatWriter* writer, size_t offset)
1052 : OatDexMethodVisitor(writer, offset) {}
1053
VisitMethod(size_t class_def_method_index,const ClassDataItemIterator & it ATTRIBUTE_UNUSED)1054 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it ATTRIBUTE_UNUSED)
1055 OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
1056 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
1057 CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1058
1059 if (HasCompiledCode(compiled_method)) {
1060 DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
1061 DCHECK_EQ(oat_class->method_headers_[method_offsets_index_].GetVmapTableOffset(), 0u);
1062
1063 ArrayRef<const uint8_t> map = compiled_method->GetVmapTable();
1064 uint32_t map_size = map.size() * sizeof(map[0]);
1065 if (map_size != 0u) {
1066 size_t offset = dedupe_map_.GetOrCreate(
1067 map.data(),
1068 [this, map_size]() {
1069 uint32_t new_offset = offset_;
1070 offset_ += map_size;
1071 return new_offset;
1072 });
1073 // Code offset is not initialized yet, so set the map offset to 0u-offset.
1074 DCHECK_EQ(oat_class->method_offsets_[method_offsets_index_].code_offset_, 0u);
1075 oat_class->method_headers_[method_offsets_index_].SetVmapTableOffset(0u - offset);
1076 }
1077 ++method_offsets_index_;
1078 }
1079
1080 return true;
1081 }
1082
1083 private:
1084 // Deduplication is already done on a pointer basis by the compiler driver,
1085 // so we can simply compare the pointers to find out if things are duplicated.
1086 SafeMap<const uint8_t*, uint32_t> dedupe_map_;
1087 };
1088
1089 class OatWriter::InitMethodInfoVisitor : public OatDexMethodVisitor {
1090 public:
InitMethodInfoVisitor(OatWriter * writer,size_t offset)1091 InitMethodInfoVisitor(OatWriter* writer, size_t offset) : OatDexMethodVisitor(writer, offset) {}
1092
VisitMethod(size_t class_def_method_index,const ClassDataItemIterator & it ATTRIBUTE_UNUSED)1093 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it ATTRIBUTE_UNUSED)
1094 OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
1095 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
1096 CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1097
1098 if (HasCompiledCode(compiled_method)) {
1099 DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
1100 DCHECK_EQ(oat_class->method_headers_[method_offsets_index_].GetMethodInfoOffset(), 0u);
1101 ArrayRef<const uint8_t> map = compiled_method->GetMethodInfo();
1102 const uint32_t map_size = map.size() * sizeof(map[0]);
1103 if (map_size != 0u) {
1104 size_t offset = dedupe_map_.GetOrCreate(
1105 map.data(),
1106 [this, map_size]() {
1107 uint32_t new_offset = offset_;
1108 offset_ += map_size;
1109 return new_offset;
1110 });
1111 // Code offset is not initialized yet, so set the map offset to 0u-offset.
1112 DCHECK_EQ(oat_class->method_offsets_[method_offsets_index_].code_offset_, 0u);
1113 oat_class->method_headers_[method_offsets_index_].SetMethodInfoOffset(0u - offset);
1114 }
1115 ++method_offsets_index_;
1116 }
1117
1118 return true;
1119 }
1120
1121 private:
1122 // Deduplication is already done on a pointer basis by the compiler driver,
1123 // so we can simply compare the pointers to find out if things are duplicated.
1124 SafeMap<const uint8_t*, uint32_t> dedupe_map_;
1125 };
1126
1127 class OatWriter::InitImageMethodVisitor : public OatDexMethodVisitor {
1128 public:
InitImageMethodVisitor(OatWriter * writer,size_t offset,const std::vector<const DexFile * > * dex_files)1129 InitImageMethodVisitor(OatWriter* writer,
1130 size_t offset,
1131 const std::vector<const DexFile*>* dex_files)
1132 : OatDexMethodVisitor(writer, offset),
1133 pointer_size_(GetInstructionSetPointerSize(writer_->compiler_driver_->GetInstructionSet())),
1134 class_loader_(writer->HasImage() ? writer->image_writer_->GetClassLoader() : nullptr),
1135 dex_files_(dex_files),
1136 class_linker_(Runtime::Current()->GetClassLinker()) {}
1137
1138 // Handle copied methods here. Copy pointer to quick code from
1139 // an origin method to a copied method only if they are
1140 // in the same oat file. If the origin and the copied methods are
1141 // in different oat files don't touch the copied method.
1142 // References to other oat files are not supported yet.
StartClass(const DexFile * dex_file,size_t class_def_index)1143 bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE
1144 REQUIRES_SHARED(Locks::mutator_lock_) {
1145 OatDexMethodVisitor::StartClass(dex_file, class_def_index);
1146 // Skip classes that are not in the image.
1147 if (!IsImageClass()) {
1148 return true;
1149 }
1150 ObjPtr<mirror::DexCache> dex_cache = class_linker_->FindDexCache(Thread::Current(), *dex_file);
1151 const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
1152 mirror::Class* klass = dex_cache->GetResolvedType(class_def.class_idx_);
1153 if (klass != nullptr) {
1154 for (ArtMethod& method : klass->GetCopiedMethods(pointer_size_)) {
1155 // Find origin method. Declaring class and dex_method_idx
1156 // in the copied method should be the same as in the origin
1157 // method.
1158 mirror::Class* declaring_class = method.GetDeclaringClass();
1159 ArtMethod* origin = declaring_class->FindClassMethod(
1160 declaring_class->GetDexCache(),
1161 method.GetDexMethodIndex(),
1162 pointer_size_);
1163 CHECK(origin != nullptr);
1164 CHECK(!origin->IsDirect());
1165 CHECK(origin->GetDeclaringClass() == declaring_class);
1166 if (IsInOatFile(&declaring_class->GetDexFile())) {
1167 const void* code_ptr =
1168 origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_);
1169 if (code_ptr == nullptr) {
1170 methods_to_process_.push_back(std::make_pair(&method, origin));
1171 } else {
1172 method.SetEntryPointFromQuickCompiledCodePtrSize(
1173 code_ptr, pointer_size_);
1174 }
1175 }
1176 }
1177 }
1178 return true;
1179 }
1180
VisitMethod(size_t class_def_method_index,const ClassDataItemIterator & it)1181 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE
1182 REQUIRES_SHARED(Locks::mutator_lock_) {
1183 // Skip methods that are not in the image.
1184 if (!IsImageClass()) {
1185 return true;
1186 }
1187
1188 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
1189 CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1190
1191 OatMethodOffsets offsets(0u);
1192 if (HasCompiledCode(compiled_method)) {
1193 DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
1194 offsets = oat_class->method_offsets_[method_offsets_index_];
1195 ++method_offsets_index_;
1196 }
1197
1198 Thread* self = Thread::Current();
1199 ObjPtr<mirror::DexCache> dex_cache = class_linker_->FindDexCache(self, *dex_file_);
1200 ArtMethod* method;
1201 if (writer_->HasBootImage()) {
1202 const InvokeType invoke_type = it.GetMethodInvokeType(
1203 dex_file_->GetClassDef(class_def_index_));
1204 // Unchecked as we hold mutator_lock_ on entry.
1205 ScopedObjectAccessUnchecked soa(self);
1206 StackHandleScope<1> hs(self);
1207 method = class_linker_->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
1208 *dex_file_,
1209 it.GetMemberIndex(),
1210 hs.NewHandle(dex_cache),
1211 ScopedNullHandle<mirror::ClassLoader>(),
1212 nullptr,
1213 invoke_type);
1214 if (method == nullptr) {
1215 LOG(FATAL_WITHOUT_ABORT) << "Unexpected failure to resolve a method: "
1216 << dex_file_->PrettyMethod(it.GetMemberIndex(), true);
1217 self->AssertPendingException();
1218 mirror::Throwable* exc = self->GetException();
1219 std::string dump = exc->Dump();
1220 LOG(FATAL) << dump;
1221 UNREACHABLE();
1222 }
1223 } else {
1224 // Should already have been resolved by the compiler.
1225 // It may not be resolved if the class failed to verify, in this case, don't set the
1226 // entrypoint. This is not fatal since we shall use a resolution method.
1227 method = class_linker_->LookupResolvedMethod(it.GetMemberIndex(), dex_cache, class_loader_);
1228 }
1229 if (method != nullptr &&
1230 compiled_method != nullptr &&
1231 compiled_method->GetQuickCode().size() != 0) {
1232 method->SetEntryPointFromQuickCompiledCodePtrSize(
1233 reinterpret_cast<void*>(offsets.code_offset_), pointer_size_);
1234 }
1235
1236 return true;
1237 }
1238
1239 // Check whether current class is image class
IsImageClass()1240 bool IsImageClass() {
1241 const DexFile::TypeId& type_id =
1242 dex_file_->GetTypeId(dex_file_->GetClassDef(class_def_index_).class_idx_);
1243 const char* class_descriptor = dex_file_->GetTypeDescriptor(type_id);
1244 return writer_->GetCompilerDriver()->IsImageClass(class_descriptor);
1245 }
1246
1247 // Check whether specified dex file is in the compiled oat file.
IsInOatFile(const DexFile * dex_file)1248 bool IsInOatFile(const DexFile* dex_file) {
1249 return ContainsElement(*dex_files_, dex_file);
1250 }
1251
1252 // Assign a pointer to quick code for copied methods
1253 // not handled in the method StartClass
Postprocess()1254 void Postprocess() {
1255 for (std::pair<ArtMethod*, ArtMethod*>& p : methods_to_process_) {
1256 ArtMethod* method = p.first;
1257 ArtMethod* origin = p.second;
1258 const void* code_ptr =
1259 origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_);
1260 if (code_ptr != nullptr) {
1261 method->SetEntryPointFromQuickCompiledCodePtrSize(code_ptr, pointer_size_);
1262 }
1263 }
1264 }
1265
1266 private:
1267 const PointerSize pointer_size_;
1268 ObjPtr<mirror::ClassLoader> class_loader_;
1269 const std::vector<const DexFile*>* dex_files_;
1270 ClassLinker* const class_linker_;
1271 std::vector<std::pair<ArtMethod*, ArtMethod*>> methods_to_process_;
1272 };
1273
1274 class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor {
1275 public:
WriteCodeMethodVisitor(OatWriter * writer,OutputStream * out,const size_t file_offset,size_t relative_offset)1276 WriteCodeMethodVisitor(OatWriter* writer, OutputStream* out, const size_t file_offset,
1277 size_t relative_offset) SHARED_LOCK_FUNCTION(Locks::mutator_lock_)
1278 : OatDexMethodVisitor(writer, relative_offset),
1279 pointer_size_(GetInstructionSetPointerSize(writer_->compiler_driver_->GetInstructionSet())),
1280 class_loader_(writer->HasImage() ? writer->image_writer_->GetClassLoader() : nullptr),
1281 out_(out),
1282 file_offset_(file_offset),
1283 soa_(Thread::Current()),
1284 no_thread_suspension_("OatWriter patching"),
1285 class_linker_(Runtime::Current()->GetClassLinker()),
1286 dex_cache_(nullptr) {
1287 patched_code_.reserve(16 * KB);
1288 if (writer_->HasBootImage()) {
1289 // If we're creating the image, the address space must be ready so that we can apply patches.
1290 CHECK(writer_->image_writer_->IsImageAddressSpaceReady());
1291 }
1292 }
1293
UNLOCK_FUNCTION(Locks::mutator_lock_)1294 ~WriteCodeMethodVisitor() UNLOCK_FUNCTION(Locks::mutator_lock_) {
1295 }
1296
StartClass(const DexFile * dex_file,size_t class_def_index)1297 bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE
1298 REQUIRES_SHARED(Locks::mutator_lock_) {
1299 OatDexMethodVisitor::StartClass(dex_file, class_def_index);
1300 if (writer_->GetCompilerDriver()->GetCompilerOptions().IsAotCompilationEnabled()) {
1301 // Only need to set the dex cache if we have compilation. Other modes might have unloaded it.
1302 if (dex_cache_ == nullptr || dex_cache_->GetDexFile() != dex_file) {
1303 dex_cache_ = class_linker_->FindDexCache(Thread::Current(), *dex_file);
1304 DCHECK(dex_cache_ != nullptr);
1305 }
1306 }
1307 return true;
1308 }
1309
EndClass()1310 bool EndClass() OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
1311 bool result = OatDexMethodVisitor::EndClass();
1312 if (oat_class_index_ == writer_->oat_classes_.size()) {
1313 DCHECK(result); // OatDexMethodVisitor::EndClass() never fails.
1314 offset_ = writer_->relative_patcher_->WriteThunks(out_, offset_);
1315 if (UNLIKELY(offset_ == 0u)) {
1316 PLOG(ERROR) << "Failed to write final relative call thunks";
1317 result = false;
1318 }
1319 }
1320 return result;
1321 }
1322
VisitMethod(size_t class_def_method_index,const ClassDataItemIterator & it)1323 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE
1324 REQUIRES_SHARED(Locks::mutator_lock_) {
1325 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
1326 const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1327
1328 // No thread suspension since dex_cache_ that may get invalidated if that occurs.
1329 ScopedAssertNoThreadSuspension tsc(__FUNCTION__);
1330 if (HasCompiledCode(compiled_method)) {
1331 size_t file_offset = file_offset_;
1332 OutputStream* out = out_;
1333
1334 ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
1335 uint32_t code_size = quick_code.size() * sizeof(uint8_t);
1336
1337 // Deduplicate code arrays.
1338 const OatMethodOffsets& method_offsets = oat_class->method_offsets_[method_offsets_index_];
1339 if (method_offsets.code_offset_ > offset_) {
1340 offset_ = writer_->relative_patcher_->WriteThunks(out, offset_);
1341 if (offset_ == 0u) {
1342 ReportWriteFailure("relative call thunk", it);
1343 return false;
1344 }
1345 uint32_t alignment_size = CodeAlignmentSize(offset_, *compiled_method);
1346 if (alignment_size != 0) {
1347 if (!writer_->WriteCodeAlignment(out, alignment_size)) {
1348 ReportWriteFailure("code alignment padding", it);
1349 return false;
1350 }
1351 offset_ += alignment_size;
1352 DCHECK_OFFSET_();
1353 }
1354 DCHECK_ALIGNED_PARAM(offset_ + sizeof(OatQuickMethodHeader),
1355 GetInstructionSetAlignment(compiled_method->GetInstructionSet()));
1356 DCHECK_EQ(method_offsets.code_offset_,
1357 offset_ + sizeof(OatQuickMethodHeader) + compiled_method->CodeDelta())
1358 << dex_file_->PrettyMethod(it.GetMemberIndex());
1359 const OatQuickMethodHeader& method_header =
1360 oat_class->method_headers_[method_offsets_index_];
1361 if (!out->WriteFully(&method_header, sizeof(method_header))) {
1362 ReportWriteFailure("method header", it);
1363 return false;
1364 }
1365 writer_->size_method_header_ += sizeof(method_header);
1366 offset_ += sizeof(method_header);
1367 DCHECK_OFFSET_();
1368
1369 if (!compiled_method->GetPatches().empty()) {
1370 patched_code_.assign(quick_code.begin(), quick_code.end());
1371 quick_code = ArrayRef<const uint8_t>(patched_code_);
1372 for (const LinkerPatch& patch : compiled_method->GetPatches()) {
1373 uint32_t literal_offset = patch.LiteralOffset();
1374 switch (patch.GetType()) {
1375 case LinkerPatch::Type::kMethodBssEntry: {
1376 uint32_t target_offset =
1377 writer_->bss_start_ + writer_->bss_method_entries_.Get(patch.TargetMethod());
1378 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1379 patch,
1380 offset_ + literal_offset,
1381 target_offset);
1382 break;
1383 }
1384 case LinkerPatch::Type::kCallRelative: {
1385 // NOTE: Relative calls across oat files are not supported.
1386 uint32_t target_offset = GetTargetOffset(patch);
1387 writer_->relative_patcher_->PatchCall(&patched_code_,
1388 literal_offset,
1389 offset_ + literal_offset,
1390 target_offset);
1391 break;
1392 }
1393 case LinkerPatch::Type::kStringRelative: {
1394 uint32_t target_offset = GetTargetObjectOffset(GetTargetString(patch));
1395 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1396 patch,
1397 offset_ + literal_offset,
1398 target_offset);
1399 break;
1400 }
1401 case LinkerPatch::Type::kStringBssEntry: {
1402 StringReference ref(patch.TargetStringDexFile(), patch.TargetStringIndex());
1403 uint32_t target_offset =
1404 writer_->bss_start_ + writer_->bss_string_entries_.Get(ref);
1405 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1406 patch,
1407 offset_ + literal_offset,
1408 target_offset);
1409 break;
1410 }
1411 case LinkerPatch::Type::kTypeRelative: {
1412 uint32_t target_offset = GetTargetObjectOffset(GetTargetType(patch));
1413 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1414 patch,
1415 offset_ + literal_offset,
1416 target_offset);
1417 break;
1418 }
1419 case LinkerPatch::Type::kTypeBssEntry: {
1420 TypeReference ref(patch.TargetTypeDexFile(), patch.TargetTypeIndex());
1421 uint32_t target_offset = writer_->bss_start_ + writer_->bss_type_entries_.Get(ref);
1422 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1423 patch,
1424 offset_ + literal_offset,
1425 target_offset);
1426 break;
1427 }
1428 case LinkerPatch::Type::kCall: {
1429 uint32_t target_offset = GetTargetOffset(patch);
1430 PatchCodeAddress(&patched_code_, literal_offset, target_offset);
1431 break;
1432 }
1433 case LinkerPatch::Type::kMethodRelative: {
1434 uint32_t target_offset = GetTargetMethodOffset(GetTargetMethod(patch));
1435 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1436 patch,
1437 offset_ + literal_offset,
1438 target_offset);
1439 break;
1440 }
1441 case LinkerPatch::Type::kBakerReadBarrierBranch: {
1442 writer_->relative_patcher_->PatchBakerReadBarrierBranch(&patched_code_,
1443 patch,
1444 offset_ + literal_offset);
1445 break;
1446 }
1447 default: {
1448 DCHECK(false) << "Unexpected linker patch type: " << patch.GetType();
1449 break;
1450 }
1451 }
1452 }
1453 }
1454
1455 if (!out->WriteFully(quick_code.data(), code_size)) {
1456 ReportWriteFailure("method code", it);
1457 return false;
1458 }
1459 writer_->size_code_ += code_size;
1460 offset_ += code_size;
1461 }
1462 DCHECK_OFFSET_();
1463 ++method_offsets_index_;
1464 }
1465
1466 return true;
1467 }
1468
1469 private:
1470 const PointerSize pointer_size_;
1471 ObjPtr<mirror::ClassLoader> class_loader_;
1472 OutputStream* const out_;
1473 const size_t file_offset_;
1474 const ScopedObjectAccess soa_;
1475 const ScopedAssertNoThreadSuspension no_thread_suspension_;
1476 ClassLinker* const class_linker_;
1477 ObjPtr<mirror::DexCache> dex_cache_;
1478 std::vector<uint8_t> patched_code_;
1479
ReportWriteFailure(const char * what,const ClassDataItemIterator & it)1480 void ReportWriteFailure(const char* what, const ClassDataItemIterator& it) {
1481 PLOG(ERROR) << "Failed to write " << what << " for "
1482 << dex_file_->PrettyMethod(it.GetMemberIndex()) << " to " << out_->GetLocation();
1483 }
1484
GetTargetMethod(const LinkerPatch & patch)1485 ArtMethod* GetTargetMethod(const LinkerPatch& patch)
1486 REQUIRES_SHARED(Locks::mutator_lock_) {
1487 MethodReference ref = patch.TargetMethod();
1488 ObjPtr<mirror::DexCache> dex_cache =
1489 (dex_file_ == ref.dex_file) ? dex_cache_ : class_linker_->FindDexCache(
1490 Thread::Current(), *ref.dex_file);
1491 ArtMethod* method =
1492 class_linker_->LookupResolvedMethod(ref.dex_method_index, dex_cache, class_loader_);
1493 CHECK(method != nullptr);
1494 return method;
1495 }
1496
GetTargetOffset(const LinkerPatch & patch)1497 uint32_t GetTargetOffset(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) {
1498 uint32_t target_offset = writer_->relative_patcher_->GetOffset(patch.TargetMethod());
1499 // If there's no new compiled code, either we're compiling an app and the target method
1500 // is in the boot image, or we need to point to the correct trampoline.
1501 if (UNLIKELY(target_offset == 0)) {
1502 ArtMethod* target = GetTargetMethod(patch);
1503 DCHECK(target != nullptr);
1504 const void* oat_code_offset =
1505 target->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_);
1506 if (oat_code_offset != 0) {
1507 DCHECK(!writer_->HasBootImage());
1508 DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickResolutionStub(oat_code_offset));
1509 DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickToInterpreterBridge(oat_code_offset));
1510 DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickGenericJniStub(oat_code_offset));
1511 target_offset = PointerToLowMemUInt32(oat_code_offset);
1512 } else {
1513 target_offset = target->IsNative()
1514 ? writer_->oat_header_->GetQuickGenericJniTrampolineOffset()
1515 : writer_->oat_header_->GetQuickToInterpreterBridgeOffset();
1516 }
1517 }
1518 return target_offset;
1519 }
1520
GetDexCache(const DexFile * target_dex_file)1521 ObjPtr<mirror::DexCache> GetDexCache(const DexFile* target_dex_file)
1522 REQUIRES_SHARED(Locks::mutator_lock_) {
1523 return (target_dex_file == dex_file_)
1524 ? dex_cache_
1525 : class_linker_->FindDexCache(Thread::Current(), *target_dex_file);
1526 }
1527
GetTargetType(const LinkerPatch & patch)1528 mirror::Class* GetTargetType(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) {
1529 DCHECK(writer_->HasImage());
1530 ObjPtr<mirror::DexCache> dex_cache = GetDexCache(patch.TargetTypeDexFile());
1531 ObjPtr<mirror::Class> type =
1532 ClassLinker::LookupResolvedType(patch.TargetTypeIndex(), dex_cache, class_loader_);
1533 CHECK(type != nullptr);
1534 return type.Ptr();
1535 }
1536
GetTargetString(const LinkerPatch & patch)1537 mirror::String* GetTargetString(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) {
1538 ScopedObjectAccessUnchecked soa(Thread::Current());
1539 ClassLinker* linker = Runtime::Current()->GetClassLinker();
1540 mirror::String* string = linker->LookupString(*patch.TargetStringDexFile(),
1541 patch.TargetStringIndex(),
1542 GetDexCache(patch.TargetStringDexFile()));
1543 DCHECK(string != nullptr);
1544 DCHECK(writer_->HasBootImage() ||
1545 Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(string));
1546 return string;
1547 }
1548
GetTargetMethodOffset(ArtMethod * method)1549 uint32_t GetTargetMethodOffset(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) {
1550 DCHECK(writer_->HasBootImage());
1551 method = writer_->image_writer_->GetImageMethodAddress(method);
1552 size_t oat_index = writer_->image_writer_->GetOatIndexForDexFile(dex_file_);
1553 uintptr_t oat_data_begin = writer_->image_writer_->GetOatDataBegin(oat_index);
1554 // TODO: Clean up offset types. The target offset must be treated as signed.
1555 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(method) - oat_data_begin);
1556 }
1557
GetTargetObjectOffset(mirror::Object * object)1558 uint32_t GetTargetObjectOffset(mirror::Object* object) REQUIRES_SHARED(Locks::mutator_lock_) {
1559 DCHECK(writer_->HasBootImage());
1560 object = writer_->image_writer_->GetImageAddress(object);
1561 size_t oat_index = writer_->image_writer_->GetOatIndexForDexFile(dex_file_);
1562 uintptr_t oat_data_begin = writer_->image_writer_->GetOatDataBegin(oat_index);
1563 // TODO: Clean up offset types. The target offset must be treated as signed.
1564 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(object) - oat_data_begin);
1565 }
1566
PatchObjectAddress(std::vector<uint8_t> * code,uint32_t offset,mirror::Object * object)1567 void PatchObjectAddress(std::vector<uint8_t>* code, uint32_t offset, mirror::Object* object)
1568 REQUIRES_SHARED(Locks::mutator_lock_) {
1569 if (writer_->HasBootImage()) {
1570 object = writer_->image_writer_->GetImageAddress(object);
1571 } else {
1572 // NOTE: We're using linker patches for app->boot references when the image can
1573 // be relocated and therefore we need to emit .oat_patches. We're not using this
1574 // for app->app references, so check that the object is in the image space.
1575 DCHECK(Runtime::Current()->GetHeap()->FindSpaceFromObject(object, false)->IsImageSpace());
1576 }
1577 // Note: We only patch targeting Objects in image which is in the low 4gb.
1578 uint32_t address = PointerToLowMemUInt32(object);
1579 DCHECK_LE(offset + 4, code->size());
1580 uint8_t* data = &(*code)[offset];
1581 data[0] = address & 0xffu;
1582 data[1] = (address >> 8) & 0xffu;
1583 data[2] = (address >> 16) & 0xffu;
1584 data[3] = (address >> 24) & 0xffu;
1585 }
1586
PatchCodeAddress(std::vector<uint8_t> * code,uint32_t offset,uint32_t target_offset)1587 void PatchCodeAddress(std::vector<uint8_t>* code, uint32_t offset, uint32_t target_offset)
1588 REQUIRES_SHARED(Locks::mutator_lock_) {
1589 uint32_t address = target_offset;
1590 if (writer_->HasBootImage()) {
1591 size_t oat_index = writer_->image_writer_->GetOatIndexForDexCache(dex_cache_);
1592 // TODO: Clean up offset types.
1593 // The target_offset must be treated as signed for cross-oat patching.
1594 const void* target = reinterpret_cast<const void*>(
1595 writer_->image_writer_->GetOatDataBegin(oat_index) +
1596 static_cast<int32_t>(target_offset));
1597 address = PointerToLowMemUInt32(target);
1598 }
1599 DCHECK_LE(offset + 4, code->size());
1600 uint8_t* data = &(*code)[offset];
1601 data[0] = address & 0xffu;
1602 data[1] = (address >> 8) & 0xffu;
1603 data[2] = (address >> 16) & 0xffu;
1604 data[3] = (address >> 24) & 0xffu;
1605 }
1606 };
1607
1608 class OatWriter::WriteMapMethodVisitor : public OatDexMethodVisitor {
1609 public:
WriteMapMethodVisitor(OatWriter * writer,OutputStream * out,const size_t file_offset,size_t relative_offset)1610 WriteMapMethodVisitor(OatWriter* writer,
1611 OutputStream* out,
1612 const size_t file_offset,
1613 size_t relative_offset)
1614 : OatDexMethodVisitor(writer, relative_offset),
1615 out_(out),
1616 file_offset_(file_offset) {}
1617
VisitMethod(size_t class_def_method_index,const ClassDataItemIterator & it)1618 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE {
1619 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
1620 const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1621
1622 if (HasCompiledCode(compiled_method)) {
1623 size_t file_offset = file_offset_;
1624 OutputStream* out = out_;
1625
1626 uint32_t map_offset = oat_class->method_headers_[method_offsets_index_].GetVmapTableOffset();
1627 uint32_t code_offset = oat_class->method_offsets_[method_offsets_index_].code_offset_;
1628 ++method_offsets_index_;
1629
1630 DCHECK((compiled_method->GetVmapTable().size() == 0u && map_offset == 0u) ||
1631 (compiled_method->GetVmapTable().size() != 0u && map_offset != 0u))
1632 << compiled_method->GetVmapTable().size() << " " << map_offset << " "
1633 << dex_file_->PrettyMethod(it.GetMemberIndex());
1634
1635 // If vdex is enabled, only emit the map for compiled code. The quickening info
1636 // is emitted in the vdex already.
1637 if (map_offset != 0u) {
1638 // Transform map_offset to actual oat data offset.
1639 map_offset = (code_offset - compiled_method->CodeDelta()) - map_offset;
1640 DCHECK_NE(map_offset, 0u);
1641 DCHECK_LE(map_offset, offset_) << dex_file_->PrettyMethod(it.GetMemberIndex());
1642
1643 ArrayRef<const uint8_t> map = compiled_method->GetVmapTable();
1644 size_t map_size = map.size() * sizeof(map[0]);
1645 if (map_offset == offset_) {
1646 // Write deduplicated map (code info for Optimizing or transformation info for dex2dex).
1647 if (UNLIKELY(!out->WriteFully(map.data(), map_size))) {
1648 ReportWriteFailure(it);
1649 return false;
1650 }
1651 offset_ += map_size;
1652 }
1653 }
1654 DCHECK_OFFSET_();
1655 }
1656
1657 return true;
1658 }
1659
1660 private:
1661 OutputStream* const out_;
1662 size_t const file_offset_;
1663
ReportWriteFailure(const ClassDataItemIterator & it)1664 void ReportWriteFailure(const ClassDataItemIterator& it) {
1665 PLOG(ERROR) << "Failed to write map for "
1666 << dex_file_->PrettyMethod(it.GetMemberIndex()) << " to " << out_->GetLocation();
1667 }
1668 };
1669
1670 class OatWriter::WriteMethodInfoVisitor : public OatDexMethodVisitor {
1671 public:
WriteMethodInfoVisitor(OatWriter * writer,OutputStream * out,const size_t file_offset,size_t relative_offset)1672 WriteMethodInfoVisitor(OatWriter* writer,
1673 OutputStream* out,
1674 const size_t file_offset,
1675 size_t relative_offset)
1676 : OatDexMethodVisitor(writer, relative_offset),
1677 out_(out),
1678 file_offset_(file_offset) {}
1679
VisitMethod(size_t class_def_method_index,const ClassDataItemIterator & it)1680 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE {
1681 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
1682 const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1683
1684 if (HasCompiledCode(compiled_method)) {
1685 size_t file_offset = file_offset_;
1686 OutputStream* out = out_;
1687 uint32_t map_offset = oat_class->method_headers_[method_offsets_index_].GetMethodInfoOffset();
1688 uint32_t code_offset = oat_class->method_offsets_[method_offsets_index_].code_offset_;
1689 ++method_offsets_index_;
1690 DCHECK((compiled_method->GetMethodInfo().size() == 0u && map_offset == 0u) ||
1691 (compiled_method->GetMethodInfo().size() != 0u && map_offset != 0u))
1692 << compiled_method->GetMethodInfo().size() << " " << map_offset << " "
1693 << dex_file_->PrettyMethod(it.GetMemberIndex());
1694 if (map_offset != 0u) {
1695 // Transform map_offset to actual oat data offset.
1696 map_offset = (code_offset - compiled_method->CodeDelta()) - map_offset;
1697 DCHECK_NE(map_offset, 0u);
1698 DCHECK_LE(map_offset, offset_) << dex_file_->PrettyMethod(it.GetMemberIndex());
1699
1700 ArrayRef<const uint8_t> map = compiled_method->GetMethodInfo();
1701 size_t map_size = map.size() * sizeof(map[0]);
1702 if (map_offset == offset_) {
1703 // Write deduplicated map (code info for Optimizing or transformation info for dex2dex).
1704 if (UNLIKELY(!out->WriteFully(map.data(), map_size))) {
1705 ReportWriteFailure(it);
1706 return false;
1707 }
1708 offset_ += map_size;
1709 }
1710 }
1711 DCHECK_OFFSET_();
1712 }
1713
1714 return true;
1715 }
1716
1717 private:
1718 OutputStream* const out_;
1719 size_t const file_offset_;
1720
ReportWriteFailure(const ClassDataItemIterator & it)1721 void ReportWriteFailure(const ClassDataItemIterator& it) {
1722 PLOG(ERROR) << "Failed to write map for "
1723 << dex_file_->PrettyMethod(it.GetMemberIndex()) << " to " << out_->GetLocation();
1724 }
1725 };
1726
1727 // Visit all methods from all classes in all dex files with the specified visitor.
VisitDexMethods(DexMethodVisitor * visitor)1728 bool OatWriter::VisitDexMethods(DexMethodVisitor* visitor) {
1729 for (const DexFile* dex_file : *dex_files_) {
1730 const size_t class_def_count = dex_file->NumClassDefs();
1731 for (size_t class_def_index = 0; class_def_index != class_def_count; ++class_def_index) {
1732 if (UNLIKELY(!visitor->StartClass(dex_file, class_def_index))) {
1733 return false;
1734 }
1735 if (MayHaveCompiledMethods()) {
1736 const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
1737 const uint8_t* class_data = dex_file->GetClassData(class_def);
1738 if (class_data != nullptr) { // ie not an empty class, such as a marker interface
1739 ClassDataItemIterator it(*dex_file, class_data);
1740 it.SkipAllFields();
1741 size_t class_def_method_index = 0u;
1742 while (it.HasNextDirectMethod()) {
1743 if (!visitor->VisitMethod(class_def_method_index, it)) {
1744 return false;
1745 }
1746 ++class_def_method_index;
1747 it.Next();
1748 }
1749 while (it.HasNextVirtualMethod()) {
1750 if (UNLIKELY(!visitor->VisitMethod(class_def_method_index, it))) {
1751 return false;
1752 }
1753 ++class_def_method_index;
1754 it.Next();
1755 }
1756 }
1757 }
1758 if (UNLIKELY(!visitor->EndClass())) {
1759 return false;
1760 }
1761 }
1762 }
1763 return true;
1764 }
1765
InitOatHeader(InstructionSet instruction_set,const InstructionSetFeatures * instruction_set_features,uint32_t num_dex_files,SafeMap<std::string,std::string> * key_value_store)1766 size_t OatWriter::InitOatHeader(InstructionSet instruction_set,
1767 const InstructionSetFeatures* instruction_set_features,
1768 uint32_t num_dex_files,
1769 SafeMap<std::string, std::string>* key_value_store) {
1770 TimingLogger::ScopedTiming split("InitOatHeader", timings_);
1771 oat_header_.reset(OatHeader::Create(instruction_set,
1772 instruction_set_features,
1773 num_dex_files,
1774 key_value_store));
1775 size_oat_header_ += sizeof(OatHeader);
1776 size_oat_header_key_value_store_ += oat_header_->GetHeaderSize() - sizeof(OatHeader);
1777 return oat_header_->GetHeaderSize();
1778 }
1779
InitClassOffsets(size_t offset)1780 size_t OatWriter::InitClassOffsets(size_t offset) {
1781 // Reserve space for class offsets in OAT and update class_offsets_offset_.
1782 for (OatDexFile& oat_dex_file : oat_dex_files_) {
1783 DCHECK_EQ(oat_dex_file.class_offsets_offset_, 0u);
1784 if (!oat_dex_file.class_offsets_.empty()) {
1785 // Class offsets are required to be 4 byte aligned.
1786 offset = RoundUp(offset, 4u);
1787 oat_dex_file.class_offsets_offset_ = offset;
1788 offset += oat_dex_file.GetClassOffsetsRawSize();
1789 DCHECK_ALIGNED(offset, 4u);
1790 }
1791 }
1792 return offset;
1793 }
1794
InitOatClasses(size_t offset)1795 size_t OatWriter::InitOatClasses(size_t offset) {
1796 // calculate the offsets within OatDexFiles to OatClasses
1797 InitOatClassesMethodVisitor visitor(this, offset);
1798 bool success = VisitDexMethods(&visitor);
1799 CHECK(success);
1800 offset = visitor.GetOffset();
1801
1802 // Update oat_dex_files_.
1803 auto oat_class_it = oat_class_headers_.begin();
1804 for (OatDexFile& oat_dex_file : oat_dex_files_) {
1805 for (uint32_t& class_offset : oat_dex_file.class_offsets_) {
1806 DCHECK(oat_class_it != oat_class_headers_.end());
1807 class_offset = oat_class_it->offset_;
1808 ++oat_class_it;
1809 }
1810 }
1811 CHECK(oat_class_it == oat_class_headers_.end());
1812
1813 return offset;
1814 }
1815
InitOatMaps(size_t offset)1816 size_t OatWriter::InitOatMaps(size_t offset) {
1817 if (!MayHaveCompiledMethods()) {
1818 return offset;
1819 }
1820 {
1821 InitMapMethodVisitor visitor(this, offset);
1822 bool success = VisitDexMethods(&visitor);
1823 DCHECK(success);
1824 offset = visitor.GetOffset();
1825 }
1826 {
1827 InitMethodInfoVisitor visitor(this, offset);
1828 bool success = VisitDexMethods(&visitor);
1829 DCHECK(success);
1830 offset = visitor.GetOffset();
1831 }
1832 return offset;
1833 }
1834
InitMethodBssMappings(size_t offset)1835 size_t OatWriter::InitMethodBssMappings(size_t offset) {
1836 size_t number_of_dex_files = 0u;
1837 for (size_t i = 0, size = dex_files_->size(); i != size; ++i) {
1838 const DexFile* dex_file = (*dex_files_)[i];
1839 auto it = bss_method_entry_references_.find(dex_file);
1840 if (it != bss_method_entry_references_.end()) {
1841 const BitVector& method_indexes = it->second;
1842 ++number_of_dex_files;
1843 // If there are any classes, the class offsets allocation aligns the offset
1844 // and we cannot have method bss mappings without class offsets.
1845 static_assert(alignof(MethodBssMapping) == 4u, "MethodBssMapping alignment check.");
1846 DCHECK_ALIGNED(offset, 4u);
1847 oat_dex_files_[i].method_bss_mapping_offset_ = offset;
1848
1849 linker::MethodBssMappingEncoder encoder(
1850 GetInstructionSetPointerSize(oat_header_->GetInstructionSet()));
1851 size_t number_of_entries = 0u;
1852 bool first_index = true;
1853 for (uint32_t method_index : method_indexes.Indexes()) {
1854 uint32_t bss_offset = bss_method_entries_.Get(MethodReference(dex_file, method_index));
1855 if (first_index || !encoder.TryMerge(method_index, bss_offset)) {
1856 encoder.Reset(method_index, bss_offset);
1857 ++number_of_entries;
1858 first_index = false;
1859 }
1860 }
1861 DCHECK_NE(number_of_entries, 0u);
1862 offset += MethodBssMapping::ComputeSize(number_of_entries);
1863 }
1864 }
1865 // Check that all dex files targeted by method bss entries are in `*dex_files_`.
1866 CHECK_EQ(number_of_dex_files, bss_method_entry_references_.size());
1867 return offset;
1868 }
1869
InitOatDexFiles(size_t offset)1870 size_t OatWriter::InitOatDexFiles(size_t offset) {
1871 // Initialize offsets of oat dex files.
1872 for (OatDexFile& oat_dex_file : oat_dex_files_) {
1873 oat_dex_file.offset_ = offset;
1874 offset += oat_dex_file.SizeOf();
1875 }
1876 return offset;
1877 }
1878
InitOatCode(size_t offset)1879 size_t OatWriter::InitOatCode(size_t offset) {
1880 // calculate the offsets within OatHeader to executable code
1881 size_t old_offset = offset;
1882 size_t adjusted_offset = offset;
1883 // required to be on a new page boundary
1884 offset = RoundUp(offset, kPageSize);
1885 oat_header_->SetExecutableOffset(offset);
1886 size_executable_offset_alignment_ = offset - old_offset;
1887 if (compiler_driver_->GetCompilerOptions().IsBootImage()) {
1888 InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
1889
1890 #define DO_TRAMPOLINE(field, fn_name) \
1891 offset = CompiledCode::AlignCode(offset, instruction_set); \
1892 adjusted_offset = offset + CompiledCode::CodeDelta(instruction_set); \
1893 oat_header_->Set ## fn_name ## Offset(adjusted_offset); \
1894 (field) = compiler_driver_->Create ## fn_name(); \
1895 offset += (field)->size();
1896
1897 DO_TRAMPOLINE(jni_dlsym_lookup_, JniDlsymLookup);
1898 DO_TRAMPOLINE(quick_generic_jni_trampoline_, QuickGenericJniTrampoline);
1899 DO_TRAMPOLINE(quick_imt_conflict_trampoline_, QuickImtConflictTrampoline);
1900 DO_TRAMPOLINE(quick_resolution_trampoline_, QuickResolutionTrampoline);
1901 DO_TRAMPOLINE(quick_to_interpreter_bridge_, QuickToInterpreterBridge);
1902
1903 #undef DO_TRAMPOLINE
1904 } else {
1905 oat_header_->SetInterpreterToInterpreterBridgeOffset(0);
1906 oat_header_->SetInterpreterToCompiledCodeBridgeOffset(0);
1907 oat_header_->SetJniDlsymLookupOffset(0);
1908 oat_header_->SetQuickGenericJniTrampolineOffset(0);
1909 oat_header_->SetQuickImtConflictTrampolineOffset(0);
1910 oat_header_->SetQuickResolutionTrampolineOffset(0);
1911 oat_header_->SetQuickToInterpreterBridgeOffset(0);
1912 }
1913 return offset;
1914 }
1915
InitOatCodeDexFiles(size_t offset)1916 size_t OatWriter::InitOatCodeDexFiles(size_t offset) {
1917 if (!compiler_driver_->GetCompilerOptions().IsAnyCompilationEnabled()) {
1918 return offset;
1919 }
1920 InitCodeMethodVisitor code_visitor(this, offset);
1921 bool success = VisitDexMethods(&code_visitor);
1922 DCHECK(success);
1923 offset = code_visitor.GetOffset();
1924
1925 if (HasImage()) {
1926 InitImageMethodVisitor image_visitor(this, offset, dex_files_);
1927 success = VisitDexMethods(&image_visitor);
1928 image_visitor.Postprocess();
1929 DCHECK(success);
1930 offset = image_visitor.GetOffset();
1931 }
1932
1933 return offset;
1934 }
1935
InitBssLayout(InstructionSet instruction_set)1936 void OatWriter::InitBssLayout(InstructionSet instruction_set) {
1937 {
1938 InitBssLayoutMethodVisitor visitor(this);
1939 bool success = VisitDexMethods(&visitor);
1940 DCHECK(success);
1941 }
1942
1943 DCHECK_EQ(bss_size_, 0u);
1944 if (HasBootImage()) {
1945 DCHECK(bss_string_entries_.empty());
1946 if (bss_method_entries_.empty() && bss_type_entries_.empty()) {
1947 // Nothing to put to the .bss section.
1948 return;
1949 }
1950 }
1951
1952 // Allocate space for app dex cache arrays in the .bss section.
1953 PointerSize pointer_size = GetInstructionSetPointerSize(instruction_set);
1954 if (!HasBootImage()) {
1955 for (const DexFile* dex_file : *dex_files_) {
1956 DexCacheArraysLayout layout(pointer_size, dex_file);
1957 bss_size_ += layout.Size();
1958 }
1959 }
1960
1961 bss_methods_offset_ = bss_size_;
1962
1963 // Prepare offsets for .bss ArtMethod entries.
1964 for (auto& entry : bss_method_entries_) {
1965 DCHECK_EQ(entry.second, 0u);
1966 entry.second = bss_size_;
1967 bss_size_ += static_cast<size_t>(pointer_size);
1968 }
1969
1970 bss_roots_offset_ = bss_size_;
1971
1972 // Prepare offsets for .bss Class entries.
1973 for (auto& entry : bss_type_entries_) {
1974 DCHECK_EQ(entry.second, 0u);
1975 entry.second = bss_size_;
1976 bss_size_ += sizeof(GcRoot<mirror::Class>);
1977 }
1978 // Prepare offsets for .bss String entries.
1979 for (auto& entry : bss_string_entries_) {
1980 DCHECK_EQ(entry.second, 0u);
1981 entry.second = bss_size_;
1982 bss_size_ += sizeof(GcRoot<mirror::String>);
1983 }
1984 }
1985
WriteRodata(OutputStream * out)1986 bool OatWriter::WriteRodata(OutputStream* out) {
1987 CHECK(write_state_ == WriteState::kWriteRoData);
1988
1989 size_t file_offset = oat_data_offset_;
1990 off_t current_offset = out->Seek(0, kSeekCurrent);
1991 if (current_offset == static_cast<off_t>(-1)) {
1992 PLOG(ERROR) << "Failed to retrieve current position in " << out->GetLocation();
1993 }
1994 DCHECK_GE(static_cast<size_t>(current_offset), file_offset + oat_header_->GetHeaderSize());
1995 size_t relative_offset = current_offset - file_offset;
1996
1997 // Wrap out to update checksum with each write.
1998 ChecksumUpdatingOutputStream checksum_updating_out(out, oat_header_.get());
1999 out = &checksum_updating_out;
2000
2001 relative_offset = WriteClassOffsets(out, file_offset, relative_offset);
2002 if (relative_offset == 0) {
2003 PLOG(ERROR) << "Failed to write class offsets to " << out->GetLocation();
2004 return false;
2005 }
2006
2007 relative_offset = WriteClasses(out, file_offset, relative_offset);
2008 if (relative_offset == 0) {
2009 PLOG(ERROR) << "Failed to write classes to " << out->GetLocation();
2010 return false;
2011 }
2012
2013 relative_offset = WriteMethodBssMappings(out, file_offset, relative_offset);
2014 if (relative_offset == 0) {
2015 PLOG(ERROR) << "Failed to write method bss mappings to " << out->GetLocation();
2016 return false;
2017 }
2018
2019 relative_offset = WriteMaps(out, file_offset, relative_offset);
2020 if (relative_offset == 0) {
2021 PLOG(ERROR) << "Failed to write oat code to " << out->GetLocation();
2022 return false;
2023 }
2024
2025 relative_offset = WriteOatDexFiles(out, file_offset, relative_offset);
2026 if (relative_offset == 0) {
2027 PLOG(ERROR) << "Failed to write oat dex information to " << out->GetLocation();
2028 return false;
2029 }
2030
2031 // Write padding.
2032 off_t new_offset = out->Seek(size_executable_offset_alignment_, kSeekCurrent);
2033 relative_offset += size_executable_offset_alignment_;
2034 DCHECK_EQ(relative_offset, oat_header_->GetExecutableOffset());
2035 size_t expected_file_offset = file_offset + relative_offset;
2036 if (static_cast<uint32_t>(new_offset) != expected_file_offset) {
2037 PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
2038 << " Expected: " << expected_file_offset << " File: " << out->GetLocation();
2039 return 0;
2040 }
2041 DCHECK_OFFSET();
2042
2043 write_state_ = WriteState::kWriteText;
2044 return true;
2045 }
2046
2047 class OatWriter::WriteQuickeningInfoMethodVisitor : public DexMethodVisitor {
2048 public:
WriteQuickeningInfoMethodVisitor(OatWriter * writer,OutputStream * out,uint32_t offset,SafeMap<const uint8_t *,uint32_t> * offset_map)2049 WriteQuickeningInfoMethodVisitor(OatWriter* writer,
2050 OutputStream* out,
2051 uint32_t offset,
2052 SafeMap<const uint8_t*, uint32_t>* offset_map)
2053 : DexMethodVisitor(writer, offset),
2054 out_(out),
2055 written_bytes_(0u),
2056 offset_map_(offset_map) {}
2057
VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED,const ClassDataItemIterator & it)2058 bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED, const ClassDataItemIterator& it)
2059 OVERRIDE {
2060 uint32_t method_idx = it.GetMemberIndex();
2061 CompiledMethod* compiled_method =
2062 writer_->compiler_driver_->GetCompiledMethod(MethodReference(dex_file_, method_idx));
2063
2064 if (HasQuickeningInfo(compiled_method)) {
2065 ArrayRef<const uint8_t> map = compiled_method->GetVmapTable();
2066 // Deduplication is already done on a pointer basis by the compiler driver,
2067 // so we can simply compare the pointers to find out if things are duplicated.
2068 if (offset_map_->find(map.data()) == offset_map_->end()) {
2069 uint32_t length = map.size() * sizeof(map.front());
2070 offset_map_->Put(map.data(), written_bytes_);
2071 if (!out_->WriteFully(&length, sizeof(length)) ||
2072 !out_->WriteFully(map.data(), length)) {
2073 PLOG(ERROR) << "Failed to write quickening info for "
2074 << dex_file_->PrettyMethod(it.GetMemberIndex()) << " to "
2075 << out_->GetLocation();
2076 return false;
2077 }
2078 written_bytes_ += sizeof(length) + length;
2079 offset_ += sizeof(length) + length;
2080 }
2081 }
2082
2083 return true;
2084 }
2085
GetNumberOfWrittenBytes() const2086 size_t GetNumberOfWrittenBytes() const {
2087 return written_bytes_;
2088 }
2089
2090 private:
2091 OutputStream* const out_;
2092 size_t written_bytes_;
2093 // Maps quickening map to its offset in the file.
2094 SafeMap<const uint8_t*, uint32_t>* offset_map_;
2095 };
2096
2097 class OatWriter::WriteQuickeningIndicesMethodVisitor {
2098 public:
WriteQuickeningIndicesMethodVisitor(OutputStream * out,uint32_t indices_offset,const SafeMap<const uint8_t *,uint32_t> & offset_map,std::vector<uint32_t> * dex_files_offset)2099 WriteQuickeningIndicesMethodVisitor(OutputStream* out,
2100 uint32_t indices_offset,
2101 const SafeMap<const uint8_t*, uint32_t>& offset_map,
2102 std::vector<uint32_t>* dex_files_offset)
2103 : out_(out),
2104 indices_offset_(indices_offset),
2105 written_bytes_(0u),
2106 dex_files_offset_(dex_files_offset),
2107 offset_map_(offset_map) {}
2108
VisitDexMethods(const std::vector<const DexFile * > & dex_files,const CompilerDriver & driver)2109 bool VisitDexMethods(const std::vector<const DexFile*>& dex_files, const CompilerDriver& driver) {
2110 for (const DexFile* dex_file : dex_files) {
2111 // Record the offset for this current dex file. It will be written in the vdex file
2112 // later.
2113 dex_files_offset_->push_back(indices_offset_ + GetNumberOfWrittenBytes());
2114 const size_t class_def_count = dex_file->NumClassDefs();
2115 for (size_t class_def_index = 0; class_def_index != class_def_count; ++class_def_index) {
2116 const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
2117 const uint8_t* class_data = dex_file->GetClassData(class_def);
2118 if (class_data == nullptr) {
2119 continue;
2120 }
2121 for (ClassDataItemIterator class_it(*dex_file, class_data);
2122 class_it.HasNext();
2123 class_it.Next()) {
2124 if (!class_it.IsAtMethod()) {
2125 continue;
2126 }
2127 uint32_t method_idx = class_it.GetMemberIndex();
2128 CompiledMethod* compiled_method =
2129 driver.GetCompiledMethod(MethodReference(dex_file, method_idx));
2130 if (HasQuickeningInfo(compiled_method)) {
2131 uint32_t code_item_offset = class_it.GetMethodCodeItemOffset();
2132 uint32_t offset = offset_map_.Get(compiled_method->GetVmapTable().data());
2133 if (!out_->WriteFully(&code_item_offset, sizeof(code_item_offset)) ||
2134 !out_->WriteFully(&offset, sizeof(offset))) {
2135 PLOG(ERROR) << "Failed to write quickening info for "
2136 << dex_file->PrettyMethod(method_idx) << " to "
2137 << out_->GetLocation();
2138 return false;
2139 }
2140 written_bytes_ += sizeof(code_item_offset) + sizeof(offset);
2141 }
2142 }
2143 }
2144 }
2145 return true;
2146 }
2147
GetNumberOfWrittenBytes() const2148 size_t GetNumberOfWrittenBytes() const {
2149 return written_bytes_;
2150 }
2151
2152 private:
2153 OutputStream* const out_;
2154 const uint32_t indices_offset_;
2155 size_t written_bytes_;
2156 std::vector<uint32_t>* dex_files_offset_;
2157 // Maps quickening map to its offset in the file.
2158 const SafeMap<const uint8_t*, uint32_t>& offset_map_;
2159 };
2160
WriteQuickeningInfo(OutputStream * vdex_out)2161 bool OatWriter::WriteQuickeningInfo(OutputStream* vdex_out) {
2162 if (!kIsVdexEnabled) {
2163 return true;
2164 }
2165
2166 size_t initial_offset = vdex_size_;
2167 size_t start_offset = RoundUp(initial_offset, 4u);
2168
2169 vdex_size_ = start_offset;
2170 vdex_quickening_info_offset_ = vdex_size_;
2171 size_quickening_info_alignment_ = start_offset - initial_offset;
2172
2173 off_t actual_offset = vdex_out->Seek(start_offset, kSeekSet);
2174 if (actual_offset != static_cast<off_t>(start_offset)) {
2175 PLOG(ERROR) << "Failed to seek to quickening info section. Actual: " << actual_offset
2176 << " Expected: " << start_offset
2177 << " Output: " << vdex_out->GetLocation();
2178 return false;
2179 }
2180
2181 if (compiler_driver_->GetCompilerOptions().IsAnyCompilationEnabled()) {
2182 std::vector<uint32_t> dex_files_indices;
2183 SafeMap<const uint8_t*, uint32_t> offset_map;
2184 WriteQuickeningInfoMethodVisitor visitor1(this, vdex_out, start_offset, &offset_map);
2185 if (!VisitDexMethods(&visitor1)) {
2186 PLOG(ERROR) << "Failed to write the vdex quickening info. File: " << vdex_out->GetLocation();
2187 return false;
2188 }
2189
2190 WriteQuickeningIndicesMethodVisitor visitor2(vdex_out,
2191 visitor1.GetNumberOfWrittenBytes(),
2192 offset_map,
2193 &dex_files_indices);
2194 if (!visitor2.VisitDexMethods(*dex_files_, *compiler_driver_)) {
2195 PLOG(ERROR) << "Failed to write the vdex quickening info. File: " << vdex_out->GetLocation();
2196 return false;
2197 }
2198
2199 DCHECK_EQ(dex_files_->size(), dex_files_indices.size());
2200 if (!vdex_out->WriteFully(
2201 dex_files_indices.data(), sizeof(dex_files_indices[0]) * dex_files_indices.size())) {
2202 PLOG(ERROR) << "Failed to write the vdex quickening info. File: " << vdex_out->GetLocation();
2203 return false;
2204 }
2205
2206 if (!vdex_out->Flush()) {
2207 PLOG(ERROR) << "Failed to flush stream after writing quickening info."
2208 << " File: " << vdex_out->GetLocation();
2209 return false;
2210 }
2211 size_quickening_info_ = visitor1.GetNumberOfWrittenBytes() +
2212 visitor2.GetNumberOfWrittenBytes() +
2213 dex_files_->size() * sizeof(uint32_t);
2214 } else {
2215 // We know we did not quicken.
2216 size_quickening_info_ = 0;
2217 }
2218
2219 vdex_size_ += size_quickening_info_;
2220 return true;
2221 }
2222
WriteVerifierDeps(OutputStream * vdex_out,verifier::VerifierDeps * verifier_deps)2223 bool OatWriter::WriteVerifierDeps(OutputStream* vdex_out, verifier::VerifierDeps* verifier_deps) {
2224 if (!kIsVdexEnabled) {
2225 return true;
2226 }
2227
2228 if (verifier_deps == nullptr) {
2229 // Nothing to write. Record the offset, but no need
2230 // for alignment.
2231 vdex_verifier_deps_offset_ = vdex_size_;
2232 return true;
2233 }
2234
2235 size_t initial_offset = vdex_size_;
2236 size_t start_offset = RoundUp(initial_offset, 4u);
2237
2238 vdex_size_ = start_offset;
2239 vdex_verifier_deps_offset_ = vdex_size_;
2240 size_verifier_deps_alignment_ = start_offset - initial_offset;
2241
2242 off_t actual_offset = vdex_out->Seek(start_offset, kSeekSet);
2243 if (actual_offset != static_cast<off_t>(start_offset)) {
2244 PLOG(ERROR) << "Failed to seek to verifier deps section. Actual: " << actual_offset
2245 << " Expected: " << start_offset
2246 << " Output: " << vdex_out->GetLocation();
2247 return false;
2248 }
2249
2250 std::vector<uint8_t> buffer;
2251 verifier_deps->Encode(*dex_files_, &buffer);
2252
2253 if (!vdex_out->WriteFully(buffer.data(), buffer.size())) {
2254 PLOG(ERROR) << "Failed to write verifier deps."
2255 << " File: " << vdex_out->GetLocation();
2256 return false;
2257 }
2258 if (!vdex_out->Flush()) {
2259 PLOG(ERROR) << "Failed to flush stream after writing verifier deps."
2260 << " File: " << vdex_out->GetLocation();
2261 return false;
2262 }
2263
2264 size_verifier_deps_ = buffer.size();
2265 vdex_size_ += size_verifier_deps_;
2266 return true;
2267 }
2268
WriteCode(OutputStream * out)2269 bool OatWriter::WriteCode(OutputStream* out) {
2270 CHECK(write_state_ == WriteState::kWriteText);
2271
2272 // Wrap out to update checksum with each write.
2273 ChecksumUpdatingOutputStream checksum_updating_out(out, oat_header_.get());
2274 out = &checksum_updating_out;
2275
2276 SetMultiOatRelativePatcherAdjustment();
2277
2278 const size_t file_offset = oat_data_offset_;
2279 size_t relative_offset = oat_header_->GetExecutableOffset();
2280 DCHECK_OFFSET();
2281
2282 relative_offset = WriteCode(out, file_offset, relative_offset);
2283 if (relative_offset == 0) {
2284 LOG(ERROR) << "Failed to write oat code to " << out->GetLocation();
2285 return false;
2286 }
2287
2288 relative_offset = WriteCodeDexFiles(out, file_offset, relative_offset);
2289 if (relative_offset == 0) {
2290 LOG(ERROR) << "Failed to write oat code for dex files to " << out->GetLocation();
2291 return false;
2292 }
2293
2294 const off_t oat_end_file_offset = out->Seek(0, kSeekCurrent);
2295 if (oat_end_file_offset == static_cast<off_t>(-1)) {
2296 LOG(ERROR) << "Failed to get oat end file offset in " << out->GetLocation();
2297 return false;
2298 }
2299
2300 if (kIsDebugBuild) {
2301 uint32_t size_total = 0;
2302 #define DO_STAT(x) \
2303 VLOG(compiler) << #x "=" << PrettySize(x) << " (" << (x) << "B)"; \
2304 size_total += (x);
2305
2306 DO_STAT(size_vdex_header_);
2307 DO_STAT(size_vdex_checksums_);
2308 DO_STAT(size_dex_file_alignment_);
2309 DO_STAT(size_executable_offset_alignment_);
2310 DO_STAT(size_oat_header_);
2311 DO_STAT(size_oat_header_key_value_store_);
2312 DO_STAT(size_dex_file_);
2313 DO_STAT(size_verifier_deps_);
2314 DO_STAT(size_verifier_deps_alignment_);
2315 DO_STAT(size_quickening_info_);
2316 DO_STAT(size_quickening_info_alignment_);
2317 DO_STAT(size_interpreter_to_interpreter_bridge_);
2318 DO_STAT(size_interpreter_to_compiled_code_bridge_);
2319 DO_STAT(size_jni_dlsym_lookup_);
2320 DO_STAT(size_quick_generic_jni_trampoline_);
2321 DO_STAT(size_quick_imt_conflict_trampoline_);
2322 DO_STAT(size_quick_resolution_trampoline_);
2323 DO_STAT(size_quick_to_interpreter_bridge_);
2324 DO_STAT(size_trampoline_alignment_);
2325 DO_STAT(size_method_header_);
2326 DO_STAT(size_code_);
2327 DO_STAT(size_code_alignment_);
2328 DO_STAT(size_relative_call_thunks_);
2329 DO_STAT(size_misc_thunks_);
2330 DO_STAT(size_vmap_table_);
2331 DO_STAT(size_method_info_);
2332 DO_STAT(size_oat_dex_file_location_size_);
2333 DO_STAT(size_oat_dex_file_location_data_);
2334 DO_STAT(size_oat_dex_file_location_checksum_);
2335 DO_STAT(size_oat_dex_file_offset_);
2336 DO_STAT(size_oat_dex_file_class_offsets_offset_);
2337 DO_STAT(size_oat_dex_file_lookup_table_offset_);
2338 DO_STAT(size_oat_dex_file_dex_layout_sections_offset_);
2339 DO_STAT(size_oat_dex_file_dex_layout_sections_);
2340 DO_STAT(size_oat_dex_file_dex_layout_sections_alignment_);
2341 DO_STAT(size_oat_dex_file_method_bss_mapping_offset_);
2342 DO_STAT(size_oat_lookup_table_alignment_);
2343 DO_STAT(size_oat_lookup_table_);
2344 DO_STAT(size_oat_class_offsets_alignment_);
2345 DO_STAT(size_oat_class_offsets_);
2346 DO_STAT(size_oat_class_type_);
2347 DO_STAT(size_oat_class_status_);
2348 DO_STAT(size_oat_class_method_bitmaps_);
2349 DO_STAT(size_oat_class_method_offsets_);
2350 DO_STAT(size_method_bss_mappings_);
2351 #undef DO_STAT
2352
2353 VLOG(compiler) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)";
2354
2355 CHECK_EQ(vdex_size_ + oat_size_, size_total);
2356 CHECK_EQ(file_offset + size_total - vdex_size_, static_cast<size_t>(oat_end_file_offset));
2357 }
2358
2359 CHECK_EQ(file_offset + oat_size_, static_cast<size_t>(oat_end_file_offset));
2360 CHECK_EQ(oat_size_, relative_offset);
2361
2362 write_state_ = WriteState::kWriteHeader;
2363 return true;
2364 }
2365
WriteHeader(OutputStream * out,uint32_t image_file_location_oat_checksum,uintptr_t image_file_location_oat_begin,int32_t image_patch_delta)2366 bool OatWriter::WriteHeader(OutputStream* out,
2367 uint32_t image_file_location_oat_checksum,
2368 uintptr_t image_file_location_oat_begin,
2369 int32_t image_patch_delta) {
2370 CHECK(write_state_ == WriteState::kWriteHeader);
2371
2372 oat_header_->SetImageFileLocationOatChecksum(image_file_location_oat_checksum);
2373 oat_header_->SetImageFileLocationOatDataBegin(image_file_location_oat_begin);
2374 if (compiler_driver_->GetCompilerOptions().IsBootImage()) {
2375 CHECK_EQ(image_patch_delta, 0);
2376 CHECK_EQ(oat_header_->GetImagePatchDelta(), 0);
2377 } else {
2378 CHECK_ALIGNED(image_patch_delta, kPageSize);
2379 oat_header_->SetImagePatchDelta(image_patch_delta);
2380 }
2381 oat_header_->UpdateChecksumWithHeaderData();
2382
2383 const size_t file_offset = oat_data_offset_;
2384
2385 off_t current_offset = out->Seek(0, kSeekCurrent);
2386 if (current_offset == static_cast<off_t>(-1)) {
2387 PLOG(ERROR) << "Failed to get current offset from " << out->GetLocation();
2388 return false;
2389 }
2390 if (out->Seek(file_offset, kSeekSet) == static_cast<off_t>(-1)) {
2391 PLOG(ERROR) << "Failed to seek to oat header position in " << out->GetLocation();
2392 return false;
2393 }
2394 DCHECK_EQ(file_offset, static_cast<size_t>(out->Seek(0, kSeekCurrent)));
2395
2396 // Flush all other data before writing the header.
2397 if (!out->Flush()) {
2398 PLOG(ERROR) << "Failed to flush before writing oat header to " << out->GetLocation();
2399 return false;
2400 }
2401 // Write the header.
2402 size_t header_size = oat_header_->GetHeaderSize();
2403 if (!out->WriteFully(oat_header_.get(), header_size)) {
2404 PLOG(ERROR) << "Failed to write oat header to " << out->GetLocation();
2405 return false;
2406 }
2407 // Flush the header data.
2408 if (!out->Flush()) {
2409 PLOG(ERROR) << "Failed to flush after writing oat header to " << out->GetLocation();
2410 return false;
2411 }
2412
2413 if (out->Seek(current_offset, kSeekSet) == static_cast<off_t>(-1)) {
2414 PLOG(ERROR) << "Failed to seek back after writing oat header to " << out->GetLocation();
2415 return false;
2416 }
2417 DCHECK_EQ(current_offset, out->Seek(0, kSeekCurrent));
2418
2419 write_state_ = WriteState::kDone;
2420 return true;
2421 }
2422
WriteClassOffsets(OutputStream * out,size_t file_offset,size_t relative_offset)2423 size_t OatWriter::WriteClassOffsets(OutputStream* out, size_t file_offset, size_t relative_offset) {
2424 for (OatDexFile& oat_dex_file : oat_dex_files_) {
2425 if (oat_dex_file.class_offsets_offset_ != 0u) {
2426 // Class offsets are required to be 4 byte aligned.
2427 if (UNLIKELY(!IsAligned<4u>(relative_offset))) {
2428 size_t padding_size = RoundUp(relative_offset, 4u) - relative_offset;
2429 if (!WriteUpTo16BytesAlignment(out, padding_size, &size_oat_class_offsets_alignment_)) {
2430 return 0u;
2431 }
2432 relative_offset += padding_size;
2433 }
2434 DCHECK_OFFSET();
2435 if (!oat_dex_file.WriteClassOffsets(this, out)) {
2436 return 0u;
2437 }
2438 relative_offset += oat_dex_file.GetClassOffsetsRawSize();
2439 }
2440 }
2441 return relative_offset;
2442 }
2443
WriteClasses(OutputStream * out,size_t file_offset,size_t relative_offset)2444 size_t OatWriter::WriteClasses(OutputStream* out, size_t file_offset, size_t relative_offset) {
2445 const bool may_have_compiled = MayHaveCompiledMethods();
2446 if (may_have_compiled) {
2447 CHECK_EQ(oat_class_headers_.size(), oat_classes_.size());
2448 }
2449 for (size_t i = 0; i < oat_class_headers_.size(); ++i) {
2450 // If there are any classes, the class offsets allocation aligns the offset.
2451 DCHECK_ALIGNED(relative_offset, 4u);
2452 DCHECK_OFFSET();
2453 if (!oat_class_headers_[i].Write(this, out, oat_data_offset_)) {
2454 return 0u;
2455 }
2456 relative_offset += oat_class_headers_[i].SizeOf();
2457 if (may_have_compiled) {
2458 if (!oat_classes_[i].Write(this, out)) {
2459 return 0u;
2460 }
2461 relative_offset += oat_classes_[i].SizeOf();
2462 }
2463 }
2464 return relative_offset;
2465 }
2466
WriteMaps(OutputStream * out,size_t file_offset,size_t relative_offset)2467 size_t OatWriter::WriteMaps(OutputStream* out, size_t file_offset, size_t relative_offset) {
2468 {
2469 size_t vmap_tables_offset = relative_offset;
2470 WriteMapMethodVisitor visitor(this, out, file_offset, relative_offset);
2471 if (UNLIKELY(!VisitDexMethods(&visitor))) {
2472 return 0;
2473 }
2474 relative_offset = visitor.GetOffset();
2475 size_vmap_table_ = relative_offset - vmap_tables_offset;
2476 }
2477 {
2478 size_t method_infos_offset = relative_offset;
2479 WriteMethodInfoVisitor visitor(this, out, file_offset, relative_offset);
2480 if (UNLIKELY(!VisitDexMethods(&visitor))) {
2481 return 0;
2482 }
2483 relative_offset = visitor.GetOffset();
2484 size_method_info_ = relative_offset - method_infos_offset;
2485 }
2486
2487 return relative_offset;
2488 }
2489
WriteMethodBssMappings(OutputStream * out,size_t file_offset,size_t relative_offset)2490 size_t OatWriter::WriteMethodBssMappings(OutputStream* out,
2491 size_t file_offset,
2492 size_t relative_offset) {
2493 TimingLogger::ScopedTiming split("WriteMethodBssMappings", timings_);
2494
2495 for (size_t i = 0, size = dex_files_->size(); i != size; ++i) {
2496 const DexFile* dex_file = (*dex_files_)[i];
2497 OatDexFile* oat_dex_file = &oat_dex_files_[i];
2498 auto it = bss_method_entry_references_.find(dex_file);
2499 if (it != bss_method_entry_references_.end()) {
2500 const BitVector& method_indexes = it->second;
2501 // If there are any classes, the class offsets allocation aligns the offset
2502 // and we cannot have method bss mappings without class offsets.
2503 static_assert(alignof(MethodBssMapping) == sizeof(uint32_t),
2504 "MethodBssMapping alignment check.");
2505 DCHECK_ALIGNED(relative_offset, sizeof(uint32_t));
2506
2507 linker::MethodBssMappingEncoder encoder(
2508 GetInstructionSetPointerSize(oat_header_->GetInstructionSet()));
2509 // Allocate a sufficiently large MethodBssMapping.
2510 size_t number_of_method_indexes = method_indexes.NumSetBits();
2511 DCHECK_NE(number_of_method_indexes, 0u);
2512 size_t max_mappings_size = MethodBssMapping::ComputeSize(number_of_method_indexes);
2513 DCHECK_ALIGNED(max_mappings_size, sizeof(uint32_t));
2514 std::unique_ptr<uint32_t[]> storage(new uint32_t[max_mappings_size / sizeof(uint32_t)]);
2515 MethodBssMapping* mappings = new(storage.get()) MethodBssMapping(number_of_method_indexes);
2516 mappings->ClearPadding();
2517 // Encode the MethodBssMapping.
2518 auto init_it = mappings->begin();
2519 bool first_index = true;
2520 for (uint32_t method_index : method_indexes.Indexes()) {
2521 size_t bss_offset = bss_method_entries_.Get(MethodReference(dex_file, method_index));
2522 if (first_index) {
2523 first_index = false;
2524 encoder.Reset(method_index, bss_offset);
2525 } else if (!encoder.TryMerge(method_index, bss_offset)) {
2526 *init_it = encoder.GetEntry();
2527 ++init_it;
2528 encoder.Reset(method_index, bss_offset);
2529 }
2530 }
2531 // Store the last entry and shrink the mapping to the actual size.
2532 *init_it = encoder.GetEntry();
2533 ++init_it;
2534 DCHECK(init_it <= mappings->end());
2535 mappings->SetSize(std::distance(mappings->begin(), init_it));
2536 size_t mappings_size = MethodBssMapping::ComputeSize(mappings->size());
2537
2538 DCHECK_EQ(relative_offset, oat_dex_file->method_bss_mapping_offset_);
2539 DCHECK_OFFSET();
2540 if (!out->WriteFully(storage.get(), mappings_size)) {
2541 return 0u;
2542 }
2543 size_method_bss_mappings_ += mappings_size;
2544 relative_offset += mappings_size;
2545 } else {
2546 DCHECK_EQ(0u, oat_dex_file->method_bss_mapping_offset_);
2547 }
2548 }
2549 return relative_offset;
2550 }
2551
WriteOatDexFiles(OutputStream * out,size_t file_offset,size_t relative_offset)2552 size_t OatWriter::WriteOatDexFiles(OutputStream* out, size_t file_offset, size_t relative_offset) {
2553 TimingLogger::ScopedTiming split("WriteOatDexFiles", timings_);
2554
2555 for (size_t i = 0, size = oat_dex_files_.size(); i != size; ++i) {
2556 OatDexFile* oat_dex_file = &oat_dex_files_[i];
2557 DCHECK_EQ(relative_offset, oat_dex_file->offset_);
2558 DCHECK_OFFSET();
2559
2560 // Write OatDexFile.
2561 if (!oat_dex_file->Write(this, out)) {
2562 return 0u;
2563 }
2564 relative_offset += oat_dex_file->SizeOf();
2565 }
2566
2567 return relative_offset;
2568 }
2569
WriteCode(OutputStream * out,size_t file_offset,size_t relative_offset)2570 size_t OatWriter::WriteCode(OutputStream* out, size_t file_offset, size_t relative_offset) {
2571 if (compiler_driver_->GetCompilerOptions().IsBootImage()) {
2572 InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
2573
2574 #define DO_TRAMPOLINE(field) \
2575 do { \
2576 uint32_t aligned_offset = CompiledCode::AlignCode(relative_offset, instruction_set); \
2577 uint32_t alignment_padding = aligned_offset - relative_offset; \
2578 out->Seek(alignment_padding, kSeekCurrent); \
2579 size_trampoline_alignment_ += alignment_padding; \
2580 if (!out->WriteFully((field)->data(), (field)->size())) { \
2581 PLOG(ERROR) << "Failed to write " # field " to " << out->GetLocation(); \
2582 return false; \
2583 } \
2584 size_ ## field += (field)->size(); \
2585 relative_offset += alignment_padding + (field)->size(); \
2586 DCHECK_OFFSET(); \
2587 } while (false)
2588
2589 DO_TRAMPOLINE(jni_dlsym_lookup_);
2590 DO_TRAMPOLINE(quick_generic_jni_trampoline_);
2591 DO_TRAMPOLINE(quick_imt_conflict_trampoline_);
2592 DO_TRAMPOLINE(quick_resolution_trampoline_);
2593 DO_TRAMPOLINE(quick_to_interpreter_bridge_);
2594 #undef DO_TRAMPOLINE
2595 }
2596 return relative_offset;
2597 }
2598
WriteCodeDexFiles(OutputStream * out,size_t file_offset,size_t relative_offset)2599 size_t OatWriter::WriteCodeDexFiles(OutputStream* out,
2600 size_t file_offset,
2601 size_t relative_offset) {
2602 #define VISIT(VisitorType) \
2603 do { \
2604 VisitorType visitor(this, out, file_offset, relative_offset); \
2605 if (UNLIKELY(!VisitDexMethods(&visitor))) { \
2606 return 0; \
2607 } \
2608 relative_offset = visitor.GetOffset(); \
2609 } while (false)
2610
2611 VISIT(WriteCodeMethodVisitor);
2612
2613 #undef VISIT
2614
2615 size_code_alignment_ += relative_patcher_->CodeAlignmentSize();
2616 size_relative_call_thunks_ += relative_patcher_->RelativeCallThunksSize();
2617 size_misc_thunks_ += relative_patcher_->MiscThunksSize();
2618
2619 return relative_offset;
2620 }
2621
RecordOatDataOffset(OutputStream * out)2622 bool OatWriter::RecordOatDataOffset(OutputStream* out) {
2623 // Get the elf file offset of the oat file.
2624 const off_t raw_file_offset = out->Seek(0, kSeekCurrent);
2625 if (raw_file_offset == static_cast<off_t>(-1)) {
2626 LOG(ERROR) << "Failed to get file offset in " << out->GetLocation();
2627 return false;
2628 }
2629 oat_data_offset_ = static_cast<size_t>(raw_file_offset);
2630 return true;
2631 }
2632
ReadDexFileHeader(File * file,OatDexFile * oat_dex_file)2633 bool OatWriter::ReadDexFileHeader(File* file, OatDexFile* oat_dex_file) {
2634 // Read the dex file header and perform minimal verification.
2635 uint8_t raw_header[sizeof(DexFile::Header)];
2636 if (!file->ReadFully(&raw_header, sizeof(DexFile::Header))) {
2637 PLOG(ERROR) << "Failed to read dex file header. Actual: "
2638 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2639 return false;
2640 }
2641 if (!ValidateDexFileHeader(raw_header, oat_dex_file->GetLocation())) {
2642 return false;
2643 }
2644
2645 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_header);
2646 oat_dex_file->dex_file_size_ = header->file_size_;
2647 oat_dex_file->dex_file_location_checksum_ = header->checksum_;
2648 oat_dex_file->class_offsets_.resize(header->class_defs_size_);
2649 return true;
2650 }
2651
ValidateDexFileHeader(const uint8_t * raw_header,const char * location)2652 bool OatWriter::ValidateDexFileHeader(const uint8_t* raw_header, const char* location) {
2653 if (!DexFile::IsMagicValid(raw_header)) {
2654 LOG(ERROR) << "Invalid magic number in dex file header. " << " File: " << location;
2655 return false;
2656 }
2657 if (!DexFile::IsVersionValid(raw_header)) {
2658 LOG(ERROR) << "Invalid version number in dex file header. " << " File: " << location;
2659 return false;
2660 }
2661 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_header);
2662 if (header->file_size_ < sizeof(DexFile::Header)) {
2663 LOG(ERROR) << "Dex file header specifies file size insufficient to contain the header."
2664 << " File: " << location;
2665 return false;
2666 }
2667 return true;
2668 }
2669
WriteDexFiles(OutputStream * out,File * file,bool update_input_vdex)2670 bool OatWriter::WriteDexFiles(OutputStream* out, File* file, bool update_input_vdex) {
2671 TimingLogger::ScopedTiming split("Write Dex files", timings_);
2672
2673 vdex_dex_files_offset_ = vdex_size_;
2674
2675 // Write dex files.
2676 for (OatDexFile& oat_dex_file : oat_dex_files_) {
2677 if (!WriteDexFile(out, file, &oat_dex_file, update_input_vdex)) {
2678 return false;
2679 }
2680 }
2681
2682 CloseSources();
2683 return true;
2684 }
2685
CloseSources()2686 void OatWriter::CloseSources() {
2687 for (OatDexFile& oat_dex_file : oat_dex_files_) {
2688 oat_dex_file.source_.Clear(); // Get rid of the reference, it's about to be invalidated.
2689 }
2690 zipped_dex_files_.clear();
2691 zip_archives_.clear();
2692 raw_dex_files_.clear();
2693 }
2694
WriteDexFile(OutputStream * out,File * file,OatDexFile * oat_dex_file,bool update_input_vdex)2695 bool OatWriter::WriteDexFile(OutputStream* out,
2696 File* file,
2697 OatDexFile* oat_dex_file,
2698 bool update_input_vdex) {
2699 if (!SeekToDexFile(out, file, oat_dex_file)) {
2700 return false;
2701 }
2702 if (profile_compilation_info_ != nullptr) {
2703 CHECK(!update_input_vdex) << "We should never update the input vdex when doing dexlayout";
2704 if (!LayoutAndWriteDexFile(out, oat_dex_file)) {
2705 return false;
2706 }
2707 } else if (oat_dex_file->source_.IsZipEntry()) {
2708 DCHECK(!update_input_vdex);
2709 if (!WriteDexFile(out, file, oat_dex_file, oat_dex_file->source_.GetZipEntry())) {
2710 return false;
2711 }
2712 } else if (oat_dex_file->source_.IsRawFile()) {
2713 DCHECK(!update_input_vdex);
2714 if (!WriteDexFile(out, file, oat_dex_file, oat_dex_file->source_.GetRawFile())) {
2715 return false;
2716 }
2717 } else {
2718 DCHECK(oat_dex_file->source_.IsRawData());
2719 if (!WriteDexFile(out, oat_dex_file, oat_dex_file->source_.GetRawData(), update_input_vdex)) {
2720 return false;
2721 }
2722 }
2723
2724 // Update current size and account for the written data.
2725 if (kIsVdexEnabled) {
2726 DCHECK_EQ(vdex_size_, oat_dex_file->dex_file_offset_);
2727 vdex_size_ += oat_dex_file->dex_file_size_;
2728 } else {
2729 DCHECK(!update_input_vdex);
2730 DCHECK_EQ(oat_size_, oat_dex_file->dex_file_offset_);
2731 oat_size_ += oat_dex_file->dex_file_size_;
2732 }
2733 size_dex_file_ += oat_dex_file->dex_file_size_;
2734 return true;
2735 }
2736
SeekToDexFile(OutputStream * out,File * file,OatDexFile * oat_dex_file)2737 bool OatWriter::SeekToDexFile(OutputStream* out, File* file, OatDexFile* oat_dex_file) {
2738 // Dex files are required to be 4 byte aligned.
2739 size_t initial_offset = kIsVdexEnabled ? vdex_size_ : oat_size_;
2740 size_t start_offset = RoundUp(initial_offset, 4);
2741 size_t file_offset = kIsVdexEnabled ? start_offset : (oat_data_offset_ + start_offset);
2742 size_dex_file_alignment_ += start_offset - initial_offset;
2743
2744 // Seek to the start of the dex file and flush any pending operations in the stream.
2745 // Verify that, after flushing the stream, the file is at the same offset as the stream.
2746 off_t actual_offset = out->Seek(file_offset, kSeekSet);
2747 if (actual_offset != static_cast<off_t>(file_offset)) {
2748 PLOG(ERROR) << "Failed to seek to dex file section. Actual: " << actual_offset
2749 << " Expected: " << file_offset
2750 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2751 return false;
2752 }
2753 if (!out->Flush()) {
2754 PLOG(ERROR) << "Failed to flush before writing dex file."
2755 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2756 return false;
2757 }
2758 actual_offset = lseek(file->Fd(), 0, SEEK_CUR);
2759 if (actual_offset != static_cast<off_t>(file_offset)) {
2760 PLOG(ERROR) << "Stream/file position mismatch! Actual: " << actual_offset
2761 << " Expected: " << file_offset
2762 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2763 return false;
2764 }
2765
2766 if (kIsVdexEnabled) {
2767 vdex_size_ = start_offset;
2768 } else {
2769 oat_size_ = start_offset;
2770 }
2771 oat_dex_file->dex_file_offset_ = start_offset;
2772 return true;
2773 }
2774
LayoutAndWriteDexFile(OutputStream * out,OatDexFile * oat_dex_file)2775 bool OatWriter::LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_file) {
2776 TimingLogger::ScopedTiming split("Dex Layout", timings_);
2777 std::string error_msg;
2778 std::string location(oat_dex_file->GetLocation());
2779 std::unique_ptr<const DexFile> dex_file;
2780 if (oat_dex_file->source_.IsZipEntry()) {
2781 ZipEntry* zip_entry = oat_dex_file->source_.GetZipEntry();
2782 std::unique_ptr<MemMap> mem_map(
2783 zip_entry->ExtractToMemMap(location.c_str(), "classes.dex", &error_msg));
2784 if (mem_map == nullptr) {
2785 LOG(ERROR) << "Failed to extract dex file to mem map for layout: " << error_msg;
2786 return false;
2787 }
2788 dex_file = DexFile::Open(location,
2789 zip_entry->GetCrc32(),
2790 std::move(mem_map),
2791 /* verify */ true,
2792 /* verify_checksum */ true,
2793 &error_msg);
2794 } else if (oat_dex_file->source_.IsRawFile()) {
2795 File* raw_file = oat_dex_file->source_.GetRawFile();
2796 dex_file = DexFile::OpenDex(raw_file->Fd(), location, /* verify_checksum */ true, &error_msg);
2797 } else {
2798 // The source data is a vdex file.
2799 CHECK(oat_dex_file->source_.IsRawData())
2800 << static_cast<size_t>(oat_dex_file->source_.GetType());
2801 const uint8_t* raw_dex_file = oat_dex_file->source_.GetRawData();
2802 // Note: The raw data has already been checked to contain the header
2803 // and all the data that the header specifies as the file size.
2804 DCHECK(raw_dex_file != nullptr);
2805 DCHECK(ValidateDexFileHeader(raw_dex_file, oat_dex_file->GetLocation()));
2806 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_dex_file);
2807 // Since the source may have had its layout changed, or may be quickened, don't verify it.
2808 dex_file = DexFile::Open(raw_dex_file,
2809 header->file_size_,
2810 location,
2811 oat_dex_file->dex_file_location_checksum_,
2812 nullptr,
2813 /* verify */ false,
2814 /* verify_checksum */ false,
2815 &error_msg);
2816 }
2817 if (dex_file == nullptr) {
2818 LOG(ERROR) << "Failed to open dex file for layout: " << error_msg;
2819 return false;
2820 }
2821 Options options;
2822 options.output_to_memmap_ = true;
2823 DexLayout dex_layout(options, profile_compilation_info_, nullptr);
2824 dex_layout.ProcessDexFile(location.c_str(), dex_file.get(), 0);
2825 std::unique_ptr<MemMap> mem_map(dex_layout.GetAndReleaseMemMap());
2826 if (!WriteDexFile(out, oat_dex_file, mem_map->Begin(), /* update_input_vdex */ false)) {
2827 return false;
2828 }
2829 oat_dex_file->dex_sections_layout_ = dex_layout.GetSections();
2830 // Set the checksum of the new oat dex file to be the original file's checksum.
2831 oat_dex_file->dex_file_location_checksum_ = dex_file->GetLocationChecksum();
2832 return true;
2833 }
2834
WriteDexFile(OutputStream * out,File * file,OatDexFile * oat_dex_file,ZipEntry * dex_file)2835 bool OatWriter::WriteDexFile(OutputStream* out,
2836 File* file,
2837 OatDexFile* oat_dex_file,
2838 ZipEntry* dex_file) {
2839 size_t start_offset = kIsVdexEnabled ? vdex_size_ : oat_data_offset_ + oat_size_;
2840 DCHECK_EQ(static_cast<off_t>(start_offset), out->Seek(0, kSeekCurrent));
2841
2842 // Extract the dex file and get the extracted size.
2843 std::string error_msg;
2844 if (!dex_file->ExtractToFile(*file, &error_msg)) {
2845 LOG(ERROR) << "Failed to extract dex file from ZIP entry: " << error_msg
2846 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2847 return false;
2848 }
2849 if (file->Flush() != 0) {
2850 PLOG(ERROR) << "Failed to flush dex file from ZIP entry."
2851 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2852 return false;
2853 }
2854 off_t extracted_end = lseek(file->Fd(), 0, SEEK_CUR);
2855 if (extracted_end == static_cast<off_t>(-1)) {
2856 PLOG(ERROR) << "Failed get end offset after writing dex file from ZIP entry."
2857 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2858 return false;
2859 }
2860 if (extracted_end < static_cast<off_t>(start_offset)) {
2861 LOG(ERROR) << "Dex file end position is before start position! End: " << extracted_end
2862 << " Start: " << start_offset
2863 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2864 return false;
2865 }
2866 uint64_t extracted_size = static_cast<uint64_t>(extracted_end - start_offset);
2867 if (extracted_size < sizeof(DexFile::Header)) {
2868 LOG(ERROR) << "Extracted dex file is shorter than dex file header. size: "
2869 << extracted_size << " File: " << oat_dex_file->GetLocation();
2870 return false;
2871 }
2872
2873 // Read the dex file header and extract required data to OatDexFile.
2874 off_t actual_offset = lseek(file->Fd(), start_offset, SEEK_SET);
2875 if (actual_offset != static_cast<off_t>(start_offset)) {
2876 PLOG(ERROR) << "Failed to seek back to dex file header. Actual: " << actual_offset
2877 << " Expected: " << start_offset
2878 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2879 return false;
2880 }
2881 if (!ReadDexFileHeader(file, oat_dex_file)) {
2882 return false;
2883 }
2884 if (extracted_size < oat_dex_file->dex_file_size_) {
2885 LOG(ERROR) << "Extracted truncated dex file. Extracted size: " << extracted_size
2886 << " file size from header: " << oat_dex_file->dex_file_size_
2887 << " File: " << oat_dex_file->GetLocation();
2888 return false;
2889 }
2890
2891 // Override the checksum from header with the CRC from ZIP entry.
2892 oat_dex_file->dex_file_location_checksum_ = dex_file->GetCrc32();
2893
2894 // Seek both file and stream to the end offset.
2895 size_t end_offset = start_offset + oat_dex_file->dex_file_size_;
2896 actual_offset = lseek(file->Fd(), end_offset, SEEK_SET);
2897 if (actual_offset != static_cast<off_t>(end_offset)) {
2898 PLOG(ERROR) << "Failed to seek to end of dex file. Actual: " << actual_offset
2899 << " Expected: " << end_offset
2900 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2901 return false;
2902 }
2903 actual_offset = out->Seek(end_offset, kSeekSet);
2904 if (actual_offset != static_cast<off_t>(end_offset)) {
2905 PLOG(ERROR) << "Failed to seek stream to end of dex file. Actual: " << actual_offset
2906 << " Expected: " << end_offset << " File: " << oat_dex_file->GetLocation();
2907 return false;
2908 }
2909 if (!out->Flush()) {
2910 PLOG(ERROR) << "Failed to flush stream after seeking over dex file."
2911 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2912 return false;
2913 }
2914
2915 // If we extracted more than the size specified in the header, truncate the file.
2916 if (extracted_size > oat_dex_file->dex_file_size_) {
2917 if (file->SetLength(end_offset) != 0) {
2918 PLOG(ERROR) << "Failed to truncate excessive dex file length."
2919 << " File: " << oat_dex_file->GetLocation()
2920 << " Output: " << file->GetPath();
2921 return false;
2922 }
2923 }
2924
2925 return true;
2926 }
2927
WriteDexFile(OutputStream * out,File * file,OatDexFile * oat_dex_file,File * dex_file)2928 bool OatWriter::WriteDexFile(OutputStream* out,
2929 File* file,
2930 OatDexFile* oat_dex_file,
2931 File* dex_file) {
2932 size_t start_offset = kIsVdexEnabled ? vdex_size_ : oat_data_offset_ + oat_size_;
2933 DCHECK_EQ(static_cast<off_t>(start_offset), out->Seek(0, kSeekCurrent));
2934
2935 off_t input_offset = lseek(dex_file->Fd(), 0, SEEK_SET);
2936 if (input_offset != static_cast<off_t>(0)) {
2937 PLOG(ERROR) << "Failed to seek to dex file header. Actual: " << input_offset
2938 << " Expected: 0"
2939 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2940 return false;
2941 }
2942 if (!ReadDexFileHeader(dex_file, oat_dex_file)) {
2943 return false;
2944 }
2945
2946 // Copy the input dex file using sendfile().
2947 if (!file->Copy(dex_file, 0, oat_dex_file->dex_file_size_)) {
2948 PLOG(ERROR) << "Failed to copy dex file to oat file."
2949 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2950 return false;
2951 }
2952 if (file->Flush() != 0) {
2953 PLOG(ERROR) << "Failed to flush dex file."
2954 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2955 return false;
2956 }
2957
2958 // Check file position and seek the stream to the end offset.
2959 size_t end_offset = start_offset + oat_dex_file->dex_file_size_;
2960 off_t actual_offset = lseek(file->Fd(), 0, SEEK_CUR);
2961 if (actual_offset != static_cast<off_t>(end_offset)) {
2962 PLOG(ERROR) << "Unexpected file position after copying dex file. Actual: " << actual_offset
2963 << " Expected: " << end_offset
2964 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2965 return false;
2966 }
2967 actual_offset = out->Seek(end_offset, kSeekSet);
2968 if (actual_offset != static_cast<off_t>(end_offset)) {
2969 PLOG(ERROR) << "Failed to seek stream to end of dex file. Actual: " << actual_offset
2970 << " Expected: " << end_offset << " File: " << oat_dex_file->GetLocation();
2971 return false;
2972 }
2973 if (!out->Flush()) {
2974 PLOG(ERROR) << "Failed to flush stream after seeking over dex file."
2975 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2976 return false;
2977 }
2978
2979 return true;
2980 }
2981
WriteDexFile(OutputStream * out,OatDexFile * oat_dex_file,const uint8_t * dex_file,bool update_input_vdex)2982 bool OatWriter::WriteDexFile(OutputStream* out,
2983 OatDexFile* oat_dex_file,
2984 const uint8_t* dex_file,
2985 bool update_input_vdex) {
2986 // Note: The raw data has already been checked to contain the header
2987 // and all the data that the header specifies as the file size.
2988 DCHECK(dex_file != nullptr);
2989 DCHECK(ValidateDexFileHeader(dex_file, oat_dex_file->GetLocation()));
2990 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(dex_file);
2991
2992 if (update_input_vdex) {
2993 // The vdex already contains the dex code, no need to write it again.
2994 } else {
2995 if (!out->WriteFully(dex_file, header->file_size_)) {
2996 PLOG(ERROR) << "Failed to write dex file " << oat_dex_file->GetLocation()
2997 << " to " << out->GetLocation();
2998 return false;
2999 }
3000 if (!out->Flush()) {
3001 PLOG(ERROR) << "Failed to flush stream after writing dex file."
3002 << " File: " << oat_dex_file->GetLocation();
3003 return false;
3004 }
3005 }
3006
3007 // Update dex file size and resize class offsets in the OatDexFile.
3008 // Note: For raw data, the checksum is passed directly to AddRawDexFileSource().
3009 // Note: For vdex, the checksum is copied from the existing vdex file.
3010 oat_dex_file->dex_file_size_ = header->file_size_;
3011 oat_dex_file->class_offsets_.resize(header->class_defs_size_);
3012 return true;
3013 }
3014
OpenDexFiles(File * file,bool verify,std::unique_ptr<MemMap> * opened_dex_files_map,std::vector<std::unique_ptr<const DexFile>> * opened_dex_files)3015 bool OatWriter::OpenDexFiles(
3016 File* file,
3017 bool verify,
3018 /*out*/ std::unique_ptr<MemMap>* opened_dex_files_map,
3019 /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) {
3020 TimingLogger::ScopedTiming split("OpenDexFiles", timings_);
3021
3022 if (oat_dex_files_.empty()) {
3023 // Nothing to do.
3024 return true;
3025 }
3026
3027 size_t map_offset = oat_dex_files_[0].dex_file_offset_;
3028 size_t length = kIsVdexEnabled ? (vdex_size_ - map_offset) : (oat_size_ - map_offset);
3029
3030 std::string error_msg;
3031 std::unique_ptr<MemMap> dex_files_map(MemMap::MapFile(
3032 length,
3033 PROT_READ | PROT_WRITE,
3034 MAP_SHARED,
3035 file->Fd(),
3036 kIsVdexEnabled ? map_offset : (oat_data_offset_ + map_offset),
3037 /* low_4gb */ false,
3038 file->GetPath().c_str(),
3039 &error_msg));
3040 if (dex_files_map == nullptr) {
3041 LOG(ERROR) << "Failed to mmap() dex files from oat file. File: " << file->GetPath()
3042 << " error: " << error_msg;
3043 return false;
3044 }
3045 std::vector<std::unique_ptr<const DexFile>> dex_files;
3046 for (OatDexFile& oat_dex_file : oat_dex_files_) {
3047 // Make sure no one messed with input files while we were copying data.
3048 // At the very least we need consistent file size and number of class definitions.
3049 const uint8_t* raw_dex_file =
3050 dex_files_map->Begin() + oat_dex_file.dex_file_offset_ - map_offset;
3051 if (!ValidateDexFileHeader(raw_dex_file, oat_dex_file.GetLocation())) {
3052 // Note: ValidateDexFileHeader() already logged an error message.
3053 LOG(ERROR) << "Failed to verify written dex file header!"
3054 << " Output: " << file->GetPath() << " ~ " << std::hex << map_offset
3055 << " ~ " << static_cast<const void*>(raw_dex_file);
3056 return false;
3057 }
3058 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_dex_file);
3059 if (header->file_size_ != oat_dex_file.dex_file_size_) {
3060 LOG(ERROR) << "File size mismatch in written dex file header! Expected: "
3061 << oat_dex_file.dex_file_size_ << " Actual: " << header->file_size_
3062 << " Output: " << file->GetPath();
3063 return false;
3064 }
3065 if (header->class_defs_size_ != oat_dex_file.class_offsets_.size()) {
3066 LOG(ERROR) << "Class defs size mismatch in written dex file header! Expected: "
3067 << oat_dex_file.class_offsets_.size() << " Actual: " << header->class_defs_size_
3068 << " Output: " << file->GetPath();
3069 return false;
3070 }
3071
3072 // Now, open the dex file.
3073 dex_files.emplace_back(DexFile::Open(raw_dex_file,
3074 oat_dex_file.dex_file_size_,
3075 oat_dex_file.GetLocation(),
3076 oat_dex_file.dex_file_location_checksum_,
3077 /* oat_dex_file */ nullptr,
3078 verify,
3079 verify,
3080 &error_msg));
3081 if (dex_files.back() == nullptr) {
3082 LOG(ERROR) << "Failed to open dex file from oat file. File: " << oat_dex_file.GetLocation()
3083 << " Error: " << error_msg;
3084 return false;
3085 }
3086 }
3087
3088 *opened_dex_files_map = std::move(dex_files_map);
3089 *opened_dex_files = std::move(dex_files);
3090 return true;
3091 }
3092
WriteTypeLookupTables(OutputStream * oat_rodata,const std::vector<std::unique_ptr<const DexFile>> & opened_dex_files)3093 bool OatWriter::WriteTypeLookupTables(
3094 OutputStream* oat_rodata,
3095 const std::vector<std::unique_ptr<const DexFile>>& opened_dex_files) {
3096 TimingLogger::ScopedTiming split("WriteTypeLookupTables", timings_);
3097
3098 uint32_t expected_offset = oat_data_offset_ + oat_size_;
3099 off_t actual_offset = oat_rodata->Seek(expected_offset, kSeekSet);
3100 if (static_cast<uint32_t>(actual_offset) != expected_offset) {
3101 PLOG(ERROR) << "Failed to seek to TypeLookupTable section. Actual: " << actual_offset
3102 << " Expected: " << expected_offset << " File: " << oat_rodata->GetLocation();
3103 return false;
3104 }
3105
3106 DCHECK_EQ(opened_dex_files.size(), oat_dex_files_.size());
3107 for (size_t i = 0, size = opened_dex_files.size(); i != size; ++i) {
3108 OatDexFile* oat_dex_file = &oat_dex_files_[i];
3109 DCHECK_EQ(oat_dex_file->lookup_table_offset_, 0u);
3110
3111 if (oat_dex_file->create_type_lookup_table_ != CreateTypeLookupTable::kCreate ||
3112 oat_dex_file->class_offsets_.empty()) {
3113 continue;
3114 }
3115
3116 size_t table_size = TypeLookupTable::RawDataLength(oat_dex_file->class_offsets_.size());
3117 if (table_size == 0u) {
3118 continue;
3119 }
3120
3121 // Create the lookup table. When `nullptr` is given as the storage buffer,
3122 // TypeLookupTable allocates its own and OatDexFile takes ownership.
3123 const DexFile& dex_file = *opened_dex_files[i];
3124 {
3125 std::unique_ptr<TypeLookupTable> type_lookup_table =
3126 TypeLookupTable::Create(dex_file, /* storage */ nullptr);
3127 type_lookup_table_oat_dex_files_.push_back(
3128 std::make_unique<art::OatDexFile>(std::move(type_lookup_table)));
3129 dex_file.SetOatDexFile(type_lookup_table_oat_dex_files_.back().get());
3130 }
3131 TypeLookupTable* const table = type_lookup_table_oat_dex_files_.back()->GetTypeLookupTable();
3132
3133 // Type tables are required to be 4 byte aligned.
3134 size_t initial_offset = oat_size_;
3135 size_t rodata_offset = RoundUp(initial_offset, 4);
3136 size_t padding_size = rodata_offset - initial_offset;
3137
3138 if (padding_size != 0u) {
3139 std::vector<uint8_t> buffer(padding_size, 0u);
3140 if (!oat_rodata->WriteFully(buffer.data(), padding_size)) {
3141 PLOG(ERROR) << "Failed to write lookup table alignment padding."
3142 << " File: " << oat_dex_file->GetLocation()
3143 << " Output: " << oat_rodata->GetLocation();
3144 return false;
3145 }
3146 }
3147
3148 DCHECK_EQ(oat_data_offset_ + rodata_offset,
3149 static_cast<size_t>(oat_rodata->Seek(0u, kSeekCurrent)));
3150 DCHECK_EQ(table_size, table->RawDataLength());
3151
3152 if (!oat_rodata->WriteFully(table->RawData(), table_size)) {
3153 PLOG(ERROR) << "Failed to write lookup table."
3154 << " File: " << oat_dex_file->GetLocation()
3155 << " Output: " << oat_rodata->GetLocation();
3156 return false;
3157 }
3158
3159 oat_dex_file->lookup_table_offset_ = rodata_offset;
3160
3161 oat_size_ += padding_size + table_size;
3162 size_oat_lookup_table_ += table_size;
3163 size_oat_lookup_table_alignment_ += padding_size;
3164 }
3165
3166 if (!oat_rodata->Flush()) {
3167 PLOG(ERROR) << "Failed to flush stream after writing type lookup tables."
3168 << " File: " << oat_rodata->GetLocation();
3169 return false;
3170 }
3171
3172 return true;
3173 }
3174
WriteDexLayoutSections(OutputStream * oat_rodata,const std::vector<std::unique_ptr<const DexFile>> & opened_dex_files)3175 bool OatWriter::WriteDexLayoutSections(
3176 OutputStream* oat_rodata,
3177 const std::vector<std::unique_ptr<const DexFile>>& opened_dex_files) {
3178 TimingLogger::ScopedTiming split(__FUNCTION__, timings_);
3179
3180 if (!kWriteDexLayoutInfo) {
3181 return true;;
3182 }
3183
3184 uint32_t expected_offset = oat_data_offset_ + oat_size_;
3185 off_t actual_offset = oat_rodata->Seek(expected_offset, kSeekSet);
3186 if (static_cast<uint32_t>(actual_offset) != expected_offset) {
3187 PLOG(ERROR) << "Failed to seek to dex layout section offset section. Actual: " << actual_offset
3188 << " Expected: " << expected_offset << " File: " << oat_rodata->GetLocation();
3189 return false;
3190 }
3191
3192 DCHECK_EQ(opened_dex_files.size(), oat_dex_files_.size());
3193 size_t rodata_offset = oat_size_;
3194 for (size_t i = 0, size = opened_dex_files.size(); i != size; ++i) {
3195 OatDexFile* oat_dex_file = &oat_dex_files_[i];
3196 DCHECK_EQ(oat_dex_file->dex_sections_layout_offset_, 0u);
3197
3198 // Write dex layout section alignment bytes.
3199 const size_t padding_size =
3200 RoundUp(rodata_offset, alignof(DexLayoutSections)) - rodata_offset;
3201 if (padding_size != 0u) {
3202 std::vector<uint8_t> buffer(padding_size, 0u);
3203 if (!oat_rodata->WriteFully(buffer.data(), padding_size)) {
3204 PLOG(ERROR) << "Failed to write lookup table alignment padding."
3205 << " File: " << oat_dex_file->GetLocation()
3206 << " Output: " << oat_rodata->GetLocation();
3207 return false;
3208 }
3209 size_oat_dex_file_dex_layout_sections_alignment_ += padding_size;
3210 rodata_offset += padding_size;
3211 }
3212
3213 DCHECK_ALIGNED(rodata_offset, alignof(DexLayoutSections));
3214 DCHECK_EQ(oat_data_offset_ + rodata_offset,
3215 static_cast<size_t>(oat_rodata->Seek(0u, kSeekCurrent)));
3216 DCHECK(oat_dex_file != nullptr);
3217 if (!oat_rodata->WriteFully(&oat_dex_file->dex_sections_layout_,
3218 sizeof(oat_dex_file->dex_sections_layout_))) {
3219 PLOG(ERROR) << "Failed to write dex layout sections."
3220 << " File: " << oat_dex_file->GetLocation()
3221 << " Output: " << oat_rodata->GetLocation();
3222 return false;
3223 }
3224 oat_dex_file->dex_sections_layout_offset_ = rodata_offset;
3225 size_oat_dex_file_dex_layout_sections_ += sizeof(oat_dex_file->dex_sections_layout_);
3226 rodata_offset += sizeof(oat_dex_file->dex_sections_layout_);
3227 }
3228 oat_size_ = rodata_offset;
3229
3230 if (!oat_rodata->Flush()) {
3231 PLOG(ERROR) << "Failed to flush stream after writing type dex layout sections."
3232 << " File: " << oat_rodata->GetLocation();
3233 return false;
3234 }
3235
3236 return true;
3237 }
3238
WriteChecksumsAndVdexHeader(OutputStream * vdex_out)3239 bool OatWriter::WriteChecksumsAndVdexHeader(OutputStream* vdex_out) {
3240 if (!kIsVdexEnabled) {
3241 return true;
3242 }
3243 // Write checksums
3244 off_t actual_offset = vdex_out->Seek(sizeof(VdexFile::Header), kSeekSet);
3245 if (actual_offset != sizeof(VdexFile::Header)) {
3246 PLOG(ERROR) << "Failed to seek to the checksum location of vdex file. Actual: " << actual_offset
3247 << " File: " << vdex_out->GetLocation();
3248 return false;
3249 }
3250
3251 for (size_t i = 0, size = oat_dex_files_.size(); i != size; ++i) {
3252 OatDexFile* oat_dex_file = &oat_dex_files_[i];
3253 if (!vdex_out->WriteFully(
3254 &oat_dex_file->dex_file_location_checksum_, sizeof(VdexFile::VdexChecksum))) {
3255 PLOG(ERROR) << "Failed to write dex file location checksum. File: "
3256 << vdex_out->GetLocation();
3257 return false;
3258 }
3259 size_vdex_checksums_ += sizeof(VdexFile::VdexChecksum);
3260 }
3261
3262 // Write header.
3263 actual_offset = vdex_out->Seek(0, kSeekSet);
3264 if (actual_offset != 0) {
3265 PLOG(ERROR) << "Failed to seek to the beginning of vdex file. Actual: " << actual_offset
3266 << " File: " << vdex_out->GetLocation();
3267 return false;
3268 }
3269
3270 DCHECK_NE(vdex_dex_files_offset_, 0u);
3271 DCHECK_NE(vdex_verifier_deps_offset_, 0u);
3272
3273 size_t dex_section_size = vdex_verifier_deps_offset_ - vdex_dex_files_offset_;
3274 size_t verifier_deps_section_size = vdex_quickening_info_offset_ - vdex_verifier_deps_offset_;
3275 size_t quickening_info_section_size = vdex_size_ - vdex_quickening_info_offset_;
3276
3277 VdexFile::Header vdex_header(oat_dex_files_.size(),
3278 dex_section_size,
3279 verifier_deps_section_size,
3280 quickening_info_section_size);
3281 if (!vdex_out->WriteFully(&vdex_header, sizeof(VdexFile::Header))) {
3282 PLOG(ERROR) << "Failed to write vdex header. File: " << vdex_out->GetLocation();
3283 return false;
3284 }
3285 size_vdex_header_ = sizeof(VdexFile::Header);
3286
3287 if (!vdex_out->Flush()) {
3288 PLOG(ERROR) << "Failed to flush stream after writing to vdex file."
3289 << " File: " << vdex_out->GetLocation();
3290 return false;
3291 }
3292
3293 return true;
3294 }
3295
WriteCodeAlignment(OutputStream * out,uint32_t aligned_code_delta)3296 bool OatWriter::WriteCodeAlignment(OutputStream* out, uint32_t aligned_code_delta) {
3297 return WriteUpTo16BytesAlignment(out, aligned_code_delta, &size_code_alignment_);
3298 }
3299
WriteUpTo16BytesAlignment(OutputStream * out,uint32_t size,uint32_t * stat)3300 bool OatWriter::WriteUpTo16BytesAlignment(OutputStream* out, uint32_t size, uint32_t* stat) {
3301 static const uint8_t kPadding[] = {
3302 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u
3303 };
3304 DCHECK_LE(size, sizeof(kPadding));
3305 if (UNLIKELY(!out->WriteFully(kPadding, size))) {
3306 return false;
3307 }
3308 *stat += size;
3309 return true;
3310 }
3311
SetMultiOatRelativePatcherAdjustment()3312 void OatWriter::SetMultiOatRelativePatcherAdjustment() {
3313 DCHECK(dex_files_ != nullptr);
3314 DCHECK(relative_patcher_ != nullptr);
3315 DCHECK_NE(oat_data_offset_, 0u);
3316 if (image_writer_ != nullptr && !dex_files_->empty()) {
3317 // The oat data begin may not be initialized yet but the oat file offset is ready.
3318 size_t oat_index = image_writer_->GetOatIndexForDexFile(dex_files_->front());
3319 size_t elf_file_offset = image_writer_->GetOatFileOffset(oat_index);
3320 relative_patcher_->StartOatFile(elf_file_offset + oat_data_offset_);
3321 }
3322 }
3323
OatDexFile(const char * dex_file_location,DexFileSource source,CreateTypeLookupTable create_type_lookup_table)3324 OatWriter::OatDexFile::OatDexFile(const char* dex_file_location,
3325 DexFileSource source,
3326 CreateTypeLookupTable create_type_lookup_table)
3327 : source_(source),
3328 create_type_lookup_table_(create_type_lookup_table),
3329 dex_file_size_(0),
3330 offset_(0),
3331 dex_file_location_size_(strlen(dex_file_location)),
3332 dex_file_location_data_(dex_file_location),
3333 dex_file_location_checksum_(0u),
3334 dex_file_offset_(0u),
3335 class_offsets_offset_(0u),
3336 lookup_table_offset_(0u),
3337 method_bss_mapping_offset_(0u),
3338 dex_sections_layout_offset_(0u),
3339 class_offsets_() {
3340 }
3341
SizeOf() const3342 size_t OatWriter::OatDexFile::SizeOf() const {
3343 return sizeof(dex_file_location_size_)
3344 + dex_file_location_size_
3345 + sizeof(dex_file_location_checksum_)
3346 + sizeof(dex_file_offset_)
3347 + sizeof(class_offsets_offset_)
3348 + sizeof(lookup_table_offset_)
3349 + sizeof(method_bss_mapping_offset_)
3350 + sizeof(dex_sections_layout_offset_);
3351 }
3352
Write(OatWriter * oat_writer,OutputStream * out) const3353 bool OatWriter::OatDexFile::Write(OatWriter* oat_writer, OutputStream* out) const {
3354 const size_t file_offset = oat_writer->oat_data_offset_;
3355 DCHECK_OFFSET_();
3356
3357 if (!out->WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
3358 PLOG(ERROR) << "Failed to write dex file location length to " << out->GetLocation();
3359 return false;
3360 }
3361 oat_writer->size_oat_dex_file_location_size_ += sizeof(dex_file_location_size_);
3362
3363 if (!out->WriteFully(dex_file_location_data_, dex_file_location_size_)) {
3364 PLOG(ERROR) << "Failed to write dex file location data to " << out->GetLocation();
3365 return false;
3366 }
3367 oat_writer->size_oat_dex_file_location_data_ += dex_file_location_size_;
3368
3369 if (!out->WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) {
3370 PLOG(ERROR) << "Failed to write dex file location checksum to " << out->GetLocation();
3371 return false;
3372 }
3373 oat_writer->size_oat_dex_file_location_checksum_ += sizeof(dex_file_location_checksum_);
3374
3375 if (!out->WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
3376 PLOG(ERROR) << "Failed to write dex file offset to " << out->GetLocation();
3377 return false;
3378 }
3379 oat_writer->size_oat_dex_file_offset_ += sizeof(dex_file_offset_);
3380
3381 if (!out->WriteFully(&class_offsets_offset_, sizeof(class_offsets_offset_))) {
3382 PLOG(ERROR) << "Failed to write class offsets offset to " << out->GetLocation();
3383 return false;
3384 }
3385 oat_writer->size_oat_dex_file_class_offsets_offset_ += sizeof(class_offsets_offset_);
3386
3387 if (!out->WriteFully(&lookup_table_offset_, sizeof(lookup_table_offset_))) {
3388 PLOG(ERROR) << "Failed to write lookup table offset to " << out->GetLocation();
3389 return false;
3390 }
3391 oat_writer->size_oat_dex_file_lookup_table_offset_ += sizeof(lookup_table_offset_);
3392
3393 if (!out->WriteFully(&dex_sections_layout_offset_, sizeof(dex_sections_layout_offset_))) {
3394 PLOG(ERROR) << "Failed to write dex section layout info to " << out->GetLocation();
3395 return false;
3396 }
3397 oat_writer->size_oat_dex_file_dex_layout_sections_offset_ += sizeof(dex_sections_layout_offset_);
3398
3399 if (!out->WriteFully(&method_bss_mapping_offset_, sizeof(method_bss_mapping_offset_))) {
3400 PLOG(ERROR) << "Failed to write method bss mapping offset to " << out->GetLocation();
3401 return false;
3402 }
3403 oat_writer->size_oat_dex_file_method_bss_mapping_offset_ += sizeof(method_bss_mapping_offset_);
3404
3405 return true;
3406 }
3407
WriteClassOffsets(OatWriter * oat_writer,OutputStream * out)3408 bool OatWriter::OatDexFile::WriteClassOffsets(OatWriter* oat_writer, OutputStream* out) {
3409 if (!out->WriteFully(class_offsets_.data(), GetClassOffsetsRawSize())) {
3410 PLOG(ERROR) << "Failed to write oat class offsets for " << GetLocation()
3411 << " to " << out->GetLocation();
3412 return false;
3413 }
3414 oat_writer->size_oat_class_offsets_ += GetClassOffsetsRawSize();
3415 return true;
3416 }
3417
OatClass(const dchecked_vector<CompiledMethod * > & compiled_methods,uint32_t compiled_methods_with_code,uint16_t oat_class_type)3418 OatWriter::OatClass::OatClass(const dchecked_vector<CompiledMethod*>& compiled_methods,
3419 uint32_t compiled_methods_with_code,
3420 uint16_t oat_class_type)
3421 : compiled_methods_(compiled_methods) {
3422 const uint32_t num_methods = compiled_methods.size();
3423 CHECK_LE(compiled_methods_with_code, num_methods);
3424
3425 oat_method_offsets_offsets_from_oat_class_.resize(num_methods);
3426
3427 method_offsets_.resize(compiled_methods_with_code);
3428 method_headers_.resize(compiled_methods_with_code);
3429
3430 uint32_t oat_method_offsets_offset_from_oat_class = OatClassHeader::SizeOf();
3431 // We only create this instance if there are at least some compiled.
3432 if (oat_class_type == kOatClassSomeCompiled) {
3433 method_bitmap_.reset(new BitVector(num_methods, false, Allocator::GetMallocAllocator()));
3434 method_bitmap_size_ = method_bitmap_->GetSizeOf();
3435 oat_method_offsets_offset_from_oat_class += sizeof(method_bitmap_size_);
3436 oat_method_offsets_offset_from_oat_class += method_bitmap_size_;
3437 } else {
3438 method_bitmap_ = nullptr;
3439 method_bitmap_size_ = 0;
3440 }
3441
3442 for (size_t i = 0; i < num_methods; i++) {
3443 CompiledMethod* compiled_method = compiled_methods_[i];
3444 if (HasCompiledCode(compiled_method)) {
3445 oat_method_offsets_offsets_from_oat_class_[i] = oat_method_offsets_offset_from_oat_class;
3446 oat_method_offsets_offset_from_oat_class += sizeof(OatMethodOffsets);
3447 if (oat_class_type == kOatClassSomeCompiled) {
3448 method_bitmap_->SetBit(i);
3449 }
3450 } else {
3451 oat_method_offsets_offsets_from_oat_class_[i] = 0;
3452 }
3453 }
3454 }
3455
SizeOf() const3456 size_t OatWriter::OatClass::SizeOf() const {
3457 return ((method_bitmap_size_ == 0) ? 0 : sizeof(method_bitmap_size_))
3458 + method_bitmap_size_
3459 + (sizeof(method_offsets_[0]) * method_offsets_.size());
3460 }
3461
Write(OatWriter * oat_writer,OutputStream * out,const size_t file_offset) const3462 bool OatWriter::OatClassHeader::Write(OatWriter* oat_writer,
3463 OutputStream* out,
3464 const size_t file_offset) const {
3465 DCHECK_OFFSET_();
3466 if (!out->WriteFully(&status_, sizeof(status_))) {
3467 PLOG(ERROR) << "Failed to write class status to " << out->GetLocation();
3468 return false;
3469 }
3470 oat_writer->size_oat_class_status_ += sizeof(status_);
3471
3472 if (!out->WriteFully(&type_, sizeof(type_))) {
3473 PLOG(ERROR) << "Failed to write oat class type to " << out->GetLocation();
3474 return false;
3475 }
3476 oat_writer->size_oat_class_type_ += sizeof(type_);
3477 return true;
3478 }
3479
Write(OatWriter * oat_writer,OutputStream * out) const3480 bool OatWriter::OatClass::Write(OatWriter* oat_writer, OutputStream* out) const {
3481 if (method_bitmap_size_ != 0) {
3482 if (!out->WriteFully(&method_bitmap_size_, sizeof(method_bitmap_size_))) {
3483 PLOG(ERROR) << "Failed to write method bitmap size to " << out->GetLocation();
3484 return false;
3485 }
3486 oat_writer->size_oat_class_method_bitmaps_ += sizeof(method_bitmap_size_);
3487
3488 if (!out->WriteFully(method_bitmap_->GetRawStorage(), method_bitmap_size_)) {
3489 PLOG(ERROR) << "Failed to write method bitmap to " << out->GetLocation();
3490 return false;
3491 }
3492 oat_writer->size_oat_class_method_bitmaps_ += method_bitmap_size_;
3493 }
3494
3495 if (!out->WriteFully(method_offsets_.data(), GetMethodOffsetsRawSize())) {
3496 PLOG(ERROR) << "Failed to write method offsets to " << out->GetLocation();
3497 return false;
3498 }
3499 oat_writer->size_oat_class_method_offsets_ += GetMethodOffsetsRawSize();
3500 return true;
3501 }
3502
3503 } // namespace art
3504