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