Home | History | Annotate | Download | only in jit
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "profile_compilation_info.h"
     18 
     19 #include "errno.h"
     20 #include <limits.h>
     21 #include <string>
     22 #include <vector>
     23 #include <stdlib.h>
     24 #include <sys/file.h>
     25 #include <sys/stat.h>
     26 #include <sys/uio.h>
     27 #include <sys/types.h>
     28 #include <unistd.h>
     29 #include <sys/types.h>
     30 #include <unistd.h>
     31 #include <zlib.h>
     32 #include <base/time_utils.h>
     33 
     34 #include "base/arena_allocator.h"
     35 #include "base/dumpable.h"
     36 #include "base/mutex.h"
     37 #include "base/scoped_flock.h"
     38 #include "base/stl_util.h"
     39 #include "base/systrace.h"
     40 #include "base/unix_file/fd_file.h"
     41 #include "jit/profiling_info.h"
     42 #include "os.h"
     43 #include "safe_map.h"
     44 #include "utils.h"
     45 #include "android-base/file.h"
     46 
     47 namespace art {
     48 
     49 const uint8_t ProfileCompilationInfo::kProfileMagic[] = { 'p', 'r', 'o', '\0' };
     50 // Last profile version: update the multidex separator.
     51 const uint8_t ProfileCompilationInfo::kProfileVersion[] = { '0', '0', '9', '\0' };
     52 
     53 static constexpr uint16_t kMaxDexFileKeyLength = PATH_MAX;
     54 
     55 // Debug flag to ignore checksums when testing if a method or a class is present in the profile.
     56 // Used to facilitate testing profile guided compilation across a large number of apps
     57 // using the same test profile.
     58 static constexpr bool kDebugIgnoreChecksum = false;
     59 
     60 static constexpr uint8_t kIsMissingTypesEncoding = 6;
     61 static constexpr uint8_t kIsMegamorphicEncoding = 7;
     62 
     63 static_assert(sizeof(InlineCache::kIndividualCacheSize) == sizeof(uint8_t),
     64               "InlineCache::kIndividualCacheSize does not have the expect type size");
     65 static_assert(InlineCache::kIndividualCacheSize < kIsMegamorphicEncoding,
     66               "InlineCache::kIndividualCacheSize is larger than expected");
     67 static_assert(InlineCache::kIndividualCacheSize < kIsMissingTypesEncoding,
     68               "InlineCache::kIndividualCacheSize is larger than expected");
     69 
     70 static bool ChecksumMatch(uint32_t dex_file_checksum, uint32_t checksum) {
     71   return kDebugIgnoreChecksum || dex_file_checksum == checksum;
     72 }
     73 
     74 ProfileCompilationInfo::ProfileCompilationInfo(ArenaPool* custom_arena_pool)
     75     : default_arena_pool_(),
     76       arena_(custom_arena_pool),
     77       info_(arena_.Adapter(kArenaAllocProfile)),
     78       profile_key_map_(std::less<const std::string>(), arena_.Adapter(kArenaAllocProfile)) {
     79 }
     80 
     81 ProfileCompilationInfo::ProfileCompilationInfo()
     82     : default_arena_pool_(/*use_malloc*/true, /*low_4gb*/false, "ProfileCompilationInfo"),
     83       arena_(&default_arena_pool_),
     84       info_(arena_.Adapter(kArenaAllocProfile)),
     85       profile_key_map_(std::less<const std::string>(), arena_.Adapter(kArenaAllocProfile)) {
     86 }
     87 
     88 ProfileCompilationInfo::~ProfileCompilationInfo() {
     89   VLOG(profiler) << Dumpable<MemStats>(arena_.GetMemStats());
     90   for (DexFileData* data : info_) {
     91     delete data;
     92   }
     93 }
     94 
     95 void ProfileCompilationInfo::DexPcData::AddClass(uint16_t dex_profile_idx,
     96                                                  const dex::TypeIndex& type_idx) {
     97   if (is_megamorphic || is_missing_types) {
     98     return;
     99   }
    100 
    101   // Perform an explicit lookup for the type instead of directly emplacing the
    102   // element. We do this because emplace() allocates the node before doing the
    103   // lookup and if it then finds an identical element, it shall deallocate the
    104   // node. For Arena allocations, that's essentially a leak.
    105   ClassReference ref(dex_profile_idx, type_idx);
    106   auto it = classes.find(ref);
    107   if (it != classes.end()) {
    108     // The type index exists.
    109     return;
    110   }
    111 
    112   // Check if the adding the type will cause the cache to become megamorphic.
    113   if (classes.size() + 1 >= InlineCache::kIndividualCacheSize) {
    114     is_megamorphic = true;
    115     classes.clear();
    116     return;
    117   }
    118 
    119   // The type does not exist and the inline cache will not be megamorphic.
    120   classes.insert(ref);
    121 }
    122 
    123 // Transform the actual dex location into relative paths.
    124 // Note: this is OK because we don't store profiles of different apps into the same file.
    125 // Apps with split apks don't cause trouble because each split has a different name and will not
    126 // collide with other entries.
    127 std::string ProfileCompilationInfo::GetProfileDexFileKey(const std::string& dex_location) {
    128   DCHECK(!dex_location.empty());
    129   size_t last_sep_index = dex_location.find_last_of('/');
    130   if (last_sep_index == std::string::npos) {
    131     return dex_location;
    132   } else {
    133     DCHECK(last_sep_index < dex_location.size());
    134     return dex_location.substr(last_sep_index + 1);
    135   }
    136 }
    137 
    138 bool ProfileCompilationInfo::AddMethodIndex(MethodHotness::Flag flags, const MethodReference& ref) {
    139   DexFileData* data = GetOrAddDexFileData(ref.dex_file);
    140   if (data == nullptr) {
    141     return false;
    142   }
    143   return data->AddMethod(flags, ref.dex_method_index);
    144 }
    145 
    146 bool ProfileCompilationInfo::AddMethodIndex(MethodHotness::Flag flags,
    147                                             const std::string& dex_location,
    148                                             uint32_t checksum,
    149                                             uint16_t method_idx,
    150                                             uint32_t num_method_ids) {
    151   DexFileData* data = GetOrAddDexFileData(GetProfileDexFileKey(dex_location),
    152                                           checksum,
    153                                           num_method_ids);
    154   if (data == nullptr) {
    155     return false;
    156   }
    157   return data->AddMethod(flags, method_idx);
    158 }
    159 
    160 bool ProfileCompilationInfo::AddMethods(const std::vector<ProfileMethodInfo>& methods) {
    161   for (const ProfileMethodInfo& method : methods) {
    162     if (!AddMethod(method)) {
    163       return false;
    164     }
    165   }
    166   return true;
    167 }
    168 
    169 bool ProfileCompilationInfo::AddClasses(const std::set<DexCacheResolvedClasses>& resolved_classes) {
    170   for (const DexCacheResolvedClasses& dex_cache : resolved_classes) {
    171     if (!AddResolvedClasses(dex_cache)) {
    172       return false;
    173     }
    174   }
    175   return true;
    176 }
    177 
    178 bool ProfileCompilationInfo::Load(const std::string& filename, bool clear_if_invalid) {
    179   ScopedTrace trace(__PRETTY_FUNCTION__);
    180   std::string error;
    181   int flags = O_RDWR | O_NOFOLLOW | O_CLOEXEC;
    182   // There's no need to fsync profile data right away. We get many chances
    183   // to write it again in case something goes wrong. We can rely on a simple
    184   // close(), no sync, and let to the kernel decide when to write to disk.
    185   ScopedFlock profile_file = LockedFile::Open(filename.c_str(), flags,
    186                                               /*block*/false, &error);
    187 
    188   if (profile_file.get() == nullptr) {
    189     LOG(WARNING) << "Couldn't lock the profile file " << filename << ": " << error;
    190     return false;
    191   }
    192 
    193   int fd = profile_file->Fd();
    194 
    195   ProfileLoadSatus status = LoadInternal(fd, &error);
    196   if (status == kProfileLoadSuccess) {
    197     return true;
    198   }
    199 
    200   if (clear_if_invalid &&
    201       ((status == kProfileLoadVersionMismatch) || (status == kProfileLoadBadData))) {
    202     LOG(WARNING) << "Clearing bad or obsolete profile data from file "
    203                  << filename << ": " << error;
    204     if (profile_file->ClearContent()) {
    205       return true;
    206     } else {
    207       PLOG(WARNING) << "Could not clear profile file: " << filename;
    208       return false;
    209     }
    210   }
    211 
    212   LOG(WARNING) << "Could not load profile data from file " << filename << ": " << error;
    213   return false;
    214 }
    215 
    216 bool ProfileCompilationInfo::Save(const std::string& filename, uint64_t* bytes_written) {
    217   ScopedTrace trace(__PRETTY_FUNCTION__);
    218   std::string error;
    219   int flags = O_WRONLY | O_NOFOLLOW | O_CLOEXEC;
    220   // There's no need to fsync profile data right away. We get many chances
    221   // to write it again in case something goes wrong. We can rely on a simple
    222   // close(), no sync, and let to the kernel decide when to write to disk.
    223   ScopedFlock profile_file = LockedFile::Open(filename.c_str(), flags,
    224                                               /*block*/false, &error);
    225   if (profile_file.get() == nullptr) {
    226     LOG(WARNING) << "Couldn't lock the profile file " << filename << ": " << error;
    227     return false;
    228   }
    229 
    230   int fd = profile_file->Fd();
    231 
    232   // We need to clear the data because we don't support appending to the profiles yet.
    233   if (!profile_file->ClearContent()) {
    234     PLOG(WARNING) << "Could not clear profile file: " << filename;
    235     return false;
    236   }
    237 
    238   // This doesn't need locking because we are trying to lock the file for exclusive
    239   // access and fail immediately if we can't.
    240   bool result = Save(fd);
    241   if (result) {
    242     int64_t size = GetFileSizeBytes(filename);
    243     if (size != -1) {
    244       VLOG(profiler)
    245         << "Successfully saved profile info to " << filename << " Size: "
    246         << size;
    247       if (bytes_written != nullptr) {
    248         *bytes_written = static_cast<uint64_t>(size);
    249       }
    250     }
    251   } else {
    252     VLOG(profiler) << "Failed to save profile info to " << filename;
    253   }
    254   return result;
    255 }
    256 
    257 // Returns true if all the bytes were successfully written to the file descriptor.
    258 static bool WriteBuffer(int fd, const uint8_t* buffer, size_t byte_count) {
    259   while (byte_count > 0) {
    260     int bytes_written = TEMP_FAILURE_RETRY(write(fd, buffer, byte_count));
    261     if (bytes_written == -1) {
    262       return false;
    263     }
    264     byte_count -= bytes_written;  // Reduce the number of remaining bytes.
    265     buffer += bytes_written;  // Move the buffer forward.
    266   }
    267   return true;
    268 }
    269 
    270 // Add the string bytes to the buffer.
    271 static void AddStringToBuffer(std::vector<uint8_t>* buffer, const std::string& value) {
    272   buffer->insert(buffer->end(), value.begin(), value.end());
    273 }
    274 
    275 // Insert each byte, from low to high into the buffer.
    276 template <typename T>
    277 static void AddUintToBuffer(std::vector<uint8_t>* buffer, T value) {
    278   for (size_t i = 0; i < sizeof(T); i++) {
    279     buffer->push_back((value >> (i * kBitsPerByte)) & 0xff);
    280   }
    281 }
    282 
    283 static constexpr size_t kLineHeaderSize =
    284     2 * sizeof(uint16_t) +  // class_set.size + dex_location.size
    285     3 * sizeof(uint32_t);   // method_map.size + checksum + num_method_ids
    286 
    287 /**
    288  * Serialization format:
    289  *    magic,version,number_of_dex_files,uncompressed_size_of_zipped_data,compressed_data_size,
    290  *    zipped[dex_location1,number_of_classes1,methods_region_size,dex_location_checksum1
    291  *        num_method_ids,
    292  *        method_encoding_11,method_encoding_12...,class_id1,class_id2...
    293  *        startup/post startup bitmap,
    294  *    dex_location2,number_of_classes2,methods_region_size,dex_location_checksum2, num_method_ids,
    295  *        method_encoding_21,method_encoding_22...,,class_id1,class_id2...
    296  *        startup/post startup bitmap,
    297  *    .....]
    298  * The method_encoding is:
    299  *    method_id,number_of_inline_caches,inline_cache1,inline_cache2...
    300  * The inline_cache is:
    301  *    dex_pc,[M|dex_map_size], dex_profile_index,class_id1,class_id2...,dex_profile_index2,...
    302  *    dex_map_size is the number of dex_indeces that follows.
    303  *       Classes are grouped per their dex files and the line
    304  *       `dex_profile_index,class_id1,class_id2...,dex_profile_index2,...` encodes the
    305  *       mapping from `dex_profile_index` to the set of classes `class_id1,class_id2...`
    306  *    M stands for megamorphic or missing types and it's encoded as either
    307  *    the byte kIsMegamorphicEncoding or kIsMissingTypesEncoding.
    308  *    When present, there will be no class ids following.
    309  **/
    310 bool ProfileCompilationInfo::Save(int fd) {
    311   uint64_t start = NanoTime();
    312   ScopedTrace trace(__PRETTY_FUNCTION__);
    313   DCHECK_GE(fd, 0);
    314 
    315   // Use a vector wrapper to avoid keeping track of offsets when we add elements.
    316   std::vector<uint8_t> buffer;
    317   if (!WriteBuffer(fd, kProfileMagic, sizeof(kProfileMagic))) {
    318     return false;
    319   }
    320   if (!WriteBuffer(fd, kProfileVersion, sizeof(kProfileVersion))) {
    321     return false;
    322   }
    323   DCHECK_LE(info_.size(), std::numeric_limits<uint8_t>::max());
    324   AddUintToBuffer(&buffer, static_cast<uint8_t>(info_.size()));
    325 
    326   uint32_t required_capacity = 0;
    327   for (const DexFileData* dex_data_ptr : info_) {
    328     const DexFileData& dex_data = *dex_data_ptr;
    329     uint32_t methods_region_size = GetMethodsRegionSize(dex_data);
    330     required_capacity += kLineHeaderSize +
    331         dex_data.profile_key.size() +
    332         sizeof(uint16_t) * dex_data.class_set.size() +
    333         methods_region_size +
    334         dex_data.bitmap_storage.size();
    335   }
    336   // Allow large profiles for non target builds for the case where we are merging many profiles
    337   // to generate a boot image profile.
    338   if (kIsTargetBuild && required_capacity > kProfileSizeErrorThresholdInBytes) {
    339     LOG(ERROR) << "Profile data size exceeds "
    340                << std::to_string(kProfileSizeErrorThresholdInBytes)
    341                << " bytes. Profile will not be written to disk.";
    342     return false;
    343   }
    344   if (required_capacity > kProfileSizeWarningThresholdInBytes) {
    345     LOG(WARNING) << "Profile data size exceeds "
    346                  << std::to_string(kProfileSizeWarningThresholdInBytes);
    347   }
    348   AddUintToBuffer(&buffer, required_capacity);
    349   if (!WriteBuffer(fd, buffer.data(), buffer.size())) {
    350     return false;
    351   }
    352   // Make sure that the buffer has enough capacity to avoid repeated resizings
    353   // while we add data.
    354   buffer.reserve(required_capacity);
    355   buffer.clear();
    356 
    357   // Dex files must be written in the order of their profile index. This
    358   // avoids writing the index in the output file and simplifies the parsing logic.
    359   for (const DexFileData* dex_data_ptr : info_) {
    360     const DexFileData& dex_data = *dex_data_ptr;
    361 
    362     // Note that we allow dex files without any methods or classes, so that
    363     // inline caches can refer valid dex files.
    364 
    365     if (dex_data.profile_key.size() >= kMaxDexFileKeyLength) {
    366       LOG(WARNING) << "DexFileKey exceeds allocated limit";
    367       return false;
    368     }
    369 
    370     uint32_t methods_region_size = GetMethodsRegionSize(dex_data);
    371 
    372     DCHECK_LE(dex_data.profile_key.size(), std::numeric_limits<uint16_t>::max());
    373     DCHECK_LE(dex_data.class_set.size(), std::numeric_limits<uint16_t>::max());
    374     // Write profile line header.
    375     AddUintToBuffer(&buffer, static_cast<uint16_t>(dex_data.profile_key.size()));
    376     AddUintToBuffer(&buffer, static_cast<uint16_t>(dex_data.class_set.size()));
    377     AddUintToBuffer(&buffer, methods_region_size);  // uint32_t
    378     AddUintToBuffer(&buffer, dex_data.checksum);  // uint32_t
    379     AddUintToBuffer(&buffer, dex_data.num_method_ids);  // uint32_t
    380 
    381     AddStringToBuffer(&buffer, dex_data.profile_key);
    382 
    383     uint16_t last_method_index = 0;
    384     for (const auto& method_it : dex_data.method_map) {
    385       // Store the difference between the method indices. The SafeMap is ordered by
    386       // method_id, so the difference will always be non negative.
    387       DCHECK_GE(method_it.first, last_method_index);
    388       uint16_t diff_with_last_method_index = method_it.first - last_method_index;
    389       last_method_index = method_it.first;
    390       AddUintToBuffer(&buffer, diff_with_last_method_index);
    391       AddInlineCacheToBuffer(&buffer, method_it.second);
    392     }
    393 
    394     uint16_t last_class_index = 0;
    395     for (const auto& class_id : dex_data.class_set) {
    396       // Store the difference between the class indices. The set is ordered by
    397       // class_id, so the difference will always be non negative.
    398       DCHECK_GE(class_id.index_, last_class_index);
    399       uint16_t diff_with_last_class_index = class_id.index_ - last_class_index;
    400       last_class_index = class_id.index_;
    401       AddUintToBuffer(&buffer, diff_with_last_class_index);
    402     }
    403 
    404     buffer.insert(buffer.end(),
    405                   dex_data.bitmap_storage.begin(),
    406                   dex_data.bitmap_storage.end());
    407   }
    408 
    409   uint32_t output_size = 0;
    410   std::unique_ptr<uint8_t[]> compressed_buffer = DeflateBuffer(buffer.data(),
    411                                                                required_capacity,
    412                                                                &output_size);
    413 
    414   buffer.clear();
    415   AddUintToBuffer(&buffer, output_size);
    416 
    417   if (!WriteBuffer(fd, buffer.data(), buffer.size())) {
    418     return false;
    419   }
    420   if (!WriteBuffer(fd, compressed_buffer.get(), output_size)) {
    421     return false;
    422   }
    423   uint64_t total_time = NanoTime() - start;
    424   VLOG(profiler) << "Compressed from "
    425                  << std::to_string(required_capacity)
    426                  << " to "
    427                  << std::to_string(output_size);
    428   VLOG(profiler) << "Time to save profile: " << std::to_string(total_time);
    429   return true;
    430 }
    431 
    432 void ProfileCompilationInfo::AddInlineCacheToBuffer(std::vector<uint8_t>* buffer,
    433                                                     const InlineCacheMap& inline_cache_map) {
    434   // Add inline cache map size.
    435   AddUintToBuffer(buffer, static_cast<uint16_t>(inline_cache_map.size()));
    436   if (inline_cache_map.size() == 0) {
    437     return;
    438   }
    439   for (const auto& inline_cache_it : inline_cache_map) {
    440     uint16_t dex_pc = inline_cache_it.first;
    441     const DexPcData dex_pc_data = inline_cache_it.second;
    442     const ClassSet& classes = dex_pc_data.classes;
    443 
    444     // Add the dex pc.
    445     AddUintToBuffer(buffer, dex_pc);
    446 
    447     // Add the megamorphic/missing_types encoding if needed and continue.
    448     // In either cases we don't add any classes to the profiles and so there's
    449     // no point to continue.
    450     // TODO(calin): in case we miss types there is still value to add the
    451     // rest of the classes. They can be added without bumping the profile version.
    452     if (dex_pc_data.is_missing_types) {
    453       DCHECK(!dex_pc_data.is_megamorphic);  // at this point the megamorphic flag should not be set.
    454       DCHECK_EQ(classes.size(), 0u);
    455       AddUintToBuffer(buffer, kIsMissingTypesEncoding);
    456       continue;
    457     } else if (dex_pc_data.is_megamorphic) {
    458       DCHECK_EQ(classes.size(), 0u);
    459       AddUintToBuffer(buffer, kIsMegamorphicEncoding);
    460       continue;
    461     }
    462 
    463     DCHECK_LT(classes.size(), InlineCache::kIndividualCacheSize);
    464     DCHECK_NE(classes.size(), 0u) << "InlineCache contains a dex_pc with 0 classes";
    465 
    466     SafeMap<uint8_t, std::vector<dex::TypeIndex>> dex_to_classes_map;
    467     // Group the classes by dex. We expect that most of the classes will come from
    468     // the same dex, so this will be more efficient than encoding the dex index
    469     // for each class reference.
    470     GroupClassesByDex(classes, &dex_to_classes_map);
    471     // Add the dex map size.
    472     AddUintToBuffer(buffer, static_cast<uint8_t>(dex_to_classes_map.size()));
    473     for (const auto& dex_it : dex_to_classes_map) {
    474       uint8_t dex_profile_index = dex_it.first;
    475       const std::vector<dex::TypeIndex>& dex_classes = dex_it.second;
    476       // Add the dex profile index.
    477       AddUintToBuffer(buffer, dex_profile_index);
    478       // Add the the number of classes for each dex profile index.
    479       AddUintToBuffer(buffer, static_cast<uint8_t>(dex_classes.size()));
    480       for (size_t i = 0; i < dex_classes.size(); i++) {
    481         // Add the type index of the classes.
    482         AddUintToBuffer(buffer, dex_classes[i].index_);
    483       }
    484     }
    485   }
    486 }
    487 
    488 uint32_t ProfileCompilationInfo::GetMethodsRegionSize(const DexFileData& dex_data) {
    489   // ((uint16_t)method index + (uint16_t)inline cache size) * number of methods
    490   uint32_t size = 2 * sizeof(uint16_t) * dex_data.method_map.size();
    491   for (const auto& method_it : dex_data.method_map) {
    492     const InlineCacheMap& inline_cache = method_it.second;
    493     size += sizeof(uint16_t) * inline_cache.size();  // dex_pc
    494     for (const auto& inline_cache_it : inline_cache) {
    495       const ClassSet& classes = inline_cache_it.second.classes;
    496       SafeMap<uint8_t, std::vector<dex::TypeIndex>> dex_to_classes_map;
    497       GroupClassesByDex(classes, &dex_to_classes_map);
    498       size += sizeof(uint8_t);  // dex_to_classes_map size
    499       for (const auto& dex_it : dex_to_classes_map) {
    500         size += sizeof(uint8_t);  // dex profile index
    501         size += sizeof(uint8_t);  // number of classes
    502         const std::vector<dex::TypeIndex>& dex_classes = dex_it.second;
    503         size += sizeof(uint16_t) * dex_classes.size();  // the actual classes
    504       }
    505     }
    506   }
    507   return size;
    508 }
    509 
    510 void ProfileCompilationInfo::GroupClassesByDex(
    511     const ClassSet& classes,
    512     /*out*/SafeMap<uint8_t, std::vector<dex::TypeIndex>>* dex_to_classes_map) {
    513   for (const auto& classes_it : classes) {
    514     auto dex_it = dex_to_classes_map->FindOrAdd(classes_it.dex_profile_index);
    515     dex_it->second.push_back(classes_it.type_index);
    516   }
    517 }
    518 
    519 ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::GetOrAddDexFileData(
    520     const std::string& profile_key,
    521     uint32_t checksum,
    522     uint32_t num_method_ids) {
    523   const auto profile_index_it = profile_key_map_.FindOrAdd(profile_key, profile_key_map_.size());
    524   if (profile_key_map_.size() > std::numeric_limits<uint8_t>::max()) {
    525     // Allow only 255 dex files to be profiled. This allows us to save bytes
    526     // when encoding. The number is well above what we expect for normal applications.
    527     if (kIsDebugBuild) {
    528       LOG(ERROR) << "Exceeded the maximum number of dex files (255). Something went wrong";
    529     }
    530     profile_key_map_.erase(profile_key);
    531     return nullptr;
    532   }
    533 
    534   uint8_t profile_index = profile_index_it->second;
    535   if (info_.size() <= profile_index) {
    536     // This is a new addition. Add it to the info_ array.
    537     DexFileData* dex_file_data = new (&arena_) DexFileData(
    538         &arena_,
    539         profile_key,
    540         checksum,
    541         profile_index,
    542         num_method_ids);
    543     info_.push_back(dex_file_data);
    544   }
    545   DexFileData* result = info_[profile_index];
    546 
    547   // Check that the checksum matches.
    548   // This may different if for example the dex file was updated and we had a record of the old one.
    549   if (result->checksum != checksum) {
    550     LOG(WARNING) << "Checksum mismatch for dex " << profile_key;
    551     return nullptr;
    552   }
    553 
    554   // DCHECK that profile info map key is consistent with the one stored in the dex file data.
    555   // This should always be the case since since the cache map is managed by ProfileCompilationInfo.
    556   DCHECK_EQ(profile_key, result->profile_key);
    557   DCHECK_EQ(profile_index, result->profile_index);
    558 
    559   if (num_method_ids != result->num_method_ids) {
    560     // This should not happen... added to help investigating b/65812889.
    561     LOG(ERROR) << "num_method_ids mismatch for dex " << profile_key
    562         << ", expected=" << num_method_ids
    563         << ", actual=" << result->num_method_ids;
    564     return nullptr;
    565   }
    566 
    567   return result;
    568 }
    569 
    570 const ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::FindDexData(
    571       const std::string& profile_key,
    572       uint32_t checksum,
    573       bool verify_checksum) const {
    574   const auto profile_index_it = profile_key_map_.find(profile_key);
    575   if (profile_index_it == profile_key_map_.end()) {
    576     return nullptr;
    577   }
    578 
    579   uint8_t profile_index = profile_index_it->second;
    580   const DexFileData* result = info_[profile_index];
    581   if (verify_checksum && !ChecksumMatch(result->checksum, checksum)) {
    582     return nullptr;
    583   }
    584   DCHECK_EQ(profile_key, result->profile_key);
    585   DCHECK_EQ(profile_index, result->profile_index);
    586   return result;
    587 }
    588 
    589 bool ProfileCompilationInfo::AddResolvedClasses(const DexCacheResolvedClasses& classes) {
    590   const std::string dex_location = GetProfileDexFileKey(classes.GetDexLocation());
    591   const uint32_t checksum = classes.GetLocationChecksum();
    592   DexFileData* const data = GetOrAddDexFileData(dex_location, checksum, classes.NumMethodIds());
    593   if (data == nullptr) {
    594     return false;
    595   }
    596   data->class_set.insert(classes.GetClasses().begin(), classes.GetClasses().end());
    597   return true;
    598 }
    599 
    600 bool ProfileCompilationInfo::AddMethod(const std::string& dex_location,
    601                                        uint32_t dex_checksum,
    602                                        uint16_t method_index,
    603                                        uint32_t num_method_ids,
    604                                        const OfflineProfileMethodInfo& pmi) {
    605   DexFileData* const data = GetOrAddDexFileData(GetProfileDexFileKey(dex_location),
    606                                                 dex_checksum,
    607                                                 num_method_ids);
    608   if (data == nullptr) {  // checksum mismatch
    609     return false;
    610   }
    611   // Add the method.
    612   InlineCacheMap* inline_cache = data->FindOrAddMethod(method_index);
    613 
    614   if (pmi.inline_caches == nullptr) {
    615     // If we don't have inline caches return success right away.
    616     return true;
    617   }
    618   for (const auto& pmi_inline_cache_it : *pmi.inline_caches) {
    619     uint16_t pmi_ic_dex_pc = pmi_inline_cache_it.first;
    620     const DexPcData& pmi_ic_dex_pc_data = pmi_inline_cache_it.second;
    621     DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, pmi_ic_dex_pc);
    622     if (dex_pc_data->is_missing_types || dex_pc_data->is_megamorphic) {
    623       // We are already megamorphic or we are missing types; no point in going forward.
    624       continue;
    625     }
    626 
    627     if (pmi_ic_dex_pc_data.is_missing_types) {
    628       dex_pc_data->SetIsMissingTypes();
    629       continue;
    630     }
    631     if (pmi_ic_dex_pc_data.is_megamorphic) {
    632       dex_pc_data->SetIsMegamorphic();
    633       continue;
    634     }
    635 
    636     for (const ClassReference& class_ref : pmi_ic_dex_pc_data.classes) {
    637       const DexReference& dex_ref = pmi.dex_references[class_ref.dex_profile_index];
    638       DexFileData* class_dex_data = GetOrAddDexFileData(
    639           GetProfileDexFileKey(dex_ref.dex_location),
    640           dex_ref.dex_checksum,
    641           dex_ref.num_method_ids);
    642       if (class_dex_data == nullptr) {  // checksum mismatch
    643         return false;
    644       }
    645       dex_pc_data->AddClass(class_dex_data->profile_index, class_ref.type_index);
    646     }
    647   }
    648   return true;
    649 }
    650 
    651 bool ProfileCompilationInfo::AddMethod(const ProfileMethodInfo& pmi) {
    652   DexFileData* const data = GetOrAddDexFileData(pmi.ref.dex_file);
    653   if (data == nullptr) {  // checksum mismatch
    654     return false;
    655   }
    656   InlineCacheMap* inline_cache = data->FindOrAddMethod(pmi.ref.dex_method_index);
    657 
    658   for (const ProfileMethodInfo::ProfileInlineCache& cache : pmi.inline_caches) {
    659     if (cache.is_missing_types) {
    660       FindOrAddDexPc(inline_cache, cache.dex_pc)->SetIsMissingTypes();
    661       continue;
    662     }
    663     for (const TypeReference& class_ref : cache.classes) {
    664       DexFileData* class_dex_data = GetOrAddDexFileData(class_ref.dex_file);
    665       if (class_dex_data == nullptr) {  // checksum mismatch
    666         return false;
    667       }
    668       DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, cache.dex_pc);
    669       if (dex_pc_data->is_missing_types) {
    670         // Don't bother adding classes if we are missing types.
    671         break;
    672       }
    673       dex_pc_data->AddClass(class_dex_data->profile_index, class_ref.type_index);
    674     }
    675   }
    676   return true;
    677 }
    678 
    679 bool ProfileCompilationInfo::AddClassIndex(const std::string& dex_location,
    680                                            uint32_t checksum,
    681                                            dex::TypeIndex type_idx,
    682                                            uint32_t num_method_ids) {
    683   DexFileData* const data = GetOrAddDexFileData(dex_location, checksum, num_method_ids);
    684   if (data == nullptr) {
    685     return false;
    686   }
    687   data->class_set.insert(type_idx);
    688   return true;
    689 }
    690 
    691 #define READ_UINT(type, buffer, dest, error)            \
    692   do {                                                  \
    693     if (!(buffer).ReadUintAndAdvance<type>(&(dest))) {  \
    694       *(error) = "Could not read "#dest;                \
    695       return false;                                     \
    696     }                                                   \
    697   }                                                     \
    698   while (false)
    699 
    700 bool ProfileCompilationInfo::ReadInlineCache(SafeBuffer& buffer,
    701                                              uint8_t number_of_dex_files,
    702                                              /*out*/ InlineCacheMap* inline_cache,
    703                                              /*out*/ std::string* error) {
    704   uint16_t inline_cache_size;
    705   READ_UINT(uint16_t, buffer, inline_cache_size, error);
    706   for (; inline_cache_size > 0; inline_cache_size--) {
    707     uint16_t dex_pc;
    708     uint8_t dex_to_classes_map_size;
    709     READ_UINT(uint16_t, buffer, dex_pc, error);
    710     READ_UINT(uint8_t, buffer, dex_to_classes_map_size, error);
    711     DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, dex_pc);
    712     if (dex_to_classes_map_size == kIsMissingTypesEncoding) {
    713       dex_pc_data->SetIsMissingTypes();
    714       continue;
    715     }
    716     if (dex_to_classes_map_size == kIsMegamorphicEncoding) {
    717       dex_pc_data->SetIsMegamorphic();
    718       continue;
    719     }
    720     for (; dex_to_classes_map_size > 0; dex_to_classes_map_size--) {
    721       uint8_t dex_profile_index;
    722       uint8_t dex_classes_size;
    723       READ_UINT(uint8_t, buffer, dex_profile_index, error);
    724       READ_UINT(uint8_t, buffer, dex_classes_size, error);
    725       if (dex_profile_index >= number_of_dex_files) {
    726         *error = "dex_profile_index out of bounds ";
    727         *error += std::to_string(dex_profile_index) + " " + std::to_string(number_of_dex_files);
    728         return false;
    729       }
    730       for (; dex_classes_size > 0; dex_classes_size--) {
    731         uint16_t type_index;
    732         READ_UINT(uint16_t, buffer, type_index, error);
    733         dex_pc_data->AddClass(dex_profile_index, dex::TypeIndex(type_index));
    734       }
    735     }
    736   }
    737   return true;
    738 }
    739 
    740 bool ProfileCompilationInfo::ReadMethods(SafeBuffer& buffer,
    741                                          uint8_t number_of_dex_files,
    742                                          const ProfileLineHeader& line_header,
    743                                          /*out*/std::string* error) {
    744   uint32_t unread_bytes_before_operation = buffer.CountUnreadBytes();
    745   if (unread_bytes_before_operation < line_header.method_region_size_bytes) {
    746     *error += "Profile EOF reached prematurely for ReadMethod";
    747     return kProfileLoadBadData;
    748   }
    749   size_t expected_unread_bytes_after_operation = buffer.CountUnreadBytes()
    750       - line_header.method_region_size_bytes;
    751   uint16_t last_method_index = 0;
    752   while (buffer.CountUnreadBytes() > expected_unread_bytes_after_operation) {
    753     DexFileData* const data = GetOrAddDexFileData(line_header.dex_location,
    754                                                   line_header.checksum,
    755                                                   line_header.num_method_ids);
    756     uint16_t diff_with_last_method_index;
    757     READ_UINT(uint16_t, buffer, diff_with_last_method_index, error);
    758     uint16_t method_index = last_method_index + diff_with_last_method_index;
    759     last_method_index = method_index;
    760     InlineCacheMap* inline_cache = data->FindOrAddMethod(method_index);
    761     if (!ReadInlineCache(buffer, number_of_dex_files, inline_cache, error)) {
    762       return false;
    763     }
    764   }
    765   uint32_t total_bytes_read = unread_bytes_before_operation - buffer.CountUnreadBytes();
    766   if (total_bytes_read != line_header.method_region_size_bytes) {
    767     *error += "Profile data inconsistent for ReadMethods";
    768     return false;
    769   }
    770   return true;
    771 }
    772 
    773 bool ProfileCompilationInfo::ReadClasses(SafeBuffer& buffer,
    774                                          const ProfileLineHeader& line_header,
    775                                          /*out*/std::string* error) {
    776   size_t unread_bytes_before_op = buffer.CountUnreadBytes();
    777   if (unread_bytes_before_op < line_header.class_set_size) {
    778     *error += "Profile EOF reached prematurely for ReadClasses";
    779     return kProfileLoadBadData;
    780   }
    781 
    782   uint16_t last_class_index = 0;
    783   for (uint16_t i = 0; i < line_header.class_set_size; i++) {
    784     uint16_t diff_with_last_class_index;
    785     READ_UINT(uint16_t, buffer, diff_with_last_class_index, error);
    786     uint16_t type_index = last_class_index + diff_with_last_class_index;
    787     last_class_index = type_index;
    788     if (!AddClassIndex(line_header.dex_location,
    789                        line_header.checksum,
    790                        dex::TypeIndex(type_index),
    791                        line_header.num_method_ids)) {
    792       return false;
    793     }
    794   }
    795   size_t total_bytes_read = unread_bytes_before_op - buffer.CountUnreadBytes();
    796   uint32_t expected_bytes_read = line_header.class_set_size * sizeof(uint16_t);
    797   if (total_bytes_read != expected_bytes_read) {
    798     *error += "Profile data inconsistent for ReadClasses";
    799     return false;
    800   }
    801   return true;
    802 }
    803 
    804 // Tests for EOF by trying to read 1 byte from the descriptor.
    805 // Returns:
    806 //   0 if the descriptor is at the EOF,
    807 //  -1 if there was an IO error
    808 //   1 if the descriptor has more content to read
    809 static int testEOF(int fd) {
    810   uint8_t buffer[1];
    811   return TEMP_FAILURE_RETRY(read(fd, buffer, 1));
    812 }
    813 
    814 // Reads an uint value previously written with AddUintToBuffer.
    815 template <typename T>
    816 bool ProfileCompilationInfo::SafeBuffer::ReadUintAndAdvance(/*out*/T* value) {
    817   static_assert(std::is_unsigned<T>::value, "Type is not unsigned");
    818   if (ptr_current_ + sizeof(T) > ptr_end_) {
    819     return false;
    820   }
    821   *value = 0;
    822   for (size_t i = 0; i < sizeof(T); i++) {
    823     *value += ptr_current_[i] << (i * kBitsPerByte);
    824   }
    825   ptr_current_ += sizeof(T);
    826   return true;
    827 }
    828 
    829 bool ProfileCompilationInfo::SafeBuffer::CompareAndAdvance(const uint8_t* data, size_t data_size) {
    830   if (ptr_current_ + data_size > ptr_end_) {
    831     return false;
    832   }
    833   if (memcmp(ptr_current_, data, data_size) == 0) {
    834     ptr_current_ += data_size;
    835     return true;
    836   }
    837   return false;
    838 }
    839 
    840 ProfileCompilationInfo::ProfileLoadSatus ProfileCompilationInfo::SafeBuffer::FillFromFd(
    841       int fd,
    842       const std::string& source,
    843       /*out*/std::string* error) {
    844   size_t byte_count = (ptr_end_ - ptr_current_) * sizeof(*ptr_current_);
    845   uint8_t* buffer = ptr_current_;
    846   while (byte_count > 0) {
    847     int bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, byte_count));
    848     if (bytes_read == 0) {
    849       *error += "Profile EOF reached prematurely for " + source;
    850       return kProfileLoadBadData;
    851     } else if (bytes_read < 0) {
    852       *error += "Profile IO error for " + source + strerror(errno);
    853       return kProfileLoadIOError;
    854     }
    855     byte_count -= bytes_read;
    856     buffer += bytes_read;
    857   }
    858   return kProfileLoadSuccess;
    859 }
    860 
    861 size_t ProfileCompilationInfo::SafeBuffer::CountUnreadBytes() {
    862   return (ptr_end_ - ptr_current_) * sizeof(*ptr_current_);
    863 }
    864 
    865 const uint8_t* ProfileCompilationInfo::SafeBuffer::GetCurrentPtr() {
    866   return ptr_current_;
    867 }
    868 
    869 void ProfileCompilationInfo::SafeBuffer::Advance(size_t data_size) {
    870   ptr_current_ += data_size;
    871 }
    872 
    873 ProfileCompilationInfo::ProfileLoadSatus ProfileCompilationInfo::ReadProfileHeader(
    874       int fd,
    875       /*out*/uint8_t* number_of_dex_files,
    876       /*out*/uint32_t* uncompressed_data_size,
    877       /*out*/uint32_t* compressed_data_size,
    878       /*out*/std::string* error) {
    879   // Read magic and version
    880   const size_t kMagicVersionSize =
    881     sizeof(kProfileMagic) +
    882     sizeof(kProfileVersion) +
    883     sizeof(uint8_t) +  // number of dex files
    884     sizeof(uint32_t) +  // size of uncompressed profile data
    885     sizeof(uint32_t);  // size of compressed profile data
    886 
    887   SafeBuffer safe_buffer(kMagicVersionSize);
    888 
    889   ProfileLoadSatus status = safe_buffer.FillFromFd(fd, "ReadProfileHeader", error);
    890   if (status != kProfileLoadSuccess) {
    891     return status;
    892   }
    893 
    894   if (!safe_buffer.CompareAndAdvance(kProfileMagic, sizeof(kProfileMagic))) {
    895     *error = "Profile missing magic";
    896     return kProfileLoadVersionMismatch;
    897   }
    898   if (!safe_buffer.CompareAndAdvance(kProfileVersion, sizeof(kProfileVersion))) {
    899     *error = "Profile version mismatch";
    900     return kProfileLoadVersionMismatch;
    901   }
    902   if (!safe_buffer.ReadUintAndAdvance<uint8_t>(number_of_dex_files)) {
    903     *error = "Cannot read the number of dex files";
    904     return kProfileLoadBadData;
    905   }
    906   if (!safe_buffer.ReadUintAndAdvance<uint32_t>(uncompressed_data_size)) {
    907     *error = "Cannot read the size of uncompressed data";
    908     return kProfileLoadBadData;
    909   }
    910   if (!safe_buffer.ReadUintAndAdvance<uint32_t>(compressed_data_size)) {
    911     *error = "Cannot read the size of compressed data";
    912     return kProfileLoadBadData;
    913   }
    914   return kProfileLoadSuccess;
    915 }
    916 
    917 bool ProfileCompilationInfo::ReadProfileLineHeaderElements(SafeBuffer& buffer,
    918                                                            /*out*/uint16_t* dex_location_size,
    919                                                            /*out*/ProfileLineHeader* line_header,
    920                                                            /*out*/std::string* error) {
    921   READ_UINT(uint16_t, buffer, *dex_location_size, error);
    922   READ_UINT(uint16_t, buffer, line_header->class_set_size, error);
    923   READ_UINT(uint32_t, buffer, line_header->method_region_size_bytes, error);
    924   READ_UINT(uint32_t, buffer, line_header->checksum, error);
    925   READ_UINT(uint32_t, buffer, line_header->num_method_ids, error);
    926   return true;
    927 }
    928 
    929 ProfileCompilationInfo::ProfileLoadSatus ProfileCompilationInfo::ReadProfileLineHeader(
    930     SafeBuffer& buffer,
    931     /*out*/ProfileLineHeader* line_header,
    932     /*out*/std::string* error) {
    933   if (buffer.CountUnreadBytes() < kLineHeaderSize) {
    934     *error += "Profile EOF reached prematurely for ReadProfileLineHeader";
    935     return kProfileLoadBadData;
    936   }
    937 
    938   uint16_t dex_location_size;
    939   if (!ReadProfileLineHeaderElements(buffer, &dex_location_size, line_header, error)) {
    940     return kProfileLoadBadData;
    941   }
    942 
    943   if (dex_location_size == 0 || dex_location_size > kMaxDexFileKeyLength) {
    944     *error = "DexFileKey has an invalid size: " +
    945         std::to_string(static_cast<uint32_t>(dex_location_size));
    946     return kProfileLoadBadData;
    947   }
    948 
    949   if (buffer.CountUnreadBytes() < dex_location_size) {
    950     *error += "Profile EOF reached prematurely for ReadProfileHeaderDexLocation";
    951     return kProfileLoadBadData;
    952   }
    953   const uint8_t* base_ptr = buffer.GetCurrentPtr();
    954   line_header->dex_location.assign(
    955       reinterpret_cast<const char*>(base_ptr), dex_location_size);
    956   buffer.Advance(dex_location_size);
    957   return kProfileLoadSuccess;
    958 }
    959 
    960 ProfileCompilationInfo::ProfileLoadSatus ProfileCompilationInfo::ReadProfileLine(
    961       SafeBuffer& buffer,
    962       uint8_t number_of_dex_files,
    963       const ProfileLineHeader& line_header,
    964       /*out*/std::string* error) {
    965   DexFileData* data = GetOrAddDexFileData(line_header.dex_location,
    966                                           line_header.checksum,
    967                                           line_header.num_method_ids);
    968   if (data == nullptr) {
    969     *error = "Error when reading profile file line header: checksum mismatch for "
    970         + line_header.dex_location;
    971     return kProfileLoadBadData;
    972   }
    973 
    974   if (!ReadMethods(buffer, number_of_dex_files, line_header, error)) {
    975     return kProfileLoadBadData;
    976   }
    977 
    978   if (!ReadClasses(buffer, line_header, error)) {
    979     return kProfileLoadBadData;
    980   }
    981 
    982   const size_t bytes = data->bitmap_storage.size();
    983   if (buffer.CountUnreadBytes() < bytes) {
    984     *error += "Profile EOF reached prematurely for ReadProfileHeaderDexLocation";
    985     return kProfileLoadBadData;
    986   }
    987   const uint8_t* base_ptr = buffer.GetCurrentPtr();
    988   std::copy_n(base_ptr, bytes, &data->bitmap_storage[0]);
    989   buffer.Advance(bytes);
    990   // Read method bitmap.
    991   return kProfileLoadSuccess;
    992 }
    993 
    994 // TODO(calin): Fix this API. ProfileCompilationInfo::Load should be static and
    995 // return a unique pointer to a ProfileCompilationInfo upon success.
    996 bool ProfileCompilationInfo::Load(int fd) {
    997   std::string error;
    998   ProfileLoadSatus status = LoadInternal(fd, &error);
    999 
   1000   if (status == kProfileLoadSuccess) {
   1001     return true;
   1002   } else {
   1003     LOG(WARNING) << "Error when reading profile: " << error;
   1004     return false;
   1005   }
   1006 }
   1007 
   1008 // TODO(calin): fail fast if the dex checksums don't match.
   1009 ProfileCompilationInfo::ProfileLoadSatus ProfileCompilationInfo::LoadInternal(
   1010       int fd, std::string* error) {
   1011   ScopedTrace trace(__PRETTY_FUNCTION__);
   1012   DCHECK_GE(fd, 0);
   1013 
   1014   if (!IsEmpty()) {
   1015     return kProfileLoadWouldOverwiteData;
   1016   }
   1017 
   1018   struct stat stat_buffer;
   1019   if (fstat(fd, &stat_buffer) != 0) {
   1020     return kProfileLoadIOError;
   1021   }
   1022   // We allow empty profile files.
   1023   // Profiles may be created by ActivityManager or installd before we manage to
   1024   // process them in the runtime or profman.
   1025   if (stat_buffer.st_size == 0) {
   1026     return kProfileLoadSuccess;
   1027   }
   1028   // Read profile header: magic + version + number_of_dex_files.
   1029   uint8_t number_of_dex_files;
   1030   uint32_t uncompressed_data_size;
   1031   uint32_t compressed_data_size;
   1032   ProfileLoadSatus status = ReadProfileHeader(fd,
   1033                                               &number_of_dex_files,
   1034                                               &uncompressed_data_size,
   1035                                               &compressed_data_size,
   1036                                               error);
   1037 
   1038   if (status != kProfileLoadSuccess) {
   1039     return status;
   1040   }
   1041   // Allow large profiles for non target builds for the case where we are merging many profiles
   1042   // to generate a boot image profile.
   1043   if (kIsTargetBuild && uncompressed_data_size > kProfileSizeErrorThresholdInBytes) {
   1044     LOG(ERROR) << "Profile data size exceeds "
   1045                << std::to_string(kProfileSizeErrorThresholdInBytes)
   1046                << " bytes";
   1047     return kProfileLoadBadData;
   1048   }
   1049   if (uncompressed_data_size > kProfileSizeWarningThresholdInBytes) {
   1050     LOG(WARNING) << "Profile data size exceeds "
   1051                  << std::to_string(kProfileSizeWarningThresholdInBytes)
   1052                  << " bytes";
   1053   }
   1054 
   1055   std::unique_ptr<uint8_t[]> compressed_data(new uint8_t[compressed_data_size]);
   1056   bool bytes_read_success =
   1057       android::base::ReadFully(fd, compressed_data.get(), compressed_data_size);
   1058 
   1059   if (testEOF(fd) != 0) {
   1060     *error += "Unexpected data in the profile file.";
   1061     return kProfileLoadBadData;
   1062   }
   1063 
   1064   if (!bytes_read_success) {
   1065     *error += "Unable to read compressed profile data";
   1066     return kProfileLoadBadData;
   1067   }
   1068 
   1069   SafeBuffer uncompressed_data(uncompressed_data_size);
   1070 
   1071   int ret = InflateBuffer(compressed_data.get(),
   1072                           compressed_data_size,
   1073                           uncompressed_data_size,
   1074                           uncompressed_data.Get());
   1075 
   1076   if (ret != Z_STREAM_END) {
   1077     *error += "Error reading uncompressed profile data";
   1078     return kProfileLoadBadData;
   1079   }
   1080 
   1081   for (uint8_t k = 0; k < number_of_dex_files; k++) {
   1082     ProfileLineHeader line_header;
   1083 
   1084     // First, read the line header to get the amount of data we need to read.
   1085     status = ReadProfileLineHeader(uncompressed_data, &line_header, error);
   1086     if (status != kProfileLoadSuccess) {
   1087       return status;
   1088     }
   1089 
   1090     // Now read the actual profile line.
   1091     status = ReadProfileLine(uncompressed_data, number_of_dex_files, line_header, error);
   1092     if (status != kProfileLoadSuccess) {
   1093       return status;
   1094     }
   1095   }
   1096 
   1097   // Check that we read everything and that profiles don't contain junk data.
   1098   if (uncompressed_data.CountUnreadBytes() > 0) {
   1099     *error = "Unexpected content in the profile file";
   1100     return kProfileLoadBadData;
   1101   } else {
   1102     return kProfileLoadSuccess;
   1103   }
   1104 }
   1105 
   1106 std::unique_ptr<uint8_t[]> ProfileCompilationInfo::DeflateBuffer(const uint8_t* in_buffer,
   1107                                                                  uint32_t in_size,
   1108                                                                  uint32_t* compressed_data_size) {
   1109   z_stream strm;
   1110   strm.zalloc = Z_NULL;
   1111   strm.zfree = Z_NULL;
   1112   strm.opaque = Z_NULL;
   1113   int ret = deflateInit(&strm, 1);
   1114   if (ret != Z_OK) {
   1115     return nullptr;
   1116   }
   1117 
   1118   uint32_t out_size = deflateBound(&strm, in_size);
   1119 
   1120   std::unique_ptr<uint8_t[]> compressed_buffer(new uint8_t[out_size]);
   1121   strm.avail_in = in_size;
   1122   strm.next_in = const_cast<uint8_t*>(in_buffer);
   1123   strm.avail_out = out_size;
   1124   strm.next_out = &compressed_buffer[0];
   1125   ret = deflate(&strm, Z_FINISH);
   1126   if (ret == Z_STREAM_ERROR) {
   1127     return nullptr;
   1128   }
   1129   *compressed_data_size = out_size - strm.avail_out;
   1130   deflateEnd(&strm);
   1131   return compressed_buffer;
   1132 }
   1133 
   1134 int ProfileCompilationInfo::InflateBuffer(const uint8_t* in_buffer,
   1135                                           uint32_t in_size,
   1136                                           uint32_t expected_uncompressed_data_size,
   1137                                           uint8_t* out_buffer) {
   1138   z_stream strm;
   1139 
   1140   /* allocate inflate state */
   1141   strm.zalloc = Z_NULL;
   1142   strm.zfree = Z_NULL;
   1143   strm.opaque = Z_NULL;
   1144   strm.avail_in = in_size;
   1145   strm.next_in = const_cast<uint8_t*>(in_buffer);
   1146   strm.avail_out = expected_uncompressed_data_size;
   1147   strm.next_out = out_buffer;
   1148 
   1149   int ret;
   1150   inflateInit(&strm);
   1151   ret = inflate(&strm, Z_NO_FLUSH);
   1152 
   1153   if (strm.avail_in != 0 || strm.avail_out != 0) {
   1154     return Z_DATA_ERROR;
   1155   }
   1156   inflateEnd(&strm);
   1157   return ret;
   1158 }
   1159 
   1160 bool ProfileCompilationInfo::MergeWith(const ProfileCompilationInfo& other,
   1161                                        bool merge_classes) {
   1162   // First verify that all checksums match. This will avoid adding garbage to
   1163   // the current profile info.
   1164   // Note that the number of elements should be very small, so this should not
   1165   // be a performance issue.
   1166   for (const DexFileData* other_dex_data : other.info_) {
   1167     // verify_checksum is false because we want to differentiate between a missing dex data and
   1168     // a mismatched checksum.
   1169     const DexFileData* dex_data = FindDexData(other_dex_data->profile_key,
   1170                                               0u,
   1171                                               /* verify_checksum */ false);
   1172     if ((dex_data != nullptr) && (dex_data->checksum != other_dex_data->checksum)) {
   1173       LOG(WARNING) << "Checksum mismatch for dex " << other_dex_data->profile_key;
   1174       return false;
   1175     }
   1176   }
   1177   // All checksums match. Import the data.
   1178 
   1179   // The other profile might have a different indexing of dex files.
   1180   // That is because each dex files gets a 'dex_profile_index' on a first come first served basis.
   1181   // That means that the order in with the methods are added to the profile matters for the
   1182   // actual indices.
   1183   // The reason we cannot rely on the actual multidex index is that a single profile may store
   1184   // data from multiple splits. This means that a profile may contain a classes2.dex from split-A
   1185   // and one from split-B.
   1186 
   1187   // First, build a mapping from other_dex_profile_index to this_dex_profile_index.
   1188   // This will make sure that the ClassReferences  will point to the correct dex file.
   1189   SafeMap<uint8_t, uint8_t> dex_profile_index_remap;
   1190   for (const DexFileData* other_dex_data : other.info_) {
   1191     const DexFileData* dex_data = GetOrAddDexFileData(other_dex_data->profile_key,
   1192                                                       other_dex_data->checksum,
   1193                                                       other_dex_data->num_method_ids);
   1194     if (dex_data == nullptr) {
   1195       return false;  // Could happen if we exceed the number of allowed dex files.
   1196     }
   1197     dex_profile_index_remap.Put(other_dex_data->profile_index, dex_data->profile_index);
   1198   }
   1199 
   1200   // Merge the actual profile data.
   1201   for (const DexFileData* other_dex_data : other.info_) {
   1202     DexFileData* dex_data = const_cast<DexFileData*>(FindDexData(other_dex_data->profile_key,
   1203                                                                  other_dex_data->checksum));
   1204     DCHECK(dex_data != nullptr);
   1205 
   1206     // Merge the classes.
   1207     if (merge_classes) {
   1208       dex_data->class_set.insert(other_dex_data->class_set.begin(),
   1209                                  other_dex_data->class_set.end());
   1210     }
   1211 
   1212     // Merge the methods and the inline caches.
   1213     for (const auto& other_method_it : other_dex_data->method_map) {
   1214       uint16_t other_method_index = other_method_it.first;
   1215       InlineCacheMap* inline_cache = dex_data->FindOrAddMethod(other_method_index);
   1216       const auto& other_inline_cache = other_method_it.second;
   1217       for (const auto& other_ic_it : other_inline_cache) {
   1218         uint16_t other_dex_pc = other_ic_it.first;
   1219         const ClassSet& other_class_set = other_ic_it.second.classes;
   1220         DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, other_dex_pc);
   1221         if (other_ic_it.second.is_missing_types) {
   1222           dex_pc_data->SetIsMissingTypes();
   1223         } else if (other_ic_it.second.is_megamorphic) {
   1224           dex_pc_data->SetIsMegamorphic();
   1225         } else {
   1226           for (const auto& class_it : other_class_set) {
   1227             dex_pc_data->AddClass(dex_profile_index_remap.Get(
   1228                 class_it.dex_profile_index), class_it.type_index);
   1229           }
   1230         }
   1231       }
   1232     }
   1233 
   1234     // Merge the method bitmaps.
   1235     dex_data->MergeBitmap(*other_dex_data);
   1236   }
   1237   return true;
   1238 }
   1239 
   1240 const ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::FindDexData(
   1241     const DexFile* dex_file) const {
   1242   return FindDexData(GetProfileDexFileKey(dex_file->GetLocation()),
   1243                      dex_file->GetLocationChecksum());
   1244 }
   1245 
   1246 ProfileCompilationInfo::MethodHotness ProfileCompilationInfo::GetMethodHotness(
   1247     const MethodReference& method_ref) const {
   1248   const DexFileData* dex_data = FindDexData(method_ref.dex_file);
   1249   return dex_data != nullptr
   1250       ? dex_data->GetHotnessInfo(method_ref.dex_method_index)
   1251       : MethodHotness();
   1252 }
   1253 
   1254 bool ProfileCompilationInfo::AddMethodHotness(const MethodReference& method_ref,
   1255                                               const MethodHotness& hotness) {
   1256   DexFileData* dex_data = GetOrAddDexFileData(method_ref.dex_file);
   1257   if (dex_data != nullptr) {
   1258     // TODO: Add inline caches.
   1259     return dex_data->AddMethod(
   1260         static_cast<MethodHotness::Flag>(hotness.GetFlags()),
   1261         method_ref.dex_method_index);
   1262   }
   1263   return false;
   1264 }
   1265 
   1266 ProfileCompilationInfo::MethodHotness ProfileCompilationInfo::GetMethodHotness(
   1267     const std::string& dex_location,
   1268     uint32_t dex_checksum,
   1269     uint16_t dex_method_index) const {
   1270   const DexFileData* dex_data = FindDexData(GetProfileDexFileKey(dex_location), dex_checksum);
   1271   return dex_data != nullptr ? dex_data->GetHotnessInfo(dex_method_index) : MethodHotness();
   1272 }
   1273 
   1274 
   1275 std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> ProfileCompilationInfo::GetMethod(
   1276     const std::string& dex_location,
   1277     uint32_t dex_checksum,
   1278     uint16_t dex_method_index) const {
   1279   MethodHotness hotness(GetMethodHotness(dex_location, dex_checksum, dex_method_index));
   1280   if (!hotness.IsHot()) {
   1281     return nullptr;
   1282   }
   1283   const InlineCacheMap* inline_caches = hotness.GetInlineCacheMap();
   1284   DCHECK(inline_caches != nullptr);
   1285   std::unique_ptr<OfflineProfileMethodInfo> pmi(new OfflineProfileMethodInfo(inline_caches));
   1286 
   1287   pmi->dex_references.resize(info_.size());
   1288   for (const DexFileData* dex_data : info_) {
   1289     pmi->dex_references[dex_data->profile_index].dex_location = dex_data->profile_key;
   1290     pmi->dex_references[dex_data->profile_index].dex_checksum = dex_data->checksum;
   1291     pmi->dex_references[dex_data->profile_index].num_method_ids = dex_data->num_method_ids;
   1292   }
   1293 
   1294   return pmi;
   1295 }
   1296 
   1297 
   1298 bool ProfileCompilationInfo::ContainsClass(const DexFile& dex_file, dex::TypeIndex type_idx) const {
   1299   const DexFileData* dex_data = FindDexData(&dex_file);
   1300   if (dex_data != nullptr) {
   1301     const ArenaSet<dex::TypeIndex>& classes = dex_data->class_set;
   1302     return classes.find(type_idx) != classes.end();
   1303   }
   1304   return false;
   1305 }
   1306 
   1307 uint32_t ProfileCompilationInfo::GetNumberOfMethods() const {
   1308   uint32_t total = 0;
   1309   for (const DexFileData* dex_data : info_) {
   1310     total += dex_data->method_map.size();
   1311   }
   1312   return total;
   1313 }
   1314 
   1315 uint32_t ProfileCompilationInfo::GetNumberOfResolvedClasses() const {
   1316   uint32_t total = 0;
   1317   for (const DexFileData* dex_data : info_) {
   1318     total += dex_data->class_set.size();
   1319   }
   1320   return total;
   1321 }
   1322 
   1323 // Produce a non-owning vector from a vector.
   1324 template<typename T>
   1325 const std::vector<T*>* MakeNonOwningVector(const std::vector<std::unique_ptr<T>>* owning_vector) {
   1326   auto non_owning_vector = new std::vector<T*>();
   1327   for (auto& element : *owning_vector) {
   1328     non_owning_vector->push_back(element.get());
   1329   }
   1330   return non_owning_vector;
   1331 }
   1332 
   1333 std::string ProfileCompilationInfo::DumpInfo(
   1334     const std::vector<std::unique_ptr<const DexFile>>* dex_files,
   1335     bool print_full_dex_location) const {
   1336   std::unique_ptr<const std::vector<const DexFile*>> non_owning_dex_files(
   1337       MakeNonOwningVector(dex_files));
   1338   return DumpInfo(non_owning_dex_files.get(), print_full_dex_location);
   1339 }
   1340 
   1341 std::string ProfileCompilationInfo::DumpInfo(const std::vector<const DexFile*>* dex_files,
   1342                                              bool print_full_dex_location) const {
   1343   std::ostringstream os;
   1344   if (info_.empty()) {
   1345     return "ProfileInfo: empty";
   1346   }
   1347 
   1348   os << "ProfileInfo:";
   1349 
   1350   const std::string kFirstDexFileKeySubstitute = "!classes.dex";
   1351 
   1352   for (const DexFileData* dex_data : info_) {
   1353     os << "\n";
   1354     if (print_full_dex_location) {
   1355       os << dex_data->profile_key;
   1356     } else {
   1357       // Replace the (empty) multidex suffix of the first key with a substitute for easier reading.
   1358       std::string multidex_suffix = DexFile::GetMultiDexSuffix(dex_data->profile_key);
   1359       os << (multidex_suffix.empty() ? kFirstDexFileKeySubstitute : multidex_suffix);
   1360     }
   1361     os << " [index=" << static_cast<uint32_t>(dex_data->profile_index) << "]";
   1362     const DexFile* dex_file = nullptr;
   1363     if (dex_files != nullptr) {
   1364       for (size_t i = 0; i < dex_files->size(); i++) {
   1365         if (dex_data->profile_key == (*dex_files)[i]->GetLocation()) {
   1366           dex_file = (*dex_files)[i];
   1367         }
   1368       }
   1369     }
   1370     os << "\n\thot methods: ";
   1371     for (const auto& method_it : dex_data->method_map) {
   1372       if (dex_file != nullptr) {
   1373         os << "\n\t\t" << dex_file->PrettyMethod(method_it.first, true);
   1374       } else {
   1375         os << method_it.first;
   1376       }
   1377 
   1378       os << "[";
   1379       for (const auto& inline_cache_it : method_it.second) {
   1380         os << "{" << std::hex << inline_cache_it.first << std::dec << ":";
   1381         if (inline_cache_it.second.is_missing_types) {
   1382           os << "MT";
   1383         } else if (inline_cache_it.second.is_megamorphic) {
   1384           os << "MM";
   1385         } else {
   1386           for (const ClassReference& class_ref : inline_cache_it.second.classes) {
   1387             os << "(" << static_cast<uint32_t>(class_ref.dex_profile_index)
   1388                << "," << class_ref.type_index.index_ << ")";
   1389           }
   1390         }
   1391         os << "}";
   1392       }
   1393       os << "], ";
   1394     }
   1395     bool startup = true;
   1396     while (true) {
   1397       os << "\n\t" << (startup ? "startup methods: " : "post startup methods: ");
   1398       for (uint32_t method_idx = 0; method_idx < dex_data->num_method_ids; ++method_idx) {
   1399         MethodHotness hotness_info(dex_data->GetHotnessInfo(method_idx));
   1400         if (startup ? hotness_info.IsStartup() : hotness_info.IsPostStartup()) {
   1401           os << method_idx << ", ";
   1402         }
   1403       }
   1404       if (startup == false) {
   1405         break;
   1406       }
   1407       startup = false;
   1408     }
   1409     os << "\n\tclasses: ";
   1410     for (const auto class_it : dex_data->class_set) {
   1411       if (dex_file != nullptr) {
   1412         os << "\n\t\t" << dex_file->PrettyType(class_it);
   1413       } else {
   1414         os << class_it.index_ << ",";
   1415       }
   1416     }
   1417   }
   1418   return os.str();
   1419 }
   1420 
   1421 bool ProfileCompilationInfo::GetClassesAndMethods(
   1422     const DexFile& dex_file,
   1423     /*out*/std::set<dex::TypeIndex>* class_set,
   1424     /*out*/std::set<uint16_t>* hot_method_set,
   1425     /*out*/std::set<uint16_t>* startup_method_set,
   1426     /*out*/std::set<uint16_t>* post_startup_method_method_set) const {
   1427   std::set<std::string> ret;
   1428   const DexFileData* dex_data = FindDexData(&dex_file);
   1429   if (dex_data == nullptr) {
   1430     return false;
   1431   }
   1432   for (const auto& it : dex_data->method_map) {
   1433     hot_method_set->insert(it.first);
   1434   }
   1435   for (uint32_t method_idx = 0; method_idx < dex_data->num_method_ids; ++method_idx) {
   1436     MethodHotness hotness = dex_data->GetHotnessInfo(method_idx);
   1437     if (hotness.IsStartup()) {
   1438       startup_method_set->insert(method_idx);
   1439     }
   1440     if (hotness.IsPostStartup()) {
   1441       post_startup_method_method_set->insert(method_idx);
   1442     }
   1443   }
   1444   for (const dex::TypeIndex& type_index : dex_data->class_set) {
   1445     class_set->insert(type_index);
   1446   }
   1447   return true;
   1448 }
   1449 
   1450 bool ProfileCompilationInfo::Equals(const ProfileCompilationInfo& other) {
   1451   // No need to compare profile_key_map_. That's only a cache for fast search.
   1452   // All the information is already in the info_ vector.
   1453   if (info_.size() != other.info_.size()) {
   1454     return false;
   1455   }
   1456   for (size_t i = 0; i < info_.size(); i++) {
   1457     const DexFileData& dex_data = *info_[i];
   1458     const DexFileData& other_dex_data = *other.info_[i];
   1459     if (!(dex_data == other_dex_data)) {
   1460       return false;
   1461     }
   1462   }
   1463   return true;
   1464 }
   1465 
   1466 std::set<DexCacheResolvedClasses> ProfileCompilationInfo::GetResolvedClasses(
   1467     const std::vector<const DexFile*>& dex_files) const {
   1468   std::unordered_map<std::string, const DexFile* > key_to_dex_file;
   1469   for (const DexFile* dex_file : dex_files) {
   1470     key_to_dex_file.emplace(GetProfileDexFileKey(dex_file->GetLocation()), dex_file);
   1471   }
   1472   std::set<DexCacheResolvedClasses> ret;
   1473   for (const DexFileData* dex_data : info_) {
   1474     const auto it = key_to_dex_file.find(dex_data->profile_key);
   1475     if (it != key_to_dex_file.end()) {
   1476       const DexFile* dex_file = it->second;
   1477       const std::string& dex_location = dex_file->GetLocation();
   1478       if (dex_data->checksum != it->second->GetLocationChecksum()) {
   1479         LOG(ERROR) << "Dex checksum mismatch when getting resolved classes from profile for "
   1480             << "location " << dex_location << " (checksum=" << dex_file->GetLocationChecksum()
   1481             << ", profile checksum=" << dex_data->checksum;
   1482         return std::set<DexCacheResolvedClasses>();
   1483       }
   1484       DexCacheResolvedClasses classes(dex_location,
   1485                                       dex_location,
   1486                                       dex_data->checksum,
   1487                                       dex_data->num_method_ids);
   1488       classes.AddClasses(dex_data->class_set.begin(), dex_data->class_set.end());
   1489       ret.insert(classes);
   1490     }
   1491   }
   1492   return ret;
   1493 }
   1494 
   1495 // Naive implementation to generate a random profile file suitable for testing.
   1496 bool ProfileCompilationInfo::GenerateTestProfile(int fd,
   1497                                                  uint16_t number_of_dex_files,
   1498                                                  uint16_t method_ratio,
   1499                                                  uint16_t class_ratio,
   1500                                                  uint32_t random_seed) {
   1501   const std::string base_dex_location = "base.apk";
   1502   ProfileCompilationInfo info;
   1503   // The limits are defined by the dex specification.
   1504   const uint16_t max_method = std::numeric_limits<uint16_t>::max();
   1505   const uint16_t max_classes = std::numeric_limits<uint16_t>::max();
   1506   uint16_t number_of_methods = max_method * method_ratio / 100;
   1507   uint16_t number_of_classes = max_classes * class_ratio / 100;
   1508 
   1509   std::srand(random_seed);
   1510 
   1511   // Make sure we generate more samples with a low index value.
   1512   // This makes it more likely to hit valid method/class indices in small apps.
   1513   const uint16_t kFavorFirstN = 10000;
   1514   const uint16_t kFavorSplit = 2;
   1515 
   1516   for (uint16_t i = 0; i < number_of_dex_files; i++) {
   1517     std::string dex_location = DexFile::GetMultiDexLocation(i, base_dex_location.c_str());
   1518     std::string profile_key = GetProfileDexFileKey(dex_location);
   1519 
   1520     for (uint16_t m = 0; m < number_of_methods; m++) {
   1521       uint16_t method_idx = rand() % max_method;
   1522       if (m < (number_of_methods / kFavorSplit)) {
   1523         method_idx %= kFavorFirstN;
   1524       }
   1525       info.AddMethodIndex(MethodHotness::kFlagHot,
   1526                           profile_key,
   1527                           /*method_idx*/ 0,
   1528                           method_idx,
   1529                           max_method);
   1530     }
   1531 
   1532     for (uint16_t c = 0; c < number_of_classes; c++) {
   1533       uint16_t type_idx = rand() % max_classes;
   1534       if (c < (number_of_classes / kFavorSplit)) {
   1535         type_idx %= kFavorFirstN;
   1536       }
   1537       info.AddClassIndex(profile_key, 0, dex::TypeIndex(type_idx), max_method);
   1538     }
   1539   }
   1540   return info.Save(fd);
   1541 }
   1542 
   1543 // Naive implementation to generate a random profile file suitable for testing.
   1544 bool ProfileCompilationInfo::GenerateTestProfile(
   1545     int fd,
   1546     std::vector<std::unique_ptr<const DexFile>>& dex_files,
   1547     uint32_t random_seed) {
   1548   std::srand(random_seed);
   1549   ProfileCompilationInfo info;
   1550   for (std::unique_ptr<const DexFile>& dex_file : dex_files) {
   1551     const std::string& location = dex_file->GetLocation();
   1552     uint32_t checksum = dex_file->GetLocationChecksum();
   1553     for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) {
   1554       // Randomly add a class from the dex file (with 50% chance).
   1555       if (std::rand() % 2 != 0) {
   1556         info.AddClassIndex(location,
   1557                            checksum,
   1558                            dex_file->GetClassDef(i).class_idx_,
   1559                            dex_file->NumMethodIds());
   1560       }
   1561     }
   1562     for (uint32_t i = 0; i < dex_file->NumMethodIds(); ++i) {
   1563       // Randomly add a method from the dex file (with 50% chance).
   1564       if (std::rand() % 2 != 0) {
   1565         info.AddMethodIndex(MethodHotness::kFlagHot, MethodReference(dex_file.get(), i));
   1566       }
   1567     }
   1568   }
   1569   return info.Save(fd);
   1570 }
   1571 
   1572 bool ProfileCompilationInfo::OfflineProfileMethodInfo::operator==(
   1573       const OfflineProfileMethodInfo& other) const {
   1574   if (inline_caches->size() != other.inline_caches->size()) {
   1575     return false;
   1576   }
   1577 
   1578   // We can't use a simple equality test because we need to match the dex files
   1579   // of the inline caches which might have different profile indexes.
   1580   for (const auto& inline_cache_it : *inline_caches) {
   1581     uint16_t dex_pc = inline_cache_it.first;
   1582     const DexPcData dex_pc_data = inline_cache_it.second;
   1583     const auto& other_it = other.inline_caches->find(dex_pc);
   1584     if (other_it == other.inline_caches->end()) {
   1585       return false;
   1586     }
   1587     const DexPcData& other_dex_pc_data = other_it->second;
   1588     if (dex_pc_data.is_megamorphic != other_dex_pc_data.is_megamorphic ||
   1589         dex_pc_data.is_missing_types != other_dex_pc_data.is_missing_types) {
   1590       return false;
   1591     }
   1592     for (const ClassReference& class_ref : dex_pc_data.classes) {
   1593       bool found = false;
   1594       for (const ClassReference& other_class_ref : other_dex_pc_data.classes) {
   1595         CHECK_LE(class_ref.dex_profile_index, dex_references.size());
   1596         CHECK_LE(other_class_ref.dex_profile_index, other.dex_references.size());
   1597         const DexReference& dex_ref = dex_references[class_ref.dex_profile_index];
   1598         const DexReference& other_dex_ref = other.dex_references[other_class_ref.dex_profile_index];
   1599         if (class_ref.type_index == other_class_ref.type_index &&
   1600             dex_ref == other_dex_ref) {
   1601           found = true;
   1602           break;
   1603         }
   1604       }
   1605       if (!found) {
   1606         return false;
   1607       }
   1608     }
   1609   }
   1610   return true;
   1611 }
   1612 
   1613 bool ProfileCompilationInfo::IsEmpty() const {
   1614   DCHECK_EQ(info_.empty(), profile_key_map_.empty());
   1615   return info_.empty();
   1616 }
   1617 
   1618 ProfileCompilationInfo::InlineCacheMap*
   1619 ProfileCompilationInfo::DexFileData::FindOrAddMethod(uint16_t method_index) {
   1620   return &(method_map.FindOrAdd(
   1621       method_index,
   1622       InlineCacheMap(std::less<uint16_t>(), arena_->Adapter(kArenaAllocProfile)))->second);
   1623 }
   1624 
   1625 // Mark a method as executed at least once.
   1626 bool ProfileCompilationInfo::DexFileData::AddMethod(MethodHotness::Flag flags, size_t index) {
   1627   if (index >= num_method_ids) {
   1628     LOG(ERROR) << "Invalid method index " << index << ". num_method_ids=" << num_method_ids;
   1629     return false;
   1630   }
   1631 
   1632   if ((flags & MethodHotness::kFlagStartup) != 0) {
   1633     method_bitmap.StoreBit(MethodBitIndex(/*startup*/ true, index), /*value*/ true);
   1634   }
   1635   if ((flags & MethodHotness::kFlagPostStartup) != 0) {
   1636     method_bitmap.StoreBit(MethodBitIndex(/*startup*/ false, index), /*value*/ true);
   1637   }
   1638   if ((flags & MethodHotness::kFlagHot) != 0) {
   1639     method_map.FindOrAdd(
   1640         index,
   1641         InlineCacheMap(std::less<uint16_t>(), arena_->Adapter(kArenaAllocProfile)));
   1642   }
   1643   return true;
   1644 }
   1645 
   1646 ProfileCompilationInfo::MethodHotness ProfileCompilationInfo::DexFileData::GetHotnessInfo(
   1647     uint32_t dex_method_index) const {
   1648   MethodHotness ret;
   1649   if (method_bitmap.LoadBit(MethodBitIndex(/*startup*/ true, dex_method_index))) {
   1650     ret.AddFlag(MethodHotness::kFlagStartup);
   1651   }
   1652   if (method_bitmap.LoadBit(MethodBitIndex(/*startup*/ false, dex_method_index))) {
   1653     ret.AddFlag(MethodHotness::kFlagPostStartup);
   1654   }
   1655   auto it = method_map.find(dex_method_index);
   1656   if (it != method_map.end()) {
   1657     ret.SetInlineCacheMap(&it->second);
   1658     ret.AddFlag(MethodHotness::kFlagHot);
   1659   }
   1660   return ret;
   1661 }
   1662 
   1663 ProfileCompilationInfo::DexPcData*
   1664 ProfileCompilationInfo::FindOrAddDexPc(InlineCacheMap* inline_cache, uint32_t dex_pc) {
   1665   return &(inline_cache->FindOrAdd(dex_pc, DexPcData(&arena_))->second);
   1666 }
   1667 
   1668 std::unordered_set<std::string> ProfileCompilationInfo::GetClassDescriptors(
   1669     const std::vector<const DexFile*>& dex_files) {
   1670   std::unordered_set<std::string> ret;
   1671   for (const DexFile* dex_file : dex_files) {
   1672     const DexFileData* data = FindDexData(dex_file);
   1673     if (data != nullptr) {
   1674       for (dex::TypeIndex type_idx : data->class_set) {
   1675         if (!dex_file->IsTypeIndexValid(type_idx)) {
   1676           // Something went bad. The profile is probably corrupted. Abort and return an emtpy set.
   1677           LOG(WARNING) << "Corrupted profile: invalid type index "
   1678               << type_idx.index_ << " in dex " << dex_file->GetLocation();
   1679           return std::unordered_set<std::string>();
   1680         }
   1681         const DexFile::TypeId& type_id = dex_file->GetTypeId(type_idx);
   1682         ret.insert(dex_file->GetTypeDescriptor(type_id));
   1683       }
   1684     } else {
   1685       VLOG(compiler) << "Failed to find profile data for " << dex_file->GetLocation();
   1686     }
   1687   }
   1688   return ret;
   1689 }
   1690 
   1691 }  // namespace art
   1692