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