1 /*
2 * Copyright (C) 2015 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 "profile_compilation_info.h"
18
19 #include <fcntl.h>
20 #include <sys/file.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24 #include <zlib.h>
25
26 #include <algorithm>
27 #include <cerrno>
28 #include <climits>
29 #include <cstdio>
30 #include <cstdlib>
31 #include <iostream>
32 #include <numeric>
33 #include <random>
34 #include <string>
35 #include <unordered_map>
36 #include <unordered_set>
37 #include <vector>
38
39 #include "android-base/file.h"
40 #include "android-base/properties.h"
41 #include "android-base/scopeguard.h"
42 #include "android-base/strings.h"
43 #include "android-base/unique_fd.h"
44 #include "base/arena_allocator.h"
45 #include "base/bit_utils.h"
46 #include "base/dumpable.h"
47 #include "base/file_utils.h"
48 #include "base/globals.h"
49 #include "base/logging.h" // For VLOG.
50 #include "base/malloc_arena_pool.h"
51 #include "base/os.h"
52 #include "base/safe_map.h"
53 #include "base/scoped_flock.h"
54 #include "base/stl_util.h"
55 #include "base/systrace.h"
56 #include "base/time_utils.h"
57 #include "base/unix_file/fd_file.h"
58 #include "base/utils.h"
59 #include "base/zip_archive.h"
60 #include "dex/code_item_accessors-inl.h"
61 #include "dex/descriptors_names.h"
62 #include "dex/dex_file_loader.h"
63
64 #ifdef ART_TARGET_ANDROID
65 #include "android-modules-utils/sdk_level.h"
66 #endif
67
68 namespace art {
69
70 const uint8_t ProfileCompilationInfo::kProfileMagic[] = { 'p', 'r', 'o', '\0' };
71 // Last profile version: New extensible profile format.
72 const uint8_t ProfileCompilationInfo::kProfileVersion[] = { '0', '1', '5', '\0' };
73 const uint8_t ProfileCompilationInfo::kProfileVersionForBootImage[] = { '0', '1', '6', '\0' };
74
75 static_assert(sizeof(ProfileCompilationInfo::kProfileVersion) == 4,
76 "Invalid profile version size");
77 static_assert(sizeof(ProfileCompilationInfo::kProfileVersionForBootImage) == 4,
78 "Invalid profile version size");
79
80 // The name of the profile entry in the dex metadata file.
81 // DO NOT CHANGE THIS! (it's similar to classes.dex in the apk files).
82 const char ProfileCompilationInfo::kDexMetadataProfileEntry[] = "primary.prof";
83
84 // A synthetic annotations that can be used to denote that no annotation should
85 // be associated with the profile samples. We use the empty string for the package name
86 // because that's an invalid package name and should never occur in practice.
87 const ProfileCompilationInfo::ProfileSampleAnnotation
88 ProfileCompilationInfo::ProfileSampleAnnotation::kNone =
89 ProfileCompilationInfo::ProfileSampleAnnotation("");
90
91 static constexpr char kSampleMetadataSeparator = ':';
92
93 // Note: This used to be PATH_MAX (usually 4096) but that seems excessive
94 // and we do not want to rely on that external constant anyway.
95 static constexpr uint16_t kMaxDexFileKeyLength = 1024;
96
97 // Extra descriptors are serialized with a `uint16_t` prefix. This defines the length limit.
98 static constexpr size_t kMaxExtraDescriptorLength = std::numeric_limits<uint16_t>::max();
99
100 // According to dex file specification, there can be more than 2^16 valid method indexes
101 // but bytecode uses only 16 bits, so higher method indexes are not very useful (though
102 // such methods could be reached through virtual or interface dispatch). Consequently,
103 // dex files with more than 2^16 method indexes are not really used and the profile file
104 // format does not support higher method indexes.
105 static constexpr uint32_t kMaxSupportedMethodIndex = 0xffffu;
106
107 // Debug flag to ignore checksums when testing if a method or a class is present in the profile.
108 // Used to facilitate testing profile guided compilation across a large number of apps
109 // using the same test profile.
110 static constexpr bool kDebugIgnoreChecksum = false;
111
112 static constexpr uint8_t kIsMissingTypesEncoding = 6;
113 static constexpr uint8_t kIsMegamorphicEncoding = 7;
114
115 static_assert(sizeof(ProfileCompilationInfo::kIndividualInlineCacheSize) == sizeof(uint8_t),
116 "InlineCache::kIndividualInlineCacheSize does not have the expect type size");
117 static_assert(ProfileCompilationInfo::kIndividualInlineCacheSize < kIsMegamorphicEncoding,
118 "InlineCache::kIndividualInlineCacheSize is larger than expected");
119 static_assert(ProfileCompilationInfo::kIndividualInlineCacheSize < kIsMissingTypesEncoding,
120 "InlineCache::kIndividualInlineCacheSize is larger than expected");
121
122 static constexpr uint32_t kSizeWarningThresholdBytes = 500000U;
123 static constexpr uint32_t kSizeErrorThresholdBytes = 1500000U;
124
125 static constexpr uint32_t kSizeWarningThresholdBootBytes = 25000000U;
126 static constexpr uint32_t kSizeErrorThresholdBootBytes = 100000000U;
127
ChecksumMatch(uint32_t dex_file_checksum,uint32_t checksum)128 static bool ChecksumMatch(uint32_t dex_file_checksum, uint32_t checksum) {
129 return kDebugIgnoreChecksum || dex_file_checksum == checksum;
130 }
131
132 namespace {
133
134 // Deflate the input buffer `in_buffer`. It returns a buffer of
135 // compressed data for the input buffer of `*compressed_data_size` size.
DeflateBuffer(ArrayRef<const uint8_t> in_buffer,uint32_t * compressed_data_size)136 std::unique_ptr<uint8_t[]> DeflateBuffer(ArrayRef<const uint8_t> in_buffer,
137 /*out*/ uint32_t* compressed_data_size) {
138 z_stream strm;
139 strm.zalloc = Z_NULL;
140 strm.zfree = Z_NULL;
141 strm.opaque = Z_NULL;
142 int init_ret = deflateInit(&strm, 1);
143 if (init_ret != Z_OK) {
144 return nullptr;
145 }
146
147 uint32_t out_size = dchecked_integral_cast<uint32_t>(deflateBound(&strm, in_buffer.size()));
148
149 std::unique_ptr<uint8_t[]> compressed_buffer(new uint8_t[out_size]);
150 strm.avail_in = in_buffer.size();
151 strm.next_in = const_cast<uint8_t*>(in_buffer.data());
152 strm.avail_out = out_size;
153 strm.next_out = &compressed_buffer[0];
154 int ret = deflate(&strm, Z_FINISH);
155 if (ret == Z_STREAM_ERROR) {
156 return nullptr;
157 }
158 *compressed_data_size = out_size - strm.avail_out;
159
160 int end_ret = deflateEnd(&strm);
161 if (end_ret != Z_OK) {
162 return nullptr;
163 }
164
165 return compressed_buffer;
166 }
167
168 // Inflate the data from `in_buffer` into `out_buffer`. The `out_buffer.size()`
169 // is the expected output size of the buffer. It returns Z_STREAM_END on success.
170 // On error, it returns Z_STREAM_ERROR if the compressed data is inconsistent
171 // and Z_DATA_ERROR if the stream ended prematurely or the stream has extra data.
InflateBuffer(ArrayRef<const uint8_t> in_buffer,ArrayRef<uint8_t> out_buffer)172 int InflateBuffer(ArrayRef<const uint8_t> in_buffer, /*out*/ ArrayRef<uint8_t> out_buffer) {
173 /* allocate inflate state */
174 z_stream strm;
175 strm.zalloc = Z_NULL;
176 strm.zfree = Z_NULL;
177 strm.opaque = Z_NULL;
178 strm.avail_in = in_buffer.size();
179 strm.next_in = const_cast<uint8_t*>(in_buffer.data());
180 strm.avail_out = out_buffer.size();
181 strm.next_out = out_buffer.data();
182
183 int init_ret = inflateInit(&strm);
184 if (init_ret != Z_OK) {
185 return init_ret;
186 }
187
188 int ret = inflate(&strm, Z_NO_FLUSH);
189 if (strm.avail_in != 0 || strm.avail_out != 0) {
190 return Z_DATA_ERROR;
191 }
192
193 int end_ret = inflateEnd(&strm);
194 if (end_ret != Z_OK) {
195 return end_ret;
196 }
197
198 return ret;
199 }
200
201 } // anonymous namespace
202
203 enum class ProfileCompilationInfo::ProfileLoadStatus : uint32_t {
204 kSuccess,
205 kIOError,
206 kBadMagic,
207 kVersionMismatch,
208 kBadData,
209 kMergeError, // Merging failed. There are too many extra descriptors
210 // or classes without TypeId referenced by a dex file.
211 };
212
213 enum class ProfileCompilationInfo::FileSectionType : uint32_t {
214 // The values of section enumerators and data format for individual sections
215 // must not be changed without changing the profile file version. New sections
216 // can be added at the end and they shall be ignored by old versions of ART.
217
218 // The list of the dex files included in the profile.
219 // There must be exactly one dex file section and it must be first.
220 kDexFiles = 0,
221
222 // Extra descriptors for referencing classes that do not have a `dex::TypeId`
223 // in the referencing dex file, such as classes from a different dex file
224 // (even outside of the dex files in the profile) or array classes that were
225 // used from other dex files or created through reflection.
226 kExtraDescriptors = 1,
227
228 // Classes included in the profile.
229 kClasses = 2,
230
231 // Methods included in the profile, their hotness flags and inline caches.
232 kMethods = 3,
233
234 // The aggregation counts of the profile, classes and methods. This section is
235 // an optional reserved section not implemented on client yet.
236 kAggregationCounts = 4,
237
238 // The number of known sections.
239 kNumberOfSections = 5
240 };
241
242 class ProfileCompilationInfo::FileSectionInfo {
243 public:
244 // Constructor for reading from a `ProfileSource`. Data shall be filled from the source.
FileSectionInfo()245 FileSectionInfo() {}
246
247 // Constructor for writing to a file.
FileSectionInfo(FileSectionType type,uint32_t file_offset,uint32_t file_size,uint32_t inflated_size)248 FileSectionInfo(FileSectionType type,
249 uint32_t file_offset,
250 uint32_t file_size,
251 uint32_t inflated_size)
252 : type_(type),
253 file_offset_(file_offset),
254 file_size_(file_size),
255 inflated_size_(inflated_size) {}
256
SetFileOffset(uint32_t file_offset)257 void SetFileOffset(uint32_t file_offset) {
258 DCHECK_EQ(file_offset_, 0u);
259 DCHECK_NE(file_offset, 0u);
260 file_offset_ = file_offset;
261 }
262
GetType() const263 FileSectionType GetType() const {
264 return type_;
265 }
266
GetFileOffset() const267 uint32_t GetFileOffset() const {
268 return file_offset_;
269 }
270
GetFileSize() const271 uint32_t GetFileSize() const {
272 return file_size_;
273 }
274
GetInflatedSize() const275 uint32_t GetInflatedSize() const {
276 return inflated_size_;
277 }
278
GetMemSize() const279 uint32_t GetMemSize() const {
280 return inflated_size_ != 0u ? inflated_size_ : file_size_;
281 }
282
283 private:
284 FileSectionType type_;
285 uint32_t file_offset_;
286 uint32_t file_size_;
287 uint32_t inflated_size_; // If 0, do not inflate and use data from file directly.
288 };
289
290 // The file header.
291 class ProfileCompilationInfo::FileHeader {
292 public:
293 // Constructor for reading from a `ProfileSource`. Data shall be filled from the source.
FileHeader()294 FileHeader() {
295 DCHECK(!IsValid());
296 }
297
298 // Constructor for writing to a file.
FileHeader(const uint8_t * version,uint32_t file_section_count)299 FileHeader(const uint8_t* version, uint32_t file_section_count)
300 : file_section_count_(file_section_count) {
301 static_assert(sizeof(magic_) == sizeof(kProfileMagic));
302 static_assert(sizeof(version_) == sizeof(kProfileVersion));
303 static_assert(sizeof(version_) == sizeof(kProfileVersionForBootImage));
304 memcpy(magic_, kProfileMagic, sizeof(kProfileMagic));
305 memcpy(version_, version, sizeof(version_));
306 DCHECK_LE(file_section_count, kMaxFileSectionCount);
307 DCHECK(IsValid());
308 }
309
IsValid() const310 bool IsValid() const {
311 return memcmp(magic_, kProfileMagic, sizeof(kProfileMagic)) == 0 &&
312 (memcmp(version_, kProfileVersion, kProfileVersionSize) == 0 ||
313 memcmp(version_, kProfileVersionForBootImage, kProfileVersionSize) == 0) &&
314 file_section_count_ != 0u && // The dex files section is mandatory.
315 file_section_count_ <= kMaxFileSectionCount;
316 }
317
GetVersion() const318 const uint8_t* GetVersion() const {
319 DCHECK(IsValid());
320 return version_;
321 }
322
323 ProfileLoadStatus InvalidHeaderMessage(/*out*/ std::string* error_msg) const;
324
GetFileSectionCount() const325 uint32_t GetFileSectionCount() const {
326 DCHECK(IsValid());
327 return file_section_count_;
328 }
329
330 private:
331 // The upper bound for file section count is used to ensure that there
332 // shall be no arithmetic overflow when calculating size of the header
333 // with section information.
334 static const uint32_t kMaxFileSectionCount;
335
336 uint8_t magic_[4] = {0, 0, 0, 0};
337 uint8_t version_[4] = {0, 0, 0, 0};
338 uint32_t file_section_count_ = 0u;
339 };
340
341 const uint32_t ProfileCompilationInfo::FileHeader::kMaxFileSectionCount =
342 (std::numeric_limits<uint32_t>::max() - sizeof(FileHeader)) / sizeof(FileSectionInfo);
343
344 ProfileCompilationInfo::ProfileLoadStatus
InvalidHeaderMessage(std::string * error_msg) const345 ProfileCompilationInfo::FileHeader::InvalidHeaderMessage(/*out*/ std::string* error_msg) const {
346 if (memcmp(magic_, kProfileMagic, sizeof(kProfileMagic)) != 0) {
347 *error_msg = "Profile missing magic.";
348 return ProfileLoadStatus::kBadMagic;
349 }
350 if (memcmp(version_, kProfileVersion, sizeof(kProfileVersion)) != 0 &&
351 memcmp(version_, kProfileVersion, sizeof(kProfileVersionForBootImage)) != 0) {
352 *error_msg = "Profile version mismatch.";
353 return ProfileLoadStatus::kVersionMismatch;
354 }
355 if (file_section_count_ == 0u) {
356 *error_msg = "Missing mandatory dex files section.";
357 return ProfileLoadStatus::kBadData;
358 }
359 DCHECK_GT(file_section_count_, kMaxFileSectionCount);
360 *error_msg ="Too many sections.";
361 return ProfileLoadStatus::kBadData;
362 }
363
364 /**
365 * Encapsulate the source of profile data for loading.
366 * The source can be either a plain file or a zip file.
367 * For zip files, the profile entry will be extracted to
368 * the memory map.
369 */
370 class ProfileCompilationInfo::ProfileSource {
371 public:
372 /**
373 * Create a profile source for the given fd. The ownership of the fd
374 * remains to the caller; as this class will not attempt to close it at any
375 * point.
376 */
Create(int32_t fd)377 static ProfileSource* Create(int32_t fd) {
378 DCHECK_GT(fd, -1);
379 return new ProfileSource(fd, MemMap::Invalid());
380 }
381
382 /**
383 * Create a profile source backed by a memory map. The map can be null in
384 * which case it will the treated as an empty source.
385 */
Create(MemMap && mem_map)386 static ProfileSource* Create(MemMap&& mem_map) {
387 return new ProfileSource(/*fd*/ -1, std::move(mem_map));
388 }
389
390 // Seek to the given offset in the source.
391 bool Seek(off_t offset);
392
393 /**
394 * Read bytes from this source.
395 * Reading will advance the current source position so subsequent
396 * invocations will read from the las position.
397 */
398 ProfileLoadStatus Read(void* buffer,
399 size_t byte_count,
400 const std::string& debug_stage,
401 std::string* error);
402
403 /** Return true if the source has 0 data. */
404 bool HasEmptyContent() const;
405
406 private:
ProfileSource(int32_t fd,MemMap && mem_map)407 ProfileSource(int32_t fd, MemMap&& mem_map)
408 : fd_(fd), mem_map_(std::move(mem_map)), mem_map_cur_(0) {}
409
IsMemMap() const410 bool IsMemMap() const {
411 return fd_ == -1;
412 }
413
414 int32_t fd_; // The fd is not owned by this class.
415 MemMap mem_map_;
416 size_t mem_map_cur_; // Current position in the map to read from.
417 };
418
419 // A helper structure to make sure we don't read past our buffers in the loops.
420 // Also used for writing but the buffer should be pre-sized correctly for that, so we
421 // DCHECK() we do not write beyond the end, rather than returning `false` on failure.
422 class ProfileCompilationInfo::SafeBuffer {
423 public:
SafeBuffer()424 SafeBuffer()
425 : storage_(nullptr),
426 ptr_current_(nullptr),
427 ptr_end_(nullptr) {}
428
SafeBuffer(size_t size)429 explicit SafeBuffer(size_t size)
430 : storage_(new uint8_t[size]),
431 ptr_current_(storage_.get()),
432 ptr_end_(ptr_current_ + size) {}
433
434 // Reads an uint value and advances the current pointer.
435 template <typename T>
ReadUintAndAdvance(T * value)436 bool ReadUintAndAdvance(/*out*/ T* value) {
437 static_assert(std::is_unsigned<T>::value, "Type is not unsigned");
438 if (sizeof(T) > GetAvailableBytes()) {
439 return false;
440 }
441 *value = 0;
442 for (size_t i = 0; i < sizeof(T); i++) {
443 *value += ptr_current_[i] << (i * kBitsPerByte);
444 }
445 ptr_current_ += sizeof(T);
446 return true;
447 }
448
449 // Reads a length-prefixed string as `std::string_view` and advances the current pointer.
450 // The length is `uint16_t`.
ReadStringAndAdvance(std::string_view * value)451 bool ReadStringAndAdvance(/*out*/ std::string_view* value) {
452 uint16_t length;
453 if (!ReadUintAndAdvance(&length)) {
454 return false;
455 }
456 if (length > GetAvailableBytes()) {
457 return false;
458 }
459 const void* null_char = memchr(GetCurrentPtr(), 0, length);
460 if (null_char != nullptr) {
461 // Embedded nulls are invalid.
462 return false;
463 }
464 *value = std::string_view(reinterpret_cast<const char*>(GetCurrentPtr()), length);
465 Advance(length);
466 return true;
467 }
468
469 // Compares the given data with the content at the current pointer.
470 // If the contents are equal it advances the current pointer by data_size.
CompareAndAdvance(const uint8_t * data,size_t data_size)471 bool CompareAndAdvance(const uint8_t* data, size_t data_size) {
472 if (data_size > GetAvailableBytes()) {
473 return false;
474 }
475 if (memcmp(ptr_current_, data, data_size) == 0) {
476 ptr_current_ += data_size;
477 return true;
478 }
479 return false;
480 }
481
WriteAndAdvance(const void * data,size_t data_size)482 void WriteAndAdvance(const void* data, size_t data_size) {
483 DCHECK_LE(data_size, GetAvailableBytes());
484 memcpy(ptr_current_, data, data_size);
485 ptr_current_ += data_size;
486 }
487
488 template <typename T>
WriteUintAndAdvance(T value)489 void WriteUintAndAdvance(T value) {
490 static_assert(std::is_integral_v<T>);
491 WriteAndAdvance(&value, sizeof(value));
492 }
493
494 // Deflate a filled buffer. Replaces the internal buffer with a new one, also filled.
Deflate()495 bool Deflate() {
496 DCHECK_EQ(GetAvailableBytes(), 0u);
497 DCHECK_NE(Size(), 0u);
498 ArrayRef<const uint8_t> in_buffer(Get(), Size());
499 uint32_t output_size = 0;
500 std::unique_ptr<uint8_t[]> compressed_buffer = DeflateBuffer(in_buffer, &output_size);
501 if (compressed_buffer == nullptr) {
502 return false;
503 }
504 storage_ = std::move(compressed_buffer);
505 ptr_current_ = storage_.get() + output_size;
506 ptr_end_ = ptr_current_;
507 return true;
508 }
509
510 // Inflate an unread buffer. Replaces the internal buffer with a new one, also unread.
Inflate(size_t uncompressed_data_size)511 bool Inflate(size_t uncompressed_data_size) {
512 DCHECK(ptr_current_ == storage_.get());
513 DCHECK_NE(Size(), 0u);
514 ArrayRef<const uint8_t> in_buffer(Get(), Size());
515 SafeBuffer uncompressed_buffer(uncompressed_data_size);
516 ArrayRef<uint8_t> out_buffer(uncompressed_buffer.Get(), uncompressed_data_size);
517 int ret = InflateBuffer(in_buffer, out_buffer);
518 if (ret != Z_STREAM_END) {
519 return false;
520 }
521 Swap(uncompressed_buffer);
522 DCHECK(ptr_current_ == storage_.get());
523 return true;
524 }
525
526 // Advances current pointer by data_size.
Advance(size_t data_size)527 void Advance(size_t data_size) {
528 DCHECK_LE(data_size, GetAvailableBytes());
529 ptr_current_ += data_size;
530 }
531
532 // Returns the count of unread bytes.
GetAvailableBytes() const533 size_t GetAvailableBytes() const {
534 DCHECK_LE(static_cast<void*>(ptr_current_), static_cast<void*>(ptr_end_));
535 return (ptr_end_ - ptr_current_) * sizeof(*ptr_current_);
536 }
537
538 // Returns the current pointer.
GetCurrentPtr()539 uint8_t* GetCurrentPtr() {
540 return ptr_current_;
541 }
542
543 // Get the underlying raw buffer.
Get()544 uint8_t* Get() {
545 return storage_.get();
546 }
547
548 // Get the size of the raw buffer.
Size() const549 size_t Size() const {
550 return ptr_end_ - storage_.get();
551 }
552
Swap(SafeBuffer & other)553 void Swap(SafeBuffer& other) {
554 std::swap(storage_, other.storage_);
555 std::swap(ptr_current_, other.ptr_current_);
556 std::swap(ptr_end_, other.ptr_end_);
557 }
558
559 private:
560 std::unique_ptr<uint8_t[]> storage_;
561 uint8_t* ptr_current_;
562 uint8_t* ptr_end_;
563 };
564
ProfileCompilationInfo(ArenaPool * custom_arena_pool,bool for_boot_image)565 ProfileCompilationInfo::ProfileCompilationInfo(ArenaPool* custom_arena_pool, bool for_boot_image)
566 : default_arena_pool_(),
567 allocator_(custom_arena_pool),
568 info_(allocator_.Adapter(kArenaAllocProfile)),
569 profile_key_map_(std::less<const std::string_view>(), allocator_.Adapter(kArenaAllocProfile)),
570 extra_descriptors_(),
571 extra_descriptors_indexes_(ExtraDescriptorHash(&extra_descriptors_),
572 ExtraDescriptorEquals(&extra_descriptors_)) {
573 memcpy(version_,
574 for_boot_image ? kProfileVersionForBootImage : kProfileVersion,
575 kProfileVersionSize);
576 }
577
ProfileCompilationInfo(ArenaPool * custom_arena_pool)578 ProfileCompilationInfo::ProfileCompilationInfo(ArenaPool* custom_arena_pool)
579 : ProfileCompilationInfo(custom_arena_pool, /*for_boot_image=*/ false) { }
580
ProfileCompilationInfo()581 ProfileCompilationInfo::ProfileCompilationInfo()
582 : ProfileCompilationInfo(/*for_boot_image=*/ false) { }
583
ProfileCompilationInfo(bool for_boot_image)584 ProfileCompilationInfo::ProfileCompilationInfo(bool for_boot_image)
585 : ProfileCompilationInfo(&default_arena_pool_, for_boot_image) { }
586
~ProfileCompilationInfo()587 ProfileCompilationInfo::~ProfileCompilationInfo() {
588 VLOG(profiler) << Dumpable<MemStats>(allocator_.GetMemStats());
589 }
590
AddClass(const dex::TypeIndex & type_idx)591 void ProfileCompilationInfo::DexPcData::AddClass(const dex::TypeIndex& type_idx) {
592 if (is_megamorphic || is_missing_types) {
593 return;
594 }
595
596 // Perform an explicit lookup for the type instead of directly emplacing the
597 // element. We do this because emplace() allocates the node before doing the
598 // lookup and if it then finds an identical element, it shall deallocate the
599 // node. For Arena allocations, that's essentially a leak.
600 auto lb = classes.lower_bound(type_idx);
601 if (lb != classes.end() && *lb == type_idx) {
602 // The type index exists.
603 return;
604 }
605
606 // Check if the adding the type will cause the cache to become megamorphic.
607 if (classes.size() + 1 >= ProfileCompilationInfo::kIndividualInlineCacheSize) {
608 is_megamorphic = true;
609 classes.clear();
610 return;
611 }
612
613 // The type does not exist and the inline cache will not be megamorphic.
614 classes.emplace_hint(lb, type_idx);
615 }
616
617 // Transform the actual dex location into a key used to index the dex file in the profile.
618 // See ProfileCompilationInfo#GetProfileDexFileBaseKey as well.
GetProfileDexFileAugmentedKey(const std::string & dex_location,const ProfileSampleAnnotation & annotation)619 std::string ProfileCompilationInfo::GetProfileDexFileAugmentedKey(
620 const std::string& dex_location,
621 const ProfileSampleAnnotation& annotation) {
622 std::string base_key = GetProfileDexFileBaseKey(dex_location);
623 return annotation == ProfileSampleAnnotation::kNone
624 ? base_key
625 : base_key + kSampleMetadataSeparator + annotation.GetOriginPackageName();;
626 }
627
628 // Transform the actual dex location into a base profile key (represented as relative paths).
629 // Note: this is OK because we don't store profiles of different apps into the same file.
630 // Apps with split apks don't cause trouble because each split has a different name and will not
631 // collide with other entries.
GetProfileDexFileBaseKeyView(std::string_view dex_location)632 std::string_view ProfileCompilationInfo::GetProfileDexFileBaseKeyView(
633 std::string_view dex_location) {
634 DCHECK(!dex_location.empty());
635 size_t last_sep_index = dex_location.find_last_of('/');
636 if (last_sep_index == std::string::npos) {
637 return dex_location;
638 } else {
639 DCHECK(last_sep_index < dex_location.size());
640 return dex_location.substr(last_sep_index + 1);
641 }
642 }
643
GetProfileDexFileBaseKey(const std::string & dex_location)644 std::string ProfileCompilationInfo::GetProfileDexFileBaseKey(const std::string& dex_location) {
645 // Note: Conversions between std::string and std::string_view.
646 return std::string(GetProfileDexFileBaseKeyView(dex_location));
647 }
648
GetBaseKeyViewFromAugmentedKey(std::string_view profile_key)649 std::string_view ProfileCompilationInfo::GetBaseKeyViewFromAugmentedKey(
650 std::string_view profile_key) {
651 size_t pos = profile_key.rfind(kSampleMetadataSeparator);
652 return (pos == std::string::npos) ? profile_key : profile_key.substr(0, pos);
653 }
654
GetBaseKeyFromAugmentedKey(const std::string & profile_key)655 std::string ProfileCompilationInfo::GetBaseKeyFromAugmentedKey(
656 const std::string& profile_key) {
657 // Note: Conversions between std::string and std::string_view.
658 return std::string(GetBaseKeyViewFromAugmentedKey(profile_key));
659 }
660
MigrateAnnotationInfo(const std::string & base_key,const std::string & augmented_key)661 std::string ProfileCompilationInfo::MigrateAnnotationInfo(
662 const std::string& base_key,
663 const std::string& augmented_key) {
664 size_t pos = augmented_key.rfind(kSampleMetadataSeparator);
665 return (pos == std::string::npos)
666 ? base_key
667 : base_key + augmented_key.substr(pos);
668 }
669
GetAnnotationFromKey(const std::string & augmented_key)670 ProfileCompilationInfo::ProfileSampleAnnotation ProfileCompilationInfo::GetAnnotationFromKey(
671 const std::string& augmented_key) {
672 size_t pos = augmented_key.rfind(kSampleMetadataSeparator);
673 return (pos == std::string::npos)
674 ? ProfileSampleAnnotation::kNone
675 : ProfileSampleAnnotation(augmented_key.substr(pos + 1));
676 }
677
AddMethods(const std::vector<ProfileMethodInfo> & methods,MethodHotness::Flag flags,const ProfileSampleAnnotation & annotation,bool is_test)678 bool ProfileCompilationInfo::AddMethods(const std::vector<ProfileMethodInfo>& methods,
679 MethodHotness::Flag flags,
680 const ProfileSampleAnnotation& annotation,
681 bool is_test) {
682 for (const ProfileMethodInfo& method : methods) {
683 if (!AddMethod(method, flags, annotation, is_test)) {
684 return false;
685 }
686 }
687 return true;
688 }
689
FindOrCreateTypeIndex(const DexFile & dex_file,TypeReference class_ref)690 dex::TypeIndex ProfileCompilationInfo::FindOrCreateTypeIndex(const DexFile& dex_file,
691 TypeReference class_ref) {
692 DCHECK(class_ref.dex_file != nullptr);
693 DCHECK_LT(class_ref.TypeIndex().index_, class_ref.dex_file->NumTypeIds());
694 if (class_ref.dex_file == &dex_file) {
695 // We can use the type index from the `class_ref` as it's a valid index in the `dex_file`.
696 return class_ref.TypeIndex();
697 }
698 // Try to find a `TypeId` in the method's dex file.
699 std::string_view descriptor = class_ref.dex_file->GetTypeDescriptorView(class_ref.TypeIndex());
700 return FindOrCreateTypeIndex(dex_file, descriptor);
701 }
702
FindOrCreateTypeIndex(const DexFile & dex_file,std::string_view descriptor)703 dex::TypeIndex ProfileCompilationInfo::FindOrCreateTypeIndex(const DexFile& dex_file,
704 std::string_view descriptor) {
705 const dex::TypeId* type_id = dex_file.FindTypeId(descriptor);
706 if (type_id != nullptr) {
707 return dex_file.GetIndexForTypeId(*type_id);
708 }
709 // Try to find an existing extra descriptor.
710 uint32_t num_type_ids = dex_file.NumTypeIds();
711 uint32_t max_artificial_ids = DexFile::kDexNoIndex16 - num_type_ids;
712 // Check descriptor length for "extra descriptor". We are using `uint16_t` as prefix.
713 if (UNLIKELY(descriptor.size() > kMaxExtraDescriptorLength)) {
714 return dex::TypeIndex(); // Invalid.
715 }
716 auto it = extra_descriptors_indexes_.find(descriptor);
717 if (it != extra_descriptors_indexes_.end()) {
718 return (*it < max_artificial_ids) ? dex::TypeIndex(num_type_ids + *it) : dex::TypeIndex();
719 }
720 // Check if inserting the extra descriptor yields a valid artificial type index.
721 if (UNLIKELY(extra_descriptors_.size() >= max_artificial_ids)) {
722 return dex::TypeIndex(); // Invalid.
723 }
724 // Add the descriptor to extra descriptors and return the artificial type index.
725 ExtraDescriptorIndex new_extra_descriptor_index = AddExtraDescriptor(descriptor);
726 DCHECK_LT(new_extra_descriptor_index, max_artificial_ids);
727 return dex::TypeIndex(num_type_ids + new_extra_descriptor_index);
728 }
729
AddClass(const DexFile & dex_file,std::string_view descriptor,const ProfileSampleAnnotation & annotation)730 bool ProfileCompilationInfo::AddClass(const DexFile& dex_file,
731 std::string_view descriptor,
732 const ProfileSampleAnnotation& annotation) {
733 DexFileData* const data = GetOrAddDexFileData(&dex_file, annotation);
734 if (data == nullptr) { // checksum mismatch
735 return false;
736 }
737 dex::TypeIndex type_index = FindOrCreateTypeIndex(dex_file, descriptor);
738 if (!type_index.IsValid()) {
739 return false;
740 }
741 data->class_set.insert(type_index);
742 return true;
743 }
744
MergeWith(const std::string & filename)745 bool ProfileCompilationInfo::MergeWith(const std::string& filename) {
746 std::string error;
747 #ifdef _WIN32
748 int flags = O_RDONLY;
749 #else
750 int flags = O_RDONLY | O_NOFOLLOW | O_CLOEXEC;
751 #endif
752 ScopedFlock profile_file =
753 LockedFile::Open(filename.c_str(), flags, /*block=*/false, &error);
754
755 if (profile_file.get() == nullptr) {
756 LOG(WARNING) << "Couldn't lock the profile file " << filename << ": " << error;
757 return false;
758 }
759
760 int fd = profile_file->Fd();
761
762 ProfileLoadStatus status = LoadInternal(fd, &error);
763 if (status == ProfileLoadStatus::kSuccess) {
764 return true;
765 }
766
767 LOG(WARNING) << "Could not load profile data from file " << filename << ": " << error;
768 return false;
769 }
770
Load(const std::string & filename,bool clear_if_invalid)771 bool ProfileCompilationInfo::Load(const std::string& filename, bool clear_if_invalid) {
772 ScopedTrace trace(__PRETTY_FUNCTION__);
773 std::string error;
774
775 if (!IsEmpty()) {
776 return false;
777 }
778
779 #ifdef _WIN32
780 int flags = O_RDWR;
781 #else
782 int flags = O_RDWR | O_NOFOLLOW | O_CLOEXEC;
783 #endif
784 // There's no need to fsync profile data right away. We get many chances
785 // to write it again in case something goes wrong. We can rely on a simple
786 // close(), no sync, and let to the kernel decide when to write to disk.
787 ScopedFlock profile_file =
788 LockedFile::Open(filename.c_str(), flags, /*block=*/false, &error);
789
790 if (profile_file.get() == nullptr) {
791 if (clear_if_invalid && errno == ENOENT) {
792 return true;
793 }
794 LOG(WARNING) << "Couldn't lock the profile file " << filename << ": " << error;
795 return false;
796 }
797
798 int fd = profile_file->Fd();
799
800 ProfileLoadStatus status = LoadInternal(fd, &error);
801 if (status == ProfileLoadStatus::kSuccess) {
802 return true;
803 }
804
805 if (clear_if_invalid &&
806 ((status == ProfileLoadStatus::kBadMagic) ||
807 (status == ProfileLoadStatus::kVersionMismatch) ||
808 (status == ProfileLoadStatus::kBadData))) {
809 LOG(WARNING) << "Clearing bad or obsolete profile data from file "
810 << filename << ": " << error;
811 // When ART Service is enabled, this is the only place where we mutate a profile in place.
812 // TODO(jiakaiz): Get rid of this.
813 if (profile_file->ClearContent()) {
814 return true;
815 } else {
816 PLOG(WARNING) << "Could not clear profile file: " << filename;
817 return false;
818 }
819 }
820
821 LOG(WARNING) << "Could not load profile data from file " << filename << ": " << error;
822 return false;
823 }
824
Save(const std::string & filename,uint64_t * bytes_written)825 bool ProfileCompilationInfo::Save(const std::string& filename, uint64_t* bytes_written) {
826 ScopedTrace trace(__PRETTY_FUNCTION__);
827
828 #ifndef ART_TARGET_ANDROID
829 return SaveFallback(filename, bytes_written);
830 #else
831 // Prior to U, SELinux policy doesn't allow apps to create profile files.
832 // Additionally, when installd is being used for dexopt, it acquires a flock when working on a
833 // profile. It's unclear to us whether the flock means that the file at the fd shouldn't change or
834 // that the file at the path shouldn't change, especially when the installd code is modified by
835 // partners. Therefore, we fall back to using a flock as well just to be safe.
836 if (!android::modules::sdklevel::IsAtLeastU() ||
837 !android::base::GetBoolProperty("dalvik.vm.useartservice", /*default_value=*/false)) {
838 return SaveFallback(filename, bytes_written);
839 }
840
841 std::string tmp_filename = filename + ".XXXXXX.tmp";
842 // mkstemps creates the file with permissions 0600, which is the desired permissions, so there's
843 // no need to chmod.
844 android::base::unique_fd fd(mkostemps(tmp_filename.data(), /*suffixlen=*/4, O_CLOEXEC));
845 if (fd.get() < 0) {
846 PLOG(WARNING) << "Failed to create temp profile file for " << filename;
847 return false;
848 }
849
850 // In case anything goes wrong.
851 auto remove_tmp_file = android::base::make_scope_guard([&]() {
852 if (unlink(tmp_filename.c_str()) != 0) {
853 PLOG(WARNING) << "Failed to remove temp profile file " << tmp_filename;
854 }
855 });
856
857 bool result = Save(fd.get());
858 if (!result) {
859 VLOG(profiler) << "Failed to save profile info to temp profile file " << tmp_filename;
860 return false;
861 }
862
863 fd.reset();
864
865 // Move the temp profile file to the final location.
866 if (rename(tmp_filename.c_str(), filename.c_str()) != 0) {
867 PLOG(WARNING) << "Failed to commit profile file " << filename;
868 return false;
869 }
870
871 remove_tmp_file.Disable();
872
873 int64_t size = OS::GetFileSizeBytes(filename.c_str());
874 if (size != -1) {
875 VLOG(profiler) << "Successfully saved profile info to " << filename << " Size: " << size;
876 if (bytes_written != nullptr) {
877 *bytes_written = static_cast<uint64_t>(size);
878 }
879 } else {
880 VLOG(profiler) << "Saved profile info to " << filename
881 << " but failed to get size: " << strerror(errno);
882 }
883
884 return true;
885 #endif
886 }
887
SaveFallback(const std::string & filename,uint64_t * bytes_written)888 bool ProfileCompilationInfo::SaveFallback(const std::string& filename, uint64_t* bytes_written) {
889 std::string error;
890 #ifdef _WIN32
891 int flags = O_WRONLY | O_CREAT;
892 #else
893 int flags = O_WRONLY | O_NOFOLLOW | O_CLOEXEC | O_CREAT;
894 #endif
895 // There's no need to fsync profile data right away. We get many chances
896 // to write it again in case something goes wrong. We can rely on a simple
897 // close(), no sync, and let to the kernel decide when to write to disk.
898 ScopedFlock profile_file =
899 LockedFile::Open(filename.c_str(), flags, /*block=*/false, &error);
900 if (profile_file.get() == nullptr) {
901 LOG(WARNING) << "Couldn't lock the profile file " << filename << ": " << error;
902 return false;
903 }
904
905 int fd = profile_file->Fd();
906
907 // We need to clear the data because we don't support appending to the profiles yet.
908 if (!profile_file->ClearContent()) {
909 PLOG(WARNING) << "Could not clear profile file: " << filename;
910 return false;
911 }
912
913 // This doesn't need locking because we are trying to lock the file for exclusive
914 // access and fail immediately if we can't.
915 bool result = Save(fd);
916 if (result) {
917 int64_t size = OS::GetFileSizeBytes(filename.c_str());
918 if (size != -1) {
919 VLOG(profiler)
920 << "Successfully saved profile info to " << filename << " Size: "
921 << size;
922 if (bytes_written != nullptr) {
923 *bytes_written = static_cast<uint64_t>(size);
924 }
925 } else {
926 VLOG(profiler) << "Saved profile info to " << filename
927 << " but failed to get size: " << strerror(errno);
928 }
929 } else {
930 VLOG(profiler) << "Failed to save profile info to " << filename;
931 }
932 return result;
933 }
934
935 // Returns true if all the bytes were successfully written to the file descriptor.
WriteBuffer(int fd,const void * buffer,size_t byte_count)936 static bool WriteBuffer(int fd, const void* buffer, size_t byte_count) {
937 while (byte_count > 0) {
938 int bytes_written = TEMP_FAILURE_RETRY(write(fd, buffer, byte_count));
939 if (bytes_written == -1) {
940 return false;
941 }
942 byte_count -= bytes_written; // Reduce the number of remaining bytes.
943 reinterpret_cast<const uint8_t*&>(buffer) += bytes_written; // Move the buffer forward.
944 }
945 return true;
946 }
947
948 /**
949 * Serialization format:
950 *
951 * The file starts with a header and section information:
952 * FileHeader
953 * FileSectionInfo[]
954 * The first FileSectionInfo must be for the DexFiles section.
955 *
956 * The rest of the file is allowed to contain different sections in any order,
957 * at arbitrary offsets, with any gaps betweeen them and each section can be
958 * either plaintext or separately zipped. However, we're writing sections
959 * without any gaps with the following order and compression:
960 * DexFiles - mandatory, plaintext
961 * ExtraDescriptors - optional, zipped
962 * Classes - optional, zipped
963 * Methods - optional, zipped
964 * AggregationCounts - optional, zipped, server-side
965 *
966 * DexFiles:
967 * number_of_dex_files
968 * (checksum,num_type_ids,num_method_ids,profile_key)[number_of_dex_files]
969 * where `profile_key` is a length-prefixed string, the length is `uint16_t`.
970 *
971 * ExtraDescriptors:
972 * number_of_extra_descriptors
973 * (extra_descriptor)[number_of_extra_descriptors]
974 * where `extra_descriptor` is a length-prefixed string, the length is `uint16_t`.
975 *
976 * Classes contains records for any number of dex files, each consisting of:
977 * profile_index // Index of the dex file in DexFiles section.
978 * number_of_classes
979 * type_index_diff[number_of_classes]
980 * where instead of storing plain sorted type indexes, we store their differences
981 * as smaller numbers are likely to compress better.
982 *
983 * Methods contains records for any number of dex files, each consisting of:
984 * profile_index // Index of the dex file in DexFiles section.
985 * following_data_size // For easy skipping of remaining data when dex file is filtered out.
986 * method_flags
987 * bitmap_data
988 * method_encoding[] // Until the size indicated by `following_data_size`.
989 * where `method_flags` is a union of flags recorded for methods in the referenced dex file,
990 * `bitmap_data` contains `num_method_ids` bits for each bit set in `method_flags` other
991 * than "hot" (the size of `bitmap_data` is rounded up to whole bytes) and `method_encoding[]`
992 * contains data for hot methods. The `method_encoding` is:
993 * method_index_diff
994 * number_of_inline_caches
995 * inline_cache_encoding[number_of_inline_caches]
996 * where differences in method indexes are used for better compression,
997 * and the `inline_cache_encoding` is
998 * dex_pc
999 * (M|dex_map_size)
1000 * type_index_diff[dex_map_size]
1001 * where `M` stands for special encodings indicating missing types (kIsMissingTypesEncoding)
1002 * or memamorphic call (kIsMegamorphicEncoding) which both imply `dex_map_size == 0`.
1003 **/
Save(int fd)1004 bool ProfileCompilationInfo::Save(int fd) {
1005 uint64_t start = NanoTime();
1006 ScopedTrace trace(__PRETTY_FUNCTION__);
1007 DCHECK_GE(fd, 0);
1008
1009 // Collect uncompressed section sizes.
1010 // Use `uint64_t` and assume this cannot overflow as we would have run out of memory.
1011 uint64_t extra_descriptors_section_size = 0u;
1012 if (!extra_descriptors_.empty()) {
1013 extra_descriptors_section_size += sizeof(uint16_t); // Number of descriptors.
1014 for (const std::string& descriptor : extra_descriptors_) {
1015 // Length-prefixed string, the length is `uint16_t`.
1016 extra_descriptors_section_size += sizeof(uint16_t) + descriptor.size();
1017 }
1018 }
1019 uint64_t dex_files_section_size = sizeof(ProfileIndexType); // Number of dex files.
1020 uint64_t classes_section_size = 0u;
1021 uint64_t methods_section_size = 0u;
1022 DCHECK_LE(info_.size(), MaxProfileIndex());
1023 for (const std::unique_ptr<DexFileData>& dex_data : info_) {
1024 if (dex_data->profile_key.size() > kMaxDexFileKeyLength) {
1025 LOG(WARNING) << "DexFileKey exceeds allocated limit";
1026 return false;
1027 }
1028 dex_files_section_size +=
1029 3 * sizeof(uint32_t) + // Checksum, num_type_ids, num_method_ids.
1030 // Length-prefixed string, the length is `uint16_t`.
1031 sizeof(uint16_t) + dex_data->profile_key.size();
1032 classes_section_size += dex_data->ClassesDataSize();
1033 methods_section_size += dex_data->MethodsDataSize();
1034 }
1035
1036 const uint32_t file_section_count =
1037 /* dex files */ 1u +
1038 /* extra descriptors */ (extra_descriptors_section_size != 0u ? 1u : 0u) +
1039 /* classes */ (classes_section_size != 0u ? 1u : 0u) +
1040 /* methods */ (methods_section_size != 0u ? 1u : 0u);
1041 uint64_t header_and_infos_size =
1042 sizeof(FileHeader) + file_section_count * sizeof(FileSectionInfo);
1043
1044 // Check size limit. Allow large profiles for non target builds for the case
1045 // where we are merging many profiles to generate a boot image profile.
1046 uint64_t total_uncompressed_size =
1047 header_and_infos_size +
1048 dex_files_section_size +
1049 extra_descriptors_section_size +
1050 classes_section_size +
1051 methods_section_size;
1052 VLOG(profiler) << "Required capacity: " << total_uncompressed_size << " bytes.";
1053 if (total_uncompressed_size > GetSizeErrorThresholdBytes()) {
1054 LOG(WARNING) << "Profile data size exceeds "
1055 << GetSizeErrorThresholdBytes()
1056 << " bytes. Profile will not be written to disk."
1057 << " It requires " << total_uncompressed_size << " bytes.";
1058 return false;
1059 }
1060
1061 // Start with an invalid file header and section infos.
1062 DCHECK_EQ(lseek(fd, 0, SEEK_CUR), 0);
1063 constexpr uint32_t kMaxNumberOfSections = enum_cast<uint32_t>(FileSectionType::kNumberOfSections);
1064 constexpr uint64_t kMaxHeaderAndInfosSize =
1065 sizeof(FileHeader) + kMaxNumberOfSections * sizeof(FileSectionInfo);
1066 DCHECK_LE(header_and_infos_size, kMaxHeaderAndInfosSize);
1067 std::array<uint8_t, kMaxHeaderAndInfosSize> placeholder;
1068 memset(placeholder.data(), 0, header_and_infos_size);
1069 if (!WriteBuffer(fd, placeholder.data(), header_and_infos_size)) {
1070 return false;
1071 }
1072
1073 std::array<FileSectionInfo, kMaxNumberOfSections> section_infos;
1074 size_t section_index = 0u;
1075 uint32_t file_offset = header_and_infos_size;
1076 auto add_section_info = [&](FileSectionType type, uint32_t file_size, uint32_t inflated_size) {
1077 DCHECK_LT(section_index, section_infos.size());
1078 section_infos[section_index] = FileSectionInfo(type, file_offset, file_size, inflated_size);
1079 file_offset += file_size;
1080 section_index += 1u;
1081 };
1082
1083 // Write the dex files section.
1084 {
1085 SafeBuffer buffer(dex_files_section_size);
1086 buffer.WriteUintAndAdvance(dchecked_integral_cast<ProfileIndexType>(info_.size()));
1087 for (const std::unique_ptr<DexFileData>& dex_data : info_) {
1088 buffer.WriteUintAndAdvance(dex_data->checksum);
1089 buffer.WriteUintAndAdvance(dex_data->num_type_ids);
1090 buffer.WriteUintAndAdvance(dex_data->num_method_ids);
1091 buffer.WriteUintAndAdvance(dchecked_integral_cast<uint16_t>(dex_data->profile_key.size()));
1092 buffer.WriteAndAdvance(dex_data->profile_key.c_str(), dex_data->profile_key.size());
1093 }
1094 DCHECK_EQ(buffer.GetAvailableBytes(), 0u);
1095 // Write the dex files section uncompressed.
1096 if (!WriteBuffer(fd, buffer.Get(), dex_files_section_size)) {
1097 return false;
1098 }
1099 add_section_info(FileSectionType::kDexFiles, dex_files_section_size, /*inflated_size=*/ 0u);
1100 }
1101
1102 // Write the extra descriptors section.
1103 if (extra_descriptors_section_size != 0u) {
1104 SafeBuffer buffer(extra_descriptors_section_size);
1105 buffer.WriteUintAndAdvance(dchecked_integral_cast<uint16_t>(extra_descriptors_.size()));
1106 for (const std::string& descriptor : extra_descriptors_) {
1107 buffer.WriteUintAndAdvance(dchecked_integral_cast<uint16_t>(descriptor.size()));
1108 buffer.WriteAndAdvance(descriptor.c_str(), descriptor.size());
1109 }
1110 if (!buffer.Deflate()) {
1111 return false;
1112 }
1113 if (!WriteBuffer(fd, buffer.Get(), buffer.Size())) {
1114 return false;
1115 }
1116 add_section_info(
1117 FileSectionType::kExtraDescriptors, buffer.Size(), extra_descriptors_section_size);
1118 }
1119
1120 // Write the classes section.
1121 if (classes_section_size != 0u) {
1122 SafeBuffer buffer(classes_section_size);
1123 for (const std::unique_ptr<DexFileData>& dex_data : info_) {
1124 dex_data->WriteClasses(buffer);
1125 }
1126 if (!buffer.Deflate()) {
1127 return false;
1128 }
1129 if (!WriteBuffer(fd, buffer.Get(), buffer.Size())) {
1130 return false;
1131 }
1132 add_section_info(FileSectionType::kClasses, buffer.Size(), classes_section_size);
1133 }
1134
1135 // Write the methods section.
1136 if (methods_section_size != 0u) {
1137 SafeBuffer buffer(methods_section_size);
1138 for (const std::unique_ptr<DexFileData>& dex_data : info_) {
1139 dex_data->WriteMethods(buffer);
1140 }
1141 if (!buffer.Deflate()) {
1142 return false;
1143 }
1144 if (!WriteBuffer(fd, buffer.Get(), buffer.Size())) {
1145 return false;
1146 }
1147 add_section_info(FileSectionType::kMethods, buffer.Size(), methods_section_size);
1148 }
1149
1150 if (file_offset > GetSizeWarningThresholdBytes()) {
1151 LOG(WARNING) << "Profile data size exceeds "
1152 << GetSizeWarningThresholdBytes()
1153 << " It has " << file_offset << " bytes";
1154 }
1155
1156 // Write section infos.
1157 if (lseek64(fd, sizeof(FileHeader), SEEK_SET) != sizeof(FileHeader)) {
1158 return false;
1159 }
1160 SafeBuffer section_infos_buffer(section_index * 4u * sizeof(uint32_t));
1161 for (size_t i = 0; i != section_index; ++i) {
1162 const FileSectionInfo& info = section_infos[i];
1163 section_infos_buffer.WriteUintAndAdvance(enum_cast<uint32_t>(info.GetType()));
1164 section_infos_buffer.WriteUintAndAdvance(info.GetFileOffset());
1165 section_infos_buffer.WriteUintAndAdvance(info.GetFileSize());
1166 section_infos_buffer.WriteUintAndAdvance(info.GetInflatedSize());
1167 }
1168 DCHECK_EQ(section_infos_buffer.GetAvailableBytes(), 0u);
1169 if (!WriteBuffer(fd, section_infos_buffer.Get(), section_infos_buffer.Size())) {
1170 return false;
1171 }
1172
1173 // Write header.
1174 FileHeader header(version_, section_index);
1175 if (lseek(fd, 0, SEEK_SET) != 0) {
1176 return false;
1177 }
1178 if (!WriteBuffer(fd, &header, sizeof(FileHeader))) {
1179 return false;
1180 }
1181
1182 uint64_t total_time = NanoTime() - start;
1183 VLOG(profiler) << "Compressed from "
1184 << std::to_string(total_uncompressed_size)
1185 << " to "
1186 << std::to_string(file_offset);
1187 VLOG(profiler) << "Time to save profile: " << std::to_string(total_time);
1188 return true;
1189 }
1190
GetOrAddDexFileData(const std::string & profile_key,uint32_t checksum,uint32_t num_type_ids,uint32_t num_method_ids)1191 ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::GetOrAddDexFileData(
1192 const std::string& profile_key,
1193 uint32_t checksum,
1194 uint32_t num_type_ids,
1195 uint32_t num_method_ids) {
1196 DCHECK_EQ(profile_key_map_.size(), info_.size());
1197 auto profile_index_it = profile_key_map_.lower_bound(profile_key);
1198 if (profile_index_it == profile_key_map_.end() || profile_index_it->first != profile_key) {
1199 // We did not find the key. Create a new DexFileData if we did not reach the limit.
1200 DCHECK_LE(profile_key_map_.size(), MaxProfileIndex());
1201 if (profile_key_map_.size() == MaxProfileIndex()) {
1202 // Allow only a limited number dex files to be profiled. This allows us to save bytes
1203 // when encoding. For regular profiles this 2^8, and for boot profiles is 2^16
1204 // (well above what we expect for normal applications).
1205 LOG(ERROR) << "Exceeded the maximum number of dex file. Something went wrong";
1206 return nullptr;
1207 }
1208 ProfileIndexType new_profile_index = dchecked_integral_cast<ProfileIndexType>(info_.size());
1209 std::unique_ptr<DexFileData> dex_file_data(new (&allocator_) DexFileData(
1210 &allocator_,
1211 profile_key,
1212 checksum,
1213 new_profile_index,
1214 num_type_ids,
1215 num_method_ids,
1216 IsForBootImage()));
1217 // Record the new data in `profile_key_map_` and `info_`.
1218 std::string_view new_key(dex_file_data->profile_key);
1219 profile_index_it = profile_key_map_.PutBefore(profile_index_it, new_key, new_profile_index);
1220 info_.push_back(std::move(dex_file_data));
1221 DCHECK_EQ(profile_key_map_.size(), info_.size());
1222 }
1223
1224 ProfileIndexType profile_index = profile_index_it->second;
1225 DexFileData* result = info_[profile_index].get();
1226
1227 // Check that the checksum matches.
1228 // This may different if for example the dex file was updated and we had a record of the old one.
1229 if (result->checksum != checksum) {
1230 LOG(WARNING) << "Checksum mismatch for dex " << profile_key;
1231 return nullptr;
1232 }
1233
1234 // DCHECK that profile info map key is consistent with the one stored in the dex file data.
1235 // This should always be the case since since the cache map is managed by ProfileCompilationInfo.
1236 DCHECK_EQ(profile_key, result->profile_key);
1237 DCHECK_EQ(profile_index, result->profile_index);
1238
1239 if (num_type_ids != result->num_type_ids || num_method_ids != result->num_method_ids) {
1240 // This should not happen... added to help investigating b/65812889.
1241 LOG(ERROR) << "num_type_ids or num_method_ids mismatch for dex " << profile_key
1242 << ", types: expected=" << num_type_ids << " v. actual=" << result->num_type_ids
1243 << ", methods: expected=" << num_method_ids << " actual=" << result->num_method_ids;
1244 return nullptr;
1245 }
1246
1247 return result;
1248 }
1249
FindDexData(const std::string & profile_key,uint32_t checksum,bool verify_checksum) const1250 const ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::FindDexData(
1251 const std::string& profile_key,
1252 uint32_t checksum,
1253 bool verify_checksum) const {
1254 const auto profile_index_it = profile_key_map_.find(profile_key);
1255 if (profile_index_it == profile_key_map_.end()) {
1256 return nullptr;
1257 }
1258
1259 ProfileIndexType profile_index = profile_index_it->second;
1260 const DexFileData* result = info_[profile_index].get();
1261 if (verify_checksum && !ChecksumMatch(result->checksum, checksum)) {
1262 return nullptr;
1263 }
1264 DCHECK_EQ(profile_key, result->profile_key);
1265 DCHECK_EQ(profile_index, result->profile_index);
1266 return result;
1267 }
1268
FindDexDataUsingAnnotations(const DexFile * dex_file,const ProfileSampleAnnotation & annotation) const1269 const ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::FindDexDataUsingAnnotations(
1270 const DexFile* dex_file,
1271 const ProfileSampleAnnotation& annotation) const {
1272 if (annotation == ProfileSampleAnnotation::kNone) {
1273 std::string_view profile_key = GetProfileDexFileBaseKeyView(dex_file->GetLocation());
1274 for (const std::unique_ptr<DexFileData>& dex_data : info_) {
1275 if (profile_key == GetBaseKeyViewFromAugmentedKey(dex_data->profile_key)) {
1276 if (!ChecksumMatch(dex_data->checksum, dex_file->GetLocationChecksum())) {
1277 return nullptr;
1278 }
1279 return dex_data.get();
1280 }
1281 }
1282 } else {
1283 std::string profile_key = GetProfileDexFileAugmentedKey(dex_file->GetLocation(), annotation);
1284 return FindDexData(profile_key, dex_file->GetLocationChecksum());
1285 }
1286
1287 return nullptr;
1288 }
1289
FindAllDexData(const DexFile * dex_file,std::vector<const ProfileCompilationInfo::DexFileData * > * result) const1290 void ProfileCompilationInfo::FindAllDexData(
1291 const DexFile* dex_file,
1292 /*out*/ std::vector<const ProfileCompilationInfo::DexFileData*>* result) const {
1293 std::string_view profile_key = GetProfileDexFileBaseKeyView(dex_file->GetLocation());
1294 for (const std::unique_ptr<DexFileData>& dex_data : info_) {
1295 if (profile_key == GetBaseKeyViewFromAugmentedKey(dex_data->profile_key)) {
1296 if (ChecksumMatch(dex_data->checksum, dex_file->GetLocationChecksum())) {
1297 result->push_back(dex_data.get());
1298 }
1299 }
1300 }
1301 }
1302
AddExtraDescriptor(std::string_view extra_descriptor)1303 ProfileCompilationInfo::ExtraDescriptorIndex ProfileCompilationInfo::AddExtraDescriptor(
1304 std::string_view extra_descriptor) {
1305 DCHECK_LE(extra_descriptor.size(), kMaxExtraDescriptorLength);
1306 DCHECK(extra_descriptors_indexes_.find(extra_descriptor) == extra_descriptors_indexes_.end());
1307 ExtraDescriptorIndex new_extra_descriptor_index = extra_descriptors_.size();
1308 DCHECK_LE(new_extra_descriptor_index, kMaxExtraDescriptors);
1309 if (UNLIKELY(new_extra_descriptor_index == kMaxExtraDescriptors)) {
1310 return kMaxExtraDescriptors; // Cannot add another extra descriptor.
1311 }
1312 // Add the extra descriptor and record the new index.
1313 extra_descriptors_.emplace_back(extra_descriptor);
1314 extra_descriptors_indexes_.insert(new_extra_descriptor_index);
1315 return new_extra_descriptor_index;
1316 }
1317
AddMethod(const ProfileMethodInfo & pmi,MethodHotness::Flag flags,const ProfileSampleAnnotation & annotation,bool is_test)1318 bool ProfileCompilationInfo::AddMethod(const ProfileMethodInfo& pmi,
1319 MethodHotness::Flag flags,
1320 const ProfileSampleAnnotation& annotation,
1321 bool is_test) {
1322 DexFileData* const data = GetOrAddDexFileData(pmi.ref.dex_file, annotation);
1323 if (data == nullptr) { // checksum mismatch
1324 return false;
1325 }
1326 if (!data->AddMethod(flags, pmi.ref.index)) {
1327 return false;
1328 }
1329 if ((flags & MethodHotness::kFlagHot) == 0) {
1330 // The method is not hot, do not add inline caches.
1331 return true;
1332 }
1333
1334 // Add inline caches.
1335 InlineCacheMap* inline_cache = data->FindOrAddHotMethod(pmi.ref.index);
1336 DCHECK(inline_cache != nullptr);
1337
1338 const dex::MethodId& mid = pmi.ref.GetMethodId();
1339 const DexFile& dex_file = *pmi.ref.dex_file;
1340 const dex::ClassDef* class_def = dex_file.FindClassDef(mid.class_idx_);
1341 // If `is_test` is true, we don't try to look at whether dex_pc fit in the
1342 // code item of that method.
1343 uint32_t dex_pc_max = 0u;
1344 if (is_test) {
1345 dex_pc_max = std::numeric_limits<uint32_t>::max();
1346 } else {
1347 if (class_def == nullptr || dex_file.GetClassData(*class_def) == nullptr) {
1348 return true;
1349 }
1350 std::optional<uint32_t> offset = dex_file.GetCodeItemOffset(*class_def, pmi.ref.index);
1351 if (!offset.has_value()) {
1352 return true;
1353 }
1354 CodeItemInstructionAccessor accessor(dex_file, dex_file.GetCodeItem(offset.value()));
1355 dex_pc_max = accessor.InsnsSizeInCodeUnits();
1356 }
1357
1358 for (const ProfileMethodInfo::ProfileInlineCache& cache : pmi.inline_caches) {
1359 if (cache.dex_pc >= std::numeric_limits<uint16_t>::max()) {
1360 // Discard entries that don't fit the encoding. This should only apply to
1361 // inlined inline caches. See also `HInliner::GetInlineCacheAOT`.
1362 continue;
1363 }
1364 if (cache.dex_pc >= dex_pc_max) {
1365 // Discard entries for inlined inline caches. We don't support them in
1366 // profiles yet.
1367 continue;
1368 }
1369 if (cache.is_missing_types) {
1370 FindOrAddDexPc(inline_cache, cache.dex_pc)->SetIsMissingTypes();
1371 continue;
1372 }
1373 if (cache.is_megamorphic) {
1374 FindOrAddDexPc(inline_cache, cache.dex_pc)->SetIsMegamorphic();
1375 continue;
1376 }
1377 for (const TypeReference& class_ref : cache.classes) {
1378 DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, cache.dex_pc);
1379 if (dex_pc_data->is_missing_types || dex_pc_data->is_megamorphic) {
1380 // Don't bother adding classes if we are missing types or already megamorphic.
1381 break;
1382 }
1383 dex::TypeIndex type_index = FindOrCreateTypeIndex(*pmi.ref.dex_file, class_ref);
1384 if (type_index.IsValid()) {
1385 dex_pc_data->AddClass(type_index);
1386 } else {
1387 // Could not create artificial type index.
1388 dex_pc_data->SetIsMissingTypes();
1389 }
1390 }
1391 }
1392 return true;
1393 }
1394
1395 // TODO(calin): Fix this API. ProfileCompilationInfo::Load should be static and
1396 // return a unique pointer to a ProfileCompilationInfo upon success.
Load(int fd,bool merge_classes,const ProfileLoadFilterFn & filter_fn)1397 bool ProfileCompilationInfo::Load(
1398 int fd, bool merge_classes, const ProfileLoadFilterFn& filter_fn) {
1399 std::string error;
1400
1401 ProfileLoadStatus status = LoadInternal(fd, &error, merge_classes, filter_fn);
1402
1403 if (status == ProfileLoadStatus::kSuccess) {
1404 return true;
1405 } else {
1406 LOG(WARNING) << "Error when reading profile: " << error;
1407 return false;
1408 }
1409 }
1410
VerifyProfileData(const std::vector<const DexFile * > & dex_files)1411 bool ProfileCompilationInfo::VerifyProfileData(const std::vector<const DexFile*>& dex_files) {
1412 std::unordered_map<std::string_view, const DexFile*> key_to_dex_file;
1413 for (const DexFile* dex_file : dex_files) {
1414 key_to_dex_file.emplace(GetProfileDexFileBaseKeyView(dex_file->GetLocation()), dex_file);
1415 }
1416 for (const std::unique_ptr<DexFileData>& dex_data : info_) {
1417 // We need to remove any annotation from the key during verification.
1418 const auto it = key_to_dex_file.find(GetBaseKeyViewFromAugmentedKey(dex_data->profile_key));
1419 if (it == key_to_dex_file.end()) {
1420 // It is okay if profile contains data for additional dex files.
1421 continue;
1422 }
1423 const DexFile* dex_file = it->second;
1424 const std::string& dex_location = dex_file->GetLocation();
1425 if (!ChecksumMatch(dex_data->checksum, dex_file->GetLocationChecksum())) {
1426 LOG(ERROR) << "Dex checksum mismatch while verifying profile "
1427 << "dex location " << dex_location << " (checksum="
1428 << dex_file->GetLocationChecksum() << ", profile checksum="
1429 << dex_data->checksum;
1430 return false;
1431 }
1432
1433 if (dex_data->num_method_ids != dex_file->NumMethodIds() ||
1434 dex_data->num_type_ids != dex_file->NumTypeIds()) {
1435 LOG(ERROR) << "Number of type or method ids in dex file and profile don't match."
1436 << "dex location " << dex_location
1437 << " dex_file.NumTypeIds=" << dex_file->NumTypeIds()
1438 << " .v dex_data.num_type_ids=" << dex_data->num_type_ids
1439 << ", dex_file.NumMethodIds=" << dex_file->NumMethodIds()
1440 << " v. dex_data.num_method_ids=" << dex_data->num_method_ids;
1441 return false;
1442 }
1443
1444 // Class and method data should be valid. Verify only in debug builds.
1445 if (kIsDebugBuild) {
1446 // Verify method_encoding.
1447 for (const auto& method_it : dex_data->method_map) {
1448 CHECK_LT(method_it.first, dex_data->num_method_ids);
1449
1450 // Verify class indices of inline caches.
1451 const InlineCacheMap &inline_cache_map = method_it.second;
1452 for (const auto& inline_cache_it : inline_cache_map) {
1453 const DexPcData& dex_pc_data = inline_cache_it.second;
1454 if (dex_pc_data.is_missing_types || dex_pc_data.is_megamorphic) {
1455 // No class indices to verify.
1456 CHECK(dex_pc_data.classes.empty());
1457 continue;
1458 }
1459
1460 for (const dex::TypeIndex& type_index : dex_pc_data.classes) {
1461 if (type_index.index_ >= dex_data->num_type_ids) {
1462 CHECK_LT(type_index.index_ - dex_data->num_type_ids, extra_descriptors_.size());
1463 }
1464 }
1465 }
1466 }
1467 // Verify class_ids.
1468 for (const dex::TypeIndex& type_index : dex_data->class_set) {
1469 if (type_index.index_ >= dex_data->num_type_ids) {
1470 CHECK_LT(type_index.index_ - dex_data->num_type_ids, extra_descriptors_.size());
1471 }
1472 }
1473 }
1474 }
1475 return true;
1476 }
1477
OpenSource(int32_t fd,std::unique_ptr<ProfileSource> * source,std::string * error)1478 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::OpenSource(
1479 int32_t fd,
1480 /*out*/ std::unique_ptr<ProfileSource>* source,
1481 /*out*/ std::string* error) {
1482 if (IsProfileFile(fd)) {
1483 source->reset(ProfileSource::Create(fd));
1484 return ProfileLoadStatus::kSuccess;
1485 } else {
1486 std::unique_ptr<ZipArchive> zip_archive(
1487 ZipArchive::OpenFromFd(DupCloexec(fd), "profile", error));
1488 if (zip_archive.get() == nullptr) {
1489 *error = "Could not open the profile zip archive";
1490 return ProfileLoadStatus::kBadData;
1491 }
1492 std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(kDexMetadataProfileEntry, error));
1493 if (zip_entry == nullptr) {
1494 // Allow archives without the profile entry. In this case, create an empty profile.
1495 // This gives more flexible when ure-using archives that may miss the entry.
1496 // (e.g. dex metadata files)
1497 LOG(WARNING) << "Could not find entry " << kDexMetadataProfileEntry
1498 << " in the zip archive. Creating an empty profile.";
1499 source->reset(ProfileSource::Create(MemMap::Invalid()));
1500 return ProfileLoadStatus::kSuccess;
1501 }
1502 if (zip_entry->GetUncompressedLength() == 0) {
1503 *error = "Empty profile entry in the zip archive.";
1504 return ProfileLoadStatus::kBadData;
1505 }
1506
1507 // TODO(calin) pass along file names to assist with debugging.
1508 MemMap map = zip_entry->MapDirectlyOrExtract(
1509 kDexMetadataProfileEntry, "profile file", error, alignof(ProfileSource));
1510
1511 if (map.IsValid()) {
1512 source->reset(ProfileSource::Create(std::move(map)));
1513 return ProfileLoadStatus::kSuccess;
1514 } else {
1515 return ProfileLoadStatus::kBadData;
1516 }
1517 }
1518 }
1519
Seek(off_t offset)1520 bool ProfileCompilationInfo::ProfileSource::Seek(off_t offset) {
1521 DCHECK_GE(offset, 0);
1522 if (IsMemMap()) {
1523 if (offset > static_cast<int64_t>(mem_map_.Size())) {
1524 return false;
1525 }
1526 mem_map_cur_ = offset;
1527 return true;
1528 } else {
1529 if (lseek64(fd_, offset, SEEK_SET) != offset) {
1530 return false;
1531 }
1532 return true;
1533 }
1534 }
1535
Read(void * buffer,size_t byte_count,const std::string & debug_stage,std::string * error)1536 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ProfileSource::Read(
1537 void* buffer,
1538 size_t byte_count,
1539 const std::string& debug_stage,
1540 std::string* error) {
1541 if (IsMemMap()) {
1542 DCHECK_LE(mem_map_cur_, mem_map_.Size());
1543 if (byte_count > mem_map_.Size() - mem_map_cur_) {
1544 return ProfileLoadStatus::kBadData;
1545 }
1546 memcpy(buffer, mem_map_.Begin() + mem_map_cur_, byte_count);
1547 mem_map_cur_ += byte_count;
1548 } else {
1549 while (byte_count > 0) {
1550 int bytes_read = TEMP_FAILURE_RETRY(read(fd_, buffer, byte_count));;
1551 if (bytes_read == 0) {
1552 *error += "Profile EOF reached prematurely for " + debug_stage;
1553 return ProfileLoadStatus::kBadData;
1554 } else if (bytes_read < 0) {
1555 *error += "Profile IO error for " + debug_stage + strerror(errno);
1556 return ProfileLoadStatus::kIOError;
1557 }
1558 byte_count -= bytes_read;
1559 reinterpret_cast<uint8_t*&>(buffer) += bytes_read;
1560 }
1561 }
1562 return ProfileLoadStatus::kSuccess;
1563 }
1564
1565
HasEmptyContent() const1566 bool ProfileCompilationInfo::ProfileSource::HasEmptyContent() const {
1567 if (IsMemMap()) {
1568 return !mem_map_.IsValid() || mem_map_.Size() == 0;
1569 } else {
1570 struct stat stat_buffer;
1571 if (fstat(fd_, &stat_buffer) != 0) {
1572 return false;
1573 }
1574 return stat_buffer.st_size == 0;
1575 }
1576 }
1577
ReadSectionData(ProfileSource & source,const FileSectionInfo & section_info,SafeBuffer * buffer,std::string * error)1578 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ReadSectionData(
1579 ProfileSource& source,
1580 const FileSectionInfo& section_info,
1581 /*out*/ SafeBuffer* buffer,
1582 /*out*/ std::string* error) {
1583 DCHECK_EQ(buffer->Size(), 0u);
1584 if (!source.Seek(section_info.GetFileOffset())) {
1585 *error = "Failed to seek to section data.";
1586 return ProfileLoadStatus::kIOError;
1587 }
1588 SafeBuffer temp_buffer(section_info.GetFileSize());
1589 ProfileLoadStatus status = source.Read(
1590 temp_buffer.GetCurrentPtr(), temp_buffer.GetAvailableBytes(), "ReadSectionData", error);
1591 if (status != ProfileLoadStatus::kSuccess) {
1592 return status;
1593 }
1594 if (section_info.GetInflatedSize() != 0u &&
1595 !temp_buffer.Inflate(section_info.GetInflatedSize())) {
1596 *error += "Error uncompressing section data.";
1597 return ProfileLoadStatus::kBadData;
1598 }
1599 buffer->Swap(temp_buffer);
1600 return ProfileLoadStatus::kSuccess;
1601 }
1602
ReadDexFilesSection(ProfileSource & source,const FileSectionInfo & section_info,const ProfileLoadFilterFn & filter_fn,dchecked_vector<ProfileIndexType> * dex_profile_index_remap,std::string * error)1603 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ReadDexFilesSection(
1604 ProfileSource& source,
1605 const FileSectionInfo& section_info,
1606 const ProfileLoadFilterFn& filter_fn,
1607 /*out*/ dchecked_vector<ProfileIndexType>* dex_profile_index_remap,
1608 /*out*/ std::string* error) {
1609 DCHECK(section_info.GetType() == FileSectionType::kDexFiles);
1610 SafeBuffer buffer;
1611 ProfileLoadStatus status = ReadSectionData(source, section_info, &buffer, error);
1612 if (status != ProfileLoadStatus::kSuccess) {
1613 return status;
1614 }
1615
1616 ProfileIndexType num_dex_files;
1617 if (!buffer.ReadUintAndAdvance(&num_dex_files)) {
1618 *error = "Error reading number of dex files.";
1619 return ProfileLoadStatus::kBadData;
1620 }
1621 if (num_dex_files >= MaxProfileIndex()) {
1622 *error = "Too many dex files.";
1623 return ProfileLoadStatus::kBadData;
1624 }
1625
1626 DCHECK(dex_profile_index_remap->empty());
1627 for (ProfileIndexType i = 0u; i != num_dex_files; ++i) {
1628 uint32_t checksum, num_type_ids, num_method_ids;
1629 if (!buffer.ReadUintAndAdvance(&checksum) ||
1630 !buffer.ReadUintAndAdvance(&num_type_ids) ||
1631 !buffer.ReadUintAndAdvance(&num_method_ids)) {
1632 *error = "Error reading dex file data.";
1633 return ProfileLoadStatus::kBadData;
1634 }
1635 std::string_view profile_key_view;
1636 if (!buffer.ReadStringAndAdvance(&profile_key_view)) {
1637 *error += "Missing terminating null character for profile key.";
1638 return ProfileLoadStatus::kBadData;
1639 }
1640 if (profile_key_view.size() == 0u || profile_key_view.size() > kMaxDexFileKeyLength) {
1641 *error = "ProfileKey has an invalid size: " + std::to_string(profile_key_view.size());
1642 return ProfileLoadStatus::kBadData;
1643 }
1644 std::string profile_key(profile_key_view);
1645 if (!filter_fn(profile_key, checksum)) {
1646 // Do not load data for this key. Store invalid index to `dex_profile_index_remap`.
1647 VLOG(compiler) << "Profile: Filtered out " << profile_key << " 0x" << std::hex << checksum;
1648 dex_profile_index_remap->push_back(MaxProfileIndex());
1649 continue;
1650 }
1651 DexFileData* data = GetOrAddDexFileData(profile_key, checksum, num_type_ids, num_method_ids);
1652 if (data == nullptr) {
1653 if (UNLIKELY(profile_key_map_.size() == MaxProfileIndex()) &&
1654 profile_key_map_.find(profile_key) == profile_key_map_.end()) {
1655 *error = "Too many dex files.";
1656 } else {
1657 *error = "Checksum, NumTypeIds, or NumMethodIds mismatch for " + profile_key;
1658 }
1659 return ProfileLoadStatus::kBadData;
1660 }
1661 dex_profile_index_remap->push_back(data->profile_index);
1662 }
1663 if (buffer.GetAvailableBytes() != 0u) {
1664 *error = "Unexpected data at end of dex files section.";
1665 return ProfileLoadStatus::kBadData;
1666 }
1667 return ProfileLoadStatus::kSuccess;
1668 }
1669
ReadExtraDescriptorsSection(ProfileSource & source,const FileSectionInfo & section_info,dchecked_vector<ExtraDescriptorIndex> * extra_descriptors_remap,std::string * error)1670 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ReadExtraDescriptorsSection(
1671 ProfileSource& source,
1672 const FileSectionInfo& section_info,
1673 /*out*/ dchecked_vector<ExtraDescriptorIndex>* extra_descriptors_remap,
1674 /*out*/ std::string* error) {
1675 DCHECK(section_info.GetType() == FileSectionType::kExtraDescriptors);
1676 SafeBuffer buffer;
1677 ProfileLoadStatus status = ReadSectionData(source, section_info, &buffer, error);
1678 if (status != ProfileLoadStatus::kSuccess) {
1679 return status;
1680 }
1681
1682 uint16_t num_extra_descriptors;
1683 if (!buffer.ReadUintAndAdvance(&num_extra_descriptors)) {
1684 *error = "Error reading number of extra descriptors.";
1685 return ProfileLoadStatus::kBadData;
1686 }
1687
1688 // Note: We allow multiple extra descriptors sections in a single profile file
1689 // but that can lead to `kMergeError` if there are too many extra descriptors.
1690 // Other sections can reference only extra descriptors from preceding sections.
1691 extra_descriptors_remap->reserve(
1692 std::min<size_t>(extra_descriptors_remap->size() + num_extra_descriptors,
1693 std::numeric_limits<uint16_t>::max()));
1694 for (uint16_t i = 0; i != num_extra_descriptors; ++i) {
1695 std::string_view extra_descriptor;
1696 if (!buffer.ReadStringAndAdvance(&extra_descriptor)) {
1697 *error += "Missing terminating null character for extra descriptor.";
1698 return ProfileLoadStatus::kBadData;
1699 }
1700 if (!IsValidDescriptor(std::string(extra_descriptor).c_str())) {
1701 *error += "Invalid extra descriptor.";
1702 return ProfileLoadStatus::kBadData;
1703 }
1704 // Try to match an existing extra descriptor.
1705 auto it = extra_descriptors_indexes_.find(extra_descriptor);
1706 if (it != extra_descriptors_indexes_.end()) {
1707 extra_descriptors_remap->push_back(*it);
1708 continue;
1709 }
1710 // Try to insert a new extra descriptor.
1711 ExtraDescriptorIndex extra_descriptor_index = AddExtraDescriptor(extra_descriptor);
1712 if (extra_descriptor_index == kMaxExtraDescriptors) {
1713 *error = "Too many extra descriptors.";
1714 return ProfileLoadStatus::kMergeError;
1715 }
1716 extra_descriptors_remap->push_back(extra_descriptor_index);
1717 }
1718 return ProfileLoadStatus::kSuccess;
1719 }
1720
ReadClassesSection(ProfileSource & source,const FileSectionInfo & section_info,const dchecked_vector<ProfileIndexType> & dex_profile_index_remap,const dchecked_vector<ExtraDescriptorIndex> & extra_descriptors_remap,std::string * error)1721 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ReadClassesSection(
1722 ProfileSource& source,
1723 const FileSectionInfo& section_info,
1724 const dchecked_vector<ProfileIndexType>& dex_profile_index_remap,
1725 const dchecked_vector<ExtraDescriptorIndex>& extra_descriptors_remap,
1726 /*out*/ std::string* error) {
1727 DCHECK(section_info.GetType() == FileSectionType::kClasses);
1728 SafeBuffer buffer;
1729 ProfileLoadStatus status = ReadSectionData(source, section_info, &buffer, error);
1730 if (status != ProfileLoadStatus::kSuccess) {
1731 return status;
1732 }
1733
1734 while (buffer.GetAvailableBytes() != 0u) {
1735 ProfileIndexType profile_index;
1736 if (!buffer.ReadUintAndAdvance(&profile_index)) {
1737 *error = "Error profile index in classes section.";
1738 return ProfileLoadStatus::kBadData;
1739 }
1740 if (profile_index >= dex_profile_index_remap.size()) {
1741 *error = "Invalid profile index in classes section.";
1742 return ProfileLoadStatus::kBadData;
1743 }
1744 profile_index = dex_profile_index_remap[profile_index];
1745 if (profile_index == MaxProfileIndex()) {
1746 status = DexFileData::SkipClasses(buffer, error);
1747 } else {
1748 status = info_[profile_index]->ReadClasses(buffer, extra_descriptors_remap, error);
1749 }
1750 if (status != ProfileLoadStatus::kSuccess) {
1751 return status;
1752 }
1753 }
1754 return ProfileLoadStatus::kSuccess;
1755 }
1756
ReadMethodsSection(ProfileSource & source,const FileSectionInfo & section_info,const dchecked_vector<ProfileIndexType> & dex_profile_index_remap,const dchecked_vector<ExtraDescriptorIndex> & extra_descriptors_remap,std::string * error)1757 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ReadMethodsSection(
1758 ProfileSource& source,
1759 const FileSectionInfo& section_info,
1760 const dchecked_vector<ProfileIndexType>& dex_profile_index_remap,
1761 const dchecked_vector<ExtraDescriptorIndex>& extra_descriptors_remap,
1762 /*out*/ std::string* error) {
1763 DCHECK(section_info.GetType() == FileSectionType::kMethods);
1764 SafeBuffer buffer;
1765 ProfileLoadStatus status = ReadSectionData(source, section_info, &buffer, error);
1766 if (status != ProfileLoadStatus::kSuccess) {
1767 return status;
1768 }
1769
1770 while (buffer.GetAvailableBytes() != 0u) {
1771 ProfileIndexType profile_index;
1772 if (!buffer.ReadUintAndAdvance(&profile_index)) {
1773 *error = "Error profile index in methods section.";
1774 return ProfileLoadStatus::kBadData;
1775 }
1776 if (profile_index >= dex_profile_index_remap.size()) {
1777 *error = "Invalid profile index in methods section.";
1778 return ProfileLoadStatus::kBadData;
1779 }
1780 profile_index = dex_profile_index_remap[profile_index];
1781 if (profile_index == MaxProfileIndex()) {
1782 status = DexFileData::SkipMethods(buffer, error);
1783 } else {
1784 status = info_[profile_index]->ReadMethods(buffer, extra_descriptors_remap, error);
1785 }
1786 if (status != ProfileLoadStatus::kSuccess) {
1787 return status;
1788 }
1789 }
1790 return ProfileLoadStatus::kSuccess;
1791 }
1792
1793 // TODO(calin): fail fast if the dex checksums don't match.
LoadInternal(int32_t fd,std::string * error,bool merge_classes,const ProfileLoadFilterFn & filter_fn)1794 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::LoadInternal(
1795 int32_t fd,
1796 std::string* error,
1797 bool merge_classes,
1798 const ProfileLoadFilterFn& filter_fn) {
1799 ScopedTrace trace(__PRETTY_FUNCTION__);
1800 DCHECK_GE(fd, 0);
1801
1802 std::unique_ptr<ProfileSource> source;
1803 ProfileLoadStatus status = OpenSource(fd, &source, error);
1804 if (status != ProfileLoadStatus::kSuccess) {
1805 return status;
1806 }
1807
1808 // We allow empty profile files.
1809 // Profiles may be created by ActivityManager or installd before we manage to
1810 // process them in the runtime or profman.
1811 if (source->HasEmptyContent()) {
1812 return ProfileLoadStatus::kSuccess;
1813 }
1814
1815 // Read file header.
1816 FileHeader header;
1817 status = source->Read(&header, sizeof(FileHeader), "ReadProfileHeader", error);
1818 if (status != ProfileLoadStatus::kSuccess) {
1819 return status;
1820 }
1821 if (!header.IsValid()) {
1822 return header.InvalidHeaderMessage(error);
1823 }
1824 if (memcmp(header.GetVersion(), version_, kProfileVersionSize) != 0) {
1825 *error = IsForBootImage() ? "Expected boot profile, got app profile."
1826 : "Expected app profile, got boot profile.";
1827 return ProfileLoadStatus::kVersionMismatch;
1828 }
1829
1830 // Check if there are too many section infos.
1831 uint32_t section_count = header.GetFileSectionCount();
1832 uint32_t uncompressed_data_size = sizeof(FileHeader) + section_count * sizeof(FileSectionInfo);
1833 if (uncompressed_data_size > GetSizeErrorThresholdBytes()) {
1834 LOG(WARNING) << "Profile data size exceeds " << GetSizeErrorThresholdBytes()
1835 << " bytes. It has " << uncompressed_data_size << " bytes.";
1836 return ProfileLoadStatus::kBadData;
1837 }
1838
1839 // Read section infos.
1840 dchecked_vector<FileSectionInfo> section_infos(section_count);
1841 status = source->Read(
1842 section_infos.data(), section_count * sizeof(FileSectionInfo), "ReadSectionInfos", error);
1843 if (status != ProfileLoadStatus::kSuccess) {
1844 return status;
1845 }
1846
1847 // Finish uncompressed data size calculation.
1848 for (const FileSectionInfo& section_info : section_infos) {
1849 uint32_t mem_size = section_info.GetMemSize();
1850 if (UNLIKELY(mem_size > std::numeric_limits<uint32_t>::max() - uncompressed_data_size)) {
1851 *error = "Total memory size overflow.";
1852 return ProfileLoadStatus::kBadData;
1853 }
1854 uncompressed_data_size += mem_size;
1855 }
1856
1857 // Allow large profiles for non target builds for the case where we are merging many profiles
1858 // to generate a boot image profile.
1859 if (uncompressed_data_size > GetSizeErrorThresholdBytes()) {
1860 LOG(WARNING) << "Profile data size exceeds "
1861 << GetSizeErrorThresholdBytes()
1862 << " bytes. It has " << uncompressed_data_size << " bytes.";
1863 return ProfileLoadStatus::kBadData;
1864 }
1865 if (uncompressed_data_size > GetSizeWarningThresholdBytes()) {
1866 LOG(WARNING) << "Profile data size exceeds "
1867 << GetSizeWarningThresholdBytes()
1868 << " bytes. It has " << uncompressed_data_size << " bytes.";
1869 }
1870
1871 // Process the mandatory dex files section.
1872 DCHECK_NE(section_count, 0u); // Checked by `header.IsValid()` above.
1873 const FileSectionInfo& dex_files_section_info = section_infos[0];
1874 if (dex_files_section_info.GetType() != FileSectionType::kDexFiles) {
1875 *error = "First section is not dex files section.";
1876 return ProfileLoadStatus::kBadData;
1877 }
1878 dchecked_vector<ProfileIndexType> dex_profile_index_remap;
1879 status = ReadDexFilesSection(
1880 *source, dex_files_section_info, filter_fn, &dex_profile_index_remap, error);
1881 if (status != ProfileLoadStatus::kSuccess) {
1882 DCHECK(!error->empty());
1883 return status;
1884 }
1885
1886 // Process all other sections.
1887 dchecked_vector<ExtraDescriptorIndex> extra_descriptors_remap;
1888 for (uint32_t i = 1u; i != section_count; ++i) {
1889 const FileSectionInfo& section_info = section_infos[i];
1890 DCHECK(status == ProfileLoadStatus::kSuccess);
1891 switch (section_info.GetType()) {
1892 case FileSectionType::kDexFiles:
1893 *error = "Unsupported additional dex files section.";
1894 status = ProfileLoadStatus::kBadData;
1895 break;
1896 case FileSectionType::kExtraDescriptors:
1897 status = ReadExtraDescriptorsSection(
1898 *source, section_info, &extra_descriptors_remap, error);
1899 break;
1900 case FileSectionType::kClasses:
1901 // Skip if all dex files were filtered out.
1902 if (!info_.empty() && merge_classes) {
1903 status = ReadClassesSection(
1904 *source, section_info, dex_profile_index_remap, extra_descriptors_remap, error);
1905 }
1906 break;
1907 case FileSectionType::kMethods:
1908 // Skip if all dex files were filtered out.
1909 if (!info_.empty()) {
1910 status = ReadMethodsSection(
1911 *source, section_info, dex_profile_index_remap, extra_descriptors_remap, error);
1912 }
1913 break;
1914 case FileSectionType::kAggregationCounts:
1915 // This section is only used on server side.
1916 break;
1917 default:
1918 // Unknown section. Skip it. New versions of ART are allowed
1919 // to add sections that shall be ignored by old versions.
1920 break;
1921 }
1922 if (status != ProfileLoadStatus::kSuccess) {
1923 DCHECK(!error->empty());
1924 return status;
1925 }
1926 }
1927
1928 return ProfileLoadStatus::kSuccess;
1929 }
1930
MergeWith(const ProfileCompilationInfo & other,bool merge_classes)1931 bool ProfileCompilationInfo::MergeWith(const ProfileCompilationInfo& other,
1932 bool merge_classes) {
1933 if (!SameVersion(other)) {
1934 LOG(WARNING) << "Cannot merge different profile versions";
1935 return false;
1936 }
1937
1938 // First verify that all checksums match. This will avoid adding garbage to
1939 // the current profile info.
1940 // Note that the number of elements should be very small, so this should not
1941 // be a performance issue.
1942 for (const std::unique_ptr<DexFileData>& other_dex_data : other.info_) {
1943 // verify_checksum is false because we want to differentiate between a missing dex data and
1944 // a mismatched checksum.
1945 const DexFileData* dex_data = FindDexData(other_dex_data->profile_key,
1946 /* checksum= */ 0u,
1947 /* verify_checksum= */ false);
1948 if ((dex_data != nullptr) && (dex_data->checksum != other_dex_data->checksum)) {
1949 LOG(WARNING) << "Checksum mismatch for dex " << other_dex_data->profile_key;
1950 return false;
1951 }
1952 }
1953 // All checksums match. Import the data.
1954
1955 // The other profile might have a different indexing of dex files.
1956 // That is because each dex files gets a 'dex_profile_index' on a first come first served basis.
1957 // That means that the order in with the methods are added to the profile matters for the
1958 // actual indices.
1959 // The reason we cannot rely on the actual multidex index is that a single profile may store
1960 // data from multiple splits. This means that a profile may contain a classes2.dex from split-A
1961 // and one from split-B.
1962
1963 // First, build a mapping from other_dex_profile_index to this_dex_profile_index.
1964 dchecked_vector<ProfileIndexType> dex_profile_index_remap;
1965 dex_profile_index_remap.reserve(other.info_.size());
1966 for (const std::unique_ptr<DexFileData>& other_dex_data : other.info_) {
1967 const DexFileData* dex_data = GetOrAddDexFileData(other_dex_data->profile_key,
1968 other_dex_data->checksum,
1969 other_dex_data->num_type_ids,
1970 other_dex_data->num_method_ids);
1971 if (dex_data == nullptr) {
1972 // Could happen if we exceed the number of allowed dex files or there is
1973 // a mismatch in `num_type_ids` or `num_method_ids`.
1974 return false;
1975 }
1976 DCHECK_EQ(other_dex_data->profile_index, dex_profile_index_remap.size());
1977 dex_profile_index_remap.push_back(dex_data->profile_index);
1978 }
1979
1980 // Then merge extra descriptors.
1981 dchecked_vector<ExtraDescriptorIndex> extra_descriptors_remap;
1982 extra_descriptors_remap.reserve(other.extra_descriptors_.size());
1983 for (const std::string& other_extra_descriptor : other.extra_descriptors_) {
1984 auto it = extra_descriptors_indexes_.find(std::string_view(other_extra_descriptor));
1985 if (it != extra_descriptors_indexes_.end()) {
1986 extra_descriptors_remap.push_back(*it);
1987 } else {
1988 ExtraDescriptorIndex extra_descriptor_index = AddExtraDescriptor(other_extra_descriptor);
1989 if (extra_descriptor_index == kMaxExtraDescriptors) {
1990 // Too many extra descriptors.
1991 return false;
1992 }
1993 extra_descriptors_remap.push_back(extra_descriptor_index);
1994 }
1995 }
1996
1997 // Merge the actual profile data.
1998 for (const std::unique_ptr<DexFileData>& other_dex_data : other.info_) {
1999 DexFileData* dex_data = info_[dex_profile_index_remap[other_dex_data->profile_index]].get();
2000 DCHECK_EQ(dex_data, FindDexData(other_dex_data->profile_key, other_dex_data->checksum));
2001
2002 // Merge the classes.
2003 uint32_t num_type_ids = dex_data->num_type_ids;
2004 DCHECK_EQ(num_type_ids, other_dex_data->num_type_ids);
2005 if (merge_classes) {
2006 // Classes are ordered by the `TypeIndex`, so we have the classes with a `TypeId`
2007 // in the dex file first, followed by classes using extra descriptors.
2008 auto it = other_dex_data->class_set.lower_bound(dex::TypeIndex(num_type_ids));
2009 dex_data->class_set.insert(other_dex_data->class_set.begin(), it);
2010 for (auto end = other_dex_data->class_set.end(); it != end; ++it) {
2011 ExtraDescriptorIndex new_extra_descriptor_index =
2012 extra_descriptors_remap[it->index_ - num_type_ids];
2013 if (new_extra_descriptor_index >= DexFile::kDexNoIndex16 - num_type_ids) {
2014 // Cannot represent the type with new extra descriptor index.
2015 return false;
2016 }
2017 dex_data->class_set.insert(dex::TypeIndex(num_type_ids + new_extra_descriptor_index));
2018 }
2019 }
2020
2021 // Merge the methods and the inline caches.
2022 for (const auto& other_method_it : other_dex_data->method_map) {
2023 uint16_t other_method_index = other_method_it.first;
2024 InlineCacheMap* inline_cache = dex_data->FindOrAddHotMethod(other_method_index);
2025 if (inline_cache == nullptr) {
2026 return false;
2027 }
2028 const auto& other_inline_cache = other_method_it.second;
2029 for (const auto& other_ic_it : other_inline_cache) {
2030 uint16_t other_dex_pc = other_ic_it.first;
2031 const ArenaSet<dex::TypeIndex>& other_class_set = other_ic_it.second.classes;
2032 DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, other_dex_pc);
2033 if (other_ic_it.second.is_missing_types) {
2034 dex_pc_data->SetIsMissingTypes();
2035 } else if (other_ic_it.second.is_megamorphic) {
2036 dex_pc_data->SetIsMegamorphic();
2037 } else {
2038 for (dex::TypeIndex type_index : other_class_set) {
2039 if (type_index.index_ >= num_type_ids) {
2040 ExtraDescriptorIndex new_extra_descriptor_index =
2041 extra_descriptors_remap[type_index.index_ - num_type_ids];
2042 if (new_extra_descriptor_index >= DexFile::kDexNoIndex16 - num_type_ids) {
2043 // Cannot represent the type with new extra descriptor index.
2044 return false;
2045 }
2046 type_index = dex::TypeIndex(num_type_ids + new_extra_descriptor_index);
2047 }
2048 dex_pc_data->AddClass(type_index);
2049 }
2050 }
2051 }
2052 }
2053
2054 // Merge the method bitmaps.
2055 dex_data->MergeBitmap(*other_dex_data);
2056 }
2057
2058 return true;
2059 }
2060
GetMethodHotness(const MethodReference & method_ref,const ProfileSampleAnnotation & annotation) const2061 ProfileCompilationInfo::MethodHotness ProfileCompilationInfo::GetMethodHotness(
2062 const MethodReference& method_ref,
2063 const ProfileSampleAnnotation& annotation) const {
2064 const DexFileData* dex_data = FindDexDataUsingAnnotations(method_ref.dex_file, annotation);
2065 return dex_data != nullptr
2066 ? dex_data->GetHotnessInfo(method_ref.index)
2067 : MethodHotness();
2068 }
2069
ContainsClass(const DexFile & dex_file,dex::TypeIndex type_idx,const ProfileSampleAnnotation & annotation) const2070 bool ProfileCompilationInfo::ContainsClass(const DexFile& dex_file,
2071 dex::TypeIndex type_idx,
2072 const ProfileSampleAnnotation& annotation) const {
2073 const DexFileData* dex_data = FindDexDataUsingAnnotations(&dex_file, annotation);
2074 return (dex_data != nullptr) && dex_data->ContainsClass(type_idx);
2075 }
2076
GetNumberOfMethods() const2077 uint32_t ProfileCompilationInfo::GetNumberOfMethods() const {
2078 uint32_t total = 0;
2079 for (const std::unique_ptr<DexFileData>& dex_data : info_) {
2080 total += dex_data->method_map.size();
2081 }
2082 return total;
2083 }
2084
GetNumberOfResolvedClasses() const2085 uint32_t ProfileCompilationInfo::GetNumberOfResolvedClasses() const {
2086 uint32_t total = 0;
2087 for (const std::unique_ptr<DexFileData>& dex_data : info_) {
2088 total += dex_data->class_set.size();
2089 }
2090 return total;
2091 }
2092
DumpInfo(const std::vector<const DexFile * > & dex_files,bool print_full_dex_location) const2093 std::string ProfileCompilationInfo::DumpInfo(const std::vector<const DexFile*>& dex_files,
2094 bool print_full_dex_location) const {
2095 std::ostringstream os;
2096
2097 os << "ProfileInfo [";
2098
2099 for (size_t k = 0; k < kProfileVersionSize - 1; k++) {
2100 // Iterate to 'kProfileVersionSize - 1' because the version_ ends with '\0'
2101 // which we don't want to print.
2102 os << static_cast<char>(version_[k]);
2103 }
2104 os << "]\n";
2105
2106 if (info_.empty()) {
2107 os << "-empty-";
2108 return os.str();
2109 }
2110
2111 if (!extra_descriptors_.empty()) {
2112 os << "\nextra descriptors:";
2113 for (const std::string& str : extra_descriptors_) {
2114 os << "\n\t" << str;
2115 }
2116 os << "\n";
2117 }
2118
2119 const std::string kFirstDexFileKeySubstitute = "!classes.dex";
2120
2121 for (const std::unique_ptr<DexFileData>& dex_data : info_) {
2122 os << "\n";
2123 if (print_full_dex_location) {
2124 os << dex_data->profile_key;
2125 } else {
2126 // Replace the (empty) multidex suffix of the first key with a substitute for easier reading.
2127 std::string multidex_suffix = DexFileLoader::GetMultiDexSuffix(
2128 GetBaseKeyFromAugmentedKey(dex_data->profile_key));
2129 os << (multidex_suffix.empty() ? kFirstDexFileKeySubstitute : multidex_suffix);
2130 }
2131 os << " [index=" << static_cast<uint32_t>(dex_data->profile_index) << "]";
2132 os << " [checksum=" << std::hex << dex_data->checksum << "]" << std::dec;
2133 os << " [num_type_ids=" << dex_data->num_type_ids << "]";
2134 os << " [num_method_ids=" << dex_data->num_method_ids << "]";
2135 const DexFile* dex_file = nullptr;
2136 for (const DexFile* current : dex_files) {
2137 if (GetBaseKeyViewFromAugmentedKey(dex_data->profile_key) ==
2138 GetProfileDexFileBaseKeyView(current->GetLocation()) &&
2139 ChecksumMatch(dex_data->checksum, current->GetLocationChecksum())) {
2140 dex_file = current;
2141 break;
2142 }
2143 }
2144 os << "\n\thot methods: ";
2145 for (const auto& method_it : dex_data->method_map) {
2146 if (dex_file != nullptr) {
2147 os << "\n\t\t" << dex_file->PrettyMethod(method_it.first, true);
2148 } else {
2149 os << method_it.first;
2150 }
2151
2152 os << "[";
2153 for (const auto& inline_cache_it : method_it.second) {
2154 os << "{" << std::hex << inline_cache_it.first << std::dec << ":";
2155 if (inline_cache_it.second.is_missing_types) {
2156 os << "MT";
2157 } else if (inline_cache_it.second.is_megamorphic) {
2158 os << "MM";
2159 } else {
2160 const char* separator = "";
2161 for (dex::TypeIndex type_index : inline_cache_it.second.classes) {
2162 os << separator << type_index.index_;
2163 separator = ",";
2164 }
2165 }
2166 os << "}";
2167 }
2168 os << "], ";
2169 }
2170 bool startup = true;
2171 while (true) {
2172 os << "\n\t" << (startup ? "startup methods: " : "post startup methods: ");
2173 for (uint32_t method_idx = 0; method_idx < dex_data->num_method_ids; ++method_idx) {
2174 MethodHotness hotness_info(dex_data->GetHotnessInfo(method_idx));
2175 if (startup ? hotness_info.IsStartup() : hotness_info.IsPostStartup()) {
2176 if (dex_file != nullptr) {
2177 os << "\n\t\t" << dex_file->PrettyMethod(method_idx, true);
2178 } else {
2179 os << method_idx << ", ";
2180 }
2181 }
2182 }
2183 if (startup == false) {
2184 break;
2185 }
2186 startup = false;
2187 }
2188 os << "\n\tclasses: ";
2189 for (dex::TypeIndex type_index : dex_data->class_set) {
2190 if (dex_file != nullptr) {
2191 os << "\n\t\t" << PrettyDescriptor(GetTypeDescriptor(dex_file, type_index));
2192 } else {
2193 os << type_index.index_ << ",";
2194 }
2195 }
2196 }
2197 return os.str();
2198 }
2199
GetClassesAndMethods(const DexFile & dex_file,std::set<dex::TypeIndex> * class_set,std::set<uint16_t> * hot_method_set,std::set<uint16_t> * startup_method_set,std::set<uint16_t> * post_startup_method_method_set,const ProfileSampleAnnotation & annotation) const2200 bool ProfileCompilationInfo::GetClassesAndMethods(
2201 const DexFile& dex_file,
2202 /*out*/std::set<dex::TypeIndex>* class_set,
2203 /*out*/std::set<uint16_t>* hot_method_set,
2204 /*out*/std::set<uint16_t>* startup_method_set,
2205 /*out*/std::set<uint16_t>* post_startup_method_method_set,
2206 const ProfileSampleAnnotation& annotation) const {
2207 std::set<std::string> ret;
2208 const DexFileData* dex_data = FindDexDataUsingAnnotations(&dex_file, annotation);
2209 if (dex_data == nullptr) {
2210 return false;
2211 }
2212 for (const auto& it : dex_data->method_map) {
2213 hot_method_set->insert(it.first);
2214 }
2215 for (uint32_t method_idx = 0; method_idx < dex_data->num_method_ids; ++method_idx) {
2216 MethodHotness hotness = dex_data->GetHotnessInfo(method_idx);
2217 if (hotness.IsStartup()) {
2218 startup_method_set->insert(method_idx);
2219 }
2220 if (hotness.IsPostStartup()) {
2221 post_startup_method_method_set->insert(method_idx);
2222 }
2223 }
2224 for (const dex::TypeIndex& type_index : dex_data->class_set) {
2225 class_set->insert(type_index);
2226 }
2227 return true;
2228 }
2229
GetClasses(const DexFile & dex_file,const ProfileSampleAnnotation & annotation) const2230 const ArenaSet<dex::TypeIndex>* ProfileCompilationInfo::GetClasses(
2231 const DexFile& dex_file,
2232 const ProfileSampleAnnotation& annotation) const {
2233 const DexFileData* dex_data = FindDexDataUsingAnnotations(&dex_file, annotation);
2234 if (dex_data == nullptr) {
2235 return nullptr;
2236 }
2237 return &dex_data->class_set;
2238 }
2239
SameVersion(const ProfileCompilationInfo & other) const2240 bool ProfileCompilationInfo::SameVersion(const ProfileCompilationInfo& other) const {
2241 return memcmp(version_, other.version_, kProfileVersionSize) == 0;
2242 }
2243
Equals(const ProfileCompilationInfo & other)2244 bool ProfileCompilationInfo::Equals(const ProfileCompilationInfo& other) {
2245 // No need to compare profile_key_map_. That's only a cache for fast search.
2246 // All the information is already in the info_ vector.
2247 if (!SameVersion(other)) {
2248 return false;
2249 }
2250 if (info_.size() != other.info_.size()) {
2251 return false;
2252 }
2253 for (size_t i = 0; i < info_.size(); i++) {
2254 const DexFileData& dex_data = *info_[i];
2255 const DexFileData& other_dex_data = *other.info_[i];
2256 if (!(dex_data == other_dex_data)) {
2257 return false;
2258 }
2259 }
2260
2261 return true;
2262 }
2263
2264 // Naive implementation to generate a random profile file suitable for testing.
GenerateTestProfile(int fd,uint16_t number_of_dex_files,uint16_t method_percentage,uint16_t class_percentage,uint32_t random_seed)2265 bool ProfileCompilationInfo::GenerateTestProfile(int fd,
2266 uint16_t number_of_dex_files,
2267 uint16_t method_percentage,
2268 uint16_t class_percentage,
2269 uint32_t random_seed) {
2270 const std::string base_dex_location = "base.apk";
2271 ProfileCompilationInfo info;
2272 // The limits are defined by the dex specification.
2273 const uint16_t max_methods = std::numeric_limits<uint16_t>::max();
2274 const uint16_t max_classes = std::numeric_limits<uint16_t>::max();
2275 uint16_t number_of_methods = max_methods * method_percentage / 100;
2276 uint16_t number_of_classes = max_classes * class_percentage / 100;
2277
2278 std::srand(random_seed);
2279
2280 // Make sure we generate more samples with a low index value.
2281 // This makes it more likely to hit valid method/class indices in small apps.
2282 const uint16_t kFavorFirstN = 10000;
2283 const uint16_t kFavorSplit = 2;
2284
2285 for (uint16_t i = 0; i < number_of_dex_files; i++) {
2286 std::string dex_location = DexFileLoader::GetMultiDexLocation(i, base_dex_location.c_str());
2287 std::string profile_key = info.GetProfileDexFileBaseKey(dex_location);
2288
2289 DexFileData* const data =
2290 info.GetOrAddDexFileData(profile_key, /*checksum=*/ 0, max_classes, max_methods);
2291 for (uint16_t m = 0; m < number_of_methods; m++) {
2292 uint16_t method_idx = rand() % max_methods;
2293 if (m < (number_of_methods / kFavorSplit)) {
2294 method_idx %= kFavorFirstN;
2295 }
2296 // Alternate between startup and post startup.
2297 uint32_t flags = MethodHotness::kFlagHot;
2298 flags |= ((m & 1) != 0) ? MethodHotness::kFlagPostStartup : MethodHotness::kFlagStartup;
2299 data->AddMethod(static_cast<MethodHotness::Flag>(flags), method_idx);
2300 }
2301
2302 for (uint16_t c = 0; c < number_of_classes; c++) {
2303 uint16_t type_idx = rand() % max_classes;
2304 if (c < (number_of_classes / kFavorSplit)) {
2305 type_idx %= kFavorFirstN;
2306 }
2307 data->class_set.insert(dex::TypeIndex(type_idx));
2308 }
2309 }
2310 return info.Save(fd);
2311 }
2312
2313 // Naive implementation to generate a random profile file suitable for testing.
2314 // Description of random selection:
2315 // * Select a random starting point S.
2316 // * For every index i, add (S+i) % (N - total number of methods/classes) to profile with the
2317 // probably of 1/(N - i - number of methods/classes needed to add in profile).
GenerateTestProfile(int fd,std::vector<std::unique_ptr<const DexFile>> & dex_files,uint16_t method_percentage,uint16_t class_percentage,uint32_t random_seed)2318 bool ProfileCompilationInfo::GenerateTestProfile(
2319 int fd,
2320 std::vector<std::unique_ptr<const DexFile>>& dex_files,
2321 uint16_t method_percentage,
2322 uint16_t class_percentage,
2323 uint32_t random_seed) {
2324 ProfileCompilationInfo info;
2325 std::default_random_engine rng(random_seed);
2326 auto create_shuffled_range = [&rng](uint32_t take, uint32_t out_of) {
2327 CHECK_LE(take, out_of);
2328 std::vector<uint32_t> vec(out_of);
2329 std::iota(vec.begin(), vec.end(), 0u);
2330 std::shuffle(vec.begin(), vec.end(), rng);
2331 vec.erase(vec.begin() + take, vec.end());
2332 std::sort(vec.begin(), vec.end());
2333 return vec;
2334 };
2335 for (std::unique_ptr<const DexFile>& dex_file : dex_files) {
2336 const std::string& dex_location = dex_file->GetLocation();
2337 std::string profile_key = info.GetProfileDexFileBaseKey(dex_location);
2338 uint32_t checksum = dex_file->GetLocationChecksum();
2339
2340 uint32_t number_of_classes = dex_file->NumClassDefs();
2341 uint32_t classes_required_in_profile = (number_of_classes * class_percentage) / 100;
2342
2343 DexFileData* const data = info.GetOrAddDexFileData(
2344 profile_key, checksum, dex_file->NumTypeIds(), dex_file->NumMethodIds());
2345 for (uint32_t class_index : create_shuffled_range(classes_required_in_profile,
2346 number_of_classes)) {
2347 data->class_set.insert(dex_file->GetClassDef(class_index).class_idx_);
2348 }
2349
2350 uint32_t number_of_methods = dex_file->NumMethodIds();
2351 uint32_t methods_required_in_profile = (number_of_methods * method_percentage) / 100;
2352 for (uint32_t method_index : create_shuffled_range(methods_required_in_profile,
2353 number_of_methods)) {
2354 // Alternate between startup and post startup.
2355 uint32_t flags = MethodHotness::kFlagHot;
2356 flags |= ((method_index & 1) != 0)
2357 ? MethodHotness::kFlagPostStartup
2358 : MethodHotness::kFlagStartup;
2359 data->AddMethod(static_cast<MethodHotness::Flag>(flags), method_index);
2360 }
2361 }
2362 return info.Save(fd);
2363 }
2364
IsEmpty() const2365 bool ProfileCompilationInfo::IsEmpty() const {
2366 DCHECK_EQ(info_.size(), profile_key_map_.size());
2367 // Note that this doesn't look at the bitmap region, so we will return true
2368 // when the profile contains only non-hot methods. This is generally ok
2369 // as for speed-profile to be useful we do need hot methods and resolved classes.
2370 return GetNumberOfMethods() == 0 && GetNumberOfResolvedClasses() == 0;
2371 }
2372
2373 ProfileCompilationInfo::InlineCacheMap*
FindOrAddHotMethod(uint16_t method_index)2374 ProfileCompilationInfo::DexFileData::FindOrAddHotMethod(uint16_t method_index) {
2375 if (method_index >= num_method_ids) {
2376 LOG(ERROR) << "Invalid method index " << method_index << ". num_method_ids=" << num_method_ids;
2377 return nullptr;
2378 }
2379 return &(method_map.FindOrAdd(
2380 method_index,
2381 InlineCacheMap(std::less<uint16_t>(), allocator_->Adapter(kArenaAllocProfile)))->second);
2382 }
2383
2384 // Mark a method as executed at least once.
AddMethod(MethodHotness::Flag flags,size_t index)2385 bool ProfileCompilationInfo::DexFileData::AddMethod(MethodHotness::Flag flags, size_t index) {
2386 if (index >= num_method_ids || index > kMaxSupportedMethodIndex) {
2387 LOG(ERROR) << "Invalid method index " << index << ". num_method_ids=" << num_method_ids
2388 << ", max: " << kMaxSupportedMethodIndex;
2389 return false;
2390 }
2391
2392 SetMethodHotness(index, flags);
2393
2394 if ((flags & MethodHotness::kFlagHot) != 0) {
2395 ProfileCompilationInfo::InlineCacheMap* result = FindOrAddHotMethod(index);
2396 DCHECK(result != nullptr);
2397 }
2398 return true;
2399 }
2400
SetMethodHotness(size_t index,MethodHotness::Flag flags)2401 void ProfileCompilationInfo::DexFileData::SetMethodHotness(size_t index,
2402 MethodHotness::Flag flags) {
2403 DCHECK_LT(index, num_method_ids);
2404 ForMethodBitmapHotnessFlags([&](MethodHotness::Flag flag) {
2405 if ((flags & flag) != 0) {
2406 method_bitmap.StoreBit(MethodFlagBitmapIndex(
2407 static_cast<MethodHotness::Flag>(flag), index), /*value=*/ true);
2408 }
2409 return true;
2410 });
2411 }
2412
GetHotnessInfo(uint32_t dex_method_index) const2413 ProfileCompilationInfo::MethodHotness ProfileCompilationInfo::DexFileData::GetHotnessInfo(
2414 uint32_t dex_method_index) const {
2415 MethodHotness ret;
2416 ForMethodBitmapHotnessFlags([&](MethodHotness::Flag flag) {
2417 if (method_bitmap.LoadBit(MethodFlagBitmapIndex(
2418 static_cast<MethodHotness::Flag>(flag), dex_method_index))) {
2419 ret.AddFlag(static_cast<MethodHotness::Flag>(flag));
2420 }
2421 return true;
2422 });
2423 auto it = method_map.find(dex_method_index);
2424 if (it != method_map.end()) {
2425 ret.SetInlineCacheMap(&it->second);
2426 ret.AddFlag(MethodHotness::kFlagHot);
2427 }
2428 return ret;
2429 }
2430
2431 // To simplify the implementation we use the MethodHotness flag values as indexes into the internal
2432 // bitmap representation. As such, they should never change unless the profile version is updated
2433 // and the implementation changed accordingly.
2434 static_assert(ProfileCompilationInfo::MethodHotness::kFlagFirst == 1 << 0);
2435 static_assert(ProfileCompilationInfo::MethodHotness::kFlagHot == 1 << 0);
2436 static_assert(ProfileCompilationInfo::MethodHotness::kFlagStartup == 1 << 1);
2437 static_assert(ProfileCompilationInfo::MethodHotness::kFlagPostStartup == 1 << 2);
2438 static_assert(ProfileCompilationInfo::MethodHotness::kFlagLastRegular == 1 << 2);
2439 static_assert(ProfileCompilationInfo::MethodHotness::kFlag32bit == 1 << 3);
2440 static_assert(ProfileCompilationInfo::MethodHotness::kFlag64bit == 1 << 4);
2441 static_assert(ProfileCompilationInfo::MethodHotness::kFlagSensitiveThread == 1 << 5);
2442 static_assert(ProfileCompilationInfo::MethodHotness::kFlagAmStartup == 1 << 6);
2443 static_assert(ProfileCompilationInfo::MethodHotness::kFlagAmPostStartup == 1 << 7);
2444 static_assert(ProfileCompilationInfo::MethodHotness::kFlagBoot == 1 << 8);
2445 static_assert(ProfileCompilationInfo::MethodHotness::kFlagPostBoot == 1 << 9);
2446 static_assert(ProfileCompilationInfo::MethodHotness::kFlagStartupBin == 1 << 10);
2447 static_assert(ProfileCompilationInfo::MethodHotness::kFlagStartupMaxBin == 1 << 15);
2448 static_assert(ProfileCompilationInfo::MethodHotness::kFlagLastBoot == 1 << 15);
2449
GetUsedBitmapFlags() const2450 uint16_t ProfileCompilationInfo::DexFileData::GetUsedBitmapFlags() const {
2451 uint32_t used_flags = 0u;
2452 ForMethodBitmapHotnessFlags([&](MethodHotness::Flag flag) {
2453 size_t index = FlagBitmapIndex(static_cast<MethodHotness::Flag>(flag));
2454 if (method_bitmap.HasSomeBitSet(index * num_method_ids, num_method_ids)) {
2455 used_flags |= flag;
2456 }
2457 return true;
2458 });
2459 return dchecked_integral_cast<uint16_t>(used_flags);
2460 }
2461
2462 ProfileCompilationInfo::DexPcData*
FindOrAddDexPc(InlineCacheMap * inline_cache,uint32_t dex_pc)2463 ProfileCompilationInfo::FindOrAddDexPc(InlineCacheMap* inline_cache, uint32_t dex_pc) {
2464 return &(inline_cache->FindOrAdd(dex_pc, DexPcData(inline_cache->get_allocator()))->second);
2465 }
2466
GetClassDescriptors(const std::vector<const DexFile * > & dex_files,const ProfileSampleAnnotation & annotation)2467 HashSet<std::string> ProfileCompilationInfo::GetClassDescriptors(
2468 const std::vector<const DexFile*>& dex_files,
2469 const ProfileSampleAnnotation& annotation) {
2470 HashSet<std::string> ret;
2471 for (const DexFile* dex_file : dex_files) {
2472 const DexFileData* data = FindDexDataUsingAnnotations(dex_file, annotation);
2473 if (data != nullptr) {
2474 for (dex::TypeIndex type_idx : data->class_set) {
2475 ret.insert(GetTypeDescriptor(dex_file, type_idx));
2476 }
2477 } else {
2478 VLOG(compiler) << "Failed to find profile data for " << dex_file->GetLocation();
2479 }
2480 }
2481 return ret;
2482 }
2483
IsProfileFile(int fd)2484 bool ProfileCompilationInfo::IsProfileFile(int fd) {
2485 // First check if it's an empty file as we allow empty profile files.
2486 // Profiles may be created by ActivityManager or installd before we manage to
2487 // process them in the runtime or profman.
2488 struct stat stat_buffer;
2489 if (fstat(fd, &stat_buffer) != 0) {
2490 return false;
2491 }
2492
2493 if (stat_buffer.st_size == 0) {
2494 return true;
2495 }
2496
2497 // The files is not empty. Check if it contains the profile magic.
2498 size_t byte_count = sizeof(kProfileMagic);
2499 uint8_t buffer[sizeof(kProfileMagic)];
2500 if (!android::base::ReadFullyAtOffset(fd, buffer, byte_count, /*offset=*/ 0)) {
2501 return false;
2502 }
2503
2504 // Reset the offset to prepare the file for reading.
2505 off_t rc = TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_SET));
2506 if (rc == static_cast<off_t>(-1)) {
2507 PLOG(ERROR) << "Failed to reset the offset";
2508 return false;
2509 }
2510
2511 return memcmp(buffer, kProfileMagic, byte_count) == 0;
2512 }
2513
UpdateProfileKeys(const std::vector<std::unique_ptr<const DexFile>> & dex_files,bool * matched)2514 bool ProfileCompilationInfo::UpdateProfileKeys(
2515 const std::vector<std::unique_ptr<const DexFile>>& dex_files, /*out*/ bool* matched) {
2516 // This check aligns with when dex2oat falls back from "speed-profile" to "verify".
2517 //
2518 // ART Service relies on the exit code of profman, which is determined by the value of `matched`,
2519 // to judge whether it should re-dexopt for "speed-profile". Therefore, a misalignment will cause
2520 // repeated dexopt.
2521 if (IsEmpty()) {
2522 *matched = false;
2523 return true;
2524 }
2525 DCHECK(!info_.empty());
2526
2527 *matched = true;
2528
2529 // A map from the old base key to the new base key.
2530 std::unordered_map<std::string, std::string> old_key_to_new_key;
2531
2532 // A map from the new base key to all matching old base keys (an invert of the map above), for
2533 // detecting duplicate keys.
2534 std::unordered_map<std::string, std::unordered_set<std::string>> new_key_to_old_keys;
2535
2536 for (const std::unique_ptr<DexFileData>& dex_data : info_) {
2537 std::string old_base_key = GetBaseKeyFromAugmentedKey(dex_data->profile_key);
2538 bool found = false;
2539 for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
2540 if (dex_data->checksum == dex_file->GetLocationChecksum() &&
2541 dex_data->num_type_ids == dex_file->NumTypeIds() &&
2542 dex_data->num_method_ids == dex_file->NumMethodIds()) {
2543 std::string new_base_key = GetProfileDexFileBaseKey(dex_file->GetLocation());
2544 old_key_to_new_key[old_base_key] = new_base_key;
2545 new_key_to_old_keys[new_base_key].insert(old_base_key);
2546 found = true;
2547 break;
2548 }
2549 }
2550 if (!found) {
2551 *matched = false;
2552 // Keep the old key.
2553 old_key_to_new_key[old_base_key] = old_base_key;
2554 new_key_to_old_keys[old_base_key].insert(old_base_key);
2555 }
2556 }
2557
2558 for (const auto& [new_key, old_keys] : new_key_to_old_keys) {
2559 if (old_keys.size() > 1) {
2560 LOG(ERROR) << "Cannot update multiple profile keys [" << android::base::Join(old_keys, ", ")
2561 << "] to the same new key '" << new_key << "'";
2562 return false;
2563 }
2564 }
2565
2566 // Check passed. Now perform the actual mutation.
2567 profile_key_map_.clear();
2568
2569 for (const std::unique_ptr<DexFileData>& dex_data : info_) {
2570 std::string old_base_key = GetBaseKeyFromAugmentedKey(dex_data->profile_key);
2571 const std::string& new_base_key = old_key_to_new_key[old_base_key];
2572 DCHECK(!new_base_key.empty());
2573 // Retain the annotation (if any) during the renaming by re-attaching the info from the old key.
2574 dex_data->profile_key = MigrateAnnotationInfo(new_base_key, dex_data->profile_key);
2575 profile_key_map_.Put(dex_data->profile_key, dex_data->profile_index);
2576 }
2577
2578 return true;
2579 }
2580
ProfileFilterFnAcceptAll(const std::string & dex_location,uint32_t checksum)2581 bool ProfileCompilationInfo::ProfileFilterFnAcceptAll(
2582 [[maybe_unused]] const std::string& dex_location, [[maybe_unused]] uint32_t checksum) {
2583 return true;
2584 }
2585
ClearData()2586 void ProfileCompilationInfo::ClearData() {
2587 profile_key_map_.clear();
2588 info_.clear();
2589 extra_descriptors_indexes_.clear();
2590 extra_descriptors_.clear();
2591 }
2592
ClearDataAndAdjustVersion(bool for_boot_image)2593 void ProfileCompilationInfo::ClearDataAndAdjustVersion(bool for_boot_image) {
2594 ClearData();
2595 memcpy(version_,
2596 for_boot_image ? kProfileVersionForBootImage : kProfileVersion,
2597 kProfileVersionSize);
2598 }
2599
IsForBootImage() const2600 bool ProfileCompilationInfo::IsForBootImage() const {
2601 return memcmp(version_, kProfileVersionForBootImage, sizeof(kProfileVersionForBootImage)) == 0;
2602 }
2603
GetVersion() const2604 const uint8_t* ProfileCompilationInfo::GetVersion() const {
2605 return version_;
2606 }
2607
ContainsClass(dex::TypeIndex type_index) const2608 bool ProfileCompilationInfo::DexFileData::ContainsClass(dex::TypeIndex type_index) const {
2609 return class_set.find(type_index) != class_set.end();
2610 }
2611
ClassesDataSize() const2612 uint32_t ProfileCompilationInfo::DexFileData::ClassesDataSize() const {
2613 return class_set.empty()
2614 ? 0u
2615 : sizeof(ProfileIndexType) + // Which dex file.
2616 sizeof(uint16_t) + // Number of classes.
2617 sizeof(uint16_t) * class_set.size(); // Type index diffs.
2618 }
2619
WriteClasses(SafeBuffer & buffer) const2620 void ProfileCompilationInfo::DexFileData::WriteClasses(SafeBuffer& buffer) const {
2621 if (class_set.empty()) {
2622 return;
2623 }
2624 buffer.WriteUintAndAdvance(profile_index);
2625 buffer.WriteUintAndAdvance(dchecked_integral_cast<uint16_t>(class_set.size()));
2626 WriteClassSet(buffer, class_set);
2627 }
2628
ReadClasses(SafeBuffer & buffer,const dchecked_vector<ExtraDescriptorIndex> & extra_descriptors_remap,std::string * error)2629 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::DexFileData::ReadClasses(
2630 SafeBuffer& buffer,
2631 const dchecked_vector<ExtraDescriptorIndex>& extra_descriptors_remap,
2632 std::string* error) {
2633 uint16_t classes_size;
2634 if (!buffer.ReadUintAndAdvance(&classes_size)) {
2635 *error = "Error reading classes size.";
2636 return ProfileLoadStatus::kBadData;
2637 }
2638 uint16_t num_valid_type_indexes = dchecked_integral_cast<uint16_t>(
2639 std::min<size_t>(num_type_ids + extra_descriptors_remap.size(), DexFile::kDexNoIndex16));
2640 uint16_t type_index = 0u;
2641 for (size_t i = 0; i != classes_size; ++i) {
2642 uint16_t type_index_diff;
2643 if (!buffer.ReadUintAndAdvance(&type_index_diff)) {
2644 *error = "Error reading class type index diff.";
2645 return ProfileLoadStatus::kBadData;
2646 }
2647 if (type_index_diff == 0u && i != 0u) {
2648 *error = "Duplicate type index.";
2649 return ProfileLoadStatus::kBadData;
2650 }
2651 if (type_index_diff >= num_valid_type_indexes - type_index) {
2652 *error = "Invalid type index.";
2653 return ProfileLoadStatus::kBadData;
2654 }
2655 type_index += type_index_diff;
2656 if (type_index >= num_type_ids) {
2657 uint32_t new_extra_descriptor_index = extra_descriptors_remap[type_index - num_type_ids];
2658 if (new_extra_descriptor_index >= DexFile::kDexNoIndex16 - num_type_ids) {
2659 *error = "Remapped type index out of range.";
2660 return ProfileLoadStatus::kMergeError;
2661 }
2662 class_set.insert(dex::TypeIndex(num_type_ids + new_extra_descriptor_index));
2663 } else {
2664 class_set.insert(dex::TypeIndex(type_index));
2665 }
2666 }
2667 return ProfileLoadStatus::kSuccess;
2668 }
2669
SkipClasses(SafeBuffer & buffer,std::string * error)2670 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::DexFileData::SkipClasses(
2671 SafeBuffer& buffer,
2672 std::string* error) {
2673 uint16_t classes_size;
2674 if (!buffer.ReadUintAndAdvance(&classes_size)) {
2675 *error = "Error reading classes size to skip.";
2676 return ProfileLoadStatus::kBadData;
2677 }
2678 size_t following_data_size = static_cast<size_t>(classes_size) * sizeof(uint16_t);
2679 if (following_data_size > buffer.GetAvailableBytes()) {
2680 *error = "Classes data size to skip exceeds remaining data.";
2681 return ProfileLoadStatus::kBadData;
2682 }
2683 buffer.Advance(following_data_size);
2684 return ProfileLoadStatus::kSuccess;
2685 }
2686
MethodsDataSize(uint16_t * method_flags,size_t * saved_bitmap_bit_size) const2687 uint32_t ProfileCompilationInfo::DexFileData::MethodsDataSize(
2688 /*out*/ uint16_t* method_flags,
2689 /*out*/ size_t* saved_bitmap_bit_size) const {
2690 uint16_t local_method_flags = GetUsedBitmapFlags();
2691 size_t local_saved_bitmap_bit_size = POPCOUNT(local_method_flags) * num_method_ids;
2692 if (!method_map.empty()) {
2693 local_method_flags |= enum_cast<uint16_t>(MethodHotness::kFlagHot);
2694 }
2695 size_t size = 0u;
2696 if (local_method_flags != 0u) {
2697 size_t num_hot_methods = method_map.size();
2698 size_t num_dex_pc_entries = 0u;
2699 size_t num_class_entries = 0u;
2700 for (const auto& method_entry : method_map) {
2701 const InlineCacheMap& inline_cache_map = method_entry.second;
2702 num_dex_pc_entries += inline_cache_map.size();
2703 for (const auto& inline_cache_entry : inline_cache_map) {
2704 const DexPcData& dex_pc_data = inline_cache_entry.second;
2705 num_class_entries += dex_pc_data.classes.size();
2706 }
2707 }
2708
2709 constexpr size_t kPerHotMethodSize =
2710 sizeof(uint16_t) + // Method index diff.
2711 sizeof(uint16_t); // Inline cache size.
2712 constexpr size_t kPerDexPcEntrySize =
2713 sizeof(uint16_t) + // Dex PC.
2714 sizeof(uint8_t); // Number of inline cache classes.
2715 constexpr size_t kPerClassEntrySize =
2716 sizeof(uint16_t); // Type index diff.
2717
2718 size_t saved_bitmap_byte_size = BitsToBytesRoundUp(local_saved_bitmap_bit_size);
2719 size = sizeof(ProfileIndexType) + // Which dex file.
2720 sizeof(uint32_t) + // Total size of following data.
2721 sizeof(uint16_t) + // Method flags.
2722 saved_bitmap_byte_size + // Bitmap data.
2723 num_hot_methods * kPerHotMethodSize + // Data for hot methods.
2724 num_dex_pc_entries * kPerDexPcEntrySize + // Data for dex pc entries.
2725 num_class_entries * kPerClassEntrySize; // Data for inline cache class entries.
2726 }
2727 if (method_flags != nullptr) {
2728 *method_flags = local_method_flags;
2729 }
2730 if (saved_bitmap_bit_size != nullptr) {
2731 *saved_bitmap_bit_size = local_saved_bitmap_bit_size;
2732 }
2733 return size;
2734 }
2735
WriteMethods(SafeBuffer & buffer) const2736 void ProfileCompilationInfo::DexFileData::WriteMethods(SafeBuffer& buffer) const {
2737 uint16_t method_flags;
2738 size_t saved_bitmap_bit_size;
2739 uint32_t methods_data_size = MethodsDataSize(&method_flags, &saved_bitmap_bit_size);
2740 if (methods_data_size == 0u) {
2741 return; // No data to write.
2742 }
2743 DCHECK_GE(buffer.GetAvailableBytes(), methods_data_size);
2744 uint32_t expected_available_bytes_at_end = buffer.GetAvailableBytes() - methods_data_size;
2745
2746 // Write the profile index.
2747 buffer.WriteUintAndAdvance(profile_index);
2748 // Write the total size of the following methods data (without the profile index
2749 // and the total size itself) for easy skipping when the dex file is filtered out.
2750 uint32_t following_data_size = methods_data_size - sizeof(ProfileIndexType) - sizeof(uint32_t);
2751 buffer.WriteUintAndAdvance(following_data_size);
2752 // Write the used method flags.
2753 buffer.WriteUintAndAdvance(method_flags);
2754
2755 // Write the bitmap data.
2756 size_t saved_bitmap_byte_size = BitsToBytesRoundUp(saved_bitmap_bit_size);
2757 DCHECK_LE(saved_bitmap_byte_size, buffer.GetAvailableBytes());
2758 BitMemoryRegion saved_bitmap(buffer.GetCurrentPtr(), /*bit_start=*/ 0, saved_bitmap_bit_size);
2759 size_t saved_bitmap_index = 0u;
2760 ForMethodBitmapHotnessFlags([&](MethodHotness::Flag flag) {
2761 if ((method_flags & flag) != 0u) {
2762 size_t index = FlagBitmapIndex(static_cast<MethodHotness::Flag>(flag));
2763 BitMemoryRegion src = method_bitmap.Subregion(index * num_method_ids, num_method_ids);
2764 saved_bitmap.Subregion(saved_bitmap_index * num_method_ids, num_method_ids).CopyBits(src);
2765 ++saved_bitmap_index;
2766 }
2767 return true;
2768 });
2769 DCHECK_EQ(saved_bitmap_index * num_method_ids, saved_bitmap_bit_size);
2770 // Clear the padding bits.
2771 size_t padding_bit_size = saved_bitmap_byte_size * kBitsPerByte - saved_bitmap_bit_size;
2772 BitMemoryRegion padding_region(buffer.GetCurrentPtr(), saved_bitmap_bit_size, padding_bit_size);
2773 padding_region.StoreBits(/*bit_offset=*/ 0u, /*value=*/ 0u, /*bit_length=*/ padding_bit_size);
2774 buffer.Advance(saved_bitmap_byte_size);
2775
2776 uint16_t last_method_index = 0;
2777 for (const auto& method_entry : method_map) {
2778 uint16_t method_index = method_entry.first;
2779 const InlineCacheMap& inline_cache_map = method_entry.second;
2780
2781 // Store the difference between the method indices for better compression.
2782 // The SafeMap is ordered by method_id, so the difference will always be non negative.
2783 DCHECK_GE(method_index, last_method_index);
2784 uint16_t diff_with_last_method_index = method_index - last_method_index;
2785 last_method_index = method_index;
2786 buffer.WriteUintAndAdvance(diff_with_last_method_index);
2787
2788 // Add inline cache map size.
2789 buffer.WriteUintAndAdvance(dchecked_integral_cast<uint16_t>(inline_cache_map.size()));
2790
2791 // Add inline cache entries.
2792 for (const auto& inline_cache_entry : inline_cache_map) {
2793 uint16_t dex_pc = inline_cache_entry.first;
2794 const DexPcData& dex_pc_data = inline_cache_entry.second;
2795 const ArenaSet<dex::TypeIndex>& classes = dex_pc_data.classes;
2796
2797 // Add the dex pc.
2798 buffer.WriteUintAndAdvance(dex_pc);
2799
2800 // Add the megamorphic/missing_types encoding if needed and continue.
2801 // In either cases we don't add any classes to the profiles and so there's
2802 // no point to continue.
2803 // TODO: in case we miss types there is still value to add the rest of the
2804 // classes. (This requires changing profile version or using a new section type.)
2805 if (dex_pc_data.is_missing_types) {
2806 // At this point the megamorphic flag should not be set.
2807 DCHECK(!dex_pc_data.is_megamorphic);
2808 DCHECK_EQ(classes.size(), 0u);
2809 buffer.WriteUintAndAdvance(kIsMissingTypesEncoding);
2810 continue;
2811 } else if (dex_pc_data.is_megamorphic) {
2812 DCHECK_EQ(classes.size(), 0u);
2813 buffer.WriteUintAndAdvance(kIsMegamorphicEncoding);
2814 continue;
2815 }
2816
2817 DCHECK_LT(classes.size(), ProfileCompilationInfo::kIndividualInlineCacheSize);
2818 DCHECK_NE(classes.size(), 0u) << "InlineCache contains a dex_pc with 0 classes";
2819
2820 // Add the number of classes for the dex PC.
2821 buffer.WriteUintAndAdvance(dchecked_integral_cast<uint8_t>(classes.size()));
2822 // Store the class set.
2823 WriteClassSet(buffer, classes);
2824 }
2825 }
2826
2827 // Check if we've written the right number of bytes.
2828 DCHECK_EQ(buffer.GetAvailableBytes(), expected_available_bytes_at_end);
2829 }
2830
ReadMethods(SafeBuffer & buffer,const dchecked_vector<ExtraDescriptorIndex> & extra_descriptors_remap,std::string * error)2831 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::DexFileData::ReadMethods(
2832 SafeBuffer& buffer,
2833 const dchecked_vector<ExtraDescriptorIndex>& extra_descriptors_remap,
2834 std::string* error) {
2835 uint32_t following_data_size;
2836 if (!buffer.ReadUintAndAdvance(&following_data_size)) {
2837 *error = "Error reading methods data size.";
2838 return ProfileLoadStatus::kBadData;
2839 }
2840 if (following_data_size > buffer.GetAvailableBytes()) {
2841 *error = "Methods data size exceeds available data size.";
2842 return ProfileLoadStatus::kBadData;
2843 }
2844 uint32_t expected_available_bytes_at_end = buffer.GetAvailableBytes() - following_data_size;
2845
2846 // Read method flags.
2847 uint16_t method_flags;
2848 if (!buffer.ReadUintAndAdvance(&method_flags)) {
2849 *error = "Error reading method flags.";
2850 return ProfileLoadStatus::kBadData;
2851 }
2852 if (!is_for_boot_image && method_flags >= (MethodHotness::kFlagLastRegular << 1)) {
2853 // The profile we're loading contains data for boot image.
2854 *error = "Method flags contain boot image profile flags for non-boot image profile.";
2855 return ProfileLoadStatus::kBadData;
2856 }
2857
2858 // Read method bitmap.
2859 size_t saved_bitmap_bit_size = POPCOUNT(method_flags & ~MethodHotness::kFlagHot) * num_method_ids;
2860 size_t saved_bitmap_byte_size = BitsToBytesRoundUp(saved_bitmap_bit_size);
2861 if (sizeof(uint16_t) + saved_bitmap_byte_size > following_data_size) {
2862 *error = "Insufficient available data for method bitmap.";
2863 return ProfileLoadStatus::kBadData;
2864 }
2865 BitMemoryRegion saved_bitmap(buffer.GetCurrentPtr(), /*bit_start=*/ 0, saved_bitmap_bit_size);
2866 size_t saved_bitmap_index = 0u;
2867 ForMethodBitmapHotnessFlags([&](MethodHotness::Flag flag) {
2868 if ((method_flags & flag) != 0u) {
2869 size_t index = FlagBitmapIndex(static_cast<MethodHotness::Flag>(flag));
2870 BitMemoryRegion src =
2871 saved_bitmap.Subregion(saved_bitmap_index * num_method_ids, num_method_ids);
2872 method_bitmap.Subregion(index * num_method_ids, num_method_ids).OrBits(src);
2873 ++saved_bitmap_index;
2874 }
2875 return true;
2876 });
2877 buffer.Advance(saved_bitmap_byte_size);
2878
2879 // Load hot methods.
2880 if ((method_flags & MethodHotness::kFlagHot) != 0u) {
2881 uint32_t num_valid_method_indexes =
2882 std::min<uint32_t>(kMaxSupportedMethodIndex + 1u, num_method_ids);
2883 uint16_t num_valid_type_indexes = dchecked_integral_cast<uint16_t>(
2884 std::min<size_t>(num_type_ids + extra_descriptors_remap.size(), DexFile::kDexNoIndex16));
2885 uint16_t method_index = 0;
2886 bool first_diff = true;
2887 while (buffer.GetAvailableBytes() > expected_available_bytes_at_end) {
2888 uint16_t diff_with_last_method_index;
2889 if (!buffer.ReadUintAndAdvance(&diff_with_last_method_index)) {
2890 *error = "Error reading method index diff.";
2891 return ProfileLoadStatus::kBadData;
2892 }
2893 if (diff_with_last_method_index == 0u && !first_diff) {
2894 *error = "Duplicate method index.";
2895 return ProfileLoadStatus::kBadData;
2896 }
2897 first_diff = false;
2898 if (diff_with_last_method_index >= num_valid_method_indexes - method_index) {
2899 *error = "Invalid method index.";
2900 return ProfileLoadStatus::kBadData;
2901 }
2902 method_index += diff_with_last_method_index;
2903 InlineCacheMap* inline_cache = FindOrAddHotMethod(method_index);
2904 DCHECK(inline_cache != nullptr);
2905
2906 // Load inline cache map size.
2907 uint16_t inline_cache_size;
2908 if (!buffer.ReadUintAndAdvance(&inline_cache_size)) {
2909 *error = "Error reading inline cache size.";
2910 return ProfileLoadStatus::kBadData;
2911 }
2912 for (uint16_t ic_index = 0; ic_index != inline_cache_size; ++ic_index) {
2913 // Load dex pc.
2914 uint16_t dex_pc;
2915 if (!buffer.ReadUintAndAdvance(&dex_pc)) {
2916 *error = "Error reading inline cache dex pc.";
2917 return ProfileLoadStatus::kBadData;
2918 }
2919 DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, dex_pc);
2920 DCHECK(dex_pc_data != nullptr);
2921
2922 // Load inline cache classes.
2923 uint8_t inline_cache_classes_size;
2924 if (!buffer.ReadUintAndAdvance(&inline_cache_classes_size)) {
2925 *error = "Error reading inline cache classes size.";
2926 return ProfileLoadStatus::kBadData;
2927 }
2928 if (inline_cache_classes_size == kIsMissingTypesEncoding) {
2929 dex_pc_data->SetIsMissingTypes();
2930 } else if (inline_cache_classes_size == kIsMegamorphicEncoding) {
2931 dex_pc_data->SetIsMegamorphic();
2932 } else if (inline_cache_classes_size >= kIndividualInlineCacheSize) {
2933 *error = "Inline cache size too large.";
2934 return ProfileLoadStatus::kBadData;
2935 } else {
2936 uint16_t type_index = 0u;
2937 for (size_t i = 0; i != inline_cache_classes_size; ++i) {
2938 uint16_t type_index_diff;
2939 if (!buffer.ReadUintAndAdvance(&type_index_diff)) {
2940 *error = "Error reading inline cache type index diff.";
2941 return ProfileLoadStatus::kBadData;
2942 }
2943 if (type_index_diff == 0u && i != 0u) {
2944 *error = "Duplicate inline cache type index.";
2945 return ProfileLoadStatus::kBadData;
2946 }
2947 if (type_index_diff >= num_valid_type_indexes - type_index) {
2948 *error = "Invalid inline cache type index.";
2949 return ProfileLoadStatus::kBadData;
2950 }
2951 type_index += type_index_diff;
2952 if (type_index >= num_type_ids) {
2953 ExtraDescriptorIndex new_extra_descriptor_index =
2954 extra_descriptors_remap[type_index - num_type_ids];
2955 if (new_extra_descriptor_index >= DexFile::kDexNoIndex16 - num_type_ids) {
2956 *error = "Remapped inline cache type index out of range.";
2957 return ProfileLoadStatus::kMergeError;
2958 }
2959 dex_pc_data->AddClass(dex::TypeIndex(num_type_ids + new_extra_descriptor_index));
2960 } else {
2961 dex_pc_data->AddClass(dex::TypeIndex(type_index));
2962 }
2963 }
2964 }
2965 }
2966 }
2967 }
2968
2969 if (buffer.GetAvailableBytes() != expected_available_bytes_at_end) {
2970 *error = "Methods data did not end at expected position.";
2971 return ProfileLoadStatus::kBadData;
2972 }
2973
2974 return ProfileLoadStatus::kSuccess;
2975 }
2976
SkipMethods(SafeBuffer & buffer,std::string * error)2977 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::DexFileData::SkipMethods(
2978 SafeBuffer& buffer,
2979 std::string* error) {
2980 uint32_t following_data_size;
2981 if (!buffer.ReadUintAndAdvance(&following_data_size)) {
2982 *error = "Error reading methods data size to skip.";
2983 return ProfileLoadStatus::kBadData;
2984 }
2985 if (following_data_size > buffer.GetAvailableBytes()) {
2986 *error = "Methods data size to skip exceeds remaining data.";
2987 return ProfileLoadStatus::kBadData;
2988 }
2989 buffer.Advance(following_data_size);
2990 return ProfileLoadStatus::kSuccess;
2991 }
2992
WriteClassSet(SafeBuffer & buffer,const ArenaSet<dex::TypeIndex> & class_set)2993 void ProfileCompilationInfo::DexFileData::WriteClassSet(
2994 SafeBuffer& buffer,
2995 const ArenaSet<dex::TypeIndex>& class_set) {
2996 // Store the difference between the type indexes for better compression.
2997 uint16_t last_type_index = 0u;
2998 for (const dex::TypeIndex& type_index : class_set) {
2999 DCHECK_GE(type_index.index_, last_type_index);
3000 uint16_t diff_with_last_type_index = type_index.index_ - last_type_index;
3001 last_type_index = type_index.index_;
3002 buffer.WriteUintAndAdvance(diff_with_last_type_index);
3003 }
3004 }
3005
GetSizeWarningThresholdBytes() const3006 size_t ProfileCompilationInfo::GetSizeWarningThresholdBytes() const {
3007 return IsForBootImage() ? kSizeWarningThresholdBootBytes : kSizeWarningThresholdBytes;
3008 }
3009
GetSizeErrorThresholdBytes() const3010 size_t ProfileCompilationInfo::GetSizeErrorThresholdBytes() const {
3011 return IsForBootImage() ? kSizeErrorThresholdBootBytes : kSizeErrorThresholdBytes;
3012 }
3013
operator <<(std::ostream & stream,ProfileCompilationInfo::DexReferenceDumper dumper)3014 std::ostream& operator<<(std::ostream& stream,
3015 ProfileCompilationInfo::DexReferenceDumper dumper) {
3016 stream << "[profile_key=" << dumper.GetProfileKey()
3017 << ",dex_checksum=" << std::hex << dumper.GetDexChecksum() << std::dec
3018 << ",num_type_ids=" << dumper.GetNumTypeIds()
3019 << ",num_method_ids=" << dumper.GetNumMethodIds()
3020 << "]";
3021 return stream;
3022 }
3023
FlattenProfileData()3024 FlattenProfileData::FlattenProfileData() :
3025 max_aggregation_for_methods_(0),
3026 max_aggregation_for_classes_(0) {
3027 }
3028
ItemMetadata()3029 FlattenProfileData::ItemMetadata::ItemMetadata() :
3030 flags_(0) {
3031 }
3032
ItemMetadata(const ItemMetadata & other)3033 FlattenProfileData::ItemMetadata::ItemMetadata(const ItemMetadata& other) :
3034 flags_(other.flags_),
3035 annotations_(other.annotations_) {
3036 }
3037
ExtractProfileData(const std::vector<std::unique_ptr<const DexFile>> & dex_files) const3038 std::unique_ptr<FlattenProfileData> ProfileCompilationInfo::ExtractProfileData(
3039 const std::vector<std::unique_ptr<const DexFile>>& dex_files) const {
3040
3041 std::unique_ptr<FlattenProfileData> result(new FlattenProfileData());
3042
3043 auto create_metadata_fn = []() { return FlattenProfileData::ItemMetadata(); };
3044
3045 // Iterate through all the dex files, find the methods/classes associated with each of them,
3046 // and add them to the flatten result.
3047 for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
3048 // Find all the dex data for the given dex file.
3049 // We may have multiple dex data if the methods or classes were added using
3050 // different annotations.
3051 std::vector<const DexFileData*> all_dex_data;
3052 FindAllDexData(dex_file.get(), &all_dex_data);
3053 for (const DexFileData* dex_data : all_dex_data) {
3054 // Extract the annotation from the key as we want to store it in the flatten result.
3055 ProfileSampleAnnotation annotation = GetAnnotationFromKey(dex_data->profile_key);
3056
3057 // Check which methods from the current dex files are in the profile.
3058 for (uint32_t method_idx = 0; method_idx < dex_data->num_method_ids; ++method_idx) {
3059 MethodHotness hotness = dex_data->GetHotnessInfo(method_idx);
3060 if (!hotness.IsInProfile()) {
3061 // Not in the profile, continue.
3062 continue;
3063 }
3064 // The method is in the profile, create metadata item for it and added to the result.
3065 MethodReference ref(dex_file.get(), method_idx);
3066 FlattenProfileData::ItemMetadata& metadata =
3067 result->method_metadata_.GetOrCreate(ref, create_metadata_fn);
3068 metadata.flags_ |= hotness.flags_;
3069 metadata.annotations_.push_back(annotation);
3070 // Update the max aggregation counter for methods.
3071 // This is essentially a cache, to avoid traversing all the methods just to find out
3072 // this value.
3073 result->max_aggregation_for_methods_ = std::max(
3074 result->max_aggregation_for_methods_,
3075 static_cast<uint32_t>(metadata.annotations_.size()));
3076 }
3077
3078 // Check which classes from the current dex files are in the profile.
3079 for (const dex::TypeIndex& type_index : dex_data->class_set) {
3080 if (type_index.index_ >= dex_file->NumTypeIds()) {
3081 // Not a valid `dex::TypeIndex` for `TypeReference`.
3082 // TODO: Rewrite the API to use descriptors or the `ProfileCompilationInfo` directly
3083 // instead of the `FlattenProfileData` helper class.
3084 continue;
3085 }
3086 TypeReference ref(dex_file.get(), type_index);
3087 FlattenProfileData::ItemMetadata& metadata =
3088 result->class_metadata_.GetOrCreate(ref, create_metadata_fn);
3089 metadata.annotations_.push_back(annotation);
3090 // Update the max aggregation counter for classes.
3091 result->max_aggregation_for_classes_ = std::max(
3092 result->max_aggregation_for_classes_,
3093 static_cast<uint32_t>(metadata.annotations_.size()));
3094 }
3095 }
3096 }
3097
3098 return result;
3099 }
3100
MergeData(const FlattenProfileData & other)3101 void FlattenProfileData::MergeData(const FlattenProfileData& other) {
3102 auto create_metadata_fn = []() { return FlattenProfileData::ItemMetadata(); };
3103 for (const auto& it : other.method_metadata_) {
3104 const MethodReference& otherRef = it.first;
3105 const FlattenProfileData::ItemMetadata otherData = it.second;
3106 const std::list<ProfileCompilationInfo::ProfileSampleAnnotation>& other_annotations =
3107 otherData.GetAnnotations();
3108
3109 FlattenProfileData::ItemMetadata& metadata =
3110 method_metadata_.GetOrCreate(otherRef, create_metadata_fn);
3111 metadata.flags_ |= otherData.GetFlags();
3112 metadata.annotations_.insert(
3113 metadata.annotations_.end(), other_annotations.begin(), other_annotations.end());
3114
3115 max_aggregation_for_methods_ = std::max(
3116 max_aggregation_for_methods_,
3117 static_cast<uint32_t>(metadata.annotations_.size()));
3118 }
3119 for (const auto& it : other.class_metadata_) {
3120 const TypeReference& otherRef = it.first;
3121 const FlattenProfileData::ItemMetadata otherData = it.second;
3122 const std::list<ProfileCompilationInfo::ProfileSampleAnnotation>& other_annotations =
3123 otherData.GetAnnotations();
3124
3125 FlattenProfileData::ItemMetadata& metadata =
3126 class_metadata_.GetOrCreate(otherRef, create_metadata_fn);
3127 metadata.flags_ |= otherData.GetFlags();
3128 metadata.annotations_.insert(
3129 metadata.annotations_.end(), other_annotations.begin(), other_annotations.end());
3130
3131 max_aggregation_for_classes_ = std::max(
3132 max_aggregation_for_classes_,
3133 static_cast<uint32_t>(metadata.annotations_.size()));
3134 }
3135 }
3136
3137 } // namespace art
3138