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