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