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 #ifndef ART_RUNTIME_JIT_PROFILE_COMPILATION_INFO_H_
     18 #define ART_RUNTIME_JIT_PROFILE_COMPILATION_INFO_H_
     19 
     20 #include <set>
     21 #include <vector>
     22 
     23 #include "atomic.h"
     24 #include "base/arena_object.h"
     25 #include "base/arena_containers.h"
     26 #include "bit_memory_region.h"
     27 #include "dex_cache_resolved_classes.h"
     28 #include "dex_file.h"
     29 #include "dex_file_types.h"
     30 #include "method_reference.h"
     31 #include "safe_map.h"
     32 #include "type_reference.h"
     33 
     34 namespace art {
     35 
     36 /**
     37  *  Convenient class to pass around profile information (including inline caches)
     38  *  without the need to hold GC-able objects.
     39  */
     40 struct ProfileMethodInfo {
     41   struct ProfileInlineCache {
     42     ProfileInlineCache(uint32_t pc,
     43                        bool missing_types,
     44                        const std::vector<TypeReference>& profile_classes)
     45         : dex_pc(pc), is_missing_types(missing_types), classes(profile_classes) {}
     46 
     47     const uint32_t dex_pc;
     48     const bool is_missing_types;
     49     const std::vector<TypeReference> classes;
     50   };
     51 
     52   explicit ProfileMethodInfo(MethodReference reference) : ref(reference) {}
     53 
     54   ProfileMethodInfo(MethodReference reference, const std::vector<ProfileInlineCache>& caches)
     55       : ref(reference),
     56         inline_caches(caches) {}
     57 
     58   MethodReference ref;
     59   std::vector<ProfileInlineCache> inline_caches;
     60 };
     61 
     62 /**
     63  * Profile information in a format suitable to be queried by the compiler and
     64  * performing profile guided compilation.
     65  * It is a serialize-friendly format based on information collected by the
     66  * interpreter (ProfileInfo).
     67  * Currently it stores only the hot compiled methods.
     68  */
     69 class ProfileCompilationInfo {
     70  public:
     71   static const uint8_t kProfileMagic[];
     72   static const uint8_t kProfileVersion[];
     73 
     74   // Data structures for encoding the offline representation of inline caches.
     75   // This is exposed as public in order to make it available to dex2oat compilations
     76   // (see compiler/optimizing/inliner.cc).
     77 
     78   // A dex location together with its checksum.
     79   struct DexReference {
     80     DexReference() : dex_checksum(0), num_method_ids(0) {}
     81 
     82     DexReference(const std::string& location, uint32_t checksum, uint32_t num_methods)
     83         : dex_location(location), dex_checksum(checksum), num_method_ids(num_methods) {}
     84 
     85     bool operator==(const DexReference& other) const {
     86       return dex_checksum == other.dex_checksum &&
     87           dex_location == other.dex_location &&
     88           num_method_ids == other.num_method_ids;
     89     }
     90 
     91     bool MatchesDex(const DexFile* dex_file) const {
     92       return dex_checksum == dex_file->GetLocationChecksum() &&
     93            dex_location == GetProfileDexFileKey(dex_file->GetLocation());
     94     }
     95 
     96     std::string dex_location;
     97     uint32_t dex_checksum;
     98     uint32_t num_method_ids;
     99   };
    100 
    101   // Encodes a class reference in the profile.
    102   // The owning dex file is encoded as the index (dex_profile_index) it has in the
    103   // profile rather than as a full DexRefence(location,checksum).
    104   // This avoids excessive string copying when managing the profile data.
    105   // The dex_profile_index is an index in either of:
    106   //  - OfflineProfileMethodInfo#dex_references vector (public use)
    107   //  - DexFileData#profile_index (internal use).
    108   // Note that the dex_profile_index is not necessary the multidex index.
    109   // We cannot rely on the actual multidex index because a single profile may store
    110   // data from multiple splits. This means that a profile may contain a classes2.dex from split-A
    111   // and one from split-B.
    112   struct ClassReference : public ValueObject {
    113     ClassReference(uint8_t dex_profile_idx, const dex::TypeIndex type_idx) :
    114       dex_profile_index(dex_profile_idx), type_index(type_idx) {}
    115 
    116     bool operator==(const ClassReference& other) const {
    117       return dex_profile_index == other.dex_profile_index && type_index == other.type_index;
    118     }
    119     bool operator<(const ClassReference& other) const {
    120       return dex_profile_index == other.dex_profile_index
    121           ? type_index < other.type_index
    122           : dex_profile_index < other.dex_profile_index;
    123     }
    124 
    125     uint8_t dex_profile_index;  // the index of the owning dex in the profile info
    126     dex::TypeIndex type_index;  // the type index of the class
    127   };
    128 
    129   // The set of classes that can be found at a given dex pc.
    130   using ClassSet = ArenaSet<ClassReference>;
    131 
    132   // Encodes the actual inline cache for a given dex pc (whether or not the receiver is
    133   // megamorphic and its possible types).
    134   // If the receiver is megamorphic or is missing types the set of classes will be empty.
    135   struct DexPcData : public ArenaObject<kArenaAllocProfile> {
    136     explicit DexPcData(ArenaAllocator* arena)
    137         : is_missing_types(false),
    138           is_megamorphic(false),
    139           classes(std::less<ClassReference>(), arena->Adapter(kArenaAllocProfile)) {}
    140     void AddClass(uint16_t dex_profile_idx, const dex::TypeIndex& type_idx);
    141     void SetIsMegamorphic() {
    142       if (is_missing_types) return;
    143       is_megamorphic = true;
    144       classes.clear();
    145     }
    146     void SetIsMissingTypes() {
    147       is_megamorphic = false;
    148       is_missing_types = true;
    149       classes.clear();
    150     }
    151     bool operator==(const DexPcData& other) const {
    152       return is_megamorphic == other.is_megamorphic &&
    153           is_missing_types == other.is_missing_types &&
    154           classes == other.classes;
    155     }
    156 
    157     // Not all runtime types can be encoded in the profile. For example if the receiver
    158     // type is in a dex file which is not tracked for profiling its type cannot be
    159     // encoded. When types are missing this field will be set to true.
    160     bool is_missing_types;
    161     bool is_megamorphic;
    162     ClassSet classes;
    163   };
    164 
    165   // The inline cache map: DexPc -> DexPcData.
    166   using InlineCacheMap = ArenaSafeMap<uint16_t, DexPcData>;
    167 
    168   // Maps a method dex index to its inline cache.
    169   using MethodMap = ArenaSafeMap<uint16_t, InlineCacheMap>;
    170 
    171   // Profile method hotness information for a single method. Also includes a pointer to the inline
    172   // cache map.
    173   class MethodHotness {
    174    public:
    175     enum Flag {
    176       kFlagHot = 0x1,
    177       kFlagStartup = 0x2,
    178       kFlagPostStartup = 0x4,
    179     };
    180 
    181     bool IsHot() const {
    182       return (flags_ & kFlagHot) != 0;
    183     }
    184 
    185     bool IsStartup() const {
    186       return (flags_ & kFlagStartup) != 0;
    187     }
    188 
    189     bool IsPostStartup() const {
    190       return (flags_ & kFlagPostStartup) != 0;
    191     }
    192 
    193     void AddFlag(Flag flag) {
    194       flags_ |= flag;
    195     }
    196 
    197     uint8_t GetFlags() const {
    198       return flags_;
    199     }
    200 
    201     bool IsInProfile() const {
    202       return flags_ != 0;
    203     }
    204 
    205    private:
    206     const InlineCacheMap* inline_cache_map_ = nullptr;
    207     uint8_t flags_ = 0;
    208 
    209     const InlineCacheMap* GetInlineCacheMap() const {
    210       return inline_cache_map_;
    211     }
    212 
    213     void SetInlineCacheMap(const InlineCacheMap* info) {
    214       inline_cache_map_ = info;
    215     }
    216 
    217     friend class ProfileCompilationInfo;
    218   };
    219 
    220   // Encodes the full set of inline caches for a given method.
    221   // The dex_references vector is indexed according to the ClassReference::dex_profile_index.
    222   // i.e. the dex file of any ClassReference present in the inline caches can be found at
    223   // dex_references[ClassReference::dex_profile_index].
    224   struct OfflineProfileMethodInfo {
    225     explicit OfflineProfileMethodInfo(const InlineCacheMap* inline_cache_map)
    226         : inline_caches(inline_cache_map) {}
    227 
    228     bool operator==(const OfflineProfileMethodInfo& other) const;
    229 
    230     const InlineCacheMap* const inline_caches;
    231     std::vector<DexReference> dex_references;
    232   };
    233 
    234   // Public methods to create, extend or query the profile.
    235   ProfileCompilationInfo();
    236   explicit ProfileCompilationInfo(ArenaPool* arena_pool);
    237 
    238   ~ProfileCompilationInfo();
    239 
    240   // Add the given methods to the current profile object.
    241   bool AddMethods(const std::vector<ProfileMethodInfo>& methods);
    242 
    243   // Add the given classes to the current profile object.
    244   bool AddClasses(const std::set<DexCacheResolvedClasses>& resolved_classes);
    245 
    246   // Add multiple type ids for classes in a single dex file. Iterator is for type_ids not
    247   // class_defs.
    248   template <class Iterator>
    249   bool AddClassesForDex(const DexFile* dex_file, Iterator index_begin, Iterator index_end) {
    250     DexFileData* data = GetOrAddDexFileData(dex_file);
    251     if (data == nullptr) {
    252       return false;
    253     }
    254     data->class_set.insert(index_begin, index_end);
    255     return true;
    256   }
    257 
    258   // Add a method index to the profile (without inline caches). The method flags determine if it is
    259   // hot, startup, or post startup, or a combination of the previous.
    260   bool AddMethodIndex(MethodHotness::Flag flags,
    261                       const std::string& dex_location,
    262                       uint32_t checksum,
    263                       uint16_t method_idx,
    264                       uint32_t num_method_ids);
    265   bool AddMethodIndex(MethodHotness::Flag flags, const MethodReference& ref);
    266 
    267   // Add a method to the profile using its online representation (containing runtime structures).
    268   bool AddMethod(const ProfileMethodInfo& pmi);
    269 
    270   // Bulk add sampled methods and/or hot methods for a single dex, fast since it only has one
    271   // GetOrAddDexFileData call.
    272   template <class Iterator>
    273   bool AddMethodsForDex(MethodHotness::Flag flags,
    274                         const DexFile* dex_file,
    275                         Iterator index_begin,
    276                         Iterator index_end) {
    277     DexFileData* data = GetOrAddDexFileData(dex_file);
    278     if (data == nullptr) {
    279       return false;
    280     }
    281     for (Iterator it = index_begin; it != index_end; ++it) {
    282       DCHECK_LT(*it, data->num_method_ids);
    283       if (!data->AddMethod(flags, *it)) {
    284         return false;
    285       }
    286     }
    287     return true;
    288   }
    289 
    290   // Add hotness flags for a simple method.
    291   bool AddMethodHotness(const MethodReference& method_ref, const MethodHotness& hotness);
    292 
    293   // Load profile information from the given file descriptor.
    294   // If the current profile is non-empty the load will fail.
    295   bool Load(int fd);
    296 
    297   // Load profile information from the given file
    298   // If the current profile is non-empty the load will fail.
    299   // If clear_if_invalid is true and the file is invalid the method clears the
    300   // the file and returns true.
    301   bool Load(const std::string& filename, bool clear_if_invalid);
    302 
    303   // Merge the data from another ProfileCompilationInfo into the current object. Only merges
    304   // classes if merge_classes is true. This is used for creating the boot profile since
    305   // we don't want all of the classes to be image classes.
    306   bool MergeWith(const ProfileCompilationInfo& info, bool merge_classes = true);
    307 
    308   // Save the profile data to the given file descriptor.
    309   bool Save(int fd);
    310 
    311   // Save the current profile into the given file. The file will be cleared before saving.
    312   bool Save(const std::string& filename, uint64_t* bytes_written);
    313 
    314   // Return the number of methods that were profiled.
    315   uint32_t GetNumberOfMethods() const;
    316 
    317   // Return the number of resolved classes that were profiled.
    318   uint32_t GetNumberOfResolvedClasses() const;
    319 
    320   // Returns the profile method info for a given method reference.
    321   MethodHotness GetMethodHotness(const MethodReference& method_ref) const;
    322   MethodHotness GetMethodHotness(const std::string& dex_location,
    323                                  uint32_t dex_checksum,
    324                                  uint16_t dex_method_index) const;
    325 
    326   // Return true if the class's type is present in the profiling info.
    327   bool ContainsClass(const DexFile& dex_file, dex::TypeIndex type_idx) const;
    328 
    329   // Return the method data for the given location and index from the profiling info.
    330   // If the method index is not found or the checksum doesn't match, null is returned.
    331   // Note: the inline cache map is a pointer to the map stored in the profile and
    332   // its allocation will go away if the profile goes out of scope.
    333   std::unique_ptr<OfflineProfileMethodInfo> GetMethod(const std::string& dex_location,
    334                                                       uint32_t dex_checksum,
    335                                                       uint16_t dex_method_index) const;
    336 
    337   // Dump all the loaded profile info into a string and returns it.
    338   // If dex_files is not null then the method indices will be resolved to their
    339   // names.
    340   // This is intended for testing and debugging.
    341   std::string DumpInfo(const std::vector<std::unique_ptr<const DexFile>>* dex_files,
    342                        bool print_full_dex_location = true) const;
    343   std::string DumpInfo(const std::vector<const DexFile*>* dex_files,
    344                        bool print_full_dex_location = true) const;
    345 
    346   // Return the classes and methods for a given dex file through out args. The out args are the set
    347   // of class as well as the methods and their associated inline caches. Returns true if the dex
    348   // file is register and has a matching checksum, false otherwise.
    349   bool GetClassesAndMethods(const DexFile& dex_file,
    350                             /*out*/std::set<dex::TypeIndex>* class_set,
    351                             /*out*/std::set<uint16_t>* hot_method_set,
    352                             /*out*/std::set<uint16_t>* startup_method_set,
    353                             /*out*/std::set<uint16_t>* post_startup_method_method_set) const;
    354 
    355   // Perform an equality test with the `other` profile information.
    356   bool Equals(const ProfileCompilationInfo& other);
    357 
    358   // Return the class descriptors for all of the classes in the profiles' class sets.
    359   std::set<DexCacheResolvedClasses> GetResolvedClasses(
    360       const std::vector<const DexFile*>& dex_files_) const;
    361 
    362   // Return the profile key associated with the given dex location.
    363   static std::string GetProfileDexFileKey(const std::string& dex_location);
    364 
    365   // Generate a test profile which will contain a percentage of the total maximum
    366   // number of methods and classes (method_ratio and class_ratio).
    367   static bool GenerateTestProfile(int fd,
    368                                   uint16_t number_of_dex_files,
    369                                   uint16_t method_ratio,
    370                                   uint16_t class_ratio,
    371                                   uint32_t random_seed);
    372 
    373   // Generate a test profile which will randomly contain classes and methods from
    374   // the provided list of dex files.
    375   static bool GenerateTestProfile(int fd,
    376                                   std::vector<std::unique_ptr<const DexFile>>& dex_files,
    377                                   uint32_t random_seed);
    378 
    379   // Check that the given profile method info contain the same data.
    380   static bool Equals(const ProfileCompilationInfo::OfflineProfileMethodInfo& pmi1,
    381                      const ProfileCompilationInfo::OfflineProfileMethodInfo& pmi2);
    382 
    383   ArenaAllocator* GetArena() { return &arena_; }
    384 
    385   // Return all of the class descriptors in the profile for a set of dex files.
    386   std::unordered_set<std::string> GetClassDescriptors(const std::vector<const DexFile*>& dex_files);
    387 
    388  private:
    389   enum ProfileLoadSatus {
    390     kProfileLoadWouldOverwiteData,
    391     kProfileLoadIOError,
    392     kProfileLoadVersionMismatch,
    393     kProfileLoadBadData,
    394     kProfileLoadSuccess
    395   };
    396 
    397   const uint32_t kProfileSizeWarningThresholdInBytes = 500000U;
    398   const uint32_t kProfileSizeErrorThresholdInBytes = 1000000U;
    399 
    400   // Internal representation of the profile information belonging to a dex file.
    401   // Note that we could do without profile_key (the key used to encode the dex
    402   // file in the profile) and profile_index (the index of the dex file in the
    403   // profile) fields in this struct because we can infer them from
    404   // profile_key_map_ and info_. However, it makes the profiles logic much
    405   // simpler if we have references here as well.
    406   struct DexFileData : public DeletableArenaObject<kArenaAllocProfile> {
    407     DexFileData(ArenaAllocator* arena,
    408                 const std::string& key,
    409                 uint32_t location_checksum,
    410                 uint16_t index,
    411                 uint32_t num_methods)
    412         : arena_(arena),
    413           profile_key(key),
    414           profile_index(index),
    415           checksum(location_checksum),
    416           method_map(std::less<uint16_t>(), arena->Adapter(kArenaAllocProfile)),
    417           class_set(std::less<dex::TypeIndex>(), arena->Adapter(kArenaAllocProfile)),
    418           num_method_ids(num_methods),
    419           bitmap_storage(arena->Adapter(kArenaAllocProfile)) {
    420       const size_t num_bits = num_method_ids * kBitmapIndexCount;
    421       bitmap_storage.resize(RoundUp(num_bits, kBitsPerByte) / kBitsPerByte);
    422       if (!bitmap_storage.empty()) {
    423         method_bitmap =
    424             BitMemoryRegion(MemoryRegion(&bitmap_storage[0], bitmap_storage.size()), 0, num_bits);
    425       }
    426     }
    427 
    428     bool operator==(const DexFileData& other) const {
    429       return checksum == other.checksum && method_map == other.method_map;
    430     }
    431 
    432     // Mark a method as executed at least once.
    433     bool AddMethod(MethodHotness::Flag flags, size_t index);
    434 
    435     void MergeBitmap(const DexFileData& other) {
    436       DCHECK_EQ(bitmap_storage.size(), other.bitmap_storage.size());
    437       for (size_t i = 0; i < bitmap_storage.size(); ++i) {
    438         bitmap_storage[i] |= other.bitmap_storage[i];
    439       }
    440     }
    441 
    442     MethodHotness GetHotnessInfo(uint32_t dex_method_index) const;
    443 
    444     // The arena used to allocate new inline cache maps.
    445     ArenaAllocator* arena_;
    446     // The profile key this data belongs to.
    447     std::string profile_key;
    448     // The profile index of this dex file (matches ClassReference#dex_profile_index).
    449     uint8_t profile_index;
    450     // The dex checksum.
    451     uint32_t checksum;
    452     // The methonds' profile information.
    453     MethodMap method_map;
    454     // The classes which have been profiled. Note that these don't necessarily include
    455     // all the classes that can be found in the inline caches reference.
    456     ArenaSet<dex::TypeIndex> class_set;
    457     // Find the inline caches of the the given method index. Add an empty entry if
    458     // no previous data is found.
    459     InlineCacheMap* FindOrAddMethod(uint16_t method_index);
    460     // Num method ids.
    461     uint32_t num_method_ids;
    462     ArenaVector<uint8_t> bitmap_storage;
    463     BitMemoryRegion method_bitmap;
    464 
    465    private:
    466     enum BitmapIndex {
    467       kBitmapIndexStartup,
    468       kBitmapIndexPostStartup,
    469       kBitmapIndexCount,
    470     };
    471 
    472     size_t MethodBitIndex(bool startup, size_t index) const {
    473       DCHECK_LT(index, num_method_ids);
    474       // The format is [startup bitmap][post startup bitmap]
    475       // This compresses better than ([startup bit][post statup bit])*
    476 
    477       return index + (startup
    478           ? kBitmapIndexStartup * num_method_ids
    479           : kBitmapIndexPostStartup * num_method_ids);
    480     }
    481   };
    482 
    483   // Return the profile data for the given profile key or null if the dex location
    484   // already exists but has a different checksum
    485   DexFileData* GetOrAddDexFileData(const std::string& profile_key,
    486                                    uint32_t checksum,
    487                                    uint32_t num_method_ids);
    488 
    489   DexFileData* GetOrAddDexFileData(const DexFile* dex_file) {
    490     return GetOrAddDexFileData(GetProfileDexFileKey(dex_file->GetLocation()),
    491                                dex_file->GetLocationChecksum(),
    492                                dex_file->NumMethodIds());
    493   }
    494 
    495   // Add a method to the profile using its offline representation.
    496   // This is mostly used to facilitate testing.
    497   bool AddMethod(const std::string& dex_location,
    498                  uint32_t dex_checksum,
    499                  uint16_t method_index,
    500                  uint32_t num_method_ids,
    501                  const OfflineProfileMethodInfo& pmi);
    502 
    503   // Add a class index to the profile.
    504   bool AddClassIndex(const std::string& dex_location,
    505                      uint32_t checksum,
    506                      dex::TypeIndex type_idx,
    507                      uint32_t num_method_ids);
    508 
    509   // Add all classes from the given dex cache to the the profile.
    510   bool AddResolvedClasses(const DexCacheResolvedClasses& classes);
    511 
    512   // Encode the known dex_files into a vector. The index of a dex_reference will
    513   // be the same as the profile index of the dex file (used to encode the ClassReferences).
    514   void DexFileToProfileIndex(/*out*/std::vector<DexReference>* dex_references) const;
    515 
    516   // Return the dex data associated with the given profile key or null if the profile
    517   // doesn't contain the key.
    518   const DexFileData* FindDexData(const std::string& profile_key,
    519                                  uint32_t checksum,
    520                                  bool verify_checksum = true) const;
    521 
    522   // Return the dex data associated with the given dex file or null if the profile doesn't contain
    523   // the key or the checksum mismatches.
    524   const DexFileData* FindDexData(const DexFile* dex_file) const;
    525 
    526   // Checks if the profile is empty.
    527   bool IsEmpty() const;
    528 
    529   // Inflate the input buffer (in_buffer) of size in_size. It returns a buffer of
    530   // compressed data for the input buffer of "compressed_data_size" size.
    531   std::unique_ptr<uint8_t[]> DeflateBuffer(const uint8_t* in_buffer,
    532                                            uint32_t in_size,
    533                                            /*out*/uint32_t* compressed_data_size);
    534 
    535   // Inflate the input buffer(in_buffer) of size in_size. out_size is the expected output
    536   // size of the buffer. It puts the output in out_buffer. It returns Z_STREAM_END on
    537   // success. On error, it returns Z_STREAM_ERROR if the compressed data is inconsistent
    538   // and Z_DATA_ERROR if the stream ended prematurely or the stream has extra data.
    539   int InflateBuffer(const uint8_t* in_buffer,
    540                     uint32_t in_size,
    541                     uint32_t out_size,
    542                     /*out*/uint8_t* out_buffer);
    543 
    544   // Parsing functionality.
    545 
    546   // The information present in the header of each profile line.
    547   struct ProfileLineHeader {
    548     std::string dex_location;
    549     uint16_t class_set_size;
    550     uint32_t method_region_size_bytes;
    551     uint32_t checksum;
    552     uint32_t num_method_ids;
    553   };
    554 
    555   // A helper structure to make sure we don't read past our buffers in the loops.
    556   struct SafeBuffer {
    557    public:
    558     explicit SafeBuffer(size_t size) : storage_(new uint8_t[size]) {
    559       ptr_current_ = storage_.get();
    560       ptr_end_ = ptr_current_ + size;
    561     }
    562 
    563     // Reads the content of the descriptor at the current position.
    564     ProfileLoadSatus FillFromFd(int fd,
    565                                 const std::string& source,
    566                                 /*out*/std::string* error);
    567 
    568     ProfileLoadSatus FillFromBuffer(uint8_t* buffer_ptr,
    569                                     const std::string& source,
    570                                     /*out*/std::string* error);
    571 
    572     // Reads an uint value (high bits to low bits) and advances the current pointer
    573     // with the number of bits read.
    574     template <typename T> bool ReadUintAndAdvance(/*out*/ T* value);
    575 
    576     // Compares the given data with the content current pointer. If the contents are
    577     // equal it advances the current pointer by data_size.
    578     bool CompareAndAdvance(const uint8_t* data, size_t data_size);
    579 
    580     // Advances current pointer by data_size.
    581     void Advance(size_t data_size);
    582 
    583     // Returns the count of unread bytes.
    584     size_t CountUnreadBytes();
    585 
    586     // Returns the current pointer.
    587     const uint8_t* GetCurrentPtr();
    588 
    589     // Get the underlying raw buffer.
    590     uint8_t* Get() { return storage_.get(); }
    591 
    592    private:
    593     std::unique_ptr<uint8_t[]> storage_;
    594     uint8_t* ptr_end_;
    595     uint8_t* ptr_current_;
    596   };
    597 
    598   // Entry point for profile loding functionality.
    599   ProfileLoadSatus LoadInternal(int fd, std::string* error);
    600 
    601   // Read the profile header from the given fd and store the number of profile
    602   // lines into number_of_dex_files.
    603   ProfileLoadSatus ReadProfileHeader(int fd,
    604                                      /*out*/uint8_t* number_of_dex_files,
    605                                      /*out*/uint32_t* size_uncompressed_data,
    606                                      /*out*/uint32_t* size_compressed_data,
    607                                      /*out*/std::string* error);
    608 
    609   // Read the header of a profile line from the given fd.
    610   ProfileLoadSatus ReadProfileLineHeader(SafeBuffer& buffer,
    611                                          /*out*/ProfileLineHeader* line_header,
    612                                          /*out*/std::string* error);
    613 
    614   // Read individual elements from the profile line header.
    615   bool ReadProfileLineHeaderElements(SafeBuffer& buffer,
    616                                      /*out*/uint16_t* dex_location_size,
    617                                      /*out*/ProfileLineHeader* line_header,
    618                                      /*out*/std::string* error);
    619 
    620   // Read a single profile line from the given fd.
    621   ProfileLoadSatus ReadProfileLine(SafeBuffer& buffer,
    622                                    uint8_t number_of_dex_files,
    623                                    const ProfileLineHeader& line_header,
    624                                    /*out*/std::string* error);
    625 
    626   // Read all the classes from the buffer into the profile `info_` structure.
    627   bool ReadClasses(SafeBuffer& buffer,
    628                    const ProfileLineHeader& line_header,
    629                    /*out*/std::string* error);
    630 
    631   // Read all the methods from the buffer into the profile `info_` structure.
    632   bool ReadMethods(SafeBuffer& buffer,
    633                    uint8_t number_of_dex_files,
    634                    const ProfileLineHeader& line_header,
    635                    /*out*/std::string* error);
    636 
    637   // Read the inline cache encoding from line_bufer into inline_cache.
    638   bool ReadInlineCache(SafeBuffer& buffer,
    639                        uint8_t number_of_dex_files,
    640                        /*out*/InlineCacheMap* inline_cache,
    641                        /*out*/std::string* error);
    642 
    643   // Encode the inline cache into the given buffer.
    644   void AddInlineCacheToBuffer(std::vector<uint8_t>* buffer,
    645                               const InlineCacheMap& inline_cache);
    646 
    647   // Return the number of bytes needed to encode the profile information
    648   // for the methods in dex_data.
    649   uint32_t GetMethodsRegionSize(const DexFileData& dex_data);
    650 
    651   // Group `classes` by their owning dex profile index and put the result in
    652   // `dex_to_classes_map`.
    653   void GroupClassesByDex(
    654       const ClassSet& classes,
    655       /*out*/SafeMap<uint8_t, std::vector<dex::TypeIndex>>* dex_to_classes_map);
    656 
    657   // Find the data for the dex_pc in the inline cache. Adds an empty entry
    658   // if no previous data exists.
    659   DexPcData* FindOrAddDexPc(InlineCacheMap* inline_cache, uint32_t dex_pc);
    660 
    661   friend class ProfileCompilationInfoTest;
    662   friend class CompilerDriverProfileTest;
    663   friend class ProfileAssistantTest;
    664   friend class Dex2oatLayoutTest;
    665 
    666   ArenaPool default_arena_pool_;
    667   ArenaAllocator arena_;
    668 
    669   // Vector containing the actual profile info.
    670   // The vector index is the profile index of the dex data and
    671   // matched DexFileData::profile_index.
    672   ArenaVector<DexFileData*> info_;
    673 
    674   // Cache mapping profile keys to profile index.
    675   // This is used to speed up searches since it avoids iterating
    676   // over the info_ vector when searching by profile key.
    677   ArenaSafeMap<const std::string, uint8_t> profile_key_map_;
    678 };
    679 
    680 }  // namespace art
    681 
    682 #endif  // ART_RUNTIME_JIT_PROFILE_COMPILATION_INFO_H_
    683