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