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 <algorithm>
23 #include <memory>
24 #include <vector>
25
26 #include "arch/arm64/instruction_set_features_arm64.h"
27 #include "art_method-inl.h"
28 #include "base/allocator.h"
29 #include "base/bit_vector-inl.h"
30 #include "base/file_magic.h"
31 #include "base/file_utils.h"
32 #include "base/indenter.h"
33 #include "base/logging.h" // For VLOG
34 #include "base/os.h"
35 #include "base/pointer_size.h"
36 #include "base/safe_map.h"
37 #include "base/stl_util.h"
38 #include "base/unix_file/fd_file.h"
39 #include "base/zip_archive.h"
40 #include "class_linker.h"
41 #include "class_table-inl.h"
42 #include "code_info_table_deduper.h"
43 #include "debug/method_debug_info.h"
44 #include "dex/art_dex_file_loader.h"
45 #include "dex/class_accessor-inl.h"
46 #include "dex/dex_file-inl.h"
47 #include "dex/dex_file_loader.h"
48 #include "dex/dex_file_types.h"
49 #include "dex/dex_file_verifier.h"
50 #include "dex/proto_reference.h"
51 #include "dex/standard_dex_file.h"
52 #include "dex/type_lookup_table.h"
53 #include "dex/verification_results.h"
54 #include "driver/compiled_method-inl.h"
55 #include "driver/compiler_driver-inl.h"
56 #include "driver/compiler_options.h"
57 #include "gc/space/image_space.h"
58 #include "gc/space/space.h"
59 #include "handle_scope-inl.h"
60 #include "image_writer.h"
61 #include "linker/index_bss_mapping_encoder.h"
62 #include "linker/linker_patch.h"
63 #include "linker/multi_oat_relative_patcher.h"
64 #include "mirror/array.h"
65 #include "mirror/class_loader.h"
66 #include "mirror/dex_cache-inl.h"
67 #include "mirror/object-inl.h"
68 #include "oat/oat.h"
69 #include "oat/oat_quick_method_header.h"
70 #include "oat/stack_map.h"
71 #include "profile/profile_compilation_info.h"
72 #include "scoped_thread_state_change-inl.h"
73 #include "stream/buffered_output_stream.h"
74 #include "stream/file_output_stream.h"
75 #include "stream/output_stream.h"
76 #include "vdex_file.h"
77 #include "verifier/verifier_deps.h"
78
79 namespace art {
80 namespace linker {
81
82 namespace { // anonymous namespace
83
84 // If we write dex layout info in the oat file.
85 static constexpr bool kWriteDexLayoutInfo = true;
86
87 // Force the OAT method layout to be sorted-by-name instead of
88 // the default (class_def_idx, method_idx).
89 //
90 // Otherwise if profiles are used, that will act as
91 // the primary sort order.
92 //
93 // A bit easier to use for development since oatdump can easily
94 // show that things are being re-ordered when two methods aren't adjacent.
95 static constexpr bool kOatWriterForceOatCodeLayout = false;
96
97 static constexpr bool kOatWriterDebugOatCodeLayout = false;
98
99 using UnalignedDexFileHeader __attribute__((__aligned__(1))) = DexFile::Header;
100
AsUnalignedDexFileHeader(const uint8_t * raw_data)101 const UnalignedDexFileHeader* AsUnalignedDexFileHeader(const uint8_t* raw_data) {
102 return reinterpret_cast<const UnalignedDexFileHeader*>(raw_data);
103 }
104
CodeAlignmentSize(uint32_t header_offset,const CompiledMethod & compiled_method)105 inline uint32_t CodeAlignmentSize(uint32_t header_offset, const CompiledMethod& compiled_method) {
106 // We want to align the code rather than the preheader.
107 uint32_t unaligned_code_offset = header_offset + sizeof(OatQuickMethodHeader);
108 uint32_t aligned_code_offset = compiled_method.AlignCode(unaligned_code_offset);
109 return aligned_code_offset - unaligned_code_offset;
110 }
111
112 } // anonymous namespace
113
PutNonDeterministic(const std::string & k,const std::string & v,bool allow_truncation)114 bool OatKeyValueStore::PutNonDeterministic(const std::string& k,
115 const std::string& v,
116 bool allow_truncation) {
117 size_t length = OatHeader::GetNonDeterministicFieldLength(k);
118 DCHECK_GT(length, 0u);
119 if (v.length() <= length) {
120 map_.Put(k, v);
121 return true;
122 }
123 if (allow_truncation) {
124 LOG(WARNING) << "Key value store field " << k << " too long. Truncating";
125 map_.Put(k, v.substr(/*pos=*/0, length));
126 return true;
127 }
128 return false;
129 }
130
Put(const std::string & k,const std::string & v)131 void OatKeyValueStore::Put(const std::string& k, const std::string& v) {
132 DCHECK(OatHeader::IsDeterministicField(k));
133 map_.Put(k, v);
134 }
135
Put(const std::string & k,bool v)136 void OatKeyValueStore::Put(const std::string& k, bool v) {
137 DCHECK(OatHeader::IsDeterministicField(k));
138 map_.Put(k, v ? OatHeader::kTrueValue : OatHeader::kFalseValue);
139 }
140
141 // .bss mapping offsets used for BCP DexFiles.
142 struct OatWriter::BssMappingInfo {
143 // Offsets set in PrepareLayout.
144 uint32_t method_bss_mapping_offset = 0u;
145 uint32_t type_bss_mapping_offset = 0u;
146 uint32_t public_type_bss_mapping_offset = 0u;
147 uint32_t package_type_bss_mapping_offset = 0u;
148 uint32_t string_bss_mapping_offset = 0u;
149 uint32_t method_type_bss_mapping_offset = 0u;
150
151 // Offset of the BSSInfo start from beginning of OatHeader. It is used to validate file position
152 // when writing.
153 size_t offset_ = 0u;
154
SizeOfart::linker::OatWriter::BssMappingInfo155 static size_t SizeOf() {
156 return sizeof(method_bss_mapping_offset) +
157 sizeof(type_bss_mapping_offset) +
158 sizeof(public_type_bss_mapping_offset) +
159 sizeof(package_type_bss_mapping_offset) +
160 sizeof(string_bss_mapping_offset) +
161 sizeof(method_type_bss_mapping_offset);
162 }
163 bool Write(OatWriter* oat_writer, OutputStream* out) const;
164 };
165
166 class OatWriter::ChecksumUpdatingOutputStream : public OutputStream {
167 public:
ChecksumUpdatingOutputStream(OutputStream * out,OatWriter * writer)168 ChecksumUpdatingOutputStream(OutputStream* out, OatWriter* writer)
169 : OutputStream(out->GetLocation()), out_(out), writer_(writer) { }
170
WriteFully(const void * buffer,size_t byte_count)171 bool WriteFully(const void* buffer, size_t byte_count) override {
172 if (buffer != nullptr) {
173 const uint8_t* bytes = reinterpret_cast<const uint8_t*>(buffer);
174 uint32_t old_checksum = writer_->oat_checksum_;
175 writer_->oat_checksum_ = adler32(old_checksum, bytes, byte_count);
176 } else {
177 DCHECK_EQ(0U, byte_count);
178 }
179 return out_->WriteFully(buffer, byte_count);
180 }
181
Seek(off_t offset,Whence whence)182 off_t Seek(off_t offset, Whence whence) override {
183 return out_->Seek(offset, whence);
184 }
185
Flush()186 bool Flush() override {
187 return out_->Flush();
188 }
189
190 private:
191 OutputStream* const out_;
192 OatWriter* const writer_;
193 };
194
195 // OatClassHeader is the header only part of the oat class that is required even when compilation
196 // is not enabled.
197 class OatWriter::OatClassHeader {
198 public:
OatClassHeader(uint32_t offset,uint32_t num_non_null_compiled_methods,uint32_t num_methods,ClassStatus status)199 OatClassHeader(uint32_t offset,
200 uint32_t num_non_null_compiled_methods,
201 uint32_t num_methods,
202 ClassStatus status)
203 : status_(enum_cast<uint16_t>(status)),
204 offset_(offset) {
205 // We just arbitrarily say that 0 methods means OatClassType::kNoneCompiled and that we won't
206 // use OatClassType::kAllCompiled unless there is at least one compiled method. This means in
207 // an interpreter only system, we can assert that all classes are OatClassType::kNoneCompiled.
208 if (num_non_null_compiled_methods == 0) {
209 type_ = enum_cast<uint16_t>(OatClassType::kNoneCompiled);
210 } else if (num_non_null_compiled_methods == num_methods) {
211 type_ = enum_cast<uint16_t>(OatClassType::kAllCompiled);
212 } else {
213 type_ = enum_cast<uint16_t>(OatClassType::kSomeCompiled);
214 }
215 }
216
217 bool Write(OatWriter* oat_writer, OutputStream* out, const size_t file_offset) const;
218
SizeOf()219 static size_t SizeOf() {
220 return sizeof(status_) + sizeof(type_);
221 }
222
223 // Data to write.
224 static_assert(sizeof(ClassStatus) <= sizeof(uint16_t), "class status won't fit in 16bits");
225 uint16_t status_;
226
227 static_assert(sizeof(OatClassType) <= sizeof(uint16_t), "oat_class type won't fit in 16bits");
228 uint16_t type_;
229
230 // Offset of start of OatClass from beginning of OatHeader. It is
231 // used to validate file position when writing.
232 uint32_t offset_;
233 };
234
235 // The actual oat class body contains the information about compiled methods. It is only required
236 // for compiler filters that have any compilation.
237 class OatWriter::OatClass {
238 public:
239 OatClass(const dchecked_vector<CompiledMethod*>& compiled_methods,
240 uint32_t compiled_methods_with_code,
241 uint16_t oat_class_type);
242 OatClass(OatClass&& src) = default;
243 size_t SizeOf() const;
244 bool Write(OatWriter* oat_writer, OutputStream* out) const;
245
GetCompiledMethod(size_t class_def_method_index) const246 CompiledMethod* GetCompiledMethod(size_t class_def_method_index) const {
247 return compiled_methods_[class_def_method_index];
248 }
249
250 // CompiledMethods for each class_def_method_index, or null if no method is available.
251 dchecked_vector<CompiledMethod*> compiled_methods_;
252
253 // Offset from OatClass::offset_ to the OatMethodOffsets for the
254 // class_def_method_index. If 0, it means the corresponding
255 // CompiledMethod entry in OatClass::compiled_methods_ should be
256 // null and that the OatClass::type_ should be OatClassType::kSomeCompiled.
257 dchecked_vector<uint32_t> oat_method_offsets_offsets_from_oat_class_;
258
259 // Data to write.
260
261 // Number of methods recorded in OatClass. For `OatClassType::kNoneCompiled`
262 // this shall be zero and shall not be written to the file, otherwise it
263 // shall be the number of methods in the class definition. It is used to
264 // determine the size of `BitVector` data for `OatClassType::kSomeCompiled` and
265 // the size of the `OatMethodOffsets` table for `OatClassType::kAllCompiled`.
266 // (The size of the `OatMethodOffsets` table for `OatClassType::kSomeCompiled`
267 // is determined by the number of bits set in the `BitVector` data.)
268 uint32_t num_methods_;
269
270 // Bit vector indexed by ClassDef method index. When OatClass::type_ is
271 // OatClassType::kSomeCompiled, a set bit indicates the method has an
272 // OatMethodOffsets in methods_offsets_, otherwise
273 // the entry was omitted to save space. If OatClass::type_ is
274 // not is OatClassType::kSomeCompiled, the bitmap will be null.
275 std::unique_ptr<BitVector> method_bitmap_;
276
277 // OatMethodOffsets and OatMethodHeaders for each CompiledMethod
278 // present in the OatClass. Note that some may be missing if
279 // OatClass::compiled_methods_ contains null values (and
280 // oat_method_offsets_offsets_from_oat_class_ should contain 0
281 // values in this case).
282 dchecked_vector<OatMethodOffsets> method_offsets_;
283 dchecked_vector<OatQuickMethodHeader> method_headers_;
284
285 private:
GetMethodOffsetsRawSize() const286 size_t GetMethodOffsetsRawSize() const {
287 return method_offsets_.size() * sizeof(method_offsets_[0]);
288 }
289
290 DISALLOW_COPY_AND_ASSIGN(OatClass);
291 };
292
293 class OatWriter::OatDexFile {
294 public:
295 explicit OatDexFile(std::unique_ptr<const DexFile> dex_file);
296 OatDexFile(OatDexFile&& src) = default;
297
GetDexFile() const298 const DexFile* GetDexFile() const { return dex_file_.get(); }
299
GetLocation() const300 const char* GetLocation() const {
301 return dex_file_location_data_;
302 }
303
304 size_t SizeOf() const;
305 bool Write(OatWriter* oat_writer, OutputStream* out) const;
306 bool WriteClassOffsets(OatWriter* oat_writer, OutputStream* out);
307
GetClassOffsetsRawSize() const308 size_t GetClassOffsetsRawSize() const {
309 return class_offsets_.size() * sizeof(class_offsets_[0]);
310 }
311
312 std::unique_ptr<const DexFile> dex_file_;
313 std::unique_ptr<std::string> dex_file_location_;
314
315 // Dex file size. Passed in the constructor.
316 size_t dex_file_size_;
317
318 // Offset of start of OatDexFile from beginning of OatHeader. It is
319 // used to validate file position when writing.
320 size_t offset_;
321
322 ///// Start of data to write to vdex/oat file.
323
324 const uint32_t dex_file_location_size_;
325 const char* const dex_file_location_data_;
326
327 DexFile::Magic dex_file_magic_;
328
329 // The checksum of the dex file.
330 const uint32_t dex_file_location_checksum_;
331 const DexFile::Sha1 dex_file_sha1_;
332
333 // Offset of the dex file in the vdex file. Set when writing dex files in
334 // SeekToDexFile.
335 uint32_t dex_file_offset_;
336
337 // The lookup table offset in the oat file. Set in WriteTypeLookupTables.
338 uint32_t lookup_table_offset_;
339
340 // Class and BSS offsets set in PrepareLayout.
341 uint32_t class_offsets_offset_;
342 uint32_t method_bss_mapping_offset_;
343 uint32_t type_bss_mapping_offset_;
344 uint32_t public_type_bss_mapping_offset_;
345 uint32_t package_type_bss_mapping_offset_;
346 uint32_t string_bss_mapping_offset_;
347 uint32_t method_type_bss_mapping_offset_;
348
349 // Offset of dex sections that will have different runtime madvise states.
350 // Set in WriteDexLayoutSections.
351 uint32_t dex_sections_layout_offset_;
352
353 // Data to write to a separate section. We set the length
354 // of the vector in OpenDexFiles.
355 dchecked_vector<uint32_t> class_offsets_;
356
357 // Dex section layout info to serialize.
358 DexLayoutSections dex_sections_layout_;
359
360 ///// End of data to write to vdex/oat file.
361 private:
362 DISALLOW_COPY_AND_ASSIGN(OatDexFile);
363 };
364
365 #define DCHECK_OFFSET() \
366 DCHECK_EQ(static_cast<off_t>(file_offset + relative_offset), out->Seek(0, kSeekCurrent)) \
367 << "file_offset=" << file_offset << " relative_offset=" << relative_offset
368
369 #define DCHECK_OFFSET_() \
370 DCHECK_EQ(static_cast<off_t>(file_offset + offset_), out->Seek(0, kSeekCurrent)) \
371 << "file_offset=" << file_offset << " offset_=" << offset_
372
OatWriter(const CompilerOptions & compiler_options,TimingLogger * timings,ProfileCompilationInfo * info)373 OatWriter::OatWriter(const CompilerOptions& compiler_options,
374 TimingLogger* timings,
375 ProfileCompilationInfo* info)
376 : write_state_(WriteState::kAddingDexFileSources),
377 timings_(timings),
378 compiler_driver_(nullptr),
379 compiler_options_(compiler_options),
380 verification_results_(nullptr),
381 image_writer_(nullptr),
382 extract_dex_files_into_vdex_(true),
383 vdex_begin_(nullptr),
384 dex_files_(nullptr),
385 primary_oat_file_(false),
386 vdex_size_(0u),
387 vdex_dex_files_offset_(0u),
388 vdex_verifier_deps_offset_(0u),
389 vdex_lookup_tables_offset_(0u),
390 oat_checksum_(adler32(0L, Z_NULL, 0)),
391 code_size_(0u),
392 oat_size_(0u),
393 data_img_rel_ro_start_(0u),
394 data_img_rel_ro_size_(0u),
395 data_img_rel_ro_app_image_offset_(0u),
396 bss_start_(0u),
397 bss_size_(0u),
398 bss_methods_offset_(0u),
399 bss_roots_offset_(0u),
400 boot_image_rel_ro_entries_(),
401 bss_method_entry_references_(),
402 bss_type_entry_references_(),
403 bss_public_type_entry_references_(),
404 bss_package_type_entry_references_(),
405 bss_string_entry_references_(),
406 bss_method_type_entry_references_(),
407 app_image_rel_ro_method_entries_(),
408 bss_method_entries_(),
409 app_image_rel_ro_type_entries_(),
410 bss_type_entries_(),
411 bss_public_type_entries_(),
412 bss_package_type_entries_(),
413 bss_string_entries_(),
414 bss_method_type_entries_(),
415 oat_data_offset_(0u),
416 oat_header_(nullptr),
417 relative_patcher_(nullptr),
418 profile_compilation_info_(info) {}
419
ValidateDexFileHeader(const uint8_t * raw_header,const char * location)420 static bool ValidateDexFileHeader(const uint8_t* raw_header, const char* location) {
421 const bool valid_standard_dex_magic = DexFileLoader::IsMagicValid(raw_header);
422 if (!valid_standard_dex_magic) {
423 LOG(ERROR) << "Invalid magic number in dex file header. " << " File: " << location;
424 return false;
425 }
426 if (!DexFileLoader::IsVersionAndMagicValid(raw_header)) {
427 LOG(ERROR) << "Invalid version number in dex file header. " << " File: " << location;
428 return false;
429 }
430 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_header);
431 if (header->file_size_ < sizeof(DexFile::Header)) {
432 LOG(ERROR) << "Dex file header specifies file size insufficient to contain the header."
433 << " File: " << location;
434 return false;
435 }
436 return true;
437 }
438
AddDexFileSource(const char * filename,const char * location)439 bool OatWriter::AddDexFileSource(const char* filename, const char* location) {
440 DCHECK(write_state_ == WriteState::kAddingDexFileSources);
441 File fd(filename, O_RDONLY, /* check_usage= */ false);
442 if (fd.Fd() == -1) {
443 PLOG(ERROR) << "Failed to open dex file: '" << filename << "'";
444 return false;
445 }
446
447 return AddDexFileSource(std::move(fd), location);
448 }
449
450 // Add dex file source(s) from a file specified by a file handle.
451 // Note: The `dex_file_fd` specifies a plain dex file or a zip file.
AddDexFileSource(File && dex_file_fd,const char * location)452 bool OatWriter::AddDexFileSource(File&& dex_file_fd, const char* location) {
453 DCHECK(write_state_ == WriteState::kAddingDexFileSources);
454 std::string error_msg;
455 ArtDexFileLoader loader(&dex_file_fd, location);
456 std::vector<std::unique_ptr<const DexFile>> dex_files;
457 if (!loader.Open(/*verify=*/false,
458 /*verify_checksum=*/false,
459 &error_msg,
460 &dex_files)) {
461 LOG(ERROR) << "Failed to open dex file '" << location << "': " << error_msg;
462 return false;
463 }
464 for (auto& dex_file : dex_files) {
465 oat_dex_files_.emplace_back(std::move(dex_file));
466 }
467 return true;
468 }
469
470 // Add dex file source(s) from a vdex file specified by a file handle.
AddVdexDexFilesSource(const VdexFile & vdex_file,const char * location)471 bool OatWriter::AddVdexDexFilesSource(const VdexFile& vdex_file, const char* location) {
472 DCHECK(write_state_ == WriteState::kAddingDexFileSources);
473 DCHECK(vdex_file.HasDexSection());
474 auto container = std::make_shared<MemoryDexFileContainer>(vdex_file.Begin(), vdex_file.End());
475 const uint8_t* current_dex_data = nullptr;
476 size_t i = 0;
477 for (; i < vdex_file.GetNumberOfDexFiles(); ++i) {
478 current_dex_data = vdex_file.GetNextDexFileData(current_dex_data, i);
479 if (current_dex_data == nullptr) {
480 LOG(ERROR) << "Unexpected number of dex files in vdex " << location;
481 return false;
482 }
483
484 if (!DexFileLoader::IsMagicValid(current_dex_data)) {
485 LOG(ERROR) << "Invalid magic in vdex file created from " << location;
486 return false;
487 }
488 // We used `zipped_dex_file_locations_` to keep the strings in memory.
489 std::string multidex_location = DexFileLoader::GetMultiDexLocation(i, location);
490 if (!AddRawDexFileSource(container,
491 current_dex_data,
492 multidex_location.c_str(),
493 vdex_file.GetLocationChecksum(i))) {
494 return false;
495 }
496 }
497
498 if (vdex_file.GetNextDexFileData(current_dex_data, i) != nullptr) {
499 LOG(ERROR) << "Unexpected number of dex files in vdex " << location;
500 return false;
501 }
502
503 if (oat_dex_files_.empty()) {
504 LOG(ERROR) << "No dex files in vdex file created from " << location;
505 return false;
506 }
507 return true;
508 }
509
510 // Add dex file source from raw memory.
AddRawDexFileSource(const std::shared_ptr<DexFileContainer> & container,const uint8_t * dex_file_begin,const char * location,uint32_t location_checksum)511 bool OatWriter::AddRawDexFileSource(const std::shared_ptr<DexFileContainer>& container,
512 const uint8_t* dex_file_begin,
513 const char* location,
514 uint32_t location_checksum) {
515 DCHECK(write_state_ == WriteState::kAddingDexFileSources);
516 std::string error_msg;
517 ArtDexFileLoader loader(container->Begin(), container->Size(), location);
518 CHECK_GE(dex_file_begin, container->Begin());
519 CHECK_LE(dex_file_begin, container->End());
520 auto dex_file = loader.OpenOne(dex_file_begin - container->Begin(),
521 location_checksum,
522 nullptr,
523 /*verify=*/false,
524 /*verify_checksum=*/false,
525 &error_msg);
526 if (dex_file == nullptr) {
527 LOG(ERROR) << "Failed to open dex file '" << location << "': " << error_msg;
528 return false;
529 }
530 oat_dex_files_.emplace_back(std::move(dex_file));
531 return true;
532 }
533
GetSourceLocations() const534 dchecked_vector<std::string> OatWriter::GetSourceLocations() const {
535 dchecked_vector<std::string> locations;
536 locations.reserve(oat_dex_files_.size());
537 for (const OatDexFile& oat_dex_file : oat_dex_files_) {
538 locations.push_back(oat_dex_file.GetLocation());
539 }
540 return locations;
541 }
542
MayHaveCompiledMethods() const543 bool OatWriter::MayHaveCompiledMethods() const {
544 return GetCompilerOptions().IsAnyCompilationEnabled();
545 }
546
WriteAndOpenDexFiles(File * vdex_file,bool verify,bool use_existing_vdex,CopyOption copy_dex_files,std::vector<MemMap> * opened_dex_files_map,std::vector<std::unique_ptr<const DexFile>> * opened_dex_files)547 bool OatWriter::WriteAndOpenDexFiles(
548 File* vdex_file,
549 bool verify,
550 bool use_existing_vdex,
551 CopyOption copy_dex_files,
552 /*out*/ std::vector<MemMap>* opened_dex_files_map,
553 /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) {
554 CHECK(write_state_ == WriteState::kAddingDexFileSources);
555
556 // Reserve space for Vdex header, sections, and checksums.
557 size_vdex_header_ = sizeof(VdexFile::VdexFileHeader) +
558 VdexSection::kNumberOfSections * sizeof(VdexFile::VdexSectionHeader);
559 size_vdex_checksums_ = oat_dex_files_.size() * sizeof(VdexFile::VdexChecksum);
560 vdex_size_ = size_vdex_header_ + size_vdex_checksums_;
561
562 // Write DEX files into VDEX, mmap and open them.
563 std::vector<MemMap> dex_files_map;
564 std::vector<std::unique_ptr<const DexFile>> dex_files;
565 if (!WriteDexFiles(vdex_file, verify, use_existing_vdex, copy_dex_files, &dex_files_map) ||
566 !OpenDexFiles(vdex_file, &dex_files_map, &dex_files)) {
567 return false;
568 }
569
570 *opened_dex_files_map = std::move(dex_files_map);
571 *opened_dex_files = std::move(dex_files);
572 // Create type lookup tables to speed up lookups during compilation.
573 InitializeTypeLookupTables(*opened_dex_files);
574 write_state_ = WriteState::kStartRoData;
575 return true;
576 }
577
StartRoData(const std::vector<const DexFile * > & dex_files,OutputStream * oat_rodata,OatKeyValueStore * key_value_store)578 bool OatWriter::StartRoData(const std::vector<const DexFile*>& dex_files,
579 OutputStream* oat_rodata,
580 OatKeyValueStore* key_value_store) {
581 CHECK(write_state_ == WriteState::kStartRoData);
582
583 // Record the ELF rodata section offset, i.e. the beginning of the OAT data.
584 if (!RecordOatDataOffset(oat_rodata)) {
585 return false;
586 }
587
588 // Record whether this is the primary oat file.
589 primary_oat_file_ = (key_value_store != nullptr);
590
591 // Initialize OAT header.
592 oat_size_ = InitOatHeader(dchecked_integral_cast<uint32_t>(oat_dex_files_.size()),
593 key_value_store);
594
595 ChecksumUpdatingOutputStream checksum_updating_rodata(oat_rodata, this);
596
597 // Write dex layout sections into the oat file.
598 if (!WriteDexLayoutSections(&checksum_updating_rodata, dex_files)) {
599 return false;
600 }
601
602 write_state_ = WriteState::kInitialize;
603 return true;
604 }
605
606 // Initialize the writer with the given parameters.
Initialize(const CompilerDriver * compiler_driver,const VerificationResults * verification_results,ImageWriter * image_writer,const std::vector<const DexFile * > & dex_files)607 void OatWriter::Initialize(const CompilerDriver* compiler_driver,
608 const VerificationResults* verification_results,
609 ImageWriter* image_writer,
610 const std::vector<const DexFile*>& dex_files) {
611 CHECK(write_state_ == WriteState::kInitialize);
612 compiler_driver_ = compiler_driver;
613 verification_results_ = verification_results;
614 image_writer_ = image_writer;
615 dex_files_ = &dex_files;
616 write_state_ = WriteState::kPrepareLayout;
617 }
618
PrepareLayout(MultiOatRelativePatcher * relative_patcher)619 void OatWriter::PrepareLayout(MultiOatRelativePatcher* relative_patcher) {
620 CHECK(write_state_ == WriteState::kPrepareLayout);
621
622 relative_patcher_ = relative_patcher;
623 SetMultiOatRelativePatcherAdjustment();
624
625 if (GetCompilerOptions().IsBootImage() || GetCompilerOptions().IsBootImageExtension()) {
626 CHECK(image_writer_ != nullptr);
627 }
628 InstructionSet instruction_set = compiler_options_.GetInstructionSet();
629 CHECK_EQ(instruction_set, oat_header_->GetInstructionSet());
630
631 {
632 TimingLogger::ScopedTiming split("InitBssAndRelRoData", timings_);
633 InitBssAndRelRoData();
634 }
635
636 {
637 TimingLogger::ScopedTiming split("InitBssLayout", timings_);
638 InitBssLayout(instruction_set);
639 }
640
641 uint32_t offset = oat_size_;
642 {
643 TimingLogger::ScopedTiming split("InitClassOffsets", timings_);
644 offset = InitClassOffsets(offset);
645 }
646 {
647 TimingLogger::ScopedTiming split("InitOatClasses", timings_);
648 offset = InitOatClasses(offset);
649 }
650 {
651 TimingLogger::ScopedTiming split("InitIndexBssMappings", timings_);
652 offset = InitIndexBssMappings(offset);
653 }
654 {
655 TimingLogger::ScopedTiming split("InitOatMaps", timings_);
656 offset = InitOatMaps(offset);
657 }
658 {
659 TimingLogger::ScopedTiming split("InitOatDexFiles", timings_);
660 oat_header_->SetOatDexFilesOffset(offset);
661 offset = InitOatDexFiles(offset);
662 }
663 {
664 TimingLogger::ScopedTiming split("InitBcpBssInfo", timings_);
665 offset = InitBcpBssInfo(offset);
666 }
667 {
668 TimingLogger::ScopedTiming split("InitOatCode", timings_);
669 offset = InitOatCode(offset);
670 }
671 {
672 TimingLogger::ScopedTiming split("InitOatCodeDexFiles", timings_);
673 offset = InitOatCodeDexFiles(offset);
674 code_size_ = offset - GetOatHeader().GetExecutableOffset();
675 }
676 {
677 TimingLogger::ScopedTiming split("InitDataImgRelRoLayout", timings_);
678 offset = InitDataImgRelRoLayout(offset);
679 }
680 oat_size_ = offset; // .bss does not count towards oat_size_.
681 bss_start_ = (bss_size_ != 0u) ?
682 GetOffsetFromOatDataAlignedToFile(oat_size_, kElfSegmentAlignment) : 0u;
683
684 CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
685
686 write_state_ = WriteState::kWriteRoData;
687 }
688
~OatWriter()689 OatWriter::~OatWriter() {
690 OatHeader::Delete(oat_header_);
691 }
692
693 class OatWriter::DexMethodVisitor {
694 public:
DexMethodVisitor(OatWriter * writer,size_t offset)695 DexMethodVisitor(OatWriter* writer, size_t offset)
696 : writer_(writer),
697 offset_(offset),
698 dex_file_(nullptr),
699 class_def_index_(dex::kDexNoIndex) {}
700
StartClass(const DexFile * dex_file,size_t class_def_index)701 virtual bool StartClass(const DexFile* dex_file, size_t class_def_index) {
702 DCHECK(dex_file_ == nullptr);
703 DCHECK_EQ(class_def_index_, dex::kDexNoIndex);
704 dex_file_ = dex_file;
705 class_def_index_ = class_def_index;
706 return true;
707 }
708
709 virtual bool VisitMethod(size_t class_def_method_index, const ClassAccessor::Method& method) = 0;
710
EndClass()711 virtual bool EndClass() {
712 if (kIsDebugBuild) {
713 dex_file_ = nullptr;
714 class_def_index_ = dex::kDexNoIndex;
715 }
716 return true;
717 }
718
GetOffset() const719 size_t GetOffset() const {
720 return offset_;
721 }
722
723 protected:
~DexMethodVisitor()724 virtual ~DexMethodVisitor() { }
725
726 OatWriter* const writer_;
727
728 // The offset is usually advanced for each visited method by the derived class.
729 size_t offset_;
730
731 // The dex file and class def index are set in StartClass().
732 const DexFile* dex_file_;
733 size_t class_def_index_;
734 };
735
736 class OatWriter::OatDexMethodVisitor : public DexMethodVisitor {
737 public:
OatDexMethodVisitor(OatWriter * writer,size_t offset)738 OatDexMethodVisitor(OatWriter* writer, size_t offset)
739 : DexMethodVisitor(writer, offset),
740 oat_class_index_(0u),
741 method_offsets_index_(0u) {}
742
StartClass(const DexFile * dex_file,size_t class_def_index)743 bool StartClass(const DexFile* dex_file, size_t class_def_index) override {
744 DexMethodVisitor::StartClass(dex_file, class_def_index);
745 if (kIsDebugBuild && writer_->MayHaveCompiledMethods()) {
746 // There are no oat classes if there aren't any compiled methods.
747 CHECK_LT(oat_class_index_, writer_->oat_classes_.size());
748 }
749 method_offsets_index_ = 0u;
750 return true;
751 }
752
EndClass()753 bool EndClass() override {
754 ++oat_class_index_;
755 return DexMethodVisitor::EndClass();
756 }
757
758 protected:
759 size_t oat_class_index_;
760 size_t method_offsets_index_;
761 };
762
HasCompiledCode(const CompiledMethod * method)763 static bool HasCompiledCode(const CompiledMethod* method) {
764 return method != nullptr && !method->GetQuickCode().empty();
765 }
766
InitBssAndRelRoData()767 void OatWriter::InitBssAndRelRoData() {
768 for (const DexFile* dex_file : *dex_files_) {
769 const dchecked_vector<Atomic<CompiledMethod*>>* compiled_methods =
770 compiler_driver_->GetCompiledMethods(dex_file);
771 if (compiled_methods == nullptr) {
772 continue;
773 }
774 for (const Atomic<CompiledMethod*>& entry : *compiled_methods) {
775 CompiledMethod* compiled_method = entry.load(std::memory_order_relaxed);
776 if (compiled_method == nullptr) {
777 continue;
778 }
779 DCHECK_IMPLIES(!compiled_method->GetPatches().empty(), HasCompiledCode(compiled_method));
780 for (const LinkerPatch& patch : compiled_method->GetPatches()) {
781 if (patch.GetType() == LinkerPatch::Type::kBootImageRelRo) {
782 boot_image_rel_ro_entries_.Overwrite(patch.BootImageOffset(), /* placeholder */ 0u);
783 } else if (patch.GetType() == LinkerPatch::Type::kMethodAppImageRelRo) {
784 MethodReference target_method = patch.TargetMethod();
785 app_image_rel_ro_method_entries_.Overwrite(target_method, /* placeholder */ 0u);
786 } else if (patch.GetType() == LinkerPatch::Type::kMethodBssEntry) {
787 MethodReference target_method = patch.TargetMethod();
788 AddBssReference(target_method,
789 target_method.dex_file->NumMethodIds(),
790 &bss_method_entry_references_);
791 bss_method_entries_.Overwrite(target_method, /* placeholder */ 0u);
792 } else if (patch.GetType() == LinkerPatch::Type::kTypeAppImageRelRo) {
793 app_image_rel_ro_type_entries_.Overwrite(patch.TargetType(), /* placeholder */ 0u);
794 } else if (patch.GetType() == LinkerPatch::Type::kTypeBssEntry) {
795 TypeReference target_type = patch.TargetType();
796 AddBssReference(target_type,
797 target_type.dex_file->NumTypeIds(),
798 &bss_type_entry_references_);
799 bss_type_entries_.Overwrite(target_type, /* placeholder */ 0u);
800 } else if (patch.GetType() == LinkerPatch::Type::kPublicTypeBssEntry) {
801 TypeReference target_type = patch.TargetType();
802 AddBssReference(target_type,
803 target_type.dex_file->NumTypeIds(),
804 &bss_public_type_entry_references_);
805 bss_public_type_entries_.Overwrite(target_type, /* placeholder */ 0u);
806 } else if (patch.GetType() == LinkerPatch::Type::kPackageTypeBssEntry) {
807 TypeReference target_type = patch.TargetType();
808 AddBssReference(target_type,
809 target_type.dex_file->NumTypeIds(),
810 &bss_package_type_entry_references_);
811 bss_package_type_entries_.Overwrite(target_type, /* placeholder */ 0u);
812 } else if (patch.GetType() == LinkerPatch::Type::kStringBssEntry) {
813 StringReference target_string = patch.TargetString();
814 AddBssReference(target_string,
815 target_string.dex_file->NumStringIds(),
816 &bss_string_entry_references_);
817 bss_string_entries_.Overwrite(target_string, /* placeholder */ 0u);
818 } else if (patch.GetType() == LinkerPatch::Type::kMethodTypeBssEntry) {
819 ProtoReference target_proto = patch.TargetProto();
820 AddBssReference(target_proto,
821 target_proto.dex_file->NumProtoIds(),
822 &bss_method_type_entry_references_);
823 bss_method_type_entries_.Overwrite(target_proto, /* placeholder */ 0u);
824 }
825 }
826 }
827 }
828 }
829
AddBssReference(const DexFileReference & ref,size_t number_of_indexes,SafeMap<const DexFile *,BitVector> * references)830 inline void OatWriter::AddBssReference(const DexFileReference& ref,
831 size_t number_of_indexes,
832 /*inout*/ SafeMap<const DexFile*, BitVector>* references) {
833 DCHECK(ContainsElement(*dex_files_, ref.dex_file) ||
834 ContainsElement(Runtime::Current()->GetClassLinker()->GetBootClassPath(), ref.dex_file));
835 DCHECK_LT(ref.index, number_of_indexes);
836
837 auto refs_it = references->find(ref.dex_file);
838 if (refs_it == references->end()) {
839 refs_it = references->Put(
840 ref.dex_file,
841 BitVector(number_of_indexes, /* expandable */ false, Allocator::GetCallocAllocator()));
842 }
843 refs_it->second.SetBit(ref.index);
844 }
845
846 class OatWriter::InitOatClassesMethodVisitor : public DexMethodVisitor {
847 public:
InitOatClassesMethodVisitor(OatWriter * writer,size_t offset)848 InitOatClassesMethodVisitor(OatWriter* writer, size_t offset)
849 : DexMethodVisitor(writer, offset),
850 compiled_methods_(),
851 compiled_methods_with_code_(0u) {
852 size_t num_classes = 0u;
853 for (const OatDexFile& oat_dex_file : writer_->oat_dex_files_) {
854 num_classes += oat_dex_file.class_offsets_.size();
855 }
856 // If we aren't compiling only reserve headers.
857 writer_->oat_class_headers_.reserve(num_classes);
858 if (writer->MayHaveCompiledMethods()) {
859 writer->oat_classes_.reserve(num_classes);
860 }
861 compiled_methods_.reserve(256u);
862 // If there are any classes, the class offsets allocation aligns the offset.
863 DCHECK(num_classes == 0u || IsAligned<4u>(offset));
864 }
865
StartClass(const DexFile * dex_file,size_t class_def_index)866 bool StartClass(const DexFile* dex_file, size_t class_def_index) override {
867 DexMethodVisitor::StartClass(dex_file, class_def_index);
868 compiled_methods_.clear();
869 compiled_methods_with_code_ = 0u;
870 return true;
871 }
872
VisitMethod(size_t class_def_method_index,const ClassAccessor::Method & method)873 bool VisitMethod([[maybe_unused]] size_t class_def_method_index,
874 const ClassAccessor::Method& method) override {
875 // Fill in the compiled_methods_ array for methods that have a
876 // CompiledMethod. We track the number of non-null entries in
877 // compiled_methods_with_code_ since we only want to allocate
878 // OatMethodOffsets for the compiled methods.
879 uint32_t method_idx = method.GetIndex();
880 CompiledMethod* compiled_method =
881 writer_->compiler_driver_->GetCompiledMethod(MethodReference(dex_file_, method_idx));
882 compiled_methods_.push_back(compiled_method);
883 if (HasCompiledCode(compiled_method)) {
884 ++compiled_methods_with_code_;
885 }
886 return true;
887 }
888
EndClass()889 bool EndClass() override {
890 ClassReference class_ref(dex_file_, class_def_index_);
891 ClassStatus status;
892 bool found = writer_->compiler_driver_->GetCompiledClass(class_ref, &status);
893 if (!found) {
894 const VerificationResults* results = writer_->verification_results_;
895 if (results != nullptr && results->IsClassRejected(class_ref)) {
896 // The oat class status is used only for verification of resolved classes,
897 // so use ClassStatus::kErrorResolved whether the class was resolved or unresolved
898 // during compile-time verification.
899 status = ClassStatus::kErrorResolved;
900 } else {
901 status = ClassStatus::kNotReady;
902 }
903 }
904 // We never emit kRetryVerificationAtRuntime, instead we mark the class as
905 // resolved and the class will therefore be re-verified at runtime.
906 if (status == ClassStatus::kRetryVerificationAtRuntime) {
907 status = ClassStatus::kResolved;
908 }
909
910 writer_->oat_class_headers_.emplace_back(offset_,
911 compiled_methods_with_code_,
912 compiled_methods_.size(),
913 status);
914 OatClassHeader& header = writer_->oat_class_headers_.back();
915 offset_ += header.SizeOf();
916 if (writer_->MayHaveCompiledMethods()) {
917 writer_->oat_classes_.emplace_back(compiled_methods_,
918 compiled_methods_with_code_,
919 header.type_);
920 offset_ += writer_->oat_classes_.back().SizeOf();
921 }
922 return DexMethodVisitor::EndClass();
923 }
924
925 private:
926 dchecked_vector<CompiledMethod*> compiled_methods_;
927 size_t compiled_methods_with_code_;
928 };
929
930 // CompiledMethod + metadata required to do ordered method layout.
931 //
932 // See also OrderedMethodVisitor.
933 struct OatWriter::OrderedMethodData {
934 uint32_t hotness_bits;
935 OatClass* oat_class;
936 CompiledMethod* compiled_method;
937 MethodReference method_reference;
938 size_t method_offsets_index;
939
940 size_t class_def_index;
941 uint32_t access_flags;
942 const dex::CodeItem* code_item;
943
944 // A value of -1 denotes missing debug info
945 static constexpr size_t kDebugInfoIdxInvalid = static_cast<size_t>(-1);
946 // Index into writer_->method_info_
947 size_t debug_info_idx;
948
HasDebugInfoart::linker::OatWriter::OrderedMethodData949 bool HasDebugInfo() const {
950 return debug_info_idx != kDebugInfoIdxInvalid;
951 }
952
953 // Bin each method according to the profile flags.
954 //
955 // Groups by e.g.
956 // -- startup and hot and poststartup
957 // -- startup and hot
958 // -- startup and post-startup
959 // -- startup
960 // -- hot and post-startup
961 // -- hot
962 // -- post-startup
963 // -- not hot at all
964 //
965 // (See MethodHotness enum definition for up-to-date binning order.)
operator <art::linker::OatWriter::OrderedMethodData966 bool operator<(const OrderedMethodData& other) const {
967 if (kOatWriterForceOatCodeLayout) {
968 // Development flag: Override default behavior by sorting by name.
969
970 std::string name = method_reference.PrettyMethod();
971 std::string other_name = other.method_reference.PrettyMethod();
972 return name < other_name;
973 }
974
975 // Use the profile's method hotness to determine sort order, with startup
976 // methods appearing first.
977 if (hotness_bits > other.hotness_bits) {
978 return true;
979 }
980
981 // Default: retain the original order.
982 return false;
983 }
984 };
985
986 // Given a queue of CompiledMethod in some total order,
987 // visit each one in that order.
988 class OatWriter::OrderedMethodVisitor {
989 public:
OrderedMethodVisitor(OrderedMethodList ordered_methods)990 explicit OrderedMethodVisitor(OrderedMethodList ordered_methods)
991 : ordered_methods_(std::move(ordered_methods)) {
992 }
993
~OrderedMethodVisitor()994 virtual ~OrderedMethodVisitor() {}
995
996 // Invoke VisitMethod in the order of `ordered_methods`, then invoke VisitComplete.
Visit()997 bool Visit() REQUIRES_SHARED(Locks::mutator_lock_) {
998 if (!VisitStart()) {
999 return false;
1000 }
1001
1002 for (const OrderedMethodData& method_data : ordered_methods_) {
1003 if (!VisitMethod(method_data)) {
1004 return false;
1005 }
1006 }
1007
1008 return VisitComplete();
1009 }
1010
1011 // Invoked once at the beginning, prior to visiting anything else.
1012 //
1013 // Return false to abort further visiting.
VisitStart()1014 virtual bool VisitStart() { return true; }
1015
1016 // Invoked repeatedly in the order specified by `ordered_methods`.
1017 //
1018 // Return false to short-circuit and to stop visiting further methods.
1019 virtual bool VisitMethod(const OrderedMethodData& method_data)
1020 REQUIRES_SHARED(Locks::mutator_lock_) = 0;
1021
1022 // Invoked once at the end, after every other method has been successfully visited.
1023 //
1024 // Return false to indicate the overall `Visit` has failed.
1025 virtual bool VisitComplete() = 0;
1026
ReleaseOrderedMethods()1027 OrderedMethodList ReleaseOrderedMethods() {
1028 return std::move(ordered_methods_);
1029 }
1030
1031 private:
1032 // List of compiled methods, sorted by the order defined in OrderedMethodData.
1033 // Methods can be inserted more than once in case of duplicated methods.
1034 OrderedMethodList ordered_methods_;
1035 };
1036
1037 // Visit every compiled method in order to determine its order within the OAT file.
1038 // Methods from the same class do not need to be adjacent in the OAT code.
1039 class OatWriter::LayoutCodeMethodVisitor final : public OatDexMethodVisitor {
1040 public:
LayoutCodeMethodVisitor(OatWriter * writer,size_t offset)1041 LayoutCodeMethodVisitor(OatWriter* writer, size_t offset)
1042 : OatDexMethodVisitor(writer, offset),
1043 profile_index_(ProfileCompilationInfo::MaxProfileIndex()),
1044 profile_index_dex_file_(nullptr) {
1045 }
1046
StartClass(const DexFile * dex_file,size_t class_def_index)1047 bool StartClass(const DexFile* dex_file, size_t class_def_index) final {
1048 // Update the cached `profile_index_` if needed. This happens only once per dex file
1049 // because we visit all classes in a dex file together, so mark that as `UNLIKELY`.
1050 if (UNLIKELY(dex_file != profile_index_dex_file_)) {
1051 if (writer_->profile_compilation_info_ != nullptr) {
1052 profile_index_ = writer_->profile_compilation_info_->FindDexFile(*dex_file);
1053 } else {
1054 DCHECK_EQ(profile_index_, ProfileCompilationInfo::MaxProfileIndex());
1055 }
1056 profile_index_dex_file_ = dex_file;
1057 }
1058 return OatDexMethodVisitor::StartClass(dex_file, class_def_index);
1059 }
1060
VisitMethod(size_t class_def_method_index,const ClassAccessor::Method & method)1061 bool VisitMethod(size_t class_def_method_index, const ClassAccessor::Method& method) final
1062 REQUIRES_SHARED(Locks::mutator_lock_) {
1063 Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
1064
1065 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
1066 CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1067
1068 if (HasCompiledCode(compiled_method)) {
1069 size_t debug_info_idx = OrderedMethodData::kDebugInfoIdxInvalid;
1070
1071 {
1072 const CompilerOptions& compiler_options = writer_->GetCompilerOptions();
1073 ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
1074 uint32_t code_size = quick_code.size() * sizeof(uint8_t);
1075
1076 // Debug method info must be pushed in the original order
1077 // (i.e. all methods from the same class must be adjacent in the debug info sections)
1078 // ElfCompilationUnitWriter::Write requires this.
1079 if (compiler_options.GenerateAnyDebugInfo() && code_size != 0) {
1080 debug::MethodDebugInfo info = debug::MethodDebugInfo();
1081 writer_->method_info_.push_back(info);
1082
1083 // The debug info is filled in LayoutReserveOffsetCodeMethodVisitor
1084 // once we know the offsets.
1085 //
1086 // Store the index into writer_->method_info_ since future push-backs
1087 // could reallocate and change the underlying data address.
1088 debug_info_idx = writer_->method_info_.size() - 1;
1089 }
1090 }
1091
1092 // Determine the `hotness_bits`, used to determine relative order
1093 // for OAT code layout when determining binning.
1094 uint32_t method_index = method.GetIndex();
1095 MethodReference method_ref(dex_file_, method_index);
1096 uint32_t hotness_bits = 0u;
1097 if (profile_index_ != ProfileCompilationInfo::MaxProfileIndex()) {
1098 ProfileCompilationInfo* pci = writer_->profile_compilation_info_;
1099 DCHECK(pci != nullptr);
1100 // Note: Bin-to-bin order does not matter. If the kernel does or does not read-ahead
1101 // any memory, it only goes into the buffer cache and does not grow the PSS until the
1102 // first time that memory is referenced in the process.
1103 constexpr uint32_t kStartupBit = 4u;
1104 constexpr uint32_t kHotBit = 2u;
1105 constexpr uint32_t kPostStartupBit = 1u;
1106 hotness_bits =
1107 (pci->IsHotMethod(profile_index_, method_index) ? kHotBit : 0u) |
1108 (pci->IsStartupMethod(profile_index_, method_index) ? kStartupBit : 0u) |
1109 (pci->IsPostStartupMethod(profile_index_, method_index) ? kPostStartupBit : 0u);
1110 if (kIsDebugBuild) {
1111 // Check for bins that are always-empty given a real profile.
1112 if (hotness_bits == kHotBit) {
1113 // This is not fatal, so only warn.
1114 LOG(WARNING) << "Method " << method_ref.PrettyMethod() << " was hot but wasn't marked "
1115 << "either start-up or post-startup. Possible corrupted profile?";
1116 }
1117 }
1118 }
1119
1120 // Handle duplicate methods by pushing them repeatedly.
1121 OrderedMethodData method_data = {
1122 hotness_bits,
1123 oat_class,
1124 compiled_method,
1125 method_ref,
1126 method_offsets_index_,
1127 class_def_index_,
1128 method.GetAccessFlags(),
1129 method.GetCodeItem(),
1130 debug_info_idx
1131 };
1132 ordered_methods_.push_back(method_data);
1133
1134 method_offsets_index_++;
1135 }
1136
1137 return true;
1138 }
1139
ReleaseOrderedMethods()1140 OrderedMethodList ReleaseOrderedMethods() {
1141 if (kOatWriterForceOatCodeLayout || writer_->profile_compilation_info_ != nullptr) {
1142 // Sort by the method ordering criteria (in OrderedMethodData).
1143 // Since most methods will have the same ordering criteria,
1144 // we preserve the original insertion order within the same sort order.
1145 std::stable_sort(ordered_methods_.begin(), ordered_methods_.end());
1146 } else {
1147 // The profile-less behavior is as if every method had 0 hotness
1148 // associated with it.
1149 //
1150 // Since sorting all methods with hotness=0 should give back the same
1151 // order as before, don't do anything.
1152 DCHECK(std::is_sorted(ordered_methods_.begin(), ordered_methods_.end()));
1153 }
1154
1155 return std::move(ordered_methods_);
1156 }
1157
1158 private:
1159 // Cached profile index for the current dex file.
1160 ProfileCompilationInfo::ProfileIndexType profile_index_;
1161 const DexFile* profile_index_dex_file_;
1162
1163 // List of compiled methods, later to be sorted by order defined in OrderedMethodData.
1164 // Methods can be inserted more than once in case of duplicated methods.
1165 OrderedMethodList ordered_methods_;
1166 };
1167
1168 // Given a method order, reserve the offsets for each CompiledMethod in the OAT file.
1169 class OatWriter::LayoutReserveOffsetCodeMethodVisitor : public OrderedMethodVisitor {
1170 public:
LayoutReserveOffsetCodeMethodVisitor(OatWriter * writer,size_t offset,OrderedMethodList ordered_methods)1171 LayoutReserveOffsetCodeMethodVisitor(OatWriter* writer,
1172 size_t offset,
1173 OrderedMethodList ordered_methods)
1174 : LayoutReserveOffsetCodeMethodVisitor(writer,
1175 offset,
1176 writer->GetCompilerOptions(),
1177 std::move(ordered_methods)) {
1178 }
1179
VisitComplete()1180 bool VisitComplete() override {
1181 offset_ = writer_->relative_patcher_->ReserveSpaceEnd(offset_);
1182 if (generate_debug_info_) {
1183 std::vector<debug::MethodDebugInfo> thunk_infos =
1184 relative_patcher_->GenerateThunkDebugInfo(executable_offset_);
1185 writer_->method_info_.insert(writer_->method_info_.end(),
1186 std::make_move_iterator(thunk_infos.begin()),
1187 std::make_move_iterator(thunk_infos.end()));
1188 }
1189 return true;
1190 }
1191
VisitMethod(const OrderedMethodData & method_data)1192 bool VisitMethod(const OrderedMethodData& method_data) override
1193 REQUIRES_SHARED(Locks::mutator_lock_) {
1194 OatClass* oat_class = method_data.oat_class;
1195 CompiledMethod* compiled_method = method_data.compiled_method;
1196 const MethodReference& method_ref = method_data.method_reference;
1197 uint16_t method_offsets_index_ = method_data.method_offsets_index;
1198 size_t class_def_index = method_data.class_def_index;
1199 uint32_t access_flags = method_data.access_flags;
1200 bool has_debug_info = method_data.HasDebugInfo();
1201 size_t debug_info_idx = method_data.debug_info_idx;
1202
1203 DCHECK(HasCompiledCode(compiled_method)) << method_ref.PrettyMethod();
1204
1205 // Derived from CompiledMethod.
1206 uint32_t quick_code_offset = 0;
1207
1208 ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
1209 uint32_t code_size = quick_code.size() * sizeof(uint8_t);
1210 uint32_t thumb_offset = compiled_method->GetEntryPointAdjustment();
1211
1212 // Deduplicate code arrays if we are not producing debuggable code.
1213 bool deduped = true;
1214 if (debuggable_) {
1215 quick_code_offset = relative_patcher_->GetOffset(method_ref);
1216 if (quick_code_offset != 0u) {
1217 // Duplicate methods, we want the same code for both of them so that the oat writer puts
1218 // the same code in both ArtMethods so that we do not get different oat code at runtime.
1219 } else {
1220 quick_code_offset = NewQuickCodeOffset(compiled_method, method_ref, thumb_offset);
1221 deduped = false;
1222 }
1223 } else {
1224 quick_code_offset = dedupe_map_.GetOrCreate(
1225 compiled_method,
1226 [this, &deduped, compiled_method, &method_ref, thumb_offset]() {
1227 deduped = false;
1228 return NewQuickCodeOffset(compiled_method, method_ref, thumb_offset);
1229 });
1230 }
1231
1232 if (code_size != 0) {
1233 if (relative_patcher_->GetOffset(method_ref) != 0u) {
1234 // TODO: Should this be a hard failure?
1235 LOG(WARNING) << "Multiple definitions of "
1236 << method_ref.dex_file->PrettyMethod(method_ref.index)
1237 << " offsets " << relative_patcher_->GetOffset(method_ref)
1238 << " " << quick_code_offset;
1239 } else {
1240 relative_patcher_->SetOffset(method_ref, quick_code_offset);
1241 }
1242 }
1243
1244 // Update quick method header.
1245 DCHECK_LT(method_offsets_index_, oat_class->method_headers_.size());
1246 OatQuickMethodHeader* method_header = &oat_class->method_headers_[method_offsets_index_];
1247 uint32_t code_info_offset = method_header->GetCodeInfoOffset();
1248 uint32_t code_offset = quick_code_offset - thumb_offset;
1249 CHECK(!compiled_method->GetQuickCode().empty());
1250 // If the code is compiled, we write the offset of the stack map relative
1251 // to the code. The offset was previously stored relative to start of file.
1252 if (code_info_offset != 0u) {
1253 DCHECK_LT(code_info_offset, code_offset);
1254 code_info_offset = code_offset - code_info_offset;
1255 }
1256 *method_header = OatQuickMethodHeader(code_info_offset);
1257
1258 if (!deduped) {
1259 // Update offsets. (Checksum is updated when writing.)
1260 offset_ += sizeof(*method_header); // Method header is prepended before code.
1261 offset_ += code_size;
1262 }
1263
1264 // Exclude dex methods without native code.
1265 if (generate_debug_info_ && code_size != 0) {
1266 DCHECK(has_debug_info);
1267 const uint8_t* code_info = compiled_method->GetVmapTable().data();
1268 DCHECK(code_info != nullptr);
1269
1270 // Record debug information for this function if we are doing that.
1271 debug::MethodDebugInfo& info = writer_->method_info_[debug_info_idx];
1272 // Simpleperf relies on art_jni_trampoline to detect jni methods.
1273 info.custom_name = (access_flags & kAccNative) ? "art_jni_trampoline" : "";
1274 info.dex_file = method_ref.dex_file;
1275 info.class_def_index = class_def_index;
1276 info.dex_method_index = method_ref.index;
1277 info.access_flags = access_flags;
1278 // For intrinsics emitted by codegen, the code has no relation to the original code item.
1279 info.code_item = compiled_method->IsIntrinsic() ? nullptr : method_data.code_item;
1280 info.isa = compiled_method->GetInstructionSet();
1281 info.deduped = deduped;
1282 info.is_native_debuggable = native_debuggable_;
1283 info.is_optimized = method_header->IsOptimized();
1284 info.is_code_address_text_relative = true;
1285 info.code_address = code_offset - executable_offset_;
1286 info.code_size = code_size;
1287 info.frame_size_in_bytes = CodeInfo::DecodeFrameInfo(code_info).FrameSizeInBytes();
1288 info.code_info = code_info;
1289 info.cfi = compiled_method->GetCFIInfo();
1290 } else {
1291 DCHECK(!has_debug_info);
1292 }
1293
1294 DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
1295 OatMethodOffsets* offsets = &oat_class->method_offsets_[method_offsets_index_];
1296 offsets->code_offset_ = quick_code_offset;
1297
1298 return true;
1299 }
1300
GetOffset() const1301 size_t GetOffset() const {
1302 return offset_;
1303 }
1304
1305 private:
LayoutReserveOffsetCodeMethodVisitor(OatWriter * writer,size_t offset,const CompilerOptions & compiler_options,OrderedMethodList ordered_methods)1306 LayoutReserveOffsetCodeMethodVisitor(OatWriter* writer,
1307 size_t offset,
1308 const CompilerOptions& compiler_options,
1309 OrderedMethodList ordered_methods)
1310 : OrderedMethodVisitor(std::move(ordered_methods)),
1311 writer_(writer),
1312 offset_(offset),
1313 relative_patcher_(writer->relative_patcher_),
1314 executable_offset_(writer->oat_header_->GetExecutableOffset()),
1315 debuggable_(compiler_options.GetDebuggable()),
1316 native_debuggable_(compiler_options.GetNativeDebuggable()),
1317 generate_debug_info_(compiler_options.GenerateAnyDebugInfo()) {}
1318
1319 struct CodeOffsetsKeyComparator {
operator ()art::linker::OatWriter::LayoutReserveOffsetCodeMethodVisitor::CodeOffsetsKeyComparator1320 bool operator()(const CompiledMethod* lhs, const CompiledMethod* rhs) const {
1321 // Code is deduplicated by CompilerDriver, compare only data pointers.
1322 if (lhs->GetQuickCode().data() != rhs->GetQuickCode().data()) {
1323 return lhs->GetQuickCode().data() < rhs->GetQuickCode().data();
1324 }
1325 // If the code is the same, all other fields are likely to be the same as well.
1326 if (UNLIKELY(lhs->GetVmapTable().data() != rhs->GetVmapTable().data())) {
1327 return lhs->GetVmapTable().data() < rhs->GetVmapTable().data();
1328 }
1329 if (UNLIKELY(lhs->GetPatches().data() != rhs->GetPatches().data())) {
1330 return lhs->GetPatches().data() < rhs->GetPatches().data();
1331 }
1332 if (UNLIKELY(lhs->IsIntrinsic() != rhs->IsIntrinsic())) {
1333 return rhs->IsIntrinsic();
1334 }
1335 return false;
1336 }
1337 };
1338
NewQuickCodeOffset(CompiledMethod * compiled_method,const MethodReference & method_ref,uint32_t thumb_offset)1339 uint32_t NewQuickCodeOffset(CompiledMethod* compiled_method,
1340 const MethodReference& method_ref,
1341 uint32_t thumb_offset) {
1342 offset_ = relative_patcher_->ReserveSpace(offset_, compiled_method, method_ref);
1343 // `offset_` is relative to the oat data, but we need to align the code relative to the
1344 // beginning of the oat file to make it aligned in the memory, so we need to use the file
1345 // offset here.
1346 offset_ += CodeAlignmentSize(writer_->GetFileOffset(offset_), *compiled_method);
1347 DCHECK_ALIGNED_PARAM(writer_->GetFileOffset(offset_) + sizeof(OatQuickMethodHeader),
1348 GetInstructionSetCodeAlignment(compiled_method->GetInstructionSet()));
1349 return offset_ + sizeof(OatQuickMethodHeader) + thumb_offset;
1350 }
1351
1352 OatWriter* writer_;
1353
1354 // Offset of the code of the compiled methods.
1355 size_t offset_;
1356
1357 // Deduplication is already done on a pointer basis by the compiler driver,
1358 // so we can simply compare the pointers to find out if things are duplicated.
1359 SafeMap<const CompiledMethod*, uint32_t, CodeOffsetsKeyComparator> dedupe_map_;
1360
1361 // Cache writer_'s members and compiler options.
1362 MultiOatRelativePatcher* relative_patcher_;
1363 uint32_t executable_offset_;
1364 const bool debuggable_;
1365 const bool native_debuggable_;
1366 const bool generate_debug_info_;
1367 };
1368
1369 template <bool kDeduplicate>
1370 class OatWriter::InitMapMethodVisitor : public OatDexMethodVisitor {
1371 public:
InitMapMethodVisitor(OatWriter * writer,size_t offset)1372 InitMapMethodVisitor(OatWriter* writer, size_t offset)
1373 : OatDexMethodVisitor(writer, offset),
1374 dedupe_bit_table_(&writer_->code_info_data_) {
1375 if (kDeduplicate) {
1376 // Reserve large buffers for `CodeInfo` and bit table deduplication except for
1377 // multi-image compilation as we do not want to reserve multiple large buffers.
1378 // User devices should not do any multi-image compilation.
1379 const CompilerOptions& compiler_options = writer->GetCompilerOptions();
1380 DCHECK(compiler_options.IsAnyCompilationEnabled());
1381 if (compiler_options.DeduplicateCode() && !compiler_options.IsMultiImage()) {
1382 size_t unique_code_infos =
1383 writer->compiler_driver_->GetCompiledMethodStorage()->UniqueVMapTableEntries();
1384 dedupe_code_info_.reserve(unique_code_infos);
1385 dedupe_bit_table_.ReserveDedupeBuffer(unique_code_infos);
1386 }
1387 }
1388 }
1389
VisitMethod(size_t class_def_method_index,const ClassAccessor::Method & method)1390 bool VisitMethod(size_t class_def_method_index,
1391 [[maybe_unused]] const ClassAccessor::Method& method) override
1392 REQUIRES_SHARED(Locks::mutator_lock_) {
1393 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
1394 CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1395
1396 if (HasCompiledCode(compiled_method)) {
1397 DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
1398 DCHECK_EQ(oat_class->method_headers_[method_offsets_index_].GetCodeInfoOffset(), 0u);
1399
1400 ArrayRef<const uint8_t> map = compiled_method->GetVmapTable();
1401 if (map.size() != 0u) {
1402 size_t offset = offset_ + writer_->code_info_data_.size();
1403 if (kDeduplicate) {
1404 auto [it, inserted] = dedupe_code_info_.insert(std::make_pair(map.data(), offset));
1405 DCHECK_EQ(inserted, it->second == offset);
1406 if (inserted) {
1407 size_t dedupe_bit_table_offset = dedupe_bit_table_.Dedupe(map.data());
1408 DCHECK_EQ(offset, offset_ + dedupe_bit_table_offset);
1409 } else {
1410 offset = it->second;
1411 }
1412 } else {
1413 writer_->code_info_data_.insert(writer_->code_info_data_.end(), map.begin(), map.end());
1414 }
1415 // Code offset is not initialized yet, so set file offset for now.
1416 DCHECK_EQ(oat_class->method_offsets_[method_offsets_index_].code_offset_, 0u);
1417 oat_class->method_headers_[method_offsets_index_].SetCodeInfoOffset(offset);
1418 }
1419 ++method_offsets_index_;
1420 }
1421
1422 return true;
1423 }
1424
1425 private:
1426 // Deduplicate at CodeInfo level. The value is byte offset within code_info_data_.
1427 // This deduplicates the whole CodeInfo object without going into the inner tables.
1428 // The compiler already deduplicated the pointers but it did not dedupe the tables.
1429 HashMap<const uint8_t*, size_t> dedupe_code_info_;
1430
1431 // Deduplicate at BitTable level.
1432 CodeInfoTableDeduper dedupe_bit_table_;
1433 };
1434
1435 class OatWriter::InitImageMethodVisitor final : public OatDexMethodVisitor {
1436 public:
InitImageMethodVisitor(OatWriter * writer,size_t offset,const std::vector<const DexFile * > * dex_files)1437 InitImageMethodVisitor(OatWriter* writer,
1438 size_t offset,
1439 const std::vector<const DexFile*>* dex_files)
1440 REQUIRES_SHARED(Locks::mutator_lock_)
1441 : OatDexMethodVisitor(writer, offset),
1442 pointer_size_(GetInstructionSetPointerSize(writer_->compiler_options_.GetInstructionSet())),
1443 class_loader_(writer->image_writer_->GetAppClassLoader()),
1444 dex_files_(dex_files),
1445 class_linker_(Runtime::Current()->GetClassLinker()),
1446 dex_cache_dex_file_(nullptr),
1447 dex_cache_(nullptr),
1448 klass_(nullptr) {}
1449
1450 // Handle copied methods here. Copy pointer to quick code from
1451 // an origin method to a copied method only if they are
1452 // in the same oat file. If the origin and the copied methods are
1453 // in different oat files don't touch the copied method.
1454 // References to other oat files are not supported yet.
StartClass(const DexFile * dex_file,size_t class_def_index)1455 bool StartClass(const DexFile* dex_file, size_t class_def_index) final
1456 REQUIRES_SHARED(Locks::mutator_lock_) {
1457 OatDexMethodVisitor::StartClass(dex_file, class_def_index);
1458 // Skip classes that are not in the image.
1459 const dex::TypeId& type_id =
1460 dex_file_->GetTypeId(dex_file->GetClassDef(class_def_index).class_idx_);
1461 const char* class_descriptor = dex_file->GetTypeDescriptor(type_id);
1462 if (!writer_->GetCompilerOptions().IsImageClass(class_descriptor)) {
1463 klass_ = nullptr;
1464 return true;
1465 }
1466 if (UNLIKELY(dex_file != dex_cache_dex_file_)) {
1467 dex_cache_ = class_linker_->FindDexCache(Thread::Current(), *dex_file);
1468 DCHECK(dex_cache_ != nullptr);
1469 DCHECK(dex_cache_->GetDexFile() == dex_file);
1470 dex_cache_dex_file_ = dex_file;
1471 }
1472 const dex::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
1473 klass_ = class_linker_->LookupResolvedType(class_def.class_idx_, dex_cache_, class_loader_);
1474 if (klass_ != nullptr) {
1475 if (UNLIKELY(klass_->GetDexCache() != dex_cache_)) {
1476 klass_ = nullptr; // This class definition is hidden by another dex file.
1477 return true;
1478 }
1479 for (ArtMethod& method : klass_->GetCopiedMethods(pointer_size_)) {
1480 // Find origin method. Declaring class and dex_method_idx
1481 // in the copied method should be the same as in the origin
1482 // method.
1483 ObjPtr<mirror::Class> declaring_class = method.GetDeclaringClass();
1484 ArtMethod* origin = declaring_class->FindClassMethod(
1485 declaring_class->GetDexCache(),
1486 method.GetDexMethodIndex(),
1487 pointer_size_);
1488 CHECK(origin != nullptr);
1489 CHECK(!origin->IsDirect());
1490 CHECK(origin->GetDeclaringClass() == declaring_class);
1491 if (IsInOatFile(&declaring_class->GetDexFile())) {
1492 const void* code_ptr =
1493 origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_);
1494 if (code_ptr == nullptr) {
1495 methods_to_process_.push_back(std::make_pair(&method, origin));
1496 } else {
1497 method.SetEntryPointFromQuickCompiledCodePtrSize(
1498 code_ptr, pointer_size_);
1499 }
1500 }
1501 }
1502 }
1503 return true;
1504 }
1505
VisitMethod(size_t class_def_method_index,const ClassAccessor::Method & method)1506 bool VisitMethod(size_t class_def_method_index, const ClassAccessor::Method& method) final
1507 REQUIRES_SHARED(Locks::mutator_lock_) {
1508 // Skip methods that are not in the image.
1509 if (klass_ == nullptr) {
1510 return true;
1511 }
1512
1513 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
1514 CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1515
1516 if (HasCompiledCode(compiled_method)) {
1517 DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
1518 OatMethodOffsets offsets = oat_class->method_offsets_[method_offsets_index_];
1519 ++method_offsets_index_;
1520
1521 // Do not try to use the `DexCache` via `ClassLinker::LookupResolvedMethod()`.
1522 // As we're going over all methods, `DexCache` entries would be quickly evicted
1523 // and we do not want the overhead of `hiddenapi` checks in the slow-path call
1524 // to `ClassLinker::FindResolvedMethod()` for a method that we have compiled.
1525 ArtMethod* resolved_method = klass_->IsInterface()
1526 ? klass_->FindInterfaceMethod(dex_cache_, method.GetIndex(), pointer_size_)
1527 : klass_->FindClassMethod(dex_cache_, method.GetIndex(), pointer_size_);
1528 DCHECK(resolved_method != nullptr);
1529 resolved_method->SetEntryPointFromQuickCompiledCodePtrSize(
1530 reinterpret_cast<void*>(offsets.code_offset_), pointer_size_);
1531 }
1532
1533 return true;
1534 }
1535
1536 // Check whether specified dex file is in the compiled oat file.
IsInOatFile(const DexFile * dex_file)1537 bool IsInOatFile(const DexFile* dex_file) {
1538 return ContainsElement(*dex_files_, dex_file);
1539 }
1540
1541 // Assign a pointer to quick code for copied methods
1542 // not handled in the method StartClass
Postprocess()1543 void Postprocess() REQUIRES_SHARED(Locks::mutator_lock_) {
1544 for (std::pair<ArtMethod*, ArtMethod*>& p : methods_to_process_) {
1545 ArtMethod* method = p.first;
1546 ArtMethod* origin = p.second;
1547 const void* code_ptr =
1548 origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_);
1549 if (code_ptr != nullptr) {
1550 method->SetEntryPointFromQuickCompiledCodePtrSize(code_ptr, pointer_size_);
1551 }
1552 }
1553 }
1554
1555 private:
1556 const PointerSize pointer_size_;
1557 const ObjPtr<mirror::ClassLoader> class_loader_;
1558 const std::vector<const DexFile*>* dex_files_;
1559 ClassLinker* const class_linker_;
1560 const DexFile* dex_cache_dex_file_; // Updated in `StartClass()`.
1561 ObjPtr<mirror::DexCache> dex_cache_; // Updated in `StartClass()`.
1562 ObjPtr<mirror::Class> klass_; // Updated in `StartClass()`.
1563 std::vector<std::pair<ArtMethod*, ArtMethod*>> methods_to_process_;
1564 };
1565
1566 class OatWriter::WriteCodeMethodVisitor : public OrderedMethodVisitor {
1567 public:
WriteCodeMethodVisitor(OatWriter * writer,OutputStream * out,const size_t file_offset,size_t relative_offset,OrderedMethodList ordered_methods)1568 WriteCodeMethodVisitor(OatWriter* writer,
1569 OutputStream* out,
1570 const size_t file_offset,
1571 size_t relative_offset,
1572 OrderedMethodList ordered_methods)
1573 : OrderedMethodVisitor(std::move(ordered_methods)),
1574 writer_(writer),
1575 offset_(relative_offset),
1576 dex_file_(nullptr),
1577 pointer_size_(GetInstructionSetPointerSize(writer_->compiler_options_.GetInstructionSet())),
1578 class_loader_(writer->HasImage() ? writer->image_writer_->GetAppClassLoader() : nullptr),
1579 out_(out),
1580 file_offset_(file_offset),
1581 class_linker_(Runtime::Current()->GetClassLinker()),
1582 dex_cache_(nullptr),
1583 no_thread_suspension_("OatWriter patching") {
1584 patched_code_.reserve(16 * KB);
1585 if (writer_->GetCompilerOptions().IsBootImage() ||
1586 writer_->GetCompilerOptions().IsBootImageExtension()) {
1587 // If we're creating the image, the address space must be ready so that we can apply patches.
1588 CHECK(writer_->image_writer_->IsImageAddressSpaceReady());
1589 }
1590 }
1591
VisitStart()1592 bool VisitStart() override {
1593 return true;
1594 }
1595
UpdateDexFileAndDexCache(const DexFile * dex_file)1596 void UpdateDexFileAndDexCache(const DexFile* dex_file)
1597 REQUIRES_SHARED(Locks::mutator_lock_) {
1598 dex_file_ = dex_file;
1599
1600 // Ordered method visiting is only for compiled methods.
1601 DCHECK(writer_->MayHaveCompiledMethods());
1602
1603 if (writer_->GetCompilerOptions().IsAotCompilationEnabled()) {
1604 // Only need to set the dex cache if we have compilation. Other modes might have unloaded it.
1605 if (dex_cache_ == nullptr || dex_cache_->GetDexFile() != dex_file) {
1606 dex_cache_ = class_linker_->FindDexCache(Thread::Current(), *dex_file);
1607 DCHECK(dex_cache_ != nullptr);
1608 }
1609 }
1610 }
1611
VisitComplete()1612 bool VisitComplete() override {
1613 offset_ = writer_->relative_patcher_->WriteThunks(out_, offset_);
1614 if (UNLIKELY(offset_ == 0u)) {
1615 PLOG(ERROR) << "Failed to write final relative call thunks";
1616 return false;
1617 }
1618 return true;
1619 }
1620
VisitMethod(const OrderedMethodData & method_data)1621 bool VisitMethod(const OrderedMethodData& method_data) override
1622 REQUIRES_SHARED(Locks::mutator_lock_) {
1623 const MethodReference& method_ref = method_data.method_reference;
1624 UpdateDexFileAndDexCache(method_ref.dex_file);
1625
1626 OatClass* oat_class = method_data.oat_class;
1627 CompiledMethod* compiled_method = method_data.compiled_method;
1628 uint16_t method_offsets_index = method_data.method_offsets_index;
1629
1630 // No thread suspension since dex_cache_ that may get invalidated if that occurs.
1631 ScopedAssertNoThreadSuspension tsc(__FUNCTION__);
1632 DCHECK(HasCompiledCode(compiled_method)) << method_ref.PrettyMethod();
1633
1634 // TODO: cleanup DCHECK_OFFSET_ to accept file_offset as parameter.
1635 size_t file_offset = file_offset_; // Used by DCHECK_OFFSET_ macro.
1636 OutputStream* out = out_;
1637
1638 ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
1639 uint32_t code_size = quick_code.size() * sizeof(uint8_t);
1640
1641 // Deduplicate code arrays.
1642 const OatMethodOffsets& method_offsets = oat_class->method_offsets_[method_offsets_index];
1643 if (method_offsets.code_offset_ > offset_) {
1644 offset_ = writer_->relative_patcher_->WriteThunks(out, offset_);
1645 if (offset_ == 0u) {
1646 ReportWriteFailure("relative call thunk", method_ref);
1647 return false;
1648 }
1649 // `offset_` is relative to the oat data, but we need to align the code relative to the
1650 // beginning of the oat file to make it aligned in the memory, so we need to use the file
1651 // offset here.
1652 uint32_t alignment_size =
1653 CodeAlignmentSize(writer_->GetFileOffset(offset_), *compiled_method);
1654 if (alignment_size != 0) {
1655 if (!writer_->WriteCodeAlignment(out, alignment_size)) {
1656 ReportWriteFailure("code alignment padding", method_ref);
1657 return false;
1658 }
1659 offset_ += alignment_size;
1660 DCHECK_OFFSET_();
1661 }
1662 DCHECK_ALIGNED_PARAM(writer_->GetFileOffset(offset_) + sizeof(OatQuickMethodHeader),
1663 GetInstructionSetCodeAlignment(compiled_method->GetInstructionSet()));
1664 DCHECK_EQ(
1665 method_offsets.code_offset_,
1666 offset_ + sizeof(OatQuickMethodHeader) + compiled_method->GetEntryPointAdjustment())
1667 << dex_file_->PrettyMethod(method_ref.index);
1668 const OatQuickMethodHeader& method_header =
1669 oat_class->method_headers_[method_offsets_index];
1670 if (!out->WriteFully(&method_header, sizeof(method_header))) {
1671 ReportWriteFailure("method header", method_ref);
1672 return false;
1673 }
1674 writer_->size_method_header_ += sizeof(method_header);
1675 offset_ += sizeof(method_header);
1676 DCHECK_OFFSET_();
1677
1678 if (!compiled_method->GetPatches().empty()) {
1679 patched_code_.assign(quick_code.begin(), quick_code.end());
1680 quick_code = ArrayRef<const uint8_t>(patched_code_);
1681 for (const LinkerPatch& patch : compiled_method->GetPatches()) {
1682 uint32_t literal_offset = patch.LiteralOffset();
1683 switch (patch.GetType()) {
1684 case LinkerPatch::Type::kIntrinsicReference: {
1685 uint32_t target_offset = GetTargetIntrinsicReferenceOffset(patch);
1686 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1687 patch,
1688 offset_ + literal_offset,
1689 target_offset);
1690 break;
1691 }
1692 case LinkerPatch::Type::kBootImageRelRo: {
1693 uint32_t target_offset =
1694 writer_->data_img_rel_ro_start_ +
1695 writer_->boot_image_rel_ro_entries_.Get(patch.BootImageOffset());
1696 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1697 patch,
1698 offset_ + literal_offset,
1699 target_offset);
1700 break;
1701 }
1702 case LinkerPatch::Type::kMethodBssEntry: {
1703 uint32_t target_offset =
1704 writer_->bss_start_ + writer_->bss_method_entries_.Get(patch.TargetMethod());
1705 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1706 patch,
1707 offset_ + literal_offset,
1708 target_offset);
1709 break;
1710 }
1711 case LinkerPatch::Type::kCallRelative: {
1712 // NOTE: Relative calls across oat files are not supported.
1713 uint32_t target_offset = GetTargetOffset(patch);
1714 writer_->relative_patcher_->PatchCall(&patched_code_,
1715 literal_offset,
1716 offset_ + literal_offset,
1717 target_offset);
1718 break;
1719 }
1720 case LinkerPatch::Type::kStringRelative: {
1721 uint32_t target_offset = GetTargetObjectOffset(GetTargetString(patch));
1722 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1723 patch,
1724 offset_ + literal_offset,
1725 target_offset);
1726 break;
1727 }
1728 case LinkerPatch::Type::kStringBssEntry: {
1729 uint32_t target_offset =
1730 writer_->bss_start_ + writer_->bss_string_entries_.Get(patch.TargetString());
1731 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1732 patch,
1733 offset_ + literal_offset,
1734 target_offset);
1735 break;
1736 }
1737 case LinkerPatch::Type::kMethodAppImageRelRo: {
1738 uint32_t target_offset =
1739 writer_->data_img_rel_ro_start_ +
1740 writer_->app_image_rel_ro_method_entries_.Get(patch.TargetMethod());
1741 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1742 patch,
1743 offset_ + literal_offset,
1744 target_offset);
1745 break;
1746 }
1747 case LinkerPatch::Type::kMethodTypeBssEntry: {
1748 uint32_t target_offset =
1749 writer_->bss_start_ + writer_->bss_method_type_entries_.Get(patch.TargetProto());
1750 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1751 patch,
1752 offset_ + literal_offset,
1753 target_offset);
1754 break;
1755 }
1756 case LinkerPatch::Type::kTypeRelative: {
1757 uint32_t target_offset = GetTargetObjectOffset(GetTargetType(patch));
1758 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1759 patch,
1760 offset_ + literal_offset,
1761 target_offset);
1762 break;
1763 }
1764 case LinkerPatch::Type::kTypeAppImageRelRo: {
1765 uint32_t target_offset =
1766 writer_->data_img_rel_ro_start_ +
1767 writer_->app_image_rel_ro_type_entries_.Get(patch.TargetType());
1768 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1769 patch,
1770 offset_ + literal_offset,
1771 target_offset);
1772 break;
1773 }
1774 case LinkerPatch::Type::kTypeBssEntry: {
1775 uint32_t target_offset =
1776 writer_->bss_start_ + writer_->bss_type_entries_.Get(patch.TargetType());
1777 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1778 patch,
1779 offset_ + literal_offset,
1780 target_offset);
1781 break;
1782 }
1783 case LinkerPatch::Type::kPublicTypeBssEntry: {
1784 uint32_t target_offset =
1785 writer_->bss_start_ + writer_->bss_public_type_entries_.Get(patch.TargetType());
1786 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1787 patch,
1788 offset_ + literal_offset,
1789 target_offset);
1790 break;
1791 }
1792 case LinkerPatch::Type::kPackageTypeBssEntry: {
1793 uint32_t target_offset =
1794 writer_->bss_start_ + writer_->bss_package_type_entries_.Get(patch.TargetType());
1795 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1796 patch,
1797 offset_ + literal_offset,
1798 target_offset);
1799 break;
1800 }
1801 case LinkerPatch::Type::kMethodRelative: {
1802 uint32_t target_offset = GetTargetMethodOffset(GetTargetMethod(patch));
1803 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1804 patch,
1805 offset_ + literal_offset,
1806 target_offset);
1807 break;
1808 }
1809 case LinkerPatch::Type::kJniEntrypointRelative: {
1810 DCHECK(GetTargetMethod(patch)->IsNative());
1811 uint32_t target_offset =
1812 GetTargetMethodOffset(GetTargetMethod(patch)) +
1813 ArtMethod::EntryPointFromJniOffset(pointer_size_).Uint32Value();
1814 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1815 patch,
1816 offset_ + literal_offset,
1817 target_offset);
1818 break;
1819 }
1820 case LinkerPatch::Type::kCallEntrypoint: {
1821 writer_->relative_patcher_->PatchEntrypointCall(&patched_code_,
1822 patch,
1823 offset_ + literal_offset);
1824 break;
1825 }
1826 case LinkerPatch::Type::kBakerReadBarrierBranch: {
1827 writer_->relative_patcher_->PatchBakerReadBarrierBranch(&patched_code_,
1828 patch,
1829 offset_ + literal_offset);
1830 break;
1831 }
1832 default: {
1833 DCHECK(false) << "Unexpected linker patch type: " << patch.GetType();
1834 break;
1835 }
1836 }
1837 }
1838 }
1839
1840 if (!out->WriteFully(quick_code.data(), code_size)) {
1841 ReportWriteFailure("method code", method_ref);
1842 return false;
1843 }
1844 writer_->size_code_ += code_size;
1845 offset_ += code_size;
1846 }
1847 DCHECK_OFFSET_();
1848
1849 return true;
1850 }
1851
GetOffset() const1852 size_t GetOffset() const {
1853 return offset_;
1854 }
1855
1856 private:
1857 OatWriter* const writer_;
1858
1859 // Updated in VisitMethod as methods are written out.
1860 size_t offset_;
1861
1862 // Potentially varies with every different VisitMethod.
1863 // Used to determine which DexCache to use when finding ArtMethods.
1864 const DexFile* dex_file_;
1865
1866 // Pointer size we are compiling to.
1867 const PointerSize pointer_size_;
1868 // The image writer's classloader, if there is one, else null.
1869 ObjPtr<mirror::ClassLoader> class_loader_;
1870 // Stream to output file, where the OAT code will be written to.
1871 OutputStream* const out_;
1872 const size_t file_offset_;
1873 ClassLinker* const class_linker_;
1874 ObjPtr<mirror::DexCache> dex_cache_;
1875 std::vector<uint8_t> patched_code_;
1876 const ScopedAssertNoThreadSuspension no_thread_suspension_;
1877
ReportWriteFailure(const char * what,const MethodReference & method_ref)1878 void ReportWriteFailure(const char* what, const MethodReference& method_ref) {
1879 PLOG(ERROR) << "Failed to write " << what << " for "
1880 << method_ref.PrettyMethod() << " to " << out_->GetLocation();
1881 }
1882
GetTargetMethod(const LinkerPatch & patch)1883 ArtMethod* GetTargetMethod(const LinkerPatch& patch)
1884 REQUIRES_SHARED(Locks::mutator_lock_) {
1885 MethodReference ref = patch.TargetMethod();
1886 ObjPtr<mirror::DexCache> dex_cache =
1887 (dex_file_ == ref.dex_file) ? dex_cache_ : class_linker_->FindDexCache(
1888 Thread::Current(), *ref.dex_file);
1889 ArtMethod* method =
1890 class_linker_->LookupResolvedMethod(ref.index, dex_cache, class_loader_);
1891 CHECK(method != nullptr);
1892 return method;
1893 }
1894
GetTargetOffset(const LinkerPatch & patch)1895 uint32_t GetTargetOffset(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) {
1896 uint32_t target_offset = writer_->relative_patcher_->GetOffset(patch.TargetMethod());
1897 // If there's no new compiled code, we need to point to the correct trampoline.
1898 if (UNLIKELY(target_offset == 0)) {
1899 ArtMethod* target = GetTargetMethod(patch);
1900 DCHECK(target != nullptr);
1901 // TODO: Remove kCallRelative? This patch type is currently not in use.
1902 // If we want to use it again, we should make sure that we either use it
1903 // only for target methods that were actually compiled, or call the
1904 // method dispatch thunk. Currently, ARM/ARM64 patchers would emit the
1905 // thunk for far `target_offset` (so we could teach them to use the
1906 // thunk for `target_offset == 0`) but x86/x86-64 patchers do not.
1907 // (When this was originally implemented, every oat file contained
1908 // trampolines, so we could just return their offset here. Now only
1909 // the boot image contains them, so this is not always an option.)
1910 LOG(FATAL) << "The target method was not compiled.";
1911 }
1912 return target_offset;
1913 }
1914
GetDexCache(const DexFile * target_dex_file)1915 ObjPtr<mirror::DexCache> GetDexCache(const DexFile* target_dex_file)
1916 REQUIRES_SHARED(Locks::mutator_lock_) {
1917 return (target_dex_file == dex_file_)
1918 ? dex_cache_
1919 : class_linker_->FindDexCache(Thread::Current(), *target_dex_file);
1920 }
1921
GetTargetType(const LinkerPatch & patch)1922 ObjPtr<mirror::Class> GetTargetType(const LinkerPatch& patch)
1923 REQUIRES_SHARED(Locks::mutator_lock_) {
1924 DCHECK(writer_->HasImage());
1925 TypeReference target_type = patch.TargetType();
1926 ObjPtr<mirror::DexCache> dex_cache = GetDexCache(target_type.dex_file);
1927 ObjPtr<mirror::Class> type =
1928 class_linker_->LookupResolvedType(target_type.TypeIndex(), dex_cache, class_loader_);
1929 CHECK(type != nullptr);
1930 return type;
1931 }
1932
GetTargetString(const LinkerPatch & patch)1933 ObjPtr<mirror::String> GetTargetString(const LinkerPatch& patch)
1934 REQUIRES_SHARED(Locks::mutator_lock_) {
1935 ClassLinker* linker = Runtime::Current()->GetClassLinker();
1936 StringReference target_string = patch.TargetString();
1937 ObjPtr<mirror::String> string =
1938 linker->LookupString(target_string.StringIndex(), GetDexCache(target_string.dex_file));
1939 DCHECK(string != nullptr);
1940 DCHECK(writer_->GetCompilerOptions().IsBootImage() ||
1941 writer_->GetCompilerOptions().IsBootImageExtension());
1942 return string;
1943 }
1944
GetTargetIntrinsicReferenceOffset(const LinkerPatch & patch)1945 uint32_t GetTargetIntrinsicReferenceOffset(const LinkerPatch& patch)
1946 REQUIRES_SHARED(Locks::mutator_lock_) {
1947 DCHECK(writer_->GetCompilerOptions().IsBootImage());
1948 const void* address =
1949 writer_->image_writer_->GetIntrinsicReferenceAddress(patch.IntrinsicData());
1950 size_t oat_index = writer_->image_writer_->GetOatIndexForDexFile(dex_file_);
1951 uintptr_t oat_data_begin = writer_->image_writer_->GetOatDataBegin(oat_index);
1952 // TODO: Clean up offset types. The target offset must be treated as signed.
1953 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(address) - oat_data_begin);
1954 }
1955
GetTargetMethodOffset(ArtMethod * method)1956 uint32_t GetTargetMethodOffset(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) {
1957 DCHECK(writer_->GetCompilerOptions().IsBootImage() ||
1958 writer_->GetCompilerOptions().IsBootImageExtension());
1959 method = writer_->image_writer_->GetImageMethodAddress(method);
1960 size_t oat_index = writer_->image_writer_->GetOatIndexForDexFile(dex_file_);
1961 uintptr_t oat_data_begin = writer_->image_writer_->GetOatDataBegin(oat_index);
1962 // TODO: Clean up offset types. The target offset must be treated as signed.
1963 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(method) - oat_data_begin);
1964 }
1965
GetTargetObjectOffset(ObjPtr<mirror::Object> object)1966 uint32_t GetTargetObjectOffset(ObjPtr<mirror::Object> object)
1967 REQUIRES_SHARED(Locks::mutator_lock_) {
1968 DCHECK(writer_->GetCompilerOptions().IsBootImage() ||
1969 writer_->GetCompilerOptions().IsBootImageExtension());
1970 object = writer_->image_writer_->GetImageAddress(object.Ptr());
1971 size_t oat_index = writer_->image_writer_->GetOatIndexForDexFile(dex_file_);
1972 uintptr_t oat_data_begin = writer_->image_writer_->GetOatDataBegin(oat_index);
1973 // TODO: Clean up offset types. The target offset must be treated as signed.
1974 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(object.Ptr()) - oat_data_begin);
1975 }
1976 };
1977
1978 // Visit all methods from all classes in all dex files with the specified visitor.
VisitDexMethods(DexMethodVisitor * visitor)1979 bool OatWriter::VisitDexMethods(DexMethodVisitor* visitor) {
1980 for (const DexFile* dex_file : *dex_files_) {
1981 for (ClassAccessor accessor : dex_file->GetClasses()) {
1982 if (UNLIKELY(!visitor->StartClass(dex_file, accessor.GetClassDefIndex()))) {
1983 return false;
1984 }
1985 if (MayHaveCompiledMethods()) {
1986 size_t class_def_method_index = 0u;
1987 for (const ClassAccessor::Method& method : accessor.GetMethods()) {
1988 if (!visitor->VisitMethod(class_def_method_index, method)) {
1989 return false;
1990 }
1991 ++class_def_method_index;
1992 }
1993 }
1994 if (UNLIKELY(!visitor->EndClass())) {
1995 return false;
1996 }
1997 }
1998 }
1999 return true;
2000 }
2001
InitOatHeader(uint32_t num_dex_files,OatKeyValueStore * key_value_store)2002 size_t OatWriter::InitOatHeader(uint32_t num_dex_files, OatKeyValueStore* key_value_store) {
2003 TimingLogger::ScopedTiming split("InitOatHeader", timings_);
2004
2005 // `key_value_store` only exists in the first oat file in a multi-image boot image.
2006 if (key_value_store != nullptr) {
2007 // Add non-deterministic fields if they don't exist. These fields should always exist with fixed
2008 // lengths.
2009 for (auto [field, length] : OatHeader::kNonDeterministicFieldsAndLengths) {
2010 key_value_store->map_.FindOrAdd(std::string(field));
2011 }
2012 }
2013
2014 // Check that oat version when runtime was compiled matches the oat version
2015 // when dex2oat was compiled. We have seen cases where they got out of sync.
2016 constexpr std::array<uint8_t, 4> dex2oat_oat_version = OatHeader::kOatVersion;
2017 OatHeader::CheckOatVersion(dex2oat_oat_version);
2018 oat_header_ = OatHeader::Create(GetCompilerOptions().GetInstructionSet(),
2019 GetCompilerOptions().GetInstructionSetFeatures(),
2020 num_dex_files,
2021 key_value_store != nullptr ? &key_value_store->map_ : nullptr,
2022 oat_data_offset_);
2023 size_oat_header_ += sizeof(OatHeader);
2024 size_oat_header_key_value_store_ += oat_header_->GetHeaderSize() - sizeof(OatHeader);
2025 return oat_header_->GetHeaderSize();
2026 }
2027
InitClassOffsets(size_t offset)2028 size_t OatWriter::InitClassOffsets(size_t offset) {
2029 // Reserve space for class offsets in OAT and update class_offsets_offset_.
2030 for (OatDexFile& oat_dex_file : oat_dex_files_) {
2031 DCHECK_EQ(oat_dex_file.class_offsets_offset_, 0u);
2032 if (!oat_dex_file.class_offsets_.empty()) {
2033 // Class offsets are required to be 4 byte aligned.
2034 offset = RoundUp(offset, 4u);
2035 oat_dex_file.class_offsets_offset_ = offset;
2036 offset += oat_dex_file.GetClassOffsetsRawSize();
2037 DCHECK_ALIGNED(offset, 4u);
2038 }
2039 }
2040 return offset;
2041 }
2042
InitOatClasses(size_t offset)2043 size_t OatWriter::InitOatClasses(size_t offset) {
2044 // calculate the offsets within OatDexFiles to OatClasses
2045 InitOatClassesMethodVisitor visitor(this, offset);
2046 bool success = VisitDexMethods(&visitor);
2047 CHECK(success);
2048 offset = visitor.GetOffset();
2049
2050 // Update oat_dex_files_.
2051 auto oat_class_it = oat_class_headers_.begin();
2052 for (OatDexFile& oat_dex_file : oat_dex_files_) {
2053 for (uint32_t& class_offset : oat_dex_file.class_offsets_) {
2054 DCHECK(oat_class_it != oat_class_headers_.end());
2055 class_offset = oat_class_it->offset_;
2056 ++oat_class_it;
2057 }
2058 }
2059 CHECK(oat_class_it == oat_class_headers_.end());
2060
2061 return offset;
2062 }
2063
InitOatMaps(size_t offset)2064 size_t OatWriter::InitOatMaps(size_t offset) {
2065 if (!MayHaveCompiledMethods()) {
2066 return offset;
2067 }
2068 if (GetCompilerOptions().DeduplicateCode()) {
2069 InitMapMethodVisitor</*kDeduplicate=*/ true> visitor(this, offset);
2070 bool success = VisitDexMethods(&visitor);
2071 DCHECK(success);
2072 } else {
2073 InitMapMethodVisitor</*kDeduplicate=*/ false> visitor(this, offset);
2074 bool success = VisitDexMethods(&visitor);
2075 DCHECK(success);
2076 }
2077 code_info_data_.shrink_to_fit();
2078 offset += code_info_data_.size();
2079 return offset;
2080 }
2081
2082 template <typename GetBssOffset>
CalculateNumberOfIndexBssMappingEntries(size_t number_of_indexes,size_t slot_size,const BitVector & indexes,GetBssOffset get_bss_offset)2083 static size_t CalculateNumberOfIndexBssMappingEntries(size_t number_of_indexes,
2084 size_t slot_size,
2085 const BitVector& indexes,
2086 GetBssOffset get_bss_offset) {
2087 IndexBssMappingEncoder encoder(number_of_indexes, slot_size);
2088 size_t number_of_entries = 0u;
2089 bool first_index = true;
2090 for (uint32_t index : indexes.Indexes()) {
2091 uint32_t bss_offset = get_bss_offset(index);
2092 if (first_index || !encoder.TryMerge(index, bss_offset)) {
2093 encoder.Reset(index, bss_offset);
2094 ++number_of_entries;
2095 first_index = false;
2096 }
2097 }
2098 DCHECK_NE(number_of_entries, 0u);
2099 return number_of_entries;
2100 }
2101
2102 template <typename GetBssOffset>
CalculateIndexBssMappingSize(size_t number_of_indexes,size_t slot_size,const BitVector & indexes,GetBssOffset get_bss_offset)2103 static size_t CalculateIndexBssMappingSize(size_t number_of_indexes,
2104 size_t slot_size,
2105 const BitVector& indexes,
2106 GetBssOffset get_bss_offset) {
2107 size_t number_of_entries = CalculateNumberOfIndexBssMappingEntries(number_of_indexes,
2108 slot_size,
2109 indexes,
2110 get_bss_offset);
2111 return IndexBssMapping::ComputeSize(number_of_entries);
2112 }
2113
CalculateIndexBssMappingSize(const DexFile * dex_file,const BitVector & type_indexes,const SafeMap<TypeReference,size_t,TypeReferenceValueComparator> & bss_entries)2114 static size_t CalculateIndexBssMappingSize(
2115 const DexFile* dex_file,
2116 const BitVector& type_indexes,
2117 const SafeMap<TypeReference, size_t, TypeReferenceValueComparator>& bss_entries) {
2118 return CalculateIndexBssMappingSize(
2119 dex_file->NumTypeIds(),
2120 sizeof(GcRoot<mirror::Class>),
2121 type_indexes,
2122 [=](uint32_t index) { return bss_entries.Get({dex_file, dex::TypeIndex(index)}); });
2123 }
2124
InitIndexBssMappings(size_t offset)2125 size_t OatWriter::InitIndexBssMappings(size_t offset) {
2126 if (bss_method_entry_references_.empty() &&
2127 bss_type_entry_references_.empty() &&
2128 bss_public_type_entry_references_.empty() &&
2129 bss_package_type_entry_references_.empty() &&
2130 bss_string_entry_references_.empty() &&
2131 bss_method_type_entry_references_.empty()) {
2132 return offset;
2133 }
2134 // If there are any classes, the class offsets allocation aligns the offset
2135 // and we cannot have any index bss mappings without class offsets.
2136 static_assert(alignof(IndexBssMapping) == 4u, "IndexBssMapping alignment check.");
2137 DCHECK_ALIGNED(offset, 4u);
2138
2139 size_t number_of_method_dex_files = 0u;
2140 size_t number_of_type_dex_files = 0u;
2141 size_t number_of_public_type_dex_files = 0u;
2142 size_t number_of_package_type_dex_files = 0u;
2143 size_t number_of_string_dex_files = 0u;
2144 size_t number_of_method_type_dex_files = 0u;
2145 for (size_t i = 0, size = dex_files_->size(); i != size; ++i) {
2146 const DexFile* dex_file = (*dex_files_)[i];
2147 offset = InitIndexBssMappingsHelper(offset,
2148 dex_file,
2149 number_of_method_dex_files,
2150 number_of_type_dex_files,
2151 number_of_public_type_dex_files,
2152 number_of_package_type_dex_files,
2153 number_of_string_dex_files,
2154 number_of_method_type_dex_files,
2155 oat_dex_files_[i].method_bss_mapping_offset_,
2156 oat_dex_files_[i].type_bss_mapping_offset_,
2157 oat_dex_files_[i].public_type_bss_mapping_offset_,
2158 oat_dex_files_[i].package_type_bss_mapping_offset_,
2159 oat_dex_files_[i].string_bss_mapping_offset_,
2160 oat_dex_files_[i].method_type_bss_mapping_offset_);
2161 }
2162
2163 if (!compiler_options_.IsBootImage()) {
2164 ArrayRef<const DexFile* const> boot_class_path(
2165 Runtime::Current()->GetClassLinker()->GetBootClassPath());
2166 // We initialize bcp_bss_info except for the boot image case.
2167 // Note that we have an early break at the beginning of the method, so `bcp_bss_info_` will also
2168 // be empty in the case of having no mappings at all.
2169
2170 if (compiler_options_.IsBootImageExtension()) {
2171 // For boot image extension, the boot_class_path ends with the compiled dex files. In multi
2172 // image, we might have several oat writers so we have to get all of the compiled dex files
2173 // and not just the one we are compiling right now. Remove them to have the correct number of
2174 // references.
2175 ArrayRef<const DexFile* const> to_exclude(compiler_options_.GetDexFilesForOatFile());
2176 DCHECK_GE(boot_class_path.size(), to_exclude.size());
2177 DCHECK(std::equal(to_exclude.rbegin(), to_exclude.rend(), boot_class_path.rbegin()));
2178 boot_class_path = boot_class_path.SubArray(0, boot_class_path.size() - to_exclude.size());
2179 }
2180
2181 DCHECK(bcp_bss_info_.empty());
2182 bcp_bss_info_.resize(boot_class_path.size());
2183 for (size_t i = 0, size = bcp_bss_info_.size(); i != size; ++i) {
2184 const DexFile* dex_file = boot_class_path[i];
2185 DCHECK(!ContainsElement(*dex_files_, dex_file));
2186 offset = InitIndexBssMappingsHelper(offset,
2187 dex_file,
2188 number_of_method_dex_files,
2189 number_of_type_dex_files,
2190 number_of_public_type_dex_files,
2191 number_of_package_type_dex_files,
2192 number_of_string_dex_files,
2193 number_of_method_type_dex_files,
2194 bcp_bss_info_[i].method_bss_mapping_offset,
2195 bcp_bss_info_[i].type_bss_mapping_offset,
2196 bcp_bss_info_[i].public_type_bss_mapping_offset,
2197 bcp_bss_info_[i].package_type_bss_mapping_offset,
2198 bcp_bss_info_[i].string_bss_mapping_offset,
2199 bcp_bss_info_[i].method_type_bss_mapping_offset);
2200 }
2201 }
2202
2203 // Check that all dex files targeted by bss entries are in `*dex_files_`, or in the bootclaspath's
2204 // DexFiles in the single image case.
2205 CHECK_EQ(number_of_method_dex_files, bss_method_entry_references_.size());
2206 CHECK_EQ(number_of_type_dex_files, bss_type_entry_references_.size());
2207 CHECK_EQ(number_of_public_type_dex_files, bss_public_type_entry_references_.size());
2208 CHECK_EQ(number_of_package_type_dex_files, bss_package_type_entry_references_.size());
2209 CHECK_EQ(number_of_string_dex_files, bss_string_entry_references_.size());
2210 CHECK_EQ(number_of_method_type_dex_files, bss_method_type_entry_references_.size());
2211
2212 return offset;
2213 }
2214
InitIndexBssMappingsHelper(size_t offset,const DexFile * dex_file,size_t & number_of_method_dex_files,size_t & number_of_type_dex_files,size_t & number_of_public_type_dex_files,size_t & number_of_package_type_dex_files,size_t & number_of_string_dex_files,size_t & number_of_method_type_dex_files,uint32_t & method_bss_mapping_offset,uint32_t & type_bss_mapping_offset,uint32_t & public_type_bss_mapping_offset,uint32_t & package_type_bss_mapping_offset,uint32_t & string_bss_mapping_offset,uint32_t & method_type_bss_mapping_offset)2215 size_t OatWriter::InitIndexBssMappingsHelper(size_t offset,
2216 const DexFile* dex_file,
2217 /*inout*/ size_t& number_of_method_dex_files,
2218 /*inout*/ size_t& number_of_type_dex_files,
2219 /*inout*/ size_t& number_of_public_type_dex_files,
2220 /*inout*/ size_t& number_of_package_type_dex_files,
2221 /*inout*/ size_t& number_of_string_dex_files,
2222 /*inout*/ size_t& number_of_method_type_dex_files,
2223 /*inout*/ uint32_t& method_bss_mapping_offset,
2224 /*inout*/ uint32_t& type_bss_mapping_offset,
2225 /*inout*/ uint32_t& public_type_bss_mapping_offset,
2226 /*inout*/ uint32_t& package_type_bss_mapping_offset,
2227 /*inout*/ uint32_t& string_bss_mapping_offset,
2228 /*inout*/ uint32_t& method_type_bss_mapping_offset) {
2229 const PointerSize pointer_size = GetInstructionSetPointerSize(oat_header_->GetInstructionSet());
2230 auto method_it = bss_method_entry_references_.find(dex_file);
2231 if (method_it != bss_method_entry_references_.end()) {
2232 const BitVector& method_indexes = method_it->second;
2233 ++number_of_method_dex_files;
2234 method_bss_mapping_offset = offset;
2235 offset += CalculateIndexBssMappingSize(dex_file->NumMethodIds(),
2236 static_cast<size_t>(pointer_size),
2237 method_indexes,
2238 [this, dex_file](uint32_t index) {
2239 return bss_method_entries_.Get({dex_file, index});
2240 });
2241 }
2242
2243 auto type_it = bss_type_entry_references_.find(dex_file);
2244 if (type_it != bss_type_entry_references_.end()) {
2245 const BitVector& type_indexes = type_it->second;
2246 ++number_of_type_dex_files;
2247 type_bss_mapping_offset = offset;
2248 offset += CalculateIndexBssMappingSize(dex_file, type_indexes, bss_type_entries_);
2249 }
2250
2251 auto public_type_it = bss_public_type_entry_references_.find(dex_file);
2252 if (public_type_it != bss_public_type_entry_references_.end()) {
2253 const BitVector& type_indexes = public_type_it->second;
2254 ++number_of_public_type_dex_files;
2255 public_type_bss_mapping_offset = offset;
2256 offset += CalculateIndexBssMappingSize(dex_file, type_indexes, bss_public_type_entries_);
2257 }
2258
2259 auto package_type_it = bss_package_type_entry_references_.find(dex_file);
2260 if (package_type_it != bss_package_type_entry_references_.end()) {
2261 const BitVector& type_indexes = package_type_it->second;
2262 ++number_of_package_type_dex_files;
2263 package_type_bss_mapping_offset = offset;
2264 offset += CalculateIndexBssMappingSize(dex_file, type_indexes, bss_package_type_entries_);
2265 }
2266
2267 auto string_it = bss_string_entry_references_.find(dex_file);
2268 if (string_it != bss_string_entry_references_.end()) {
2269 const BitVector& string_indexes = string_it->second;
2270 ++number_of_string_dex_files;
2271 string_bss_mapping_offset = offset;
2272 offset += CalculateIndexBssMappingSize(
2273 dex_file->NumStringIds(),
2274 sizeof(GcRoot<mirror::String>),
2275 string_indexes,
2276 [this, dex_file](uint32_t index) {
2277 return bss_string_entries_.Get({dex_file, dex::StringIndex(index)});
2278 });
2279 }
2280
2281 auto method_type_it = bss_method_type_entry_references_.find(dex_file);
2282 if (method_type_it != bss_method_type_entry_references_.end()) {
2283 const BitVector& proto_indexes = method_type_it->second;
2284 ++number_of_method_type_dex_files;
2285 method_type_bss_mapping_offset = offset;
2286 offset += CalculateIndexBssMappingSize(
2287 dex_file->NumProtoIds(),
2288 sizeof(GcRoot<mirror::MethodType>),
2289 proto_indexes,
2290 [this, dex_file](uint32_t index) {
2291 return bss_method_type_entries_.Get({dex_file, dex::ProtoIndex(index)});
2292 });
2293 }
2294
2295 return offset;
2296 }
2297
InitOatDexFiles(size_t offset)2298 size_t OatWriter::InitOatDexFiles(size_t offset) {
2299 // Initialize offsets of oat dex files.
2300 for (OatDexFile& oat_dex_file : oat_dex_files_) {
2301 oat_dex_file.offset_ = offset;
2302 offset += oat_dex_file.SizeOf();
2303 }
2304 return offset;
2305 }
2306
InitBcpBssInfo(size_t offset)2307 size_t OatWriter::InitBcpBssInfo(size_t offset) {
2308 if (bcp_bss_info_.size() == 0) {
2309 return offset;
2310 }
2311
2312 // We first increase the offset to make room to store the number of BCP DexFiles, if we have at
2313 // least one entry.
2314 oat_header_->SetBcpBssInfoOffset(offset);
2315 offset += sizeof(uint32_t);
2316
2317 for (BssMappingInfo& info : bcp_bss_info_) {
2318 info.offset_ = offset;
2319 offset += BssMappingInfo::SizeOf();
2320 }
2321 return offset;
2322 }
2323
InitOatCode(size_t offset)2324 size_t OatWriter::InitOatCode(size_t offset) {
2325 // calculate the offsets within OatHeader to executable code
2326 size_t old_offset = offset;
2327 // required to be on a new page boundary
2328 offset = GetOffsetFromOatDataAlignedToFile(offset, kElfSegmentAlignment);
2329 oat_header_->SetExecutableOffset(offset);
2330 size_executable_offset_alignment_ = offset - old_offset;
2331 InstructionSet instruction_set = compiler_options_.GetInstructionSet();
2332 if (GetCompilerOptions().IsBootImage() && primary_oat_file_) {
2333 const bool generate_debug_info = GetCompilerOptions().GenerateAnyDebugInfo();
2334 size_t adjusted_offset = offset;
2335
2336 #define DO_TRAMPOLINE(field, fn_name) \
2337 /* Pad with at least four 0xFFs so we can do DCHECKs in OatQuickMethodHeader */ \
2338 offset = GetOffsetFromOatDataAlignedToFile(offset + 4, \
2339 GetInstructionSetCodeAlignment(instruction_set)); \
2340 adjusted_offset = offset + GetInstructionSetEntryPointAdjustment(instruction_set); \
2341 oat_header_->Set ## fn_name ## Offset(adjusted_offset); \
2342 (field) = compiler_driver_->Create ## fn_name(); \
2343 if (generate_debug_info) { \
2344 debug::MethodDebugInfo info = {}; \
2345 info.custom_name = #fn_name; \
2346 info.isa = instruction_set; \
2347 info.is_code_address_text_relative = true; \
2348 /* Use the code offset rather than the `adjusted_offset`. */ \
2349 info.code_address = offset - oat_header_->GetExecutableOffset(); \
2350 info.code_size = (field)->size(); \
2351 method_info_.push_back(std::move(info)); \
2352 } \
2353 offset += (field)->size();
2354
2355 DO_TRAMPOLINE(jni_dlsym_lookup_trampoline_, JniDlsymLookupTrampoline);
2356 DO_TRAMPOLINE(jni_dlsym_lookup_critical_trampoline_, JniDlsymLookupCriticalTrampoline);
2357 DO_TRAMPOLINE(quick_generic_jni_trampoline_, QuickGenericJniTrampoline);
2358 DO_TRAMPOLINE(quick_imt_conflict_trampoline_, QuickImtConflictTrampoline);
2359 DO_TRAMPOLINE(quick_resolution_trampoline_, QuickResolutionTrampoline);
2360 DO_TRAMPOLINE(quick_to_interpreter_bridge_, QuickToInterpreterBridge);
2361 DO_TRAMPOLINE(nterp_trampoline_, NterpTrampoline);
2362
2363 #undef DO_TRAMPOLINE
2364 } else {
2365 oat_header_->SetJniDlsymLookupTrampolineOffset(0);
2366 oat_header_->SetJniDlsymLookupCriticalTrampolineOffset(0);
2367 oat_header_->SetQuickGenericJniTrampolineOffset(0);
2368 oat_header_->SetQuickImtConflictTrampolineOffset(0);
2369 oat_header_->SetQuickResolutionTrampolineOffset(0);
2370 oat_header_->SetQuickToInterpreterBridgeOffset(0);
2371 oat_header_->SetNterpTrampolineOffset(0);
2372 }
2373 return offset;
2374 }
2375
InitOatCodeDexFiles(size_t offset)2376 size_t OatWriter::InitOatCodeDexFiles(size_t offset) {
2377 if (!GetCompilerOptions().IsAnyCompilationEnabled()) {
2378 if (kOatWriterDebugOatCodeLayout) {
2379 LOG(INFO) << "InitOatCodeDexFiles: OatWriter("
2380 << this << "), "
2381 << "compilation is disabled";
2382 }
2383
2384 return offset;
2385 }
2386 bool success = false;
2387
2388 {
2389 ScopedObjectAccess soa(Thread::Current());
2390
2391 LayoutCodeMethodVisitor layout_code_visitor(this, offset);
2392 success = VisitDexMethods(&layout_code_visitor);
2393 DCHECK(success);
2394
2395 LayoutReserveOffsetCodeMethodVisitor layout_reserve_code_visitor(
2396 this,
2397 offset,
2398 layout_code_visitor.ReleaseOrderedMethods());
2399 success = layout_reserve_code_visitor.Visit();
2400 DCHECK(success);
2401 offset = layout_reserve_code_visitor.GetOffset();
2402
2403 // Save the method order because the WriteCodeMethodVisitor will need this
2404 // order again.
2405 DCHECK(ordered_methods_ == nullptr);
2406 ordered_methods_.reset(
2407 new OrderedMethodList(
2408 layout_reserve_code_visitor.ReleaseOrderedMethods()));
2409
2410 if (kOatWriterDebugOatCodeLayout) {
2411 LOG(INFO) << "IniatOatCodeDexFiles: method order: ";
2412 for (const OrderedMethodData& ordered_method : *ordered_methods_) {
2413 std::string pretty_name = ordered_method.method_reference.PrettyMethod();
2414 LOG(INFO) << pretty_name
2415 << "@ offset "
2416 << relative_patcher_->GetOffset(ordered_method.method_reference)
2417 << " X hotness "
2418 << ordered_method.hotness_bits;
2419 }
2420 }
2421 }
2422
2423 if (HasImage()) {
2424 ScopedObjectAccess soa(Thread::Current());
2425 ScopedAssertNoThreadSuspension sants("Init image method visitor");
2426 InitImageMethodVisitor image_visitor(this, offset, dex_files_);
2427 success = VisitDexMethods(&image_visitor);
2428 image_visitor.Postprocess();
2429 DCHECK(success);
2430 offset = image_visitor.GetOffset();
2431 }
2432
2433 return offset;
2434 }
2435
InitDataImgRelRoLayout(size_t offset)2436 size_t OatWriter::InitDataImgRelRoLayout(size_t offset) {
2437 DCHECK_EQ(data_img_rel_ro_size_, 0u);
2438 if (boot_image_rel_ro_entries_.empty() &&
2439 app_image_rel_ro_method_entries_.empty() &&
2440 app_image_rel_ro_type_entries_.empty()) {
2441 // Nothing to put to the .data.img.rel.ro section.
2442 return offset;
2443 }
2444
2445 data_img_rel_ro_start_ = GetOffsetFromOatDataAlignedToFile(offset, kElfSegmentAlignment);
2446
2447 for (auto& entry : boot_image_rel_ro_entries_) {
2448 size_t& entry_offset = entry.second;
2449 entry_offset = data_img_rel_ro_size_;
2450 data_img_rel_ro_size_ += sizeof(uint32_t);
2451 }
2452
2453 data_img_rel_ro_app_image_offset_ = data_img_rel_ro_size_;
2454
2455 for (auto& entry : app_image_rel_ro_method_entries_) {
2456 size_t& entry_offset = entry.second;
2457 entry_offset = data_img_rel_ro_size_;
2458 data_img_rel_ro_size_ += sizeof(uint32_t);
2459 }
2460
2461 for (auto& entry : app_image_rel_ro_type_entries_) {
2462 size_t& entry_offset = entry.second;
2463 entry_offset = data_img_rel_ro_size_;
2464 data_img_rel_ro_size_ += sizeof(uint32_t);
2465 }
2466
2467 offset = data_img_rel_ro_start_ + data_img_rel_ro_size_;
2468 return offset;
2469 }
2470
InitBssLayout(InstructionSet instruction_set)2471 void OatWriter::InitBssLayout(InstructionSet instruction_set) {
2472 DCHECK_EQ(bss_size_, 0u);
2473 if (bss_method_entries_.empty() &&
2474 bss_type_entries_.empty() &&
2475 bss_public_type_entries_.empty() &&
2476 bss_package_type_entries_.empty() &&
2477 bss_string_entries_.empty() &&
2478 bss_method_type_entries_.empty()) {
2479 // Nothing to put to the .bss section.
2480 return;
2481 }
2482
2483 PointerSize pointer_size = GetInstructionSetPointerSize(instruction_set);
2484 bss_methods_offset_ = bss_size_;
2485
2486 // Prepare offsets for .bss ArtMethod entries.
2487 for (auto& entry : bss_method_entries_) {
2488 DCHECK_EQ(entry.second, 0u);
2489 entry.second = bss_size_;
2490 bss_size_ += static_cast<size_t>(pointer_size);
2491 }
2492
2493 bss_roots_offset_ = bss_size_;
2494
2495 // Prepare offsets for .bss Class entries.
2496 for (auto& entry : bss_type_entries_) {
2497 DCHECK_EQ(entry.second, 0u);
2498 entry.second = bss_size_;
2499 bss_size_ += sizeof(GcRoot<mirror::Class>);
2500 }
2501 // Prepare offsets for .bss public Class entries.
2502 for (auto& entry : bss_public_type_entries_) {
2503 DCHECK_EQ(entry.second, 0u);
2504 entry.second = bss_size_;
2505 bss_size_ += sizeof(GcRoot<mirror::Class>);
2506 }
2507 // Prepare offsets for .bss package Class entries.
2508 for (auto& entry : bss_package_type_entries_) {
2509 DCHECK_EQ(entry.second, 0u);
2510 entry.second = bss_size_;
2511 bss_size_ += sizeof(GcRoot<mirror::Class>);
2512 }
2513 // Prepare offsets for .bss String entries.
2514 for (auto& entry : bss_string_entries_) {
2515 DCHECK_EQ(entry.second, 0u);
2516 entry.second = bss_size_;
2517 bss_size_ += sizeof(GcRoot<mirror::String>);
2518 }
2519 // Prepare offsets for .bss MethodType entries.
2520 for (auto& entry : bss_method_type_entries_) {
2521 DCHECK_EQ(entry.second, 0u);
2522 entry.second = bss_size_;
2523 bss_size_ += sizeof(GcRoot<mirror::MethodType>);
2524 }
2525 }
2526
WriteRodata(OutputStream * out)2527 bool OatWriter::WriteRodata(OutputStream* out) {
2528 TimingLogger::ScopedTiming split("WriteRodata", timings_);
2529 CHECK(write_state_ == WriteState::kWriteRoData);
2530
2531 size_t file_offset = oat_data_offset_;
2532 off_t current_offset = out->Seek(0, kSeekCurrent);
2533 if (current_offset == static_cast<off_t>(-1)) {
2534 PLOG(ERROR) << "Failed to retrieve current position in " << out->GetLocation();
2535 }
2536 DCHECK_GE(static_cast<size_t>(current_offset), file_offset + oat_header_->GetHeaderSize());
2537 size_t relative_offset = current_offset - file_offset;
2538
2539 // Wrap out to update checksum with each write.
2540 ChecksumUpdatingOutputStream checksum_updating_out(out, this);
2541 out = &checksum_updating_out;
2542
2543 relative_offset = WriteClassOffsets(out, file_offset, relative_offset);
2544 if (relative_offset == 0) {
2545 PLOG(ERROR) << "Failed to write class offsets to " << out->GetLocation();
2546 return false;
2547 }
2548
2549 relative_offset = WriteClasses(out, file_offset, relative_offset);
2550 if (relative_offset == 0) {
2551 PLOG(ERROR) << "Failed to write classes to " << out->GetLocation();
2552 return false;
2553 }
2554
2555 relative_offset = WriteIndexBssMappings(out, file_offset, relative_offset);
2556 if (relative_offset == 0) {
2557 PLOG(ERROR) << "Failed to write method bss mappings to " << out->GetLocation();
2558 return false;
2559 }
2560
2561 relative_offset = WriteMaps(out, file_offset, relative_offset);
2562 if (relative_offset == 0) {
2563 PLOG(ERROR) << "Failed to write oat code to " << out->GetLocation();
2564 return false;
2565 }
2566
2567 relative_offset = WriteOatDexFiles(out, file_offset, relative_offset);
2568 if (relative_offset == 0) {
2569 PLOG(ERROR) << "Failed to write oat dex information to " << out->GetLocation();
2570 return false;
2571 }
2572
2573 relative_offset = WriteBcpBssInfo(out, file_offset, relative_offset);
2574 if (relative_offset == 0) {
2575 PLOG(ERROR) << "Failed to write BCP bss information to " << out->GetLocation();
2576 return false;
2577 }
2578
2579 // Write padding.
2580 off_t new_offset = out->Seek(size_executable_offset_alignment_, kSeekCurrent);
2581 relative_offset += size_executable_offset_alignment_;
2582 DCHECK_EQ(relative_offset, GetOatHeader().GetExecutableOffset());
2583 size_t expected_file_offset = file_offset + relative_offset;
2584 if (static_cast<uint32_t>(new_offset) != expected_file_offset) {
2585 PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
2586 << " Expected: " << expected_file_offset << " File: " << out->GetLocation();
2587 return false;
2588 }
2589 DCHECK_OFFSET();
2590
2591 write_state_ = WriteState::kWriteText;
2592 return true;
2593 }
2594
WriteVerifierDeps(verifier::VerifierDeps * verifier_deps,std::vector<uint8_t> * buffer)2595 void OatWriter::WriteVerifierDeps(verifier::VerifierDeps* verifier_deps,
2596 /*out*/std::vector<uint8_t>* buffer) {
2597 if (verifier_deps == nullptr) {
2598 // Nothing to write. Record the offset, but no need
2599 // for alignment.
2600 vdex_verifier_deps_offset_ = vdex_size_;
2601 return;
2602 }
2603
2604 TimingLogger::ScopedTiming split("VDEX verifier deps", timings_);
2605
2606 DCHECK(buffer->empty());
2607 verifier_deps->Encode(*dex_files_, buffer);
2608 size_verifier_deps_ = buffer->size();
2609
2610 // Verifier deps data should be 4 byte aligned.
2611 size_verifier_deps_alignment_ = RoundUp(vdex_size_, 4u) - vdex_size_;
2612 buffer->insert(buffer->begin(), size_verifier_deps_alignment_, 0u);
2613
2614 vdex_size_ += size_verifier_deps_alignment_;
2615 vdex_verifier_deps_offset_ = vdex_size_;
2616 vdex_size_ += size_verifier_deps_;
2617 }
2618
WriteCode(OutputStream * out)2619 bool OatWriter::WriteCode(OutputStream* out) {
2620 TimingLogger::ScopedTiming split("WriteCode", timings_);
2621 CHECK(write_state_ == WriteState::kWriteText);
2622
2623 // Wrap out to update checksum with each write.
2624 ChecksumUpdatingOutputStream checksum_updating_out(out, this);
2625 out = &checksum_updating_out;
2626
2627 SetMultiOatRelativePatcherAdjustment();
2628
2629 const size_t file_offset = oat_data_offset_;
2630 size_t relative_offset = oat_header_->GetExecutableOffset();
2631 DCHECK_OFFSET();
2632
2633 relative_offset = WriteCode(out, file_offset, relative_offset);
2634 if (relative_offset == 0) {
2635 LOG(ERROR) << "Failed to write oat code to " << out->GetLocation();
2636 return false;
2637 }
2638
2639 relative_offset = WriteCodeDexFiles(out, file_offset, relative_offset);
2640 if (relative_offset == 0) {
2641 LOG(ERROR) << "Failed to write oat code for dex files to " << out->GetLocation();
2642 return false;
2643 }
2644
2645 if (data_img_rel_ro_size_ != 0u) {
2646 write_state_ = WriteState::kWriteDataImgRelRo;
2647 } else {
2648 if (!CheckOatSize(out, file_offset, relative_offset)) {
2649 return false;
2650 }
2651 write_state_ = WriteState::kWriteHeader;
2652 }
2653 return true;
2654 }
2655
WriteDataImgRelRo(OutputStream * out)2656 bool OatWriter::WriteDataImgRelRo(OutputStream* out) {
2657 TimingLogger::ScopedTiming split("WriteDataImgRelRo", timings_);
2658 CHECK(write_state_ == WriteState::kWriteDataImgRelRo);
2659
2660 // Wrap out to update checksum with each write.
2661 ChecksumUpdatingOutputStream checksum_updating_out(out, this);
2662 out = &checksum_updating_out;
2663
2664 const size_t file_offset = oat_data_offset_;
2665 size_t relative_offset = data_img_rel_ro_start_;
2666
2667 // Record the padding before the .data.img.rel.ro section.
2668 // Do not write anything, this zero-filled part was skipped (Seek()) when starting the section.
2669 size_t code_end = GetOatHeader().GetExecutableOffset() + code_size_;
2670 DCHECK_EQ(GetOffsetFromOatDataAlignedToFile(code_end, kElfSegmentAlignment), relative_offset);
2671 size_t padding_size = relative_offset - code_end;
2672 DCHECK_EQ(size_data_img_rel_ro_alignment_, 0u);
2673 size_data_img_rel_ro_alignment_ = padding_size;
2674
2675 relative_offset = WriteDataImgRelRo(out, file_offset, relative_offset);
2676 if (relative_offset == 0) {
2677 LOG(ERROR) << "Failed to write boot image relocations to " << out->GetLocation();
2678 return false;
2679 }
2680
2681 if (!CheckOatSize(out, file_offset, relative_offset)) {
2682 return false;
2683 }
2684 write_state_ = WriteState::kWriteHeader;
2685 return true;
2686 }
2687
CheckOatSize(OutputStream * out,size_t file_offset,size_t relative_offset)2688 bool OatWriter::CheckOatSize(OutputStream* out, size_t file_offset, size_t relative_offset) {
2689 const off_t oat_end_file_offset = out->Seek(0, kSeekCurrent);
2690 if (oat_end_file_offset == static_cast<off_t>(-1)) {
2691 LOG(ERROR) << "Failed to get oat end file offset in " << out->GetLocation();
2692 return false;
2693 }
2694
2695 if (kIsDebugBuild) {
2696 uint32_t size_total = 0;
2697 #define DO_STAT(x) \
2698 VLOG(compiler) << #x "=" << PrettySize(x) << " (" << (x) << "B)"; \
2699 size_total += (x);
2700
2701 DO_STAT(size_vdex_header_);
2702 DO_STAT(size_vdex_checksums_);
2703 DO_STAT(size_dex_file_alignment_);
2704 DO_STAT(size_executable_offset_alignment_);
2705 DO_STAT(size_oat_header_);
2706 DO_STAT(size_oat_header_key_value_store_);
2707 DO_STAT(size_dex_file_);
2708 DO_STAT(size_verifier_deps_);
2709 DO_STAT(size_verifier_deps_alignment_);
2710 DO_STAT(size_vdex_lookup_table_);
2711 DO_STAT(size_vdex_lookup_table_alignment_);
2712 DO_STAT(size_interpreter_to_interpreter_bridge_);
2713 DO_STAT(size_interpreter_to_compiled_code_bridge_);
2714 DO_STAT(size_jni_dlsym_lookup_trampoline_);
2715 DO_STAT(size_jni_dlsym_lookup_critical_trampoline_);
2716 DO_STAT(size_quick_generic_jni_trampoline_);
2717 DO_STAT(size_quick_imt_conflict_trampoline_);
2718 DO_STAT(size_quick_resolution_trampoline_);
2719 DO_STAT(size_quick_to_interpreter_bridge_);
2720 DO_STAT(size_nterp_trampoline_);
2721 DO_STAT(size_trampoline_alignment_);
2722 DO_STAT(size_method_header_);
2723 DO_STAT(size_code_);
2724 DO_STAT(size_code_alignment_);
2725 DO_STAT(size_data_img_rel_ro_);
2726 DO_STAT(size_data_img_rel_ro_alignment_);
2727 DO_STAT(size_relative_call_thunks_);
2728 DO_STAT(size_misc_thunks_);
2729 DO_STAT(size_vmap_table_);
2730 DO_STAT(size_method_info_);
2731 DO_STAT(size_oat_dex_file_location_size_);
2732 DO_STAT(size_oat_dex_file_location_data_);
2733 DO_STAT(size_oat_dex_file_magic_);
2734 DO_STAT(size_oat_dex_file_location_checksum_);
2735 DO_STAT(size_oat_dex_file_sha1_);
2736 DO_STAT(size_oat_dex_file_offset_);
2737 DO_STAT(size_oat_dex_file_class_offsets_offset_);
2738 DO_STAT(size_oat_dex_file_lookup_table_offset_);
2739 DO_STAT(size_oat_dex_file_dex_layout_sections_offset_);
2740 DO_STAT(size_oat_dex_file_dex_layout_sections_);
2741 DO_STAT(size_oat_dex_file_dex_layout_sections_alignment_);
2742 DO_STAT(size_oat_dex_file_method_bss_mapping_offset_);
2743 DO_STAT(size_oat_dex_file_type_bss_mapping_offset_);
2744 DO_STAT(size_oat_dex_file_public_type_bss_mapping_offset_);
2745 DO_STAT(size_oat_dex_file_package_type_bss_mapping_offset_);
2746 DO_STAT(size_oat_dex_file_string_bss_mapping_offset_);
2747 DO_STAT(size_oat_dex_file_method_type_bss_mapping_offset_);
2748 DO_STAT(size_bcp_bss_info_size_);
2749 DO_STAT(size_bcp_bss_info_method_bss_mapping_offset_);
2750 DO_STAT(size_bcp_bss_info_type_bss_mapping_offset_);
2751 DO_STAT(size_bcp_bss_info_public_type_bss_mapping_offset_);
2752 DO_STAT(size_bcp_bss_info_package_type_bss_mapping_offset_);
2753 DO_STAT(size_bcp_bss_info_string_bss_mapping_offset_);
2754 DO_STAT(size_bcp_bss_info_method_type_bss_mapping_offset_);
2755 DO_STAT(size_oat_class_offsets_alignment_);
2756 DO_STAT(size_oat_class_offsets_);
2757 DO_STAT(size_oat_class_type_);
2758 DO_STAT(size_oat_class_status_);
2759 DO_STAT(size_oat_class_num_methods_);
2760 DO_STAT(size_oat_class_method_bitmaps_);
2761 DO_STAT(size_oat_class_method_offsets_);
2762 DO_STAT(size_method_bss_mappings_);
2763 DO_STAT(size_type_bss_mappings_);
2764 DO_STAT(size_public_type_bss_mappings_);
2765 DO_STAT(size_package_type_bss_mappings_);
2766 DO_STAT(size_string_bss_mappings_);
2767 DO_STAT(size_method_type_bss_mappings_);
2768 #undef DO_STAT
2769
2770 VLOG(compiler) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)";
2771
2772 CHECK_EQ(vdex_size_ + oat_size_, size_total);
2773 CHECK_EQ(file_offset + size_total - vdex_size_, static_cast<size_t>(oat_end_file_offset));
2774 }
2775
2776 CHECK_EQ(file_offset + oat_size_, static_cast<size_t>(oat_end_file_offset));
2777 CHECK_EQ(oat_size_, relative_offset);
2778
2779 write_state_ = WriteState::kWriteHeader;
2780 return true;
2781 }
2782
WriteHeader(OutputStream * out)2783 bool OatWriter::WriteHeader(OutputStream* out) {
2784 TimingLogger::ScopedTiming split("WriteHeader", timings_);
2785
2786 CHECK(write_state_ == WriteState::kWriteHeader);
2787
2788 // Update checksum with header data.
2789 DCHECK_EQ(oat_header_->GetChecksum(), 0u); // For checksum calculation.
2790 oat_header_->ComputeChecksum(&oat_checksum_);
2791 oat_header_->SetChecksum(oat_checksum_);
2792
2793 const size_t file_offset = oat_data_offset_;
2794
2795 off_t current_offset = out->Seek(0, kSeekCurrent);
2796 if (current_offset == static_cast<off_t>(-1)) {
2797 PLOG(ERROR) << "Failed to get current offset from " << out->GetLocation();
2798 return false;
2799 }
2800 if (out->Seek(file_offset, kSeekSet) == static_cast<off_t>(-1)) {
2801 PLOG(ERROR) << "Failed to seek to oat header position in " << out->GetLocation();
2802 return false;
2803 }
2804 DCHECK_EQ(file_offset, static_cast<size_t>(out->Seek(0, kSeekCurrent)));
2805
2806 // Flush all other data before writing the header.
2807 if (!out->Flush()) {
2808 PLOG(ERROR) << "Failed to flush before writing oat header to " << out->GetLocation();
2809 return false;
2810 }
2811 // Write the header.
2812 size_t header_size = oat_header_->GetHeaderSize();
2813 if (!out->WriteFully(oat_header_, header_size)) {
2814 PLOG(ERROR) << "Failed to write oat header to " << out->GetLocation();
2815 return false;
2816 }
2817 // Flush the header data.
2818 if (!out->Flush()) {
2819 PLOG(ERROR) << "Failed to flush after writing oat header to " << out->GetLocation();
2820 return false;
2821 }
2822
2823 if (out->Seek(current_offset, kSeekSet) == static_cast<off_t>(-1)) {
2824 PLOG(ERROR) << "Failed to seek back after writing oat header to " << out->GetLocation();
2825 return false;
2826 }
2827 DCHECK_EQ(current_offset, out->Seek(0, kSeekCurrent));
2828
2829 write_state_ = WriteState::kDone;
2830 return true;
2831 }
2832
WriteClassOffsets(OutputStream * out,size_t file_offset,size_t relative_offset)2833 size_t OatWriter::WriteClassOffsets(OutputStream* out, size_t file_offset, size_t relative_offset) {
2834 for (OatDexFile& oat_dex_file : oat_dex_files_) {
2835 if (oat_dex_file.class_offsets_offset_ != 0u) {
2836 // Class offsets are required to be 4 byte aligned.
2837 if (UNLIKELY(!IsAligned<4u>(relative_offset))) {
2838 size_t padding_size = RoundUp(relative_offset, 4u) - relative_offset;
2839 if (!WriteUpTo16BytesAlignment(out, padding_size, &size_oat_class_offsets_alignment_)) {
2840 return 0u;
2841 }
2842 relative_offset += padding_size;
2843 }
2844 DCHECK_OFFSET();
2845 if (!oat_dex_file.WriteClassOffsets(this, out)) {
2846 return 0u;
2847 }
2848 relative_offset += oat_dex_file.GetClassOffsetsRawSize();
2849 }
2850 }
2851 return relative_offset;
2852 }
2853
WriteClasses(OutputStream * out,size_t file_offset,size_t relative_offset)2854 size_t OatWriter::WriteClasses(OutputStream* out, size_t file_offset, size_t relative_offset) {
2855 const bool may_have_compiled = MayHaveCompiledMethods();
2856 if (may_have_compiled) {
2857 CHECK_EQ(oat_class_headers_.size(), oat_classes_.size());
2858 }
2859 for (size_t i = 0; i < oat_class_headers_.size(); ++i) {
2860 // If there are any classes, the class offsets allocation aligns the offset.
2861 DCHECK_ALIGNED(relative_offset, 4u);
2862 DCHECK_OFFSET();
2863 if (!oat_class_headers_[i].Write(this, out, oat_data_offset_)) {
2864 return 0u;
2865 }
2866 relative_offset += oat_class_headers_[i].SizeOf();
2867 if (may_have_compiled) {
2868 if (!oat_classes_[i].Write(this, out)) {
2869 return 0u;
2870 }
2871 relative_offset += oat_classes_[i].SizeOf();
2872 }
2873 }
2874 return relative_offset;
2875 }
2876
WriteMaps(OutputStream * out,size_t file_offset,size_t relative_offset)2877 size_t OatWriter::WriteMaps(OutputStream* out, size_t file_offset, size_t relative_offset) {
2878 {
2879 if (UNLIKELY(!out->WriteFully(code_info_data_.data(), code_info_data_.size()))) {
2880 return 0;
2881 }
2882 relative_offset += code_info_data_.size();
2883 size_vmap_table_ = code_info_data_.size();
2884 DCHECK_OFFSET();
2885 }
2886
2887 return relative_offset;
2888 }
2889
2890
2891 template <typename GetBssOffset>
WriteIndexBssMapping(OutputStream * out,size_t number_of_indexes,size_t slot_size,const BitVector & indexes,GetBssOffset get_bss_offset)2892 size_t WriteIndexBssMapping(OutputStream* out,
2893 size_t number_of_indexes,
2894 size_t slot_size,
2895 const BitVector& indexes,
2896 GetBssOffset get_bss_offset) {
2897 // Allocate the IndexBssMapping.
2898 size_t number_of_entries = CalculateNumberOfIndexBssMappingEntries(
2899 number_of_indexes, slot_size, indexes, get_bss_offset);
2900 size_t mappings_size = IndexBssMapping::ComputeSize(number_of_entries);
2901 DCHECK_ALIGNED(mappings_size, sizeof(uint32_t));
2902 std::unique_ptr<uint32_t[]> storage(new uint32_t[mappings_size / sizeof(uint32_t)]);
2903 IndexBssMapping* mappings = new(storage.get()) IndexBssMapping(number_of_entries);
2904 mappings->ClearPadding();
2905 // Encode the IndexBssMapping.
2906 IndexBssMappingEncoder encoder(number_of_indexes, slot_size);
2907 auto init_it = mappings->begin();
2908 bool first_index = true;
2909 for (uint32_t index : indexes.Indexes()) {
2910 size_t bss_offset = get_bss_offset(index);
2911 if (first_index) {
2912 first_index = false;
2913 encoder.Reset(index, bss_offset);
2914 } else if (!encoder.TryMerge(index, bss_offset)) {
2915 *init_it = encoder.GetEntry();
2916 ++init_it;
2917 encoder.Reset(index, bss_offset);
2918 }
2919 }
2920 // Store the last entry.
2921 *init_it = encoder.GetEntry();
2922 ++init_it;
2923 DCHECK(init_it == mappings->end());
2924
2925 if (!out->WriteFully(storage.get(), mappings_size)) {
2926 return 0u;
2927 }
2928 return mappings_size;
2929 }
2930
WriteIndexBssMapping(OutputStream * out,const DexFile * dex_file,const BitVector & type_indexes,const SafeMap<TypeReference,size_t,TypeReferenceValueComparator> & bss_entries)2931 size_t WriteIndexBssMapping(
2932 OutputStream* out,
2933 const DexFile* dex_file,
2934 const BitVector& type_indexes,
2935 const SafeMap<TypeReference, size_t, TypeReferenceValueComparator>& bss_entries) {
2936 return WriteIndexBssMapping(
2937 out,
2938 dex_file->NumTypeIds(),
2939 sizeof(GcRoot<mirror::Class>),
2940 type_indexes,
2941 [=](uint32_t index) { return bss_entries.Get({dex_file, dex::TypeIndex(index)}); });
2942 }
2943
WriteIndexBssMappingsHelper(OutputStream * out,size_t file_offset,size_t relative_offset,const DexFile * dex_file,uint32_t method_bss_mapping_offset,uint32_t type_bss_mapping_offset,uint32_t public_type_bss_mapping_offset,uint32_t package_type_bss_mapping_offset,uint32_t string_bss_mapping_offset,uint32_t method_type_bss_mapping_offset)2944 size_t OatWriter::WriteIndexBssMappingsHelper(OutputStream* out,
2945 size_t file_offset,
2946 size_t relative_offset,
2947 const DexFile* dex_file,
2948 uint32_t method_bss_mapping_offset,
2949 uint32_t type_bss_mapping_offset,
2950 uint32_t public_type_bss_mapping_offset,
2951 uint32_t package_type_bss_mapping_offset,
2952 uint32_t string_bss_mapping_offset,
2953 uint32_t method_type_bss_mapping_offset) {
2954 const PointerSize pointer_size = GetInstructionSetPointerSize(oat_header_->GetInstructionSet());
2955 auto method_it = bss_method_entry_references_.find(dex_file);
2956 if (method_it != bss_method_entry_references_.end()) {
2957 const BitVector& method_indexes = method_it->second;
2958 DCHECK_EQ(relative_offset, method_bss_mapping_offset);
2959 DCHECK_OFFSET();
2960 size_t method_mappings_size =
2961 WriteIndexBssMapping(out,
2962 dex_file->NumMethodIds(),
2963 static_cast<size_t>(pointer_size),
2964 method_indexes,
2965 [this, dex_file](uint32_t index) {
2966 return bss_method_entries_.Get({dex_file, index});
2967 });
2968 if (method_mappings_size == 0u) {
2969 return 0u;
2970 }
2971 size_method_bss_mappings_ += method_mappings_size;
2972 relative_offset += method_mappings_size;
2973 } else {
2974 DCHECK_EQ(0u, method_bss_mapping_offset);
2975 }
2976
2977 auto type_it = bss_type_entry_references_.find(dex_file);
2978 if (type_it != bss_type_entry_references_.end()) {
2979 const BitVector& type_indexes = type_it->second;
2980 DCHECK_EQ(relative_offset, type_bss_mapping_offset);
2981 DCHECK_OFFSET();
2982 size_t type_mappings_size =
2983 WriteIndexBssMapping(out, dex_file, type_indexes, bss_type_entries_);
2984 if (type_mappings_size == 0u) {
2985 return 0u;
2986 }
2987 size_type_bss_mappings_ += type_mappings_size;
2988 relative_offset += type_mappings_size;
2989 } else {
2990 DCHECK_EQ(0u, type_bss_mapping_offset);
2991 }
2992
2993 auto public_type_it = bss_public_type_entry_references_.find(dex_file);
2994 if (public_type_it != bss_public_type_entry_references_.end()) {
2995 const BitVector& type_indexes = public_type_it->second;
2996 DCHECK_EQ(relative_offset, public_type_bss_mapping_offset);
2997 DCHECK_OFFSET();
2998 size_t public_type_mappings_size =
2999 WriteIndexBssMapping(out, dex_file, type_indexes, bss_public_type_entries_);
3000 if (public_type_mappings_size == 0u) {
3001 return 0u;
3002 }
3003 size_public_type_bss_mappings_ += public_type_mappings_size;
3004 relative_offset += public_type_mappings_size;
3005 } else {
3006 DCHECK_EQ(0u, public_type_bss_mapping_offset);
3007 }
3008
3009 auto package_type_it = bss_package_type_entry_references_.find(dex_file);
3010 if (package_type_it != bss_package_type_entry_references_.end()) {
3011 const BitVector& type_indexes = package_type_it->second;
3012 DCHECK_EQ(relative_offset, package_type_bss_mapping_offset);
3013 DCHECK_OFFSET();
3014 size_t package_type_mappings_size =
3015 WriteIndexBssMapping(out, dex_file, type_indexes, bss_package_type_entries_);
3016 if (package_type_mappings_size == 0u) {
3017 return 0u;
3018 }
3019 size_package_type_bss_mappings_ += package_type_mappings_size;
3020 relative_offset += package_type_mappings_size;
3021 } else {
3022 DCHECK_EQ(0u, package_type_bss_mapping_offset);
3023 }
3024
3025 auto string_it = bss_string_entry_references_.find(dex_file);
3026 if (string_it != bss_string_entry_references_.end()) {
3027 const BitVector& string_indexes = string_it->second;
3028 DCHECK_EQ(relative_offset, string_bss_mapping_offset);
3029 DCHECK_OFFSET();
3030 size_t string_mappings_size =
3031 WriteIndexBssMapping(out,
3032 dex_file->NumStringIds(),
3033 sizeof(GcRoot<mirror::String>),
3034 string_indexes,
3035 [this, dex_file](uint32_t index) {
3036 return bss_string_entries_.Get({dex_file, dex::StringIndex(index)});
3037 });
3038 if (string_mappings_size == 0u) {
3039 return 0u;
3040 }
3041 size_string_bss_mappings_ += string_mappings_size;
3042 relative_offset += string_mappings_size;
3043 } else {
3044 DCHECK_EQ(0u, string_bss_mapping_offset);
3045 }
3046
3047 auto method_type_it = bss_method_type_entry_references_.find(dex_file);
3048 if (method_type_it != bss_method_type_entry_references_.end()) {
3049 const BitVector& method_type_indexes = method_type_it->second;
3050 DCHECK_EQ(relative_offset, method_type_bss_mapping_offset);
3051 DCHECK_OFFSET();
3052 size_t method_type_mappings_size =
3053 WriteIndexBssMapping(out,
3054 dex_file->NumProtoIds(),
3055 sizeof(GcRoot<mirror::MethodType>),
3056 method_type_indexes,
3057 [this, dex_file](uint32_t index) {
3058 return bss_method_type_entries_
3059 .Get({dex_file, dex::ProtoIndex(index)});
3060 });
3061 if (method_type_mappings_size == 0u) {
3062 return 0u;
3063 }
3064 size_method_type_bss_mappings_ += method_type_mappings_size;
3065 relative_offset += method_type_mappings_size;
3066 } else {
3067 DCHECK_EQ(0u, method_type_bss_mapping_offset);
3068 }
3069
3070 return relative_offset;
3071 }
3072
WriteIndexBssMappings(OutputStream * out,size_t file_offset,size_t relative_offset)3073 size_t OatWriter::WriteIndexBssMappings(OutputStream* out,
3074 size_t file_offset,
3075 size_t relative_offset) {
3076 if (bss_method_entry_references_.empty() &&
3077 bss_type_entry_references_.empty() &&
3078 bss_public_type_entry_references_.empty() &&
3079 bss_package_type_entry_references_.empty() &&
3080 bss_string_entry_references_.empty() &&
3081 bss_method_type_entry_references_.empty()) {
3082 return relative_offset;
3083 }
3084 // If there are any classes, the class offsets allocation aligns the offset
3085 // and we cannot have method bss mappings without class offsets.
3086 static_assert(alignof(IndexBssMapping) == sizeof(uint32_t), "IndexBssMapping alignment check.");
3087 DCHECK_ALIGNED(relative_offset, sizeof(uint32_t));
3088
3089 for (size_t i = 0, size = dex_files_->size(); i != size; ++i) {
3090 const DexFile* dex_file = (*dex_files_)[i];
3091 OatDexFile* oat_dex_file = &oat_dex_files_[i];
3092 relative_offset = WriteIndexBssMappingsHelper(out,
3093 file_offset,
3094 relative_offset,
3095 dex_file,
3096 oat_dex_file->method_bss_mapping_offset_,
3097 oat_dex_file->type_bss_mapping_offset_,
3098 oat_dex_file->public_type_bss_mapping_offset_,
3099 oat_dex_file->package_type_bss_mapping_offset_,
3100 oat_dex_file->string_bss_mapping_offset_,
3101 oat_dex_file->method_type_bss_mapping_offset_);
3102 if (relative_offset == 0u) {
3103 return 0u;
3104 }
3105 }
3106
3107 if (!compiler_options_.IsBootImage()) {
3108 ArrayRef<const DexFile* const> boot_class_path(
3109 Runtime::Current()->GetClassLinker()->GetBootClassPath());
3110
3111 if (compiler_options_.IsBootImageExtension()) {
3112 // For boot image extension, the boot_class_path ends with the compiled dex files. In multi
3113 // image, we might have several oat writers so we have to get all of the compiled dex files
3114 // and not just the one we are compiling right now. Remove them to have the correct number of
3115 // references.
3116 ArrayRef<const DexFile* const> to_exclude(compiler_options_.GetDexFilesForOatFile());
3117 DCHECK_GE(boot_class_path.size(), to_exclude.size());
3118 DCHECK(std::equal(to_exclude.rbegin(), to_exclude.rend(), boot_class_path.rbegin()));
3119 boot_class_path = boot_class_path.SubArray(0, boot_class_path.size() - to_exclude.size());
3120 }
3121
3122 for (size_t i = 0, size = bcp_bss_info_.size(); i != size; ++i) {
3123 const DexFile* dex_file = boot_class_path[i];
3124 DCHECK(!ContainsElement(*dex_files_, dex_file));
3125 relative_offset =
3126 WriteIndexBssMappingsHelper(out,
3127 file_offset,
3128 relative_offset,
3129 dex_file,
3130 bcp_bss_info_[i].method_bss_mapping_offset,
3131 bcp_bss_info_[i].type_bss_mapping_offset,
3132 bcp_bss_info_[i].public_type_bss_mapping_offset,
3133 bcp_bss_info_[i].package_type_bss_mapping_offset,
3134 bcp_bss_info_[i].string_bss_mapping_offset,
3135 bcp_bss_info_[i].method_type_bss_mapping_offset);
3136 if (relative_offset == 0u) {
3137 return 0u;
3138 }
3139 }
3140 }
3141 return relative_offset;
3142 }
3143
WriteOatDexFiles(OutputStream * out,size_t file_offset,size_t relative_offset)3144 size_t OatWriter::WriteOatDexFiles(OutputStream* out, size_t file_offset, size_t relative_offset) {
3145 for (size_t i = 0, size = oat_dex_files_.size(); i != size; ++i) {
3146 OatDexFile* oat_dex_file = &oat_dex_files_[i];
3147 DCHECK_EQ(relative_offset, oat_dex_file->offset_);
3148 DCHECK_OFFSET();
3149
3150 // Write OatDexFile.
3151 if (!oat_dex_file->Write(this, out)) {
3152 return 0u;
3153 }
3154 relative_offset += oat_dex_file->SizeOf();
3155 }
3156
3157 return relative_offset;
3158 }
3159
WriteBcpBssInfo(OutputStream * out,size_t file_offset,size_t relative_offset)3160 size_t OatWriter::WriteBcpBssInfo(OutputStream* out, size_t file_offset, size_t relative_offset) {
3161 const uint32_t number_of_bcp_dexfiles = bcp_bss_info_.size();
3162 // We skip adding the number of DexFiles if we have no .bss mappings.
3163 if (number_of_bcp_dexfiles == 0) {
3164 return relative_offset;
3165 }
3166
3167 if (!out->WriteFully(&number_of_bcp_dexfiles, sizeof(number_of_bcp_dexfiles))) {
3168 PLOG(ERROR) << "Failed to write the number of BCP dexfiles to " << out->GetLocation();
3169 return false;
3170 }
3171 size_bcp_bss_info_size_ = sizeof(number_of_bcp_dexfiles);
3172 relative_offset += size_bcp_bss_info_size_;
3173
3174 for (size_t i = 0, size = number_of_bcp_dexfiles; i != size; ++i) {
3175 DCHECK_EQ(relative_offset, bcp_bss_info_[i].offset_);
3176 DCHECK_OFFSET();
3177 if (!bcp_bss_info_[i].Write(this, out)) {
3178 return 0u;
3179 }
3180 relative_offset += BssMappingInfo::SizeOf();
3181 }
3182
3183 return relative_offset;
3184 }
3185
WriteCode(OutputStream * out,size_t file_offset,size_t relative_offset)3186 size_t OatWriter::WriteCode(OutputStream* out, size_t file_offset, size_t relative_offset) {
3187 InstructionSet instruction_set = compiler_options_.GetInstructionSet();
3188 if (GetCompilerOptions().IsBootImage() && primary_oat_file_) {
3189 #define DO_TRAMPOLINE(field) \
3190 do { \
3191 /* Pad with at least four 0xFFs so we can do DCHECKs in OatQuickMethodHeader */ \
3192 uint32_t aligned_offset = GetOffsetFromOatDataAlignedToFile( \
3193 relative_offset + 4, GetInstructionSetCodeAlignment(instruction_set)); \
3194 uint32_t alignment_padding = aligned_offset - relative_offset; \
3195 for (size_t i = 0; i < alignment_padding; i++) { \
3196 uint8_t padding = 0xFF; \
3197 out->WriteFully(&padding, 1); \
3198 } \
3199 size_trampoline_alignment_ += alignment_padding; \
3200 if (!out->WriteFully((field)->data(), (field)->size())) { \
3201 PLOG(ERROR) << "Failed to write " # field " to " << out->GetLocation(); \
3202 return false; \
3203 } \
3204 size_ ## field += (field)->size(); \
3205 relative_offset += alignment_padding + (field)->size(); \
3206 DCHECK_OFFSET(); \
3207 } while (false)
3208
3209 DO_TRAMPOLINE(jni_dlsym_lookup_trampoline_);
3210 DO_TRAMPOLINE(jni_dlsym_lookup_critical_trampoline_);
3211 DO_TRAMPOLINE(quick_generic_jni_trampoline_);
3212 DO_TRAMPOLINE(quick_imt_conflict_trampoline_);
3213 DO_TRAMPOLINE(quick_resolution_trampoline_);
3214 DO_TRAMPOLINE(quick_to_interpreter_bridge_);
3215 DO_TRAMPOLINE(nterp_trampoline_);
3216 #undef DO_TRAMPOLINE
3217 }
3218 return relative_offset;
3219 }
3220
WriteCodeDexFiles(OutputStream * out,size_t file_offset,size_t relative_offset)3221 size_t OatWriter::WriteCodeDexFiles(OutputStream* out,
3222 size_t file_offset,
3223 size_t relative_offset) {
3224 if (!GetCompilerOptions().IsAnyCompilationEnabled()) {
3225 // As with InitOatCodeDexFiles, also skip the writer if
3226 // compilation was disabled.
3227 if (kOatWriterDebugOatCodeLayout) {
3228 LOG(INFO) << "WriteCodeDexFiles: OatWriter("
3229 << this << "), "
3230 << "compilation is disabled";
3231 }
3232
3233 return relative_offset;
3234 }
3235 ScopedObjectAccess soa(Thread::Current());
3236 DCHECK(ordered_methods_ != nullptr);
3237 std::unique_ptr<OrderedMethodList> ordered_methods_ptr =
3238 std::move(ordered_methods_);
3239 WriteCodeMethodVisitor visitor(this,
3240 out,
3241 file_offset,
3242 relative_offset,
3243 std::move(*ordered_methods_ptr));
3244 if (UNLIKELY(!visitor.Visit())) {
3245 return 0;
3246 }
3247 relative_offset = visitor.GetOffset();
3248
3249 size_code_alignment_ += relative_patcher_->CodeAlignmentSize();
3250 size_relative_call_thunks_ += relative_patcher_->RelativeCallThunksSize();
3251 size_misc_thunks_ += relative_patcher_->MiscThunksSize();
3252
3253 return relative_offset;
3254 }
3255
WriteDataImgRelRo(OutputStream * out,size_t file_offset,size_t relative_offset)3256 size_t OatWriter::WriteDataImgRelRo(OutputStream* out,
3257 size_t file_offset,
3258 size_t relative_offset) {
3259 size_t size = boot_image_rel_ro_entries_.size() +
3260 app_image_rel_ro_method_entries_.size() +
3261 app_image_rel_ro_type_entries_.size();
3262 if (size == 0u) {
3263 return relative_offset;
3264 }
3265
3266 // Write the entire .data.img.rel.ro with a single WriteFully().
3267 std::vector<uint32_t> data;
3268 data.reserve(size);
3269 for (const auto& entry : boot_image_rel_ro_entries_) {
3270 uint32_t boot_image_offset = entry.first;
3271 data.push_back(boot_image_offset);
3272 }
3273 if (!app_image_rel_ro_method_entries_.empty() || !app_image_rel_ro_type_entries_.empty()) {
3274 DCHECK(GetCompilerOptions().IsAppImage());
3275 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
3276 ScopedObjectAccess soa(Thread::Current());
3277 const DexFile* last_dex_file = nullptr;
3278 ObjPtr<mirror::DexCache> dex_cache = nullptr;
3279 ObjPtr<mirror::ClassLoader> class_loader = nullptr;
3280 auto update_for_dex_file = [&](const DexFile* dex_file) REQUIRES_SHARED(Locks::mutator_lock_) {
3281 if (dex_file != last_dex_file) {
3282 dex_cache = class_linker->FindDexCache(soa.Self(), *dex_file);
3283 class_loader = dex_cache->GetClassLoader();
3284 last_dex_file = dex_file;
3285 }
3286 };
3287 for (const auto& entry : app_image_rel_ro_method_entries_) {
3288 MethodReference target_method = entry.first;
3289 update_for_dex_file(target_method.dex_file);
3290 ArtMethod* method =
3291 class_linker->LookupResolvedMethod(target_method.index, dex_cache, class_loader);
3292 CHECK(method != nullptr);
3293 uint32_t app_image_offset = image_writer_->GetGlobalImageOffset(method);
3294 data.push_back(app_image_offset);
3295 }
3296 for (const auto& entry : app_image_rel_ro_type_entries_) {
3297 TypeReference target_type = entry.first;
3298 update_for_dex_file(target_type.dex_file);
3299 ObjPtr<mirror::Class> type =
3300 class_linker->LookupResolvedType(target_type.TypeIndex(), dex_cache, class_loader);
3301 CHECK(type != nullptr);
3302 uint32_t app_image_offset = image_writer_->GetGlobalImageOffset(type.Ptr());
3303 data.push_back(app_image_offset);
3304 }
3305 }
3306 DCHECK_EQ(data.size(), size);
3307 DCHECK_OFFSET();
3308 if (!out->WriteFully(data.data(), data.size() * sizeof(data[0]))) {
3309 PLOG(ERROR) << "Failed to write .data.img.rel.ro in " << out->GetLocation();
3310 return 0u;
3311 }
3312 DCHECK_EQ(size_data_img_rel_ro_, 0u);
3313 size_data_img_rel_ro_ = data.size() * sizeof(data[0]);
3314 relative_offset += size_data_img_rel_ro_;
3315 return relative_offset;
3316 }
3317
RecordOatDataOffset(OutputStream * out)3318 bool OatWriter::RecordOatDataOffset(OutputStream* out) {
3319 // Get the elf file offset of the oat file.
3320 const off_t raw_file_offset = out->Seek(0, kSeekCurrent);
3321 if (raw_file_offset == static_cast<off_t>(-1)) {
3322 LOG(ERROR) << "Failed to get file offset in " << out->GetLocation();
3323 return false;
3324 }
3325 oat_data_offset_ = static_cast<size_t>(raw_file_offset);
3326 return true;
3327 }
3328
WriteDexFiles(File * file,bool verify,bool use_existing_vdex,CopyOption copy_dex_files,std::vector<MemMap> * opened_dex_files_map)3329 bool OatWriter::WriteDexFiles(File* file,
3330 bool verify,
3331 bool use_existing_vdex,
3332 CopyOption copy_dex_files,
3333 /*out*/ std::vector<MemMap>* opened_dex_files_map) {
3334 TimingLogger::ScopedTiming split("Write Dex files", timings_);
3335
3336 // If extraction is enabled, only do it if not all the dex files are aligned and uncompressed.
3337 if (copy_dex_files == CopyOption::kOnlyIfCompressed) {
3338 extract_dex_files_into_vdex_ = false;
3339 for (OatDexFile& oat_dex_file : oat_dex_files_) {
3340 const DexFileContainer* container = oat_dex_file.GetDexFile()->GetContainer().get();
3341 if (!container->IsFileMap()) {
3342 extract_dex_files_into_vdex_ = true;
3343 break;
3344 }
3345 }
3346 } else if (copy_dex_files == CopyOption::kAlways) {
3347 extract_dex_files_into_vdex_ = true;
3348 } else {
3349 DCHECK(copy_dex_files == CopyOption::kNever);
3350 extract_dex_files_into_vdex_ = false;
3351 }
3352
3353 if (verify) {
3354 TimingLogger::ScopedTiming split2("Verify input Dex files", timings_);
3355 for (OatDexFile& oat_dex_file : oat_dex_files_) {
3356 const DexFile* dex_file = oat_dex_file.GetDexFile();
3357 std::string error_msg;
3358 if (!dex::Verify(dex_file,
3359 dex_file->GetLocation().c_str(),
3360 /*verify_checksum=*/true,
3361 &error_msg)) {
3362 LOG(ERROR) << "Failed to verify " << dex_file->GetLocation() << ": " << error_msg;
3363 return false;
3364 }
3365 }
3366 }
3367
3368 if (extract_dex_files_into_vdex_) {
3369 vdex_dex_files_offset_ = vdex_size_;
3370
3371 // Calculate the total size after the dex files.
3372 size_t vdex_size_with_dex_files = vdex_size_;
3373 for (OatDexFile& oat_dex_file : oat_dex_files_) {
3374 // Dex files are required to be 4 byte aligned.
3375 vdex_size_with_dex_files = RoundUp(vdex_size_with_dex_files, 4u);
3376 // Record offset for the dex file.
3377 oat_dex_file.dex_file_offset_ = vdex_size_with_dex_files;
3378 // Add the size of the dex file.
3379 if (oat_dex_file.dex_file_size_ < sizeof(DexFile::Header)) {
3380 LOG(ERROR) << "Dex file " << oat_dex_file.GetLocation() << " is too short: "
3381 << oat_dex_file.dex_file_size_ << " < " << sizeof(DexFile::Header);
3382 return false;
3383 }
3384 vdex_size_with_dex_files += oat_dex_file.dex_file_size_;
3385 }
3386
3387 // Extend the file and include the full page at the end as we need to write
3388 // additional data there and do not want to mmap that page twice.
3389 //
3390 // The page size value here is used to figure out the size of the mapping below,
3391 // however it doesn't affect the file contents or its size, so should not be
3392 // replaced with kElfSegmentAlignment.
3393 size_t page_aligned_size = RoundUp(vdex_size_with_dex_files, MemMap::GetPageSize());
3394 if (!use_existing_vdex) {
3395 if (file->SetLength(page_aligned_size) != 0) {
3396 PLOG(ERROR) << "Failed to resize vdex file " << file->GetPath();
3397 return false;
3398 }
3399 }
3400
3401 std::string error_msg;
3402 MemMap dex_files_map = MemMap::MapFile(
3403 page_aligned_size,
3404 use_existing_vdex ? PROT_READ : PROT_READ | PROT_WRITE,
3405 MAP_SHARED,
3406 file->Fd(),
3407 /*start=*/ 0u,
3408 /*low_4gb=*/ false,
3409 file->GetPath().c_str(),
3410 &error_msg);
3411 if (!dex_files_map.IsValid()) {
3412 LOG(ERROR) << "Failed to mmap() dex files from oat file. File: " << file->GetPath()
3413 << " error: " << error_msg;
3414 return false;
3415 }
3416 vdex_begin_ = dex_files_map.Begin();
3417
3418 // Write dex files.
3419 for (OatDexFile& oat_dex_file : oat_dex_files_) {
3420 // Dex files are required to be 4 byte aligned.
3421 size_t old_vdex_size = vdex_size_;
3422 vdex_size_ = RoundUp(vdex_size_, 4u);
3423 size_dex_file_alignment_ += vdex_size_ - old_vdex_size;
3424 // Write the actual dex file.
3425 DCHECK_EQ(vdex_size_, oat_dex_file.dex_file_offset_);
3426 uint8_t* out = vdex_begin_ + oat_dex_file.dex_file_offset_;
3427 const DexFile* dex_file = oat_dex_file.GetDexFile();
3428 DCHECK_EQ(oat_dex_file.dex_file_size_, dex_file->Size());
3429 if (use_existing_vdex) {
3430 // The vdex already contains the data.
3431 DCHECK_EQ(memcmp(out, dex_file->Begin(), dex_file->Size()), 0);
3432 } else {
3433 memcpy(out, dex_file->Begin(), dex_file->Size());
3434 }
3435
3436 // Update current size and account for the written data.
3437 vdex_size_ += oat_dex_file.dex_file_size_;
3438 size_dex_file_ += oat_dex_file.dex_file_size_;
3439 }
3440
3441 opened_dex_files_map->push_back(std::move(dex_files_map));
3442 }
3443
3444 if (use_existing_vdex) {
3445 // If we re-use an existing vdex, artificially set the verifier deps size,
3446 // so the compiler has a correct computation of the vdex size.
3447 size_t actual_size = file->GetLength();
3448 size_verifier_deps_ = actual_size - vdex_size_;
3449 vdex_size_ = actual_size;
3450 }
3451
3452 return true;
3453 }
3454
CloseSources()3455 void OatWriter::CloseSources() {
3456 for (OatDexFile& oat_dex_file : oat_dex_files_) {
3457 oat_dex_file.dex_file_.reset();
3458 }
3459 }
3460
OpenDexFiles(File * file,std::vector<MemMap> * opened_dex_files_map,std::vector<std::unique_ptr<const DexFile>> * opened_dex_files)3461 bool OatWriter::OpenDexFiles(
3462 File* file,
3463 /*inout*/ std::vector<MemMap>* opened_dex_files_map,
3464 /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) {
3465 TimingLogger::ScopedTiming split("OpenDexFiles", timings_);
3466
3467 if (oat_dex_files_.empty()) {
3468 // Nothing to do.
3469 return true;
3470 }
3471
3472 if (!extract_dex_files_into_vdex_) {
3473 DCHECK_EQ(opened_dex_files_map->size(), 0u);
3474 std::vector<std::unique_ptr<const DexFile>> dex_files;
3475 for (OatDexFile& oat_dex_file : oat_dex_files_) {
3476 // The dex file is already open, release the reference.
3477 dex_files.emplace_back(std::move(oat_dex_file.dex_file_));
3478 oat_dex_file.class_offsets_.resize(dex_files.back()->GetHeader().class_defs_size_);
3479 }
3480 *opened_dex_files = std::move(dex_files);
3481 CloseSources();
3482 return true;
3483 }
3484 // We could have closed the sources at the point of writing the dex files, but to
3485 // make it consistent with the case we're not writing the dex files, we close them now.
3486 CloseSources();
3487
3488 DCHECK_EQ(opened_dex_files_map->size(), 1u);
3489 DCHECK(vdex_begin_ == opened_dex_files_map->front().Begin());
3490 std::vector<std::unique_ptr<const DexFile>> dex_files;
3491 auto dex_container = std::make_shared<MemoryDexFileContainer>(vdex_begin_, vdex_size_);
3492 for (OatDexFile& oat_dex_file : oat_dex_files_) {
3493 const uint8_t* raw_dex_file = vdex_begin_ + oat_dex_file.dex_file_offset_;
3494
3495 if (kIsDebugBuild) {
3496 // Check the validity of the input files.
3497 // Note that ValidateDexFileHeader() logs error messages.
3498 CHECK(ValidateDexFileHeader(raw_dex_file, oat_dex_file.GetLocation()))
3499 << "Failed to verify written dex file header!"
3500 << " Output: " << file->GetPath()
3501 << " ~ " << std::hex << static_cast<const void*>(raw_dex_file);
3502
3503 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_dex_file);
3504 CHECK_EQ(header->file_size_, oat_dex_file.dex_file_size_)
3505 << "File size mismatch in written dex file header! Expected: "
3506 << oat_dex_file.dex_file_size_ << " Actual: " << header->file_size_
3507 << " Output: " << file->GetPath();
3508 }
3509
3510 // Now, open the dex file.
3511 std::string error_msg;
3512 ArtDexFileLoader dex_file_loader(dex_container, oat_dex_file.GetLocation());
3513 // All dex files have been already verified in WriteDexFiles before we copied them.
3514 dex_files.emplace_back(dex_file_loader.OpenOne(oat_dex_file.dex_file_offset_,
3515 oat_dex_file.dex_file_location_checksum_,
3516 /*oat_dex_file=*/nullptr,
3517 /*verify=*/false,
3518 /*verify_checksum=*/false,
3519 &error_msg));
3520 if (dex_files.back() == nullptr) {
3521 LOG(ERROR) << "Failed to open dex file from oat file. File: " << oat_dex_file.GetLocation()
3522 << " Error: " << error_msg;
3523 return false;
3524 }
3525
3526 // Set the class_offsets size now that we have easy access to the DexFile and
3527 // it has been verified in dex_file_loader.Open.
3528 oat_dex_file.class_offsets_.resize(dex_files.back()->GetHeader().class_defs_size_);
3529 }
3530
3531 *opened_dex_files = std::move(dex_files);
3532 return true;
3533 }
3534
InitializeTypeLookupTables(const std::vector<std::unique_ptr<const DexFile>> & opened_dex_files)3535 void OatWriter::InitializeTypeLookupTables(
3536 const std::vector<std::unique_ptr<const DexFile>>& opened_dex_files) {
3537 TimingLogger::ScopedTiming split("InitializeTypeLookupTables", timings_);
3538 DCHECK_EQ(opened_dex_files.size(), oat_dex_files_.size());
3539 for (size_t i = 0, size = opened_dex_files.size(); i != size; ++i) {
3540 OatDexFile* oat_dex_file = &oat_dex_files_[i];
3541 DCHECK_EQ(oat_dex_file->lookup_table_offset_, 0u);
3542
3543 size_t table_size = TypeLookupTable::RawDataLength(oat_dex_file->class_offsets_.size());
3544 if (table_size == 0u) {
3545 // We want a 1:1 mapping between `dex_files_` and `type_lookup_table_oat_dex_files_`,
3546 // to simplify `WriteTypeLookupTables`. We push a null entry to notify
3547 // that the dex file at index `i` does not have a type lookup table.
3548 type_lookup_table_oat_dex_files_.push_back(nullptr);
3549 continue;
3550 }
3551
3552 const DexFile& dex_file = *opened_dex_files[i].get();
3553 TypeLookupTable type_lookup_table = TypeLookupTable::Create(dex_file);
3554 type_lookup_table_oat_dex_files_.push_back(
3555 std::make_unique<art::OatDexFile>(std::move(type_lookup_table)));
3556 dex_file.SetOatDexFile(type_lookup_table_oat_dex_files_.back().get());
3557 }
3558 }
3559
WriteDexLayoutSections(OutputStream * oat_rodata,const std::vector<const DexFile * > & opened_dex_files)3560 bool OatWriter::WriteDexLayoutSections(OutputStream* oat_rodata,
3561 const std::vector<const DexFile*>& opened_dex_files) {
3562 TimingLogger::ScopedTiming split(__FUNCTION__, timings_);
3563
3564 if (!kWriteDexLayoutInfo) {
3565 return true;
3566 }
3567
3568 uint32_t expected_offset = oat_data_offset_ + oat_size_;
3569 off_t actual_offset = oat_rodata->Seek(expected_offset, kSeekSet);
3570 if (static_cast<uint32_t>(actual_offset) != expected_offset) {
3571 PLOG(ERROR) << "Failed to seek to dex layout section offset section. Actual: " << actual_offset
3572 << " Expected: " << expected_offset << " File: " << oat_rodata->GetLocation();
3573 return false;
3574 }
3575
3576 DCHECK_EQ(opened_dex_files.size(), oat_dex_files_.size());
3577 size_t rodata_offset = oat_size_;
3578 for (size_t i = 0, size = opened_dex_files.size(); i != size; ++i) {
3579 OatDexFile* oat_dex_file = &oat_dex_files_[i];
3580 DCHECK_EQ(oat_dex_file->dex_sections_layout_offset_, 0u);
3581
3582 // Write dex layout section alignment bytes.
3583 size_t rodata_file_offset = GetFileOffset(rodata_offset);
3584 const size_t padding_size =
3585 RoundUp(rodata_file_offset, alignof(DexLayoutSections)) - rodata_file_offset;
3586 if (padding_size != 0u) {
3587 std::vector<uint8_t> buffer(padding_size, 0u);
3588 if (!oat_rodata->WriteFully(buffer.data(), padding_size)) {
3589 PLOG(ERROR) << "Failed to write lookup table alignment padding."
3590 << " File: " << oat_dex_file->GetLocation()
3591 << " Output: " << oat_rodata->GetLocation();
3592 return false;
3593 }
3594 size_oat_dex_file_dex_layout_sections_alignment_ += padding_size;
3595 rodata_offset += padding_size;
3596 }
3597
3598 DCHECK_ALIGNED(rodata_offset, alignof(DexLayoutSections));
3599 DCHECK_EQ(oat_data_offset_ + rodata_offset,
3600 static_cast<size_t>(oat_rodata->Seek(0u, kSeekCurrent)));
3601 DCHECK(oat_dex_file != nullptr);
3602 if (!oat_rodata->WriteFully(&oat_dex_file->dex_sections_layout_,
3603 sizeof(oat_dex_file->dex_sections_layout_))) {
3604 PLOG(ERROR) << "Failed to write dex layout sections."
3605 << " File: " << oat_dex_file->GetLocation()
3606 << " Output: " << oat_rodata->GetLocation();
3607 return false;
3608 }
3609 oat_dex_file->dex_sections_layout_offset_ = rodata_offset;
3610 size_oat_dex_file_dex_layout_sections_ += sizeof(oat_dex_file->dex_sections_layout_);
3611 rodata_offset += sizeof(oat_dex_file->dex_sections_layout_);
3612 }
3613 oat_size_ = rodata_offset;
3614
3615 if (!oat_rodata->Flush()) {
3616 PLOG(ERROR) << "Failed to flush stream after writing type dex layout sections."
3617 << " File: " << oat_rodata->GetLocation();
3618 return false;
3619 }
3620
3621 return true;
3622 }
3623
WriteTypeLookupTables(std::vector<uint8_t> * buffer)3624 void OatWriter::WriteTypeLookupTables(/*out*/std::vector<uint8_t>* buffer) {
3625 TimingLogger::ScopedTiming split("WriteTypeLookupTables", timings_);
3626 size_t type_lookup_table_size = 0u;
3627 for (const DexFile* dex_file : *dex_files_) {
3628 type_lookup_table_size +=
3629 sizeof(uint32_t) + TypeLookupTable::RawDataLength(dex_file->NumClassDefs());
3630 }
3631 // Reserve the space to avoid reallocations later on.
3632 buffer->reserve(buffer->size() + type_lookup_table_size);
3633
3634 // Align the start of the first type lookup table.
3635 size_t initial_offset = vdex_size_;
3636 size_t table_offset = RoundUp(initial_offset, 4);
3637 size_t padding_size = table_offset - initial_offset;
3638
3639 size_vdex_lookup_table_alignment_ += padding_size;
3640 for (uint32_t j = 0; j < padding_size; ++j) {
3641 buffer->push_back(0);
3642 }
3643 vdex_size_ += padding_size;
3644 vdex_lookup_tables_offset_ = vdex_size_;
3645 for (size_t i = 0, size = type_lookup_table_oat_dex_files_.size(); i != size; ++i) {
3646 OatDexFile* oat_dex_file = &oat_dex_files_[i];
3647 if (type_lookup_table_oat_dex_files_[i] == nullptr) {
3648 buffer->insert(buffer->end(), {0u, 0u, 0u, 0u});
3649 size_vdex_lookup_table_ += sizeof(uint32_t);
3650 vdex_size_ += sizeof(uint32_t);
3651 oat_dex_file->lookup_table_offset_ = 0u;
3652 } else {
3653 oat_dex_file->lookup_table_offset_ = vdex_size_ + sizeof(uint32_t);
3654 const TypeLookupTable& table = type_lookup_table_oat_dex_files_[i]->GetTypeLookupTable();
3655 uint32_t table_size = table.RawDataLength();
3656 DCHECK_NE(0u, table_size);
3657 DCHECK_ALIGNED(table_size, 4);
3658 size_t old_buffer_size = buffer->size();
3659 buffer->resize(old_buffer_size + table.RawDataLength() + sizeof(uint32_t), 0u);
3660 memcpy(buffer->data() + old_buffer_size, &table_size, sizeof(uint32_t));
3661 memcpy(buffer->data() + old_buffer_size + sizeof(uint32_t), table.RawData(), table_size);
3662 vdex_size_ += table_size + sizeof(uint32_t);
3663 size_vdex_lookup_table_ += table_size + sizeof(uint32_t);
3664 }
3665 }
3666 }
3667
FinishVdexFile(File * vdex_file,verifier::VerifierDeps * verifier_deps)3668 bool OatWriter::FinishVdexFile(File* vdex_file, verifier::VerifierDeps* verifier_deps) {
3669 size_t old_vdex_size = vdex_size_;
3670 std::vector<uint8_t> buffer;
3671 buffer.reserve(64 * KB);
3672 WriteVerifierDeps(verifier_deps, &buffer);
3673 WriteTypeLookupTables(&buffer);
3674 DCHECK_EQ(vdex_size_, old_vdex_size + buffer.size());
3675
3676 // Resize the vdex file.
3677 if (vdex_file->SetLength(vdex_size_) != 0) {
3678 PLOG(ERROR) << "Failed to resize vdex file " << vdex_file->GetPath();
3679 return false;
3680 }
3681
3682 uint8_t* vdex_begin = vdex_begin_;
3683 MemMap extra_map;
3684 if (extract_dex_files_into_vdex_) {
3685 DCHECK(vdex_begin != nullptr);
3686 // Write data to the last already mmapped page of the vdex file.
3687 // The size should match the page_aligned_size in the OatWriter::WriteDexFiles.
3688 size_t mmapped_vdex_size = RoundUp(old_vdex_size, MemMap::GetPageSize());
3689 size_t first_chunk_size = std::min(buffer.size(), mmapped_vdex_size - old_vdex_size);
3690 memcpy(vdex_begin + old_vdex_size, buffer.data(), first_chunk_size);
3691
3692 if (first_chunk_size != buffer.size()) {
3693 size_t tail_size = buffer.size() - first_chunk_size;
3694 std::string error_msg;
3695 extra_map = MemMap::MapFile(
3696 tail_size,
3697 PROT_READ | PROT_WRITE,
3698 MAP_SHARED,
3699 vdex_file->Fd(),
3700 /*start=*/ mmapped_vdex_size,
3701 /*low_4gb=*/ false,
3702 vdex_file->GetPath().c_str(),
3703 &error_msg);
3704 if (!extra_map.IsValid()) {
3705 LOG(ERROR) << "Failed to mmap() vdex file tail. File: " << vdex_file->GetPath()
3706 << " error: " << error_msg;
3707 return false;
3708 }
3709 memcpy(extra_map.Begin(), buffer.data() + first_chunk_size, tail_size);
3710 }
3711 } else {
3712 DCHECK(vdex_begin == nullptr);
3713 std::string error_msg;
3714 extra_map = MemMap::MapFile(
3715 vdex_size_,
3716 PROT_READ | PROT_WRITE,
3717 MAP_SHARED,
3718 vdex_file->Fd(),
3719 /*start=*/ 0u,
3720 /*low_4gb=*/ false,
3721 vdex_file->GetPath().c_str(),
3722 &error_msg);
3723 if (!extra_map.IsValid()) {
3724 LOG(ERROR) << "Failed to mmap() vdex file. File: " << vdex_file->GetPath()
3725 << " error: " << error_msg;
3726 return false;
3727 }
3728 vdex_begin = extra_map.Begin();
3729 memcpy(vdex_begin + old_vdex_size, buffer.data(), buffer.size());
3730 }
3731
3732 // Write checksums
3733 off_t checksums_offset = VdexFile::GetChecksumsOffset();
3734 VdexFile::VdexChecksum* checksums_data =
3735 reinterpret_cast<VdexFile::VdexChecksum*>(vdex_begin + checksums_offset);
3736 for (size_t i = 0, size = oat_dex_files_.size(); i != size; ++i) {
3737 OatDexFile* oat_dex_file = &oat_dex_files_[i];
3738 checksums_data[i] = oat_dex_file->dex_file_location_checksum_;
3739 }
3740
3741 // Write sections.
3742 uint8_t* ptr = vdex_begin + sizeof(VdexFile::VdexFileHeader);
3743
3744 // Checksums section.
3745 new (ptr) VdexFile::VdexSectionHeader(VdexSection::kChecksumSection,
3746 checksums_offset,
3747 size_vdex_checksums_);
3748 ptr += sizeof(VdexFile::VdexSectionHeader);
3749
3750 // Dex section.
3751 new (ptr) VdexFile::VdexSectionHeader(
3752 VdexSection::kDexFileSection,
3753 extract_dex_files_into_vdex_ ? vdex_dex_files_offset_ : 0u,
3754 extract_dex_files_into_vdex_ ? vdex_verifier_deps_offset_ - vdex_dex_files_offset_ : 0u);
3755 ptr += sizeof(VdexFile::VdexSectionHeader);
3756
3757 // VerifierDeps section.
3758 new (ptr) VdexFile::VdexSectionHeader(VdexSection::kVerifierDepsSection,
3759 vdex_verifier_deps_offset_,
3760 size_verifier_deps_);
3761 ptr += sizeof(VdexFile::VdexSectionHeader);
3762
3763 // TypeLookupTable section.
3764 new (ptr) VdexFile::VdexSectionHeader(VdexSection::kTypeLookupTableSection,
3765 vdex_lookup_tables_offset_,
3766 vdex_size_ - vdex_lookup_tables_offset_);
3767
3768 // All the contents (except the header) of the vdex file has been emitted in memory. Flush it
3769 // to disk.
3770 {
3771 TimingLogger::ScopedTiming split("VDEX flush contents", timings_);
3772 // Sync the data to the disk while the header is invalid. We do not want to end up with
3773 // a valid header and invalid data if the process is suddenly killed.
3774 if (extract_dex_files_into_vdex_) {
3775 // Note: We passed the ownership of the vdex dex file MemMap to the caller,
3776 // so we need to use msync() for the range explicitly.
3777 //
3778 // The page size here is not replaced with kElfSegmentAlignment as the
3779 // rounded up size should match the page_aligned_size in OatWriter::WriteDexFiles
3780 // which is the size the original (non-extra) mapping created there.
3781 if (msync(vdex_begin, RoundUp(old_vdex_size, MemMap::GetPageSize()), MS_SYNC) != 0) {
3782 PLOG(ERROR) << "Failed to sync vdex file contents" << vdex_file->GetPath();
3783 return false;
3784 }
3785 }
3786 if (extra_map.IsValid() && !extra_map.Sync()) {
3787 PLOG(ERROR) << "Failed to sync vdex file contents" << vdex_file->GetPath();
3788 return false;
3789 }
3790 }
3791
3792 // Now that we know all contents have been flushed to disk, we can write
3793 // the header which will mke the vdex usable.
3794 bool has_dex_section = extract_dex_files_into_vdex_;
3795 new (vdex_begin) VdexFile::VdexFileHeader(has_dex_section);
3796
3797 // Note: If `extract_dex_files_into_vdex_`, we passed the ownership of the vdex dex file
3798 // MemMap to the caller, so we need to use msync() for the range explicitly.
3799 //
3800 // The page size here should not be replaced with kElfSegmentAlignment as the size
3801 // here should match the header size rounded up to the page size. Any higher value
3802 // might happen to be larger than the size of the mapping which can in some circumstances
3803 // cause msync to fail.
3804 if (msync(vdex_begin, MemMap::GetPageSize(), MS_SYNC) != 0) {
3805 PLOG(ERROR) << "Failed to sync vdex file header " << vdex_file->GetPath();
3806 return false;
3807 }
3808
3809 return true;
3810 }
3811
WriteCodeAlignment(OutputStream * out,uint32_t aligned_code_delta)3812 bool OatWriter::WriteCodeAlignment(OutputStream* out, uint32_t aligned_code_delta) {
3813 return WriteUpTo16BytesAlignment(out, aligned_code_delta, &size_code_alignment_);
3814 }
3815
WriteUpTo16BytesAlignment(OutputStream * out,uint32_t size,uint32_t * stat)3816 bool OatWriter::WriteUpTo16BytesAlignment(OutputStream* out, uint32_t size, uint32_t* stat) {
3817 static const uint8_t kPadding[] = {
3818 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u
3819 };
3820 DCHECK_LE(size, sizeof(kPadding));
3821 if (UNLIKELY(!out->WriteFully(kPadding, size))) {
3822 return false;
3823 }
3824 *stat += size;
3825 return true;
3826 }
3827
SetMultiOatRelativePatcherAdjustment()3828 void OatWriter::SetMultiOatRelativePatcherAdjustment() {
3829 DCHECK(dex_files_ != nullptr);
3830 DCHECK(relative_patcher_ != nullptr);
3831 DCHECK_NE(oat_data_offset_, 0u);
3832 size_t elf_file_offset = 0;
3833 if (image_writer_ != nullptr && !dex_files_->empty()) {
3834 // The oat data begin may not be initialized yet but the oat file offset is ready.
3835 size_t oat_index = image_writer_->GetOatIndexForDexFile(dex_files_->front());
3836 elf_file_offset = image_writer_->GetOatFileOffset(oat_index);
3837 }
3838 // Relative patcher expects offsets from the page-aligned boundary, as the oat data is
3839 // unaligned in the ELF file we always need to set its correct start.
3840 relative_patcher_->StartOatFile(elf_file_offset + oat_data_offset_);
3841 }
3842
OatDexFile(std::unique_ptr<const DexFile> dex_file)3843 OatWriter::OatDexFile::OatDexFile(std::unique_ptr<const DexFile> dex_file)
3844 : dex_file_(std::move(dex_file)),
3845 dex_file_location_(std::make_unique<std::string>(dex_file_->GetLocation())),
3846 dex_file_size_(dex_file_->Size()),
3847 offset_(0),
3848 dex_file_location_size_(strlen(dex_file_location_->c_str())),
3849 dex_file_location_data_(dex_file_location_->c_str()),
3850 dex_file_magic_(dex_file_->GetHeader().magic_),
3851 dex_file_location_checksum_(dex_file_->GetLocationChecksum()),
3852 dex_file_sha1_(dex_file_->GetSha1()),
3853 dex_file_offset_(0u),
3854 lookup_table_offset_(0u),
3855 class_offsets_offset_(0u),
3856 method_bss_mapping_offset_(0u),
3857 type_bss_mapping_offset_(0u),
3858 public_type_bss_mapping_offset_(0u),
3859 package_type_bss_mapping_offset_(0u),
3860 string_bss_mapping_offset_(0u),
3861 method_type_bss_mapping_offset_(0u),
3862 dex_sections_layout_offset_(0u),
3863 class_offsets_() {}
3864
SizeOf() const3865 size_t OatWriter::OatDexFile::SizeOf() const {
3866 return sizeof(dex_file_location_size_) + dex_file_location_size_ + sizeof(dex_file_magic_) +
3867 sizeof(dex_file_location_checksum_) + sizeof(dex_file_sha1_) + sizeof(dex_file_offset_) +
3868 sizeof(class_offsets_offset_) + sizeof(lookup_table_offset_) +
3869 sizeof(method_bss_mapping_offset_) + sizeof(type_bss_mapping_offset_) +
3870 sizeof(public_type_bss_mapping_offset_) + sizeof(package_type_bss_mapping_offset_) +
3871 sizeof(string_bss_mapping_offset_) + sizeof(method_type_bss_mapping_offset_) +
3872 sizeof(dex_sections_layout_offset_);
3873 }
3874
Write(OatWriter * oat_writer,OutputStream * out) const3875 bool OatWriter::OatDexFile::Write(OatWriter* oat_writer, OutputStream* out) const {
3876 const size_t file_offset = oat_writer->oat_data_offset_;
3877 DCHECK_OFFSET_();
3878
3879 if (!out->WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
3880 PLOG(ERROR) << "Failed to write dex file location length to " << out->GetLocation();
3881 return false;
3882 }
3883 oat_writer->size_oat_dex_file_location_size_ += sizeof(dex_file_location_size_);
3884
3885 if (!out->WriteFully(dex_file_location_data_, dex_file_location_size_)) {
3886 PLOG(ERROR) << "Failed to write dex file location data to " << out->GetLocation();
3887 return false;
3888 }
3889 oat_writer->size_oat_dex_file_location_data_ += dex_file_location_size_;
3890
3891 if (!out->WriteFully(&dex_file_magic_, sizeof(dex_file_magic_))) {
3892 PLOG(ERROR) << "Failed to write dex file magic to " << out->GetLocation();
3893 return false;
3894 }
3895 oat_writer->size_oat_dex_file_magic_ += sizeof(dex_file_magic_);
3896
3897 if (!out->WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) {
3898 PLOG(ERROR) << "Failed to write dex file location checksum to " << out->GetLocation();
3899 return false;
3900 }
3901 oat_writer->size_oat_dex_file_location_checksum_ += sizeof(dex_file_location_checksum_);
3902
3903 if (!out->WriteFully(&dex_file_sha1_, sizeof(dex_file_sha1_))) {
3904 PLOG(ERROR) << "Failed to write dex file sha1 to " << out->GetLocation();
3905 return false;
3906 }
3907 oat_writer->size_oat_dex_file_sha1_ += sizeof(dex_file_sha1_);
3908
3909 if (!out->WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
3910 PLOG(ERROR) << "Failed to write dex file offset to " << out->GetLocation();
3911 return false;
3912 }
3913 oat_writer->size_oat_dex_file_offset_ += sizeof(dex_file_offset_);
3914
3915 if (!out->WriteFully(&class_offsets_offset_, sizeof(class_offsets_offset_))) {
3916 PLOG(ERROR) << "Failed to write class offsets offset to " << out->GetLocation();
3917 return false;
3918 }
3919 oat_writer->size_oat_dex_file_class_offsets_offset_ += sizeof(class_offsets_offset_);
3920
3921 if (!out->WriteFully(&lookup_table_offset_, sizeof(lookup_table_offset_))) {
3922 PLOG(ERROR) << "Failed to write lookup table offset to " << out->GetLocation();
3923 return false;
3924 }
3925 oat_writer->size_oat_dex_file_lookup_table_offset_ += sizeof(lookup_table_offset_);
3926
3927 if (!out->WriteFully(&dex_sections_layout_offset_, sizeof(dex_sections_layout_offset_))) {
3928 PLOG(ERROR) << "Failed to write dex section layout info to " << out->GetLocation();
3929 return false;
3930 }
3931 oat_writer->size_oat_dex_file_dex_layout_sections_offset_ += sizeof(dex_sections_layout_offset_);
3932
3933 if (!out->WriteFully(&method_bss_mapping_offset_, sizeof(method_bss_mapping_offset_))) {
3934 PLOG(ERROR) << "Failed to write method bss mapping offset to " << out->GetLocation();
3935 return false;
3936 }
3937 oat_writer->size_oat_dex_file_method_bss_mapping_offset_ += sizeof(method_bss_mapping_offset_);
3938
3939 if (!out->WriteFully(&type_bss_mapping_offset_, sizeof(type_bss_mapping_offset_))) {
3940 PLOG(ERROR) << "Failed to write type bss mapping offset to " << out->GetLocation();
3941 return false;
3942 }
3943 oat_writer->size_oat_dex_file_type_bss_mapping_offset_ += sizeof(type_bss_mapping_offset_);
3944
3945 if (!out->WriteFully(&public_type_bss_mapping_offset_, sizeof(public_type_bss_mapping_offset_))) {
3946 PLOG(ERROR) << "Failed to write public type bss mapping offset to " << out->GetLocation();
3947 return false;
3948 }
3949 oat_writer->size_oat_dex_file_public_type_bss_mapping_offset_ +=
3950 sizeof(public_type_bss_mapping_offset_);
3951
3952 if (!out->WriteFully(&package_type_bss_mapping_offset_,
3953 sizeof(package_type_bss_mapping_offset_))) {
3954 PLOG(ERROR) << "Failed to write package type bss mapping offset to " << out->GetLocation();
3955 return false;
3956 }
3957 oat_writer->size_oat_dex_file_package_type_bss_mapping_offset_ +=
3958 sizeof(package_type_bss_mapping_offset_);
3959
3960 if (!out->WriteFully(&string_bss_mapping_offset_, sizeof(string_bss_mapping_offset_))) {
3961 PLOG(ERROR) << "Failed to write string bss mapping offset to " << out->GetLocation();
3962 return false;
3963 }
3964 oat_writer->size_oat_dex_file_string_bss_mapping_offset_ += sizeof(string_bss_mapping_offset_);
3965
3966 if (!out->WriteFully(&method_type_bss_mapping_offset_, sizeof(method_type_bss_mapping_offset_))) {
3967 PLOG(ERROR) << "Failed to write MethodType bss mapping offset to " << out->GetLocation();
3968 return false;
3969 }
3970 oat_writer->size_oat_dex_file_method_type_bss_mapping_offset_ +=
3971 sizeof(method_type_bss_mapping_offset_);
3972
3973 return true;
3974 }
3975
Write(OatWriter * oat_writer,OutputStream * out) const3976 bool OatWriter::BssMappingInfo::Write(OatWriter* oat_writer, OutputStream* out) const {
3977 const size_t file_offset = oat_writer->oat_data_offset_;
3978 DCHECK_OFFSET_();
3979
3980 if (!out->WriteFully(&method_bss_mapping_offset, sizeof(method_bss_mapping_offset))) {
3981 PLOG(ERROR) << "Failed to write method bss mapping offset to " << out->GetLocation();
3982 return false;
3983 }
3984 oat_writer->size_bcp_bss_info_method_bss_mapping_offset_ += sizeof(method_bss_mapping_offset);
3985
3986 if (!out->WriteFully(&type_bss_mapping_offset, sizeof(type_bss_mapping_offset))) {
3987 PLOG(ERROR) << "Failed to write type bss mapping offset to " << out->GetLocation();
3988 return false;
3989 }
3990 oat_writer->size_bcp_bss_info_type_bss_mapping_offset_ += sizeof(type_bss_mapping_offset);
3991
3992 if (!out->WriteFully(&public_type_bss_mapping_offset, sizeof(public_type_bss_mapping_offset))) {
3993 PLOG(ERROR) << "Failed to write public type bss mapping offset to " << out->GetLocation();
3994 return false;
3995 }
3996 oat_writer->size_bcp_bss_info_public_type_bss_mapping_offset_ +=
3997 sizeof(public_type_bss_mapping_offset);
3998
3999 if (!out->WriteFully(&package_type_bss_mapping_offset, sizeof(package_type_bss_mapping_offset))) {
4000 PLOG(ERROR) << "Failed to write package type bss mapping offset to " << out->GetLocation();
4001 return false;
4002 }
4003 oat_writer->size_bcp_bss_info_package_type_bss_mapping_offset_ +=
4004 sizeof(package_type_bss_mapping_offset);
4005
4006 if (!out->WriteFully(&string_bss_mapping_offset, sizeof(string_bss_mapping_offset))) {
4007 PLOG(ERROR) << "Failed to write string bss mapping offset to " << out->GetLocation();
4008 return false;
4009 }
4010 oat_writer->size_bcp_bss_info_string_bss_mapping_offset_ += sizeof(string_bss_mapping_offset);
4011
4012 if (!out->WriteFully(&method_type_bss_mapping_offset, sizeof(method_type_bss_mapping_offset))) {
4013 PLOG(ERROR) << "Failed to write method type bss mapping offset to " << out->GetLocation();
4014 return false;
4015 }
4016 oat_writer->size_bcp_bss_info_method_type_bss_mapping_offset_ +=
4017 sizeof(method_type_bss_mapping_offset);
4018
4019 return true;
4020 }
4021
WriteClassOffsets(OatWriter * oat_writer,OutputStream * out)4022 bool OatWriter::OatDexFile::WriteClassOffsets(OatWriter* oat_writer, OutputStream* out) {
4023 if (!out->WriteFully(class_offsets_.data(), GetClassOffsetsRawSize())) {
4024 PLOG(ERROR) << "Failed to write oat class offsets for " << GetLocation()
4025 << " to " << out->GetLocation();
4026 return false;
4027 }
4028 oat_writer->size_oat_class_offsets_ += GetClassOffsetsRawSize();
4029 return true;
4030 }
4031
OatClass(const dchecked_vector<CompiledMethod * > & compiled_methods,uint32_t compiled_methods_with_code,uint16_t oat_class_type)4032 OatWriter::OatClass::OatClass(const dchecked_vector<CompiledMethod*>& compiled_methods,
4033 uint32_t compiled_methods_with_code,
4034 uint16_t oat_class_type)
4035 : compiled_methods_(compiled_methods) {
4036 const uint32_t num_methods = compiled_methods.size();
4037 CHECK_LE(compiled_methods_with_code, num_methods);
4038
4039 oat_method_offsets_offsets_from_oat_class_.resize(num_methods);
4040
4041 method_offsets_.resize(compiled_methods_with_code);
4042 method_headers_.resize(compiled_methods_with_code);
4043
4044 uint32_t oat_method_offsets_offset_from_oat_class = OatClassHeader::SizeOf();
4045 // We only write method-related data if there are at least some compiled methods.
4046 num_methods_ = 0u;
4047 DCHECK(method_bitmap_ == nullptr);
4048 if (oat_class_type != enum_cast<uint16_t>(OatClassType::kNoneCompiled)) {
4049 num_methods_ = num_methods;
4050 oat_method_offsets_offset_from_oat_class += sizeof(num_methods_);
4051 if (oat_class_type == enum_cast<uint16_t>(OatClassType::kSomeCompiled)) {
4052 method_bitmap_.reset(new BitVector(num_methods, false, Allocator::GetCallocAllocator()));
4053 uint32_t bitmap_size = BitVector::BitsToWords(num_methods) * BitVector::kWordBytes;
4054 DCHECK_EQ(bitmap_size, method_bitmap_->GetSizeOf());
4055 oat_method_offsets_offset_from_oat_class += bitmap_size;
4056 }
4057 }
4058
4059 for (size_t i = 0; i < num_methods; i++) {
4060 CompiledMethod* compiled_method = compiled_methods_[i];
4061 if (HasCompiledCode(compiled_method)) {
4062 oat_method_offsets_offsets_from_oat_class_[i] = oat_method_offsets_offset_from_oat_class;
4063 oat_method_offsets_offset_from_oat_class += sizeof(OatMethodOffsets);
4064 if (oat_class_type == enum_cast<uint16_t>(OatClassType::kSomeCompiled)) {
4065 method_bitmap_->SetBit(i);
4066 }
4067 } else {
4068 oat_method_offsets_offsets_from_oat_class_[i] = 0;
4069 }
4070 }
4071 }
4072
SizeOf() const4073 size_t OatWriter::OatClass::SizeOf() const {
4074 return ((num_methods_ == 0) ? 0 : sizeof(num_methods_)) +
4075 ((method_bitmap_ != nullptr) ? method_bitmap_->GetSizeOf() : 0u) +
4076 (sizeof(method_offsets_[0]) * method_offsets_.size());
4077 }
4078
Write(OatWriter * oat_writer,OutputStream * out,const size_t file_offset) const4079 bool OatWriter::OatClassHeader::Write(OatWriter* oat_writer,
4080 OutputStream* out,
4081 const size_t file_offset) const {
4082 DCHECK_OFFSET_();
4083 if (!out->WriteFully(&status_, sizeof(status_))) {
4084 PLOG(ERROR) << "Failed to write class status to " << out->GetLocation();
4085 return false;
4086 }
4087 oat_writer->size_oat_class_status_ += sizeof(status_);
4088
4089 if (!out->WriteFully(&type_, sizeof(type_))) {
4090 PLOG(ERROR) << "Failed to write oat class type to " << out->GetLocation();
4091 return false;
4092 }
4093 oat_writer->size_oat_class_type_ += sizeof(type_);
4094 return true;
4095 }
4096
Write(OatWriter * oat_writer,OutputStream * out) const4097 bool OatWriter::OatClass::Write(OatWriter* oat_writer, OutputStream* out) const {
4098 if (num_methods_ != 0u) {
4099 if (!out->WriteFully(&num_methods_, sizeof(num_methods_))) {
4100 PLOG(ERROR) << "Failed to write number of methods to " << out->GetLocation();
4101 return false;
4102 }
4103 oat_writer->size_oat_class_num_methods_ += sizeof(num_methods_);
4104 }
4105
4106 if (method_bitmap_ != nullptr) {
4107 if (!out->WriteFully(method_bitmap_->GetRawStorage(), method_bitmap_->GetSizeOf())) {
4108 PLOG(ERROR) << "Failed to write method bitmap to " << out->GetLocation();
4109 return false;
4110 }
4111 oat_writer->size_oat_class_method_bitmaps_ += method_bitmap_->GetSizeOf();
4112 }
4113
4114 if (!out->WriteFully(method_offsets_.data(), GetMethodOffsetsRawSize())) {
4115 PLOG(ERROR) << "Failed to write method offsets to " << out->GetLocation();
4116 return false;
4117 }
4118 oat_writer->size_oat_class_method_offsets_ += GetMethodOffsetsRawSize();
4119 return true;
4120 }
4121
GetDebugInfo() const4122 debug::DebugInfo OatWriter::GetDebugInfo() const {
4123 debug::DebugInfo debug_info{};
4124 debug_info.compiled_methods = ArrayRef<const debug::MethodDebugInfo>(method_info_);
4125 if (VdexWillContainDexFiles()) {
4126 DCHECK_EQ(dex_files_->size(), oat_dex_files_.size());
4127 for (size_t i = 0, size = dex_files_->size(); i != size; ++i) {
4128 const DexFile* dex_file = (*dex_files_)[i];
4129 const OatDexFile& oat_dex_file = oat_dex_files_[i];
4130 uint32_t dex_file_offset = oat_dex_file.dex_file_offset_;
4131 if (dex_file_offset != 0) {
4132 debug_info.dex_files.emplace(dex_file_offset, dex_file);
4133 }
4134 }
4135 }
4136 return debug_info;
4137 }
4138
4139 } // namespace linker
4140 } // namespace art
4141