Add a profiling library

Move profile_compilation_info to a separate library.  Another step
towards building many of our tools without libart[d].

Bug: 78459333
Test: make -j 50 checkbuild
Change-Id: Ib281d3d1fde6d06ebb429c5d39d62a7038af0f44
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 6b43205..f395623 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -112,7 +112,6 @@
         "jit/debugger_interface.cc",
         "jit/jit.cc",
         "jit/jit_code_cache.cc",
-        "jit/profile_compilation_info.cc",
         "jit/profiling_info.cc",
         "jit/profile_saver.cc",
         "jni_internal.cc",
@@ -471,6 +470,7 @@
     ],
     shared_libs: [
         "libdexfile",
+        "libprofile",
     ],
     export_shared_lib_headers: [
         "libdexfile",
@@ -495,6 +495,7 @@
     ],
     shared_libs: [
         "libdexfiled",
+        "libprofiled",
     ],
     export_shared_lib_headers: [
         "libdexfiled",
@@ -579,7 +580,6 @@
         "interpreter/unstarted_runtime_test.cc",
         "jdwp/jdwp_options_test.cc",
         "java_vm_ext_test.cc",
-        "jit/profile_compilation_info_test.cc",
         "method_handles_test.cc",
         "mirror/dex_cache_test.cc",
         "mirror/method_type_test.cc",
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 3f33f79..57c0d9d 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -83,7 +83,6 @@
 #include "jit/debugger_interface.h"
 #include "jit/jit.h"
 #include "jit/jit_code_cache.h"
-#include "jit/profile_compilation_info.h"
 #include "jni_internal.h"
 #include "linear_alloc.h"
 #include "mirror/call_site.h"
@@ -116,6 +115,7 @@
 #include "oat_file_assistant.h"
 #include "oat_file_manager.h"
 #include "object_lock.h"
+#include "profile/profile_compilation_info.h"
 #include "runtime.h"
 #include "runtime_callbacks.h"
 #include "scoped_thread_state_change-inl.h"
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index 813430f..d20f760 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -31,7 +31,7 @@
 #include "jit_code_cache.h"
 #include "oat_file_manager.h"
 #include "oat_quick_method_header.h"
-#include "profile_compilation_info.h"
+#include "profile/profile_compilation_info.h"
 #include "profile_saver.h"
 #include "runtime.h"
 #include "runtime_options.h"
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 6dcc871..1c8c26c 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -41,7 +41,7 @@
 #include "oat_file-inl.h"
 #include "oat_quick_method_header.h"
 #include "object_callbacks.h"
-#include "profile_compilation_info.h"
+#include "profile/profile_compilation_info.h"
 #include "scoped_thread_state_change-inl.h"
 #include "stack.h"
 #include "thread-current-inl.h"
diff --git a/runtime/jit/profile_compilation_info.cc b/runtime/jit/profile_compilation_info.cc
deleted file mode 100644
index d27465d..0000000
--- a/runtime/jit/profile_compilation_info.cc
+++ /dev/null
@@ -1,2110 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "profile_compilation_info.h"
-
-#include <sys/file.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <unistd.h>
-#include <zlib.h>
-
-#include <cerrno>
-#include <climits>
-#include <cstdlib>
-#include <string>
-#include <vector>
-#include <iostream>
-
-#include "android-base/file.h"
-
-#include "base/arena_allocator.h"
-#include "base/dumpable.h"
-#include "base/logging.h"  // For VLOG.
-#include "base/malloc_arena_pool.h"
-#include "base/os.h"
-#include "base/safe_map.h"
-#include "base/scoped_flock.h"
-#include "base/stl_util.h"
-#include "base/systrace.h"
-#include "base/time_utils.h"
-#include "base/unix_file/fd_file.h"
-#include "base/utils.h"
-#include "base/zip_archive.h"
-#include "dex/dex_file_loader.h"
-#include "jit/profiling_info.h"
-
-namespace art {
-
-const uint8_t ProfileCompilationInfo::kProfileMagic[] = { 'p', 'r', 'o', '\0' };
-// Last profile version: merge profiles directly from the file without creating
-// profile_compilation_info object. All the profile line headers are now placed together
-// before corresponding method_encodings and class_ids.
-const uint8_t ProfileCompilationInfo::kProfileVersion[] = { '0', '1', '0', '\0' };
-
-// The name of the profile entry in the dex metadata file.
-// DO NOT CHANGE THIS! (it's similar to classes.dex in the apk files).
-const char* ProfileCompilationInfo::kDexMetadataProfileEntry = "primary.prof";
-
-static constexpr uint16_t kMaxDexFileKeyLength = PATH_MAX;
-
-// Debug flag to ignore checksums when testing if a method or a class is present in the profile.
-// Used to facilitate testing profile guided compilation across a large number of apps
-// using the same test profile.
-static constexpr bool kDebugIgnoreChecksum = false;
-
-static constexpr uint8_t kIsMissingTypesEncoding = 6;
-static constexpr uint8_t kIsMegamorphicEncoding = 7;
-
-static_assert(sizeof(InlineCache::kIndividualCacheSize) == sizeof(uint8_t),
-              "InlineCache::kIndividualCacheSize does not have the expect type size");
-static_assert(InlineCache::kIndividualCacheSize < kIsMegamorphicEncoding,
-              "InlineCache::kIndividualCacheSize is larger than expected");
-static_assert(InlineCache::kIndividualCacheSize < kIsMissingTypesEncoding,
-              "InlineCache::kIndividualCacheSize is larger than expected");
-
-static bool ChecksumMatch(uint32_t dex_file_checksum, uint32_t checksum) {
-  return kDebugIgnoreChecksum || dex_file_checksum == checksum;
-}
-
-ProfileCompilationInfo::ProfileCompilationInfo(ArenaPool* custom_arena_pool)
-    : default_arena_pool_(),
-      allocator_(custom_arena_pool),
-      info_(allocator_.Adapter(kArenaAllocProfile)),
-      profile_key_map_(std::less<const std::string>(), allocator_.Adapter(kArenaAllocProfile)) {
-}
-
-ProfileCompilationInfo::ProfileCompilationInfo()
-    : default_arena_pool_(),
-      allocator_(&default_arena_pool_),
-      info_(allocator_.Adapter(kArenaAllocProfile)),
-      profile_key_map_(std::less<const std::string>(), allocator_.Adapter(kArenaAllocProfile)) {
-}
-
-ProfileCompilationInfo::~ProfileCompilationInfo() {
-  VLOG(profiler) << Dumpable<MemStats>(allocator_.GetMemStats());
-  for (DexFileData* data : info_) {
-    delete data;
-  }
-}
-
-void ProfileCompilationInfo::DexPcData::AddClass(uint16_t dex_profile_idx,
-                                                 const dex::TypeIndex& type_idx) {
-  if (is_megamorphic || is_missing_types) {
-    return;
-  }
-
-  // Perform an explicit lookup for the type instead of directly emplacing the
-  // element. We do this because emplace() allocates the node before doing the
-  // lookup and if it then finds an identical element, it shall deallocate the
-  // node. For Arena allocations, that's essentially a leak.
-  ClassReference ref(dex_profile_idx, type_idx);
-  auto it = classes.find(ref);
-  if (it != classes.end()) {
-    // The type index exists.
-    return;
-  }
-
-  // Check if the adding the type will cause the cache to become megamorphic.
-  if (classes.size() + 1 >= InlineCache::kIndividualCacheSize) {
-    is_megamorphic = true;
-    classes.clear();
-    return;
-  }
-
-  // The type does not exist and the inline cache will not be megamorphic.
-  classes.insert(ref);
-}
-
-// Transform the actual dex location into relative paths.
-// Note: this is OK because we don't store profiles of different apps into the same file.
-// Apps with split apks don't cause trouble because each split has a different name and will not
-// collide with other entries.
-std::string ProfileCompilationInfo::GetProfileDexFileKey(const std::string& dex_location) {
-  DCHECK(!dex_location.empty());
-  size_t last_sep_index = dex_location.find_last_of('/');
-  if (last_sep_index == std::string::npos) {
-    return dex_location;
-  } else {
-    DCHECK(last_sep_index < dex_location.size());
-    return dex_location.substr(last_sep_index + 1);
-  }
-}
-
-bool ProfileCompilationInfo::AddMethodIndex(MethodHotness::Flag flags, const MethodReference& ref) {
-  DexFileData* data = GetOrAddDexFileData(ref.dex_file);
-  if (data == nullptr) {
-    return false;
-  }
-  return data->AddMethod(flags, ref.index);
-}
-
-bool ProfileCompilationInfo::AddMethodIndex(MethodHotness::Flag flags,
-                                            const std::string& dex_location,
-                                            uint32_t checksum,
-                                            uint16_t method_idx,
-                                            uint32_t num_method_ids) {
-  DexFileData* data = GetOrAddDexFileData(GetProfileDexFileKey(dex_location),
-                                          checksum,
-                                          num_method_ids);
-  if (data == nullptr) {
-    return false;
-  }
-  return data->AddMethod(flags, method_idx);
-}
-
-bool ProfileCompilationInfo::AddMethods(const std::vector<ProfileMethodInfo>& methods,
-                                        MethodHotness::Flag flags) {
-  for (const ProfileMethodInfo& method : methods) {
-    if (!AddMethod(method, flags)) {
-      return false;
-    }
-  }
-  return true;
-}
-
-bool ProfileCompilationInfo::AddClasses(const std::set<DexCacheResolvedClasses>& resolved_classes) {
-  for (const DexCacheResolvedClasses& dex_cache : resolved_classes) {
-    if (!AddResolvedClasses(dex_cache)) {
-      return false;
-    }
-  }
-  return true;
-}
-
-bool ProfileCompilationInfo::MergeWith(const std::string& filename) {
-  std::string error;
-  int flags = O_RDONLY | O_NOFOLLOW | O_CLOEXEC;
-  ScopedFlock profile_file = LockedFile::Open(filename.c_str(), flags,
-      /*block*/false, &error);
-
-  if (profile_file.get() == nullptr) {
-    LOG(WARNING) << "Couldn't lock the profile file " << filename << ": " << error;
-    return false;
-  }
-
-  int fd = profile_file->Fd();
-
-  ProfileLoadStatus status = LoadInternal(fd, &error);
-  if (status == kProfileLoadSuccess) {
-    return true;
-  }
-
-  LOG(WARNING) << "Could not load profile data from file " << filename << ": " << error;
-  return false;
-}
-
-bool ProfileCompilationInfo::Load(const std::string& filename, bool clear_if_invalid) {
-  ScopedTrace trace(__PRETTY_FUNCTION__);
-  std::string error;
-
-  if (!IsEmpty()) {
-    return kProfileLoadWouldOverwiteData;
-  }
-
-  int flags = O_RDWR | O_NOFOLLOW | O_CLOEXEC;
-  // There's no need to fsync profile data right away. We get many chances
-  // to write it again in case something goes wrong. We can rely on a simple
-  // close(), no sync, and let to the kernel decide when to write to disk.
-  ScopedFlock profile_file = LockedFile::Open(filename.c_str(), flags,
-                                              /*block*/false, &error);
-
-  if (profile_file.get() == nullptr) {
-    LOG(WARNING) << "Couldn't lock the profile file " << filename << ": " << error;
-    return false;
-  }
-
-  int fd = profile_file->Fd();
-
-  ProfileLoadStatus status = LoadInternal(fd, &error);
-  if (status == kProfileLoadSuccess) {
-    return true;
-  }
-
-  if (clear_if_invalid &&
-      ((status == kProfileLoadVersionMismatch) || (status == kProfileLoadBadData))) {
-    LOG(WARNING) << "Clearing bad or obsolete profile data from file "
-                 << filename << ": " << error;
-    if (profile_file->ClearContent()) {
-      return true;
-    } else {
-      PLOG(WARNING) << "Could not clear profile file: " << filename;
-      return false;
-    }
-  }
-
-  LOG(WARNING) << "Could not load profile data from file " << filename << ": " << error;
-  return false;
-}
-
-bool ProfileCompilationInfo::Save(const std::string& filename, uint64_t* bytes_written) {
-  ScopedTrace trace(__PRETTY_FUNCTION__);
-  std::string error;
-  int flags = O_WRONLY | O_NOFOLLOW | O_CLOEXEC;
-  // There's no need to fsync profile data right away. We get many chances
-  // to write it again in case something goes wrong. We can rely on a simple
-  // close(), no sync, and let to the kernel decide when to write to disk.
-  ScopedFlock profile_file = LockedFile::Open(filename.c_str(), flags,
-                                              /*block*/false, &error);
-  if (profile_file.get() == nullptr) {
-    LOG(WARNING) << "Couldn't lock the profile file " << filename << ": " << error;
-    return false;
-  }
-
-  int fd = profile_file->Fd();
-
-  // We need to clear the data because we don't support appending to the profiles yet.
-  if (!profile_file->ClearContent()) {
-    PLOG(WARNING) << "Could not clear profile file: " << filename;
-    return false;
-  }
-
-  // This doesn't need locking because we are trying to lock the file for exclusive
-  // access and fail immediately if we can't.
-  bool result = Save(fd);
-  if (result) {
-    int64_t size = OS::GetFileSizeBytes(filename.c_str());
-    if (size != -1) {
-      VLOG(profiler)
-        << "Successfully saved profile info to " << filename << " Size: "
-        << size;
-      if (bytes_written != nullptr) {
-        *bytes_written = static_cast<uint64_t>(size);
-      }
-    }
-  } else {
-    VLOG(profiler) << "Failed to save profile info to " << filename;
-  }
-  return result;
-}
-
-// Returns true if all the bytes were successfully written to the file descriptor.
-static bool WriteBuffer(int fd, const uint8_t* buffer, size_t byte_count) {
-  while (byte_count > 0) {
-    int bytes_written = TEMP_FAILURE_RETRY(write(fd, buffer, byte_count));
-    if (bytes_written == -1) {
-      return false;
-    }
-    byte_count -= bytes_written;  // Reduce the number of remaining bytes.
-    buffer += bytes_written;  // Move the buffer forward.
-  }
-  return true;
-}
-
-// Add the string bytes to the buffer.
-static void AddStringToBuffer(std::vector<uint8_t>* buffer, const std::string& value) {
-  buffer->insert(buffer->end(), value.begin(), value.end());
-}
-
-// Insert each byte, from low to high into the buffer.
-template <typename T>
-static void AddUintToBuffer(std::vector<uint8_t>* buffer, T value) {
-  for (size_t i = 0; i < sizeof(T); i++) {
-    buffer->push_back((value >> (i * kBitsPerByte)) & 0xff);
-  }
-}
-
-static constexpr size_t kLineHeaderSize =
-    2 * sizeof(uint16_t) +  // class_set.size + dex_location.size
-    3 * sizeof(uint32_t);   // method_map.size + checksum + num_method_ids
-
-/**
- * Serialization format:
- * [profile_header, zipped[[profile_line_header1, profile_line_header2...],[profile_line_data1,
- *    profile_line_data2...]]]
- * profile_header:
- *   magic,version,number_of_dex_files,uncompressed_size_of_zipped_data,compressed_data_size
- * profile_line_header:
- *   dex_location,number_of_classes,methods_region_size,dex_location_checksum,num_method_ids
- * profile_line_data:
- *   method_encoding_1,method_encoding_2...,class_id1,class_id2...,startup/post startup bitmap
- * The method_encoding is:
- *    method_id,number_of_inline_caches,inline_cache1,inline_cache2...
- * The inline_cache is:
- *    dex_pc,[M|dex_map_size], dex_profile_index,class_id1,class_id2...,dex_profile_index2,...
- *    dex_map_size is the number of dex_indeces that follows.
- *       Classes are grouped per their dex files and the line
- *       `dex_profile_index,class_id1,class_id2...,dex_profile_index2,...` encodes the
- *       mapping from `dex_profile_index` to the set of classes `class_id1,class_id2...`
- *    M stands for megamorphic or missing types and it's encoded as either
- *    the byte kIsMegamorphicEncoding or kIsMissingTypesEncoding.
- *    When present, there will be no class ids following.
- **/
-bool ProfileCompilationInfo::Save(int fd) {
-  uint64_t start = NanoTime();
-  ScopedTrace trace(__PRETTY_FUNCTION__);
-  DCHECK_GE(fd, 0);
-
-  // Use a vector wrapper to avoid keeping track of offsets when we add elements.
-  std::vector<uint8_t> buffer;
-  if (!WriteBuffer(fd, kProfileMagic, sizeof(kProfileMagic))) {
-    return false;
-  }
-  if (!WriteBuffer(fd, kProfileVersion, sizeof(kProfileVersion))) {
-    return false;
-  }
-  DCHECK_LE(info_.size(), std::numeric_limits<uint8_t>::max());
-  AddUintToBuffer(&buffer, static_cast<uint8_t>(info_.size()));
-
-  uint32_t required_capacity = 0;
-  for (const DexFileData* dex_data_ptr : info_) {
-    const DexFileData& dex_data = *dex_data_ptr;
-    uint32_t methods_region_size = GetMethodsRegionSize(dex_data);
-    required_capacity += kLineHeaderSize +
-        dex_data.profile_key.size() +
-        sizeof(uint16_t) * dex_data.class_set.size() +
-        methods_region_size +
-        dex_data.bitmap_storage.size();
-  }
-  // Allow large profiles for non target builds for the case where we are merging many profiles
-  // to generate a boot image profile.
-  if (kIsTargetBuild && required_capacity > kProfileSizeErrorThresholdInBytes) {
-    LOG(ERROR) << "Profile data size exceeds "
-               << std::to_string(kProfileSizeErrorThresholdInBytes)
-               << " bytes. Profile will not be written to disk.";
-    return false;
-  }
-  AddUintToBuffer(&buffer, required_capacity);
-  if (!WriteBuffer(fd, buffer.data(), buffer.size())) {
-    return false;
-  }
-  // Make sure that the buffer has enough capacity to avoid repeated resizings
-  // while we add data.
-  buffer.reserve(required_capacity);
-  buffer.clear();
-
-  // Dex files must be written in the order of their profile index. This
-  // avoids writing the index in the output file and simplifies the parsing logic.
-  // Write profile line headers.
-  for (const DexFileData* dex_data_ptr : info_) {
-    const DexFileData& dex_data = *dex_data_ptr;
-
-    if (dex_data.profile_key.size() >= kMaxDexFileKeyLength) {
-      LOG(WARNING) << "DexFileKey exceeds allocated limit";
-      return false;
-    }
-
-    uint32_t methods_region_size = GetMethodsRegionSize(dex_data);
-
-    DCHECK_LE(dex_data.profile_key.size(), std::numeric_limits<uint16_t>::max());
-    DCHECK_LE(dex_data.class_set.size(), std::numeric_limits<uint16_t>::max());
-    // Write profile line header.
-    AddUintToBuffer(&buffer, static_cast<uint16_t>(dex_data.profile_key.size()));
-    AddUintToBuffer(&buffer, static_cast<uint16_t>(dex_data.class_set.size()));
-    AddUintToBuffer(&buffer, methods_region_size);  // uint32_t
-    AddUintToBuffer(&buffer, dex_data.checksum);  // uint32_t
-    AddUintToBuffer(&buffer, dex_data.num_method_ids);  // uint32_t
-
-    AddStringToBuffer(&buffer, dex_data.profile_key);
-  }
-
-  for (const DexFileData* dex_data_ptr : info_) {
-    const DexFileData& dex_data = *dex_data_ptr;
-
-    // Note that we allow dex files without any methods or classes, so that
-    // inline caches can refer valid dex files.
-
-    uint16_t last_method_index = 0;
-    for (const auto& method_it : dex_data.method_map) {
-      // Store the difference between the method indices. The SafeMap is ordered by
-      // method_id, so the difference will always be non negative.
-      DCHECK_GE(method_it.first, last_method_index);
-      uint16_t diff_with_last_method_index = method_it.first - last_method_index;
-      last_method_index = method_it.first;
-      AddUintToBuffer(&buffer, diff_with_last_method_index);
-      AddInlineCacheToBuffer(&buffer, method_it.second);
-    }
-
-    uint16_t last_class_index = 0;
-    for (const auto& class_id : dex_data.class_set) {
-      // Store the difference between the class indices. The set is ordered by
-      // class_id, so the difference will always be non negative.
-      DCHECK_GE(class_id.index_, last_class_index);
-      uint16_t diff_with_last_class_index = class_id.index_ - last_class_index;
-      last_class_index = class_id.index_;
-      AddUintToBuffer(&buffer, diff_with_last_class_index);
-    }
-
-    buffer.insert(buffer.end(),
-                  dex_data.bitmap_storage.begin(),
-                  dex_data.bitmap_storage.end());
-  }
-
-  uint32_t output_size = 0;
-  std::unique_ptr<uint8_t[]> compressed_buffer = DeflateBuffer(buffer.data(),
-                                                               required_capacity,
-                                                               &output_size);
-
-  if (output_size > kProfileSizeWarningThresholdInBytes) {
-    LOG(WARNING) << "Profile data size exceeds "
-                 << std::to_string(kProfileSizeWarningThresholdInBytes);
-  }
-
-  buffer.clear();
-  AddUintToBuffer(&buffer, output_size);
-
-  if (!WriteBuffer(fd, buffer.data(), buffer.size())) {
-    return false;
-  }
-  if (!WriteBuffer(fd, compressed_buffer.get(), output_size)) {
-    return false;
-  }
-  uint64_t total_time = NanoTime() - start;
-  VLOG(profiler) << "Compressed from "
-                 << std::to_string(required_capacity)
-                 << " to "
-                 << std::to_string(output_size);
-  VLOG(profiler) << "Time to save profile: " << std::to_string(total_time);
-  return true;
-}
-
-void ProfileCompilationInfo::AddInlineCacheToBuffer(std::vector<uint8_t>* buffer,
-                                                    const InlineCacheMap& inline_cache_map) {
-  // Add inline cache map size.
-  AddUintToBuffer(buffer, static_cast<uint16_t>(inline_cache_map.size()));
-  if (inline_cache_map.size() == 0) {
-    return;
-  }
-  for (const auto& inline_cache_it : inline_cache_map) {
-    uint16_t dex_pc = inline_cache_it.first;
-    const DexPcData dex_pc_data = inline_cache_it.second;
-    const ClassSet& classes = dex_pc_data.classes;
-
-    // Add the dex pc.
-    AddUintToBuffer(buffer, dex_pc);
-
-    // Add the megamorphic/missing_types encoding if needed and continue.
-    // In either cases we don't add any classes to the profiles and so there's
-    // no point to continue.
-    // TODO(calin): in case we miss types there is still value to add the
-    // rest of the classes. They can be added without bumping the profile version.
-    if (dex_pc_data.is_missing_types) {
-      DCHECK(!dex_pc_data.is_megamorphic);  // at this point the megamorphic flag should not be set.
-      DCHECK_EQ(classes.size(), 0u);
-      AddUintToBuffer(buffer, kIsMissingTypesEncoding);
-      continue;
-    } else if (dex_pc_data.is_megamorphic) {
-      DCHECK_EQ(classes.size(), 0u);
-      AddUintToBuffer(buffer, kIsMegamorphicEncoding);
-      continue;
-    }
-
-    DCHECK_LT(classes.size(), InlineCache::kIndividualCacheSize);
-    DCHECK_NE(classes.size(), 0u) << "InlineCache contains a dex_pc with 0 classes";
-
-    SafeMap<uint8_t, std::vector<dex::TypeIndex>> dex_to_classes_map;
-    // Group the classes by dex. We expect that most of the classes will come from
-    // the same dex, so this will be more efficient than encoding the dex index
-    // for each class reference.
-    GroupClassesByDex(classes, &dex_to_classes_map);
-    // Add the dex map size.
-    AddUintToBuffer(buffer, static_cast<uint8_t>(dex_to_classes_map.size()));
-    for (const auto& dex_it : dex_to_classes_map) {
-      uint8_t dex_profile_index = dex_it.first;
-      const std::vector<dex::TypeIndex>& dex_classes = dex_it.second;
-      // Add the dex profile index.
-      AddUintToBuffer(buffer, dex_profile_index);
-      // Add the the number of classes for each dex profile index.
-      AddUintToBuffer(buffer, static_cast<uint8_t>(dex_classes.size()));
-      for (size_t i = 0; i < dex_classes.size(); i++) {
-        // Add the type index of the classes.
-        AddUintToBuffer(buffer, dex_classes[i].index_);
-      }
-    }
-  }
-}
-
-uint32_t ProfileCompilationInfo::GetMethodsRegionSize(const DexFileData& dex_data) {
-  // ((uint16_t)method index + (uint16_t)inline cache size) * number of methods
-  uint32_t size = 2 * sizeof(uint16_t) * dex_data.method_map.size();
-  for (const auto& method_it : dex_data.method_map) {
-    const InlineCacheMap& inline_cache = method_it.second;
-    size += sizeof(uint16_t) * inline_cache.size();  // dex_pc
-    for (const auto& inline_cache_it : inline_cache) {
-      const ClassSet& classes = inline_cache_it.second.classes;
-      SafeMap<uint8_t, std::vector<dex::TypeIndex>> dex_to_classes_map;
-      GroupClassesByDex(classes, &dex_to_classes_map);
-      size += sizeof(uint8_t);  // dex_to_classes_map size
-      for (const auto& dex_it : dex_to_classes_map) {
-        size += sizeof(uint8_t);  // dex profile index
-        size += sizeof(uint8_t);  // number of classes
-        const std::vector<dex::TypeIndex>& dex_classes = dex_it.second;
-        size += sizeof(uint16_t) * dex_classes.size();  // the actual classes
-      }
-    }
-  }
-  return size;
-}
-
-void ProfileCompilationInfo::GroupClassesByDex(
-    const ClassSet& classes,
-    /*out*/SafeMap<uint8_t, std::vector<dex::TypeIndex>>* dex_to_classes_map) {
-  for (const auto& classes_it : classes) {
-    auto dex_it = dex_to_classes_map->FindOrAdd(classes_it.dex_profile_index);
-    dex_it->second.push_back(classes_it.type_index);
-  }
-}
-
-ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::GetOrAddDexFileData(
-    const std::string& profile_key,
-    uint32_t checksum,
-    uint32_t num_method_ids) {
-  const auto profile_index_it = profile_key_map_.FindOrAdd(profile_key, profile_key_map_.size());
-  if (profile_key_map_.size() > std::numeric_limits<uint8_t>::max()) {
-    // Allow only 255 dex files to be profiled. This allows us to save bytes
-    // when encoding. The number is well above what we expect for normal applications.
-    if (kIsDebugBuild) {
-      LOG(ERROR) << "Exceeded the maximum number of dex files (255). Something went wrong";
-    }
-    profile_key_map_.erase(profile_key);
-    return nullptr;
-  }
-
-  uint8_t profile_index = profile_index_it->second;
-  if (info_.size() <= profile_index) {
-    // This is a new addition. Add it to the info_ array.
-    DexFileData* dex_file_data = new (&allocator_) DexFileData(
-        &allocator_,
-        profile_key,
-        checksum,
-        profile_index,
-        num_method_ids);
-    info_.push_back(dex_file_data);
-  }
-  DexFileData* result = info_[profile_index];
-
-  // Check that the checksum matches.
-  // This may different if for example the dex file was updated and we had a record of the old one.
-  if (result->checksum != checksum) {
-    LOG(WARNING) << "Checksum mismatch for dex " << profile_key;
-    return nullptr;
-  }
-
-  // DCHECK that profile info map key is consistent with the one stored in the dex file data.
-  // This should always be the case since since the cache map is managed by ProfileCompilationInfo.
-  DCHECK_EQ(profile_key, result->profile_key);
-  DCHECK_EQ(profile_index, result->profile_index);
-
-  if (num_method_ids != result->num_method_ids) {
-    // This should not happen... added to help investigating b/65812889.
-    LOG(ERROR) << "num_method_ids mismatch for dex " << profile_key
-        << ", expected=" << num_method_ids
-        << ", actual=" << result->num_method_ids;
-    return nullptr;
-  }
-
-  return result;
-}
-
-const ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::FindDexData(
-      const std::string& profile_key,
-      uint32_t checksum,
-      bool verify_checksum) const {
-  const auto profile_index_it = profile_key_map_.find(profile_key);
-  if (profile_index_it == profile_key_map_.end()) {
-    return nullptr;
-  }
-
-  uint8_t profile_index = profile_index_it->second;
-  const DexFileData* result = info_[profile_index];
-  if (verify_checksum && !ChecksumMatch(result->checksum, checksum)) {
-    return nullptr;
-  }
-  DCHECK_EQ(profile_key, result->profile_key);
-  DCHECK_EQ(profile_index, result->profile_index);
-  return result;
-}
-
-bool ProfileCompilationInfo::AddResolvedClasses(const DexCacheResolvedClasses& classes) {
-  const std::string dex_location = GetProfileDexFileKey(classes.GetDexLocation());
-  const uint32_t checksum = classes.GetLocationChecksum();
-  DexFileData* const data = GetOrAddDexFileData(dex_location, checksum, classes.NumMethodIds());
-  if (data == nullptr) {
-    return false;
-  }
-  data->class_set.insert(classes.GetClasses().begin(), classes.GetClasses().end());
-  return true;
-}
-
-bool ProfileCompilationInfo::AddMethod(const std::string& dex_location,
-                                       uint32_t dex_checksum,
-                                       uint16_t method_index,
-                                       uint32_t num_method_ids,
-                                       const OfflineProfileMethodInfo& pmi,
-                                       MethodHotness::Flag flags) {
-  DexFileData* const data = GetOrAddDexFileData(GetProfileDexFileKey(dex_location),
-                                                dex_checksum,
-                                                num_method_ids);
-  if (data == nullptr) {
-    // The data is null if there is a mismatch in the checksum or number of method ids.
-    return false;
-  }
-
-  // Add the method.
-  InlineCacheMap* inline_cache = data->FindOrAddMethod(method_index);
-  if (inline_cache == nullptr) {
-    // Happens if the method index is outside the range (i.e. is greater then the number
-    // of methods in the dex file). This should not happen during normal execution,
-    // But tools (e.g. boot image aggregation tools) and tests stress this behaviour.
-    return false;
-  }
-
-  data->SetMethodHotness(method_index, flags);
-
-  if (pmi.inline_caches == nullptr) {
-    // If we don't have inline caches return success right away.
-    return true;
-  }
-  for (const auto& pmi_inline_cache_it : *pmi.inline_caches) {
-    uint16_t pmi_ic_dex_pc = pmi_inline_cache_it.first;
-    const DexPcData& pmi_ic_dex_pc_data = pmi_inline_cache_it.second;
-    DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, pmi_ic_dex_pc);
-    if (dex_pc_data->is_missing_types || dex_pc_data->is_megamorphic) {
-      // We are already megamorphic or we are missing types; no point in going forward.
-      continue;
-    }
-
-    if (pmi_ic_dex_pc_data.is_missing_types) {
-      dex_pc_data->SetIsMissingTypes();
-      continue;
-    }
-    if (pmi_ic_dex_pc_data.is_megamorphic) {
-      dex_pc_data->SetIsMegamorphic();
-      continue;
-    }
-
-    for (const ClassReference& class_ref : pmi_ic_dex_pc_data.classes) {
-      const DexReference& dex_ref = pmi.dex_references[class_ref.dex_profile_index];
-      DexFileData* class_dex_data = GetOrAddDexFileData(
-          GetProfileDexFileKey(dex_ref.dex_location),
-          dex_ref.dex_checksum,
-          dex_ref.num_method_ids);
-      if (class_dex_data == nullptr) {  // checksum mismatch
-        return false;
-      }
-      dex_pc_data->AddClass(class_dex_data->profile_index, class_ref.type_index);
-    }
-  }
-  return true;
-}
-
-bool ProfileCompilationInfo::AddMethod(const ProfileMethodInfo& pmi, MethodHotness::Flag flags) {
-  DexFileData* const data = GetOrAddDexFileData(pmi.ref.dex_file);
-  if (data == nullptr) {  // checksum mismatch
-    return false;
-  }
-  InlineCacheMap* inline_cache = data->FindOrAddMethod(pmi.ref.index);
-  if (inline_cache == nullptr) {
-    return false;
-  }
-  data->SetMethodHotness(pmi.ref.index, flags);
-
-  for (const ProfileMethodInfo::ProfileInlineCache& cache : pmi.inline_caches) {
-    if (cache.is_missing_types) {
-      FindOrAddDexPc(inline_cache, cache.dex_pc)->SetIsMissingTypes();
-      continue;
-    }
-    for (const TypeReference& class_ref : cache.classes) {
-      DexFileData* class_dex_data = GetOrAddDexFileData(class_ref.dex_file);
-      if (class_dex_data == nullptr) {  // checksum mismatch
-        return false;
-      }
-      DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, cache.dex_pc);
-      if (dex_pc_data->is_missing_types) {
-        // Don't bother adding classes if we are missing types.
-        break;
-      }
-      dex_pc_data->AddClass(class_dex_data->profile_index, class_ref.TypeIndex());
-    }
-  }
-  return true;
-}
-
-bool ProfileCompilationInfo::AddClassIndex(const std::string& dex_location,
-                                           uint32_t checksum,
-                                           dex::TypeIndex type_idx,
-                                           uint32_t num_method_ids) {
-  DexFileData* const data = GetOrAddDexFileData(dex_location, checksum, num_method_ids);
-  if (data == nullptr) {
-    return false;
-  }
-  data->class_set.insert(type_idx);
-  return true;
-}
-
-#define READ_UINT(type, buffer, dest, error)            \
-  do {                                                  \
-    if (!(buffer).ReadUintAndAdvance<type>(&(dest))) {  \
-      *(error) = "Could not read "#dest;                \
-      return false;                                     \
-    }                                                   \
-  }                                                     \
-  while (false)
-
-bool ProfileCompilationInfo::ReadInlineCache(
-    SafeBuffer& buffer,
-    uint8_t number_of_dex_files,
-    const SafeMap<uint8_t, uint8_t>& dex_profile_index_remap,
-    /*out*/ InlineCacheMap* inline_cache,
-    /*out*/ std::string* error) {
-  uint16_t inline_cache_size;
-  READ_UINT(uint16_t, buffer, inline_cache_size, error);
-  for (; inline_cache_size > 0; inline_cache_size--) {
-    uint16_t dex_pc;
-    uint8_t dex_to_classes_map_size;
-    READ_UINT(uint16_t, buffer, dex_pc, error);
-    READ_UINT(uint8_t, buffer, dex_to_classes_map_size, error);
-    DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, dex_pc);
-    if (dex_to_classes_map_size == kIsMissingTypesEncoding) {
-      dex_pc_data->SetIsMissingTypes();
-      continue;
-    }
-    if (dex_to_classes_map_size == kIsMegamorphicEncoding) {
-      dex_pc_data->SetIsMegamorphic();
-      continue;
-    }
-    for (; dex_to_classes_map_size > 0; dex_to_classes_map_size--) {
-      uint8_t dex_profile_index;
-      uint8_t dex_classes_size;
-      READ_UINT(uint8_t, buffer, dex_profile_index, error);
-      READ_UINT(uint8_t, buffer, dex_classes_size, error);
-      if (dex_profile_index >= number_of_dex_files) {
-        *error = "dex_profile_index out of bounds ";
-        *error += std::to_string(dex_profile_index) + " " + std::to_string(number_of_dex_files);
-        return false;
-      }
-      for (; dex_classes_size > 0; dex_classes_size--) {
-        uint16_t type_index;
-        READ_UINT(uint16_t, buffer, type_index, error);
-        auto it = dex_profile_index_remap.find(dex_profile_index);
-        if (it == dex_profile_index_remap.end()) {
-          // If we don't have an index that's because the dex file was filtered out when loading.
-          // Set missing types on the dex pc data.
-          dex_pc_data->SetIsMissingTypes();
-        } else {
-          dex_pc_data->AddClass(it->second, dex::TypeIndex(type_index));
-        }
-      }
-    }
-  }
-  return true;
-}
-
-bool ProfileCompilationInfo::ReadMethods(SafeBuffer& buffer,
-                                         uint8_t number_of_dex_files,
-                                         const ProfileLineHeader& line_header,
-                                         const SafeMap<uint8_t, uint8_t>& dex_profile_index_remap,
-                                         /*out*/std::string* error) {
-  uint32_t unread_bytes_before_operation = buffer.CountUnreadBytes();
-  if (unread_bytes_before_operation < line_header.method_region_size_bytes) {
-    *error += "Profile EOF reached prematurely for ReadMethod";
-    return kProfileLoadBadData;
-  }
-  size_t expected_unread_bytes_after_operation = buffer.CountUnreadBytes()
-      - line_header.method_region_size_bytes;
-  uint16_t last_method_index = 0;
-  while (buffer.CountUnreadBytes() > expected_unread_bytes_after_operation) {
-    DexFileData* const data = GetOrAddDexFileData(line_header.dex_location,
-                                                  line_header.checksum,
-                                                  line_header.num_method_ids);
-    uint16_t diff_with_last_method_index;
-    READ_UINT(uint16_t, buffer, diff_with_last_method_index, error);
-    uint16_t method_index = last_method_index + diff_with_last_method_index;
-    last_method_index = method_index;
-    InlineCacheMap* inline_cache = data->FindOrAddMethod(method_index);
-    if (inline_cache == nullptr) {
-      return false;
-    }
-    if (!ReadInlineCache(buffer,
-                         number_of_dex_files,
-                         dex_profile_index_remap,
-                         inline_cache,
-                         error)) {
-      return false;
-    }
-  }
-  uint32_t total_bytes_read = unread_bytes_before_operation - buffer.CountUnreadBytes();
-  if (total_bytes_read != line_header.method_region_size_bytes) {
-    *error += "Profile data inconsistent for ReadMethods";
-    return false;
-  }
-  return true;
-}
-
-bool ProfileCompilationInfo::ReadClasses(SafeBuffer& buffer,
-                                         const ProfileLineHeader& line_header,
-                                         /*out*/std::string* error) {
-  size_t unread_bytes_before_op = buffer.CountUnreadBytes();
-  if (unread_bytes_before_op < line_header.class_set_size) {
-    *error += "Profile EOF reached prematurely for ReadClasses";
-    return kProfileLoadBadData;
-  }
-
-  uint16_t last_class_index = 0;
-  for (uint16_t i = 0; i < line_header.class_set_size; i++) {
-    uint16_t diff_with_last_class_index;
-    READ_UINT(uint16_t, buffer, diff_with_last_class_index, error);
-    uint16_t type_index = last_class_index + diff_with_last_class_index;
-    last_class_index = type_index;
-    if (!AddClassIndex(line_header.dex_location,
-                       line_header.checksum,
-                       dex::TypeIndex(type_index),
-                       line_header.num_method_ids)) {
-      return false;
-    }
-  }
-  size_t total_bytes_read = unread_bytes_before_op - buffer.CountUnreadBytes();
-  uint32_t expected_bytes_read = line_header.class_set_size * sizeof(uint16_t);
-  if (total_bytes_read != expected_bytes_read) {
-    *error += "Profile data inconsistent for ReadClasses";
-    return false;
-  }
-  return true;
-}
-
-// Tests for EOF by trying to read 1 byte from the descriptor.
-// Returns:
-//   0 if the descriptor is at the EOF,
-//  -1 if there was an IO error
-//   1 if the descriptor has more content to read
-static int testEOF(int fd) {
-  uint8_t buffer[1];
-  return TEMP_FAILURE_RETRY(read(fd, buffer, 1));
-}
-
-// Reads an uint value previously written with AddUintToBuffer.
-template <typename T>
-bool ProfileCompilationInfo::SafeBuffer::ReadUintAndAdvance(/*out*/T* value) {
-  static_assert(std::is_unsigned<T>::value, "Type is not unsigned");
-  if (ptr_current_ + sizeof(T) > ptr_end_) {
-    return false;
-  }
-  *value = 0;
-  for (size_t i = 0; i < sizeof(T); i++) {
-    *value += ptr_current_[i] << (i * kBitsPerByte);
-  }
-  ptr_current_ += sizeof(T);
-  return true;
-}
-
-bool ProfileCompilationInfo::SafeBuffer::CompareAndAdvance(const uint8_t* data, size_t data_size) {
-  if (ptr_current_ + data_size > ptr_end_) {
-    return false;
-  }
-  if (memcmp(ptr_current_, data, data_size) == 0) {
-    ptr_current_ += data_size;
-    return true;
-  }
-  return false;
-}
-
-ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::SafeBuffer::Fill(
-      ProfileSource& source,
-      const std::string& debug_stage,
-      /*out*/ std::string* error) {
-  size_t byte_count = (ptr_end_ - ptr_current_) * sizeof(*ptr_current_);
-  uint8_t* buffer = ptr_current_;
-  return source.Read(buffer, byte_count, debug_stage, error);
-}
-
-size_t ProfileCompilationInfo::SafeBuffer::CountUnreadBytes() {
-  return (ptr_end_ - ptr_current_) * sizeof(*ptr_current_);
-}
-
-const uint8_t* ProfileCompilationInfo::SafeBuffer::GetCurrentPtr() {
-  return ptr_current_;
-}
-
-void ProfileCompilationInfo::SafeBuffer::Advance(size_t data_size) {
-  ptr_current_ += data_size;
-}
-
-ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ReadProfileHeader(
-      ProfileSource& source,
-      /*out*/uint8_t* number_of_dex_files,
-      /*out*/uint32_t* uncompressed_data_size,
-      /*out*/uint32_t* compressed_data_size,
-      /*out*/std::string* error) {
-  // Read magic and version
-  const size_t kMagicVersionSize =
-    sizeof(kProfileMagic) +
-    sizeof(kProfileVersion) +
-    sizeof(uint8_t) +  // number of dex files
-    sizeof(uint32_t) +  // size of uncompressed profile data
-    sizeof(uint32_t);  // size of compressed profile data
-
-  SafeBuffer safe_buffer(kMagicVersionSize);
-
-  ProfileLoadStatus status = safe_buffer.Fill(source, "ReadProfileHeader", error);
-  if (status != kProfileLoadSuccess) {
-    return status;
-  }
-
-  if (!safe_buffer.CompareAndAdvance(kProfileMagic, sizeof(kProfileMagic))) {
-    *error = "Profile missing magic";
-    return kProfileLoadVersionMismatch;
-  }
-  if (!safe_buffer.CompareAndAdvance(kProfileVersion, sizeof(kProfileVersion))) {
-    *error = "Profile version mismatch";
-    return kProfileLoadVersionMismatch;
-  }
-  if (!safe_buffer.ReadUintAndAdvance<uint8_t>(number_of_dex_files)) {
-    *error = "Cannot read the number of dex files";
-    return kProfileLoadBadData;
-  }
-  if (!safe_buffer.ReadUintAndAdvance<uint32_t>(uncompressed_data_size)) {
-    *error = "Cannot read the size of uncompressed data";
-    return kProfileLoadBadData;
-  }
-  if (!safe_buffer.ReadUintAndAdvance<uint32_t>(compressed_data_size)) {
-    *error = "Cannot read the size of compressed data";
-    return kProfileLoadBadData;
-  }
-  return kProfileLoadSuccess;
-}
-
-bool ProfileCompilationInfo::ReadProfileLineHeaderElements(SafeBuffer& buffer,
-                                                           /*out*/uint16_t* dex_location_size,
-                                                           /*out*/ProfileLineHeader* line_header,
-                                                           /*out*/std::string* error) {
-  READ_UINT(uint16_t, buffer, *dex_location_size, error);
-  READ_UINT(uint16_t, buffer, line_header->class_set_size, error);
-  READ_UINT(uint32_t, buffer, line_header->method_region_size_bytes, error);
-  READ_UINT(uint32_t, buffer, line_header->checksum, error);
-  READ_UINT(uint32_t, buffer, line_header->num_method_ids, error);
-  return true;
-}
-
-ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ReadProfileLineHeader(
-    SafeBuffer& buffer,
-    /*out*/ProfileLineHeader* line_header,
-    /*out*/std::string* error) {
-  if (buffer.CountUnreadBytes() < kLineHeaderSize) {
-    *error += "Profile EOF reached prematurely for ReadProfileLineHeader";
-    return kProfileLoadBadData;
-  }
-
-  uint16_t dex_location_size;
-  if (!ReadProfileLineHeaderElements(buffer, &dex_location_size, line_header, error)) {
-    return kProfileLoadBadData;
-  }
-
-  if (dex_location_size == 0 || dex_location_size > kMaxDexFileKeyLength) {
-    *error = "DexFileKey has an invalid size: " +
-        std::to_string(static_cast<uint32_t>(dex_location_size));
-    return kProfileLoadBadData;
-  }
-
-  if (buffer.CountUnreadBytes() < dex_location_size) {
-    *error += "Profile EOF reached prematurely for ReadProfileHeaderDexLocation";
-    return kProfileLoadBadData;
-  }
-  const uint8_t* base_ptr = buffer.GetCurrentPtr();
-  line_header->dex_location.assign(
-      reinterpret_cast<const char*>(base_ptr), dex_location_size);
-  buffer.Advance(dex_location_size);
-  return kProfileLoadSuccess;
-}
-
-ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ReadProfileLine(
-      SafeBuffer& buffer,
-      uint8_t number_of_dex_files,
-      const ProfileLineHeader& line_header,
-      const SafeMap<uint8_t, uint8_t>& dex_profile_index_remap,
-      bool merge_classes,
-      /*out*/std::string* error) {
-  DexFileData* data = GetOrAddDexFileData(line_header.dex_location,
-                                          line_header.checksum,
-                                          line_header.num_method_ids);
-  if (data == nullptr) {
-    *error = "Error when reading profile file line header: checksum mismatch for "
-        + line_header.dex_location;
-    return kProfileLoadBadData;
-  }
-
-  if (!ReadMethods(buffer, number_of_dex_files, line_header, dex_profile_index_remap, error)) {
-    return kProfileLoadBadData;
-  }
-
-  if (merge_classes) {
-    if (!ReadClasses(buffer, line_header, error)) {
-      return kProfileLoadBadData;
-    }
-  }
-
-  const size_t bytes = data->bitmap_storage.size();
-  if (buffer.CountUnreadBytes() < bytes) {
-    *error += "Profile EOF reached prematurely for ReadProfileHeaderDexLocation";
-    return kProfileLoadBadData;
-  }
-  const uint8_t* base_ptr = buffer.GetCurrentPtr();
-  std::copy_n(base_ptr, bytes, data->bitmap_storage.data());
-  buffer.Advance(bytes);
-  // Read method bitmap.
-  return kProfileLoadSuccess;
-}
-
-// TODO(calin): Fix this API. ProfileCompilationInfo::Load should be static and
-// return a unique pointer to a ProfileCompilationInfo upon success.
-bool ProfileCompilationInfo::Load(
-    int fd, bool merge_classes, const ProfileLoadFilterFn& filter_fn) {
-  std::string error;
-
-  ProfileLoadStatus status = LoadInternal(fd, &error, merge_classes, filter_fn);
-
-  if (status == kProfileLoadSuccess) {
-    return true;
-  } else {
-    LOG(WARNING) << "Error when reading profile: " << error;
-    return false;
-  }
-}
-
-bool ProfileCompilationInfo::VerifyProfileData(const std::vector<const DexFile*>& dex_files) {
-  std::unordered_map<std::string, const DexFile*> key_to_dex_file;
-  for (const DexFile* dex_file : dex_files) {
-    key_to_dex_file.emplace(GetProfileDexFileKey(dex_file->GetLocation()), dex_file);
-  }
-  for (const DexFileData* dex_data : info_) {
-    const auto it = key_to_dex_file.find(dex_data->profile_key);
-    if (it == key_to_dex_file.end()) {
-      // It is okay if profile contains data for additional dex files.
-      continue;
-    }
-    const DexFile* dex_file = it->second;
-    const std::string& dex_location = dex_file->GetLocation();
-    if (!ChecksumMatch(dex_data->checksum, dex_file->GetLocationChecksum())) {
-      LOG(ERROR) << "Dex checksum mismatch while verifying profile "
-                 << "dex location " << dex_location << " (checksum="
-                 << dex_file->GetLocationChecksum() << ", profile checksum="
-                 << dex_data->checksum;
-      return false;
-    }
-
-    if (dex_data->num_method_ids != dex_file->NumMethodIds()) {
-      LOG(ERROR) << "Number of method ids in dex file and profile don't match."
-                 << "dex location " << dex_location << " NumMethodId in DexFile"
-                 << dex_file->NumMethodIds() << ", NumMethodId in profile"
-                 << dex_data->num_method_ids;
-      return false;
-    }
-
-    // Verify method_encoding.
-    for (const auto& method_it : dex_data->method_map) {
-      size_t method_id = (size_t)(method_it.first);
-      if (method_id >= dex_file->NumMethodIds()) {
-        LOG(ERROR) << "Invalid method id in profile file. dex location="
-                   << dex_location << " method_id=" << method_id << " NumMethodIds="
-                   << dex_file->NumMethodIds();
-        return false;
-      }
-
-      // Verify class indices of inline caches.
-      const InlineCacheMap &inline_cache_map = method_it.second;
-      for (const auto& inline_cache_it : inline_cache_map) {
-        const DexPcData dex_pc_data = inline_cache_it.second;
-        if (dex_pc_data.is_missing_types || dex_pc_data.is_megamorphic) {
-          // No class indices to verify.
-          continue;
-        }
-
-        const ClassSet &classes = dex_pc_data.classes;
-        SafeMap<uint8_t, std::vector<dex::TypeIndex>> dex_to_classes_map;
-        // Group the classes by dex. We expect that most of the classes will come from
-        // the same dex, so this will be more efficient than encoding the dex index
-        // for each class reference.
-        GroupClassesByDex(classes, &dex_to_classes_map);
-        for (const auto &dex_it : dex_to_classes_map) {
-          uint8_t dex_profile_index = dex_it.first;
-          const auto dex_file_inline_cache_it = key_to_dex_file.find(
-              info_[dex_profile_index]->profile_key);
-          if (dex_file_inline_cache_it == key_to_dex_file.end()) {
-            // It is okay if profile contains data for additional dex files.
-            continue;
-          }
-          const DexFile *dex_file_for_inline_cache_check = dex_file_inline_cache_it->second;
-          const std::vector<dex::TypeIndex> &dex_classes = dex_it.second;
-          for (size_t i = 0; i < dex_classes.size(); i++) {
-            if (dex_classes[i].index_ >= dex_file_for_inline_cache_check->NumTypeIds()) {
-              LOG(ERROR) << "Invalid inline cache in profile file. dex location="
-                  << dex_location << " method_id=" << method_id
-                  << " dex_profile_index="
-                  << static_cast<uint16_t >(dex_profile_index) << " type_index="
-                  << dex_classes[i].index_
-                  << " NumTypeIds="
-                  << dex_file_for_inline_cache_check->NumTypeIds();
-              return false;
-            }
-          }
-        }
-      }
-    }
-    // Verify class_ids.
-    for (const auto& class_id : dex_data->class_set) {
-      if (class_id.index_ >= dex_file->NumTypeIds()) {
-        LOG(ERROR) << "Invalid class id in profile file. dex_file location "
-                   << dex_location << " class_id=" << class_id.index_ << " NumClassIds="
-                   << dex_file->NumClassDefs();
-        return false;
-      }
-    }
-  }
-  return true;
-}
-
-ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::OpenSource(
-    int32_t fd,
-    /*out*/ std::unique_ptr<ProfileSource>* source,
-    /*out*/ std::string* error) {
-  if (IsProfileFile(fd)) {
-    source->reset(ProfileSource::Create(fd));
-    return kProfileLoadSuccess;
-  } else {
-    std::unique_ptr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(fd, "profile", error));
-    if (zip_archive.get() == nullptr) {
-      *error = "Could not open the profile zip archive";
-      return kProfileLoadBadData;
-    }
-    std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(kDexMetadataProfileEntry, error));
-    if (zip_entry == nullptr) {
-      // Allow archives without the profile entry. In this case, create an empty profile.
-      // This gives more flexible when ure-using archives that may miss the entry.
-      // (e.g. dex metadata files)
-      LOG(WARNING) << std::string("Could not find entry ") + kDexMetadataProfileEntry +
-            " in the zip archive. Creating an empty profile.";
-      source->reset(ProfileSource::Create(nullptr));
-      return kProfileLoadSuccess;
-    }
-    if (zip_entry->GetUncompressedLength() == 0) {
-      *error = "Empty profile entry in the zip archive.";
-      return kProfileLoadBadData;
-    }
-
-    // TODO(calin) pass along file names to assist with debugging.
-    std::unique_ptr<MemMap> map(zip_entry->MapDirectlyOrExtract(kDexMetadataProfileEntry,
-                                                                "profile file",
-                                                                error));
-
-    if (map != nullptr) {
-      source->reset(ProfileSource::Create(std::move(map)));
-      return kProfileLoadSuccess;
-    } else {
-      return kProfileLoadBadData;
-    }
-  }
-}
-
-ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ProfileSource::Read(
-    uint8_t* buffer,
-    size_t byte_count,
-    const std::string& debug_stage,
-    std::string* error) {
-  if (IsMemMap()) {
-    if (mem_map_cur_ + byte_count > mem_map_->Size()) {
-      return kProfileLoadBadData;
-    }
-    for (size_t i = 0; i < byte_count; i++) {
-      buffer[i] = *(mem_map_->Begin() + mem_map_cur_);
-      mem_map_cur_++;
-    }
-  } else {
-    while (byte_count > 0) {
-      int bytes_read = TEMP_FAILURE_RETRY(read(fd_, buffer, byte_count));;
-      if (bytes_read == 0) {
-        *error += "Profile EOF reached prematurely for " + debug_stage;
-        return kProfileLoadBadData;
-      } else if (bytes_read < 0) {
-        *error += "Profile IO error for " + debug_stage + strerror(errno);
-        return kProfileLoadIOError;
-      }
-      byte_count -= bytes_read;
-      buffer += bytes_read;
-    }
-  }
-  return kProfileLoadSuccess;
-}
-
-bool ProfileCompilationInfo::ProfileSource::HasConsumedAllData() const {
-  return IsMemMap()
-      ? (mem_map_ == nullptr || mem_map_cur_ == mem_map_->Size())
-      : (testEOF(fd_) == 0);
-}
-
-bool ProfileCompilationInfo::ProfileSource::HasEmptyContent() const {
-  if (IsMemMap()) {
-    return mem_map_ == nullptr || mem_map_->Size() == 0;
-  } else {
-    struct stat stat_buffer;
-    if (fstat(fd_, &stat_buffer) != 0) {
-      return false;
-    }
-    return stat_buffer.st_size == 0;
-  }
-}
-
-// TODO(calin): fail fast if the dex checksums don't match.
-ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::LoadInternal(
-      int32_t fd,
-      std::string* error,
-      bool merge_classes,
-      const ProfileLoadFilterFn& filter_fn) {
-  ScopedTrace trace(__PRETTY_FUNCTION__);
-  DCHECK_GE(fd, 0);
-
-  std::unique_ptr<ProfileSource> source;
-  ProfileLoadStatus status = OpenSource(fd, &source, error);
-  if (status != kProfileLoadSuccess) {
-    return status;
-  }
-
-  // We allow empty profile files.
-  // Profiles may be created by ActivityManager or installd before we manage to
-  // process them in the runtime or profman.
-  if (source->HasEmptyContent()) {
-    return kProfileLoadSuccess;
-  }
-
-  // Read profile header: magic + version + number_of_dex_files.
-  uint8_t number_of_dex_files;
-  uint32_t uncompressed_data_size;
-  uint32_t compressed_data_size;
-  status = ReadProfileHeader(*source,
-                             &number_of_dex_files,
-                             &uncompressed_data_size,
-                             &compressed_data_size,
-                             error);
-
-  if (status != kProfileLoadSuccess) {
-    return status;
-  }
-  // Allow large profiles for non target builds for the case where we are merging many profiles
-  // to generate a boot image profile.
-  if (kIsTargetBuild && uncompressed_data_size > kProfileSizeErrorThresholdInBytes) {
-    LOG(ERROR) << "Profile data size exceeds "
-               << std::to_string(kProfileSizeErrorThresholdInBytes)
-               << " bytes";
-    return kProfileLoadBadData;
-  }
-  if (uncompressed_data_size > kProfileSizeWarningThresholdInBytes) {
-    LOG(WARNING) << "Profile data size exceeds "
-                 << std::to_string(kProfileSizeWarningThresholdInBytes)
-                 << " bytes";
-  }
-
-  std::unique_ptr<uint8_t[]> compressed_data(new uint8_t[compressed_data_size]);
-  status = source->Read(compressed_data.get(), compressed_data_size, "ReadContent", error);
-  if (status != kProfileLoadSuccess) {
-    *error += "Unable to read compressed profile data";
-    return status;
-  }
-
-  if (!source->HasConsumedAllData()) {
-    *error += "Unexpected data in the profile file.";
-    return kProfileLoadBadData;
-  }
-
-  SafeBuffer uncompressed_data(uncompressed_data_size);
-
-  int ret = InflateBuffer(compressed_data.get(),
-                          compressed_data_size,
-                          uncompressed_data_size,
-                          uncompressed_data.Get());
-
-  if (ret != Z_STREAM_END) {
-    *error += "Error reading uncompressed profile data";
-    return kProfileLoadBadData;
-  }
-
-  std::vector<ProfileLineHeader> profile_line_headers;
-  // Read profile line headers.
-  for (uint8_t k = 0; k < number_of_dex_files; k++) {
-    ProfileLineHeader line_header;
-
-    // First, read the line header to get the amount of data we need to read.
-    status = ReadProfileLineHeader(uncompressed_data, &line_header, error);
-    if (status != kProfileLoadSuccess) {
-      return status;
-    }
-    profile_line_headers.push_back(line_header);
-  }
-
-  SafeMap<uint8_t, uint8_t> dex_profile_index_remap;
-  if (!RemapProfileIndex(profile_line_headers, filter_fn, &dex_profile_index_remap)) {
-    return kProfileLoadBadData;
-  }
-
-  for (uint8_t k = 0; k < number_of_dex_files; k++) {
-    if (!filter_fn(profile_line_headers[k].dex_location, profile_line_headers[k].checksum)) {
-      // We have to skip the line. Advanced the current pointer of the buffer.
-      size_t profile_line_size =
-           profile_line_headers[k].class_set_size * sizeof(uint16_t) +
-           profile_line_headers[k].method_region_size_bytes +
-           DexFileData::ComputeBitmapStorage(profile_line_headers[k].num_method_ids);
-      uncompressed_data.Advance(profile_line_size);
-    } else {
-      // Now read the actual profile line.
-      status = ReadProfileLine(uncompressed_data,
-                               number_of_dex_files,
-                               profile_line_headers[k],
-                               dex_profile_index_remap,
-                               merge_classes,
-                               error);
-      if (status != kProfileLoadSuccess) {
-        return status;
-      }
-    }
-  }
-
-  // Check that we read everything and that profiles don't contain junk data.
-  if (uncompressed_data.CountUnreadBytes() > 0) {
-    *error = "Unexpected content in the profile file";
-    return kProfileLoadBadData;
-  } else {
-    return kProfileLoadSuccess;
-  }
-}
-
-bool ProfileCompilationInfo::RemapProfileIndex(
-    const std::vector<ProfileLineHeader>& profile_line_headers,
-    const ProfileLoadFilterFn& filter_fn,
-    /*out*/SafeMap<uint8_t, uint8_t>* dex_profile_index_remap) {
-  // First verify that all checksums match. This will avoid adding garbage to
-  // the current profile info.
-  // Note that the number of elements should be very small, so this should not
-  // be a performance issue.
-  for (const ProfileLineHeader other_profile_line_header : profile_line_headers) {
-    if (!filter_fn(other_profile_line_header.dex_location, other_profile_line_header.checksum)) {
-      continue;
-    }
-    // verify_checksum is false because we want to differentiate between a missing dex data and
-    // a mismatched checksum.
-    const DexFileData* dex_data = FindDexData(other_profile_line_header.dex_location,
-                                              0u,
-                                              false /* verify_checksum */);
-    if ((dex_data != nullptr) && (dex_data->checksum != other_profile_line_header.checksum)) {
-      LOG(WARNING) << "Checksum mismatch for dex " << other_profile_line_header.dex_location;
-      return false;
-    }
-  }
-  // All checksums match. Import the data.
-  uint32_t num_dex_files = static_cast<uint32_t>(profile_line_headers.size());
-  for (uint32_t i = 0; i < num_dex_files; i++) {
-    if (!filter_fn(profile_line_headers[i].dex_location, profile_line_headers[i].checksum)) {
-      continue;
-    }
-    const DexFileData* dex_data = GetOrAddDexFileData(profile_line_headers[i].dex_location,
-                                                      profile_line_headers[i].checksum,
-                                                      profile_line_headers[i].num_method_ids);
-    if (dex_data == nullptr) {
-      return false;  // Could happen if we exceed the number of allowed dex files.
-    }
-    dex_profile_index_remap->Put(i, dex_data->profile_index);
-  }
-  return true;
-}
-
-std::unique_ptr<uint8_t[]> ProfileCompilationInfo::DeflateBuffer(const uint8_t* in_buffer,
-                                                                 uint32_t in_size,
-                                                                 uint32_t* compressed_data_size) {
-  z_stream strm;
-  strm.zalloc = Z_NULL;
-  strm.zfree = Z_NULL;
-  strm.opaque = Z_NULL;
-  int ret = deflateInit(&strm, 1);
-  if (ret != Z_OK) {
-    return nullptr;
-  }
-
-  uint32_t out_size = deflateBound(&strm, in_size);
-
-  std::unique_ptr<uint8_t[]> compressed_buffer(new uint8_t[out_size]);
-  strm.avail_in = in_size;
-  strm.next_in = const_cast<uint8_t*>(in_buffer);
-  strm.avail_out = out_size;
-  strm.next_out = &compressed_buffer[0];
-  ret = deflate(&strm, Z_FINISH);
-  if (ret == Z_STREAM_ERROR) {
-    return nullptr;
-  }
-  *compressed_data_size = out_size - strm.avail_out;
-  deflateEnd(&strm);
-  return compressed_buffer;
-}
-
-int ProfileCompilationInfo::InflateBuffer(const uint8_t* in_buffer,
-                                          uint32_t in_size,
-                                          uint32_t expected_uncompressed_data_size,
-                                          uint8_t* out_buffer) {
-  z_stream strm;
-
-  /* allocate inflate state */
-  strm.zalloc = Z_NULL;
-  strm.zfree = Z_NULL;
-  strm.opaque = Z_NULL;
-  strm.avail_in = in_size;
-  strm.next_in = const_cast<uint8_t*>(in_buffer);
-  strm.avail_out = expected_uncompressed_data_size;
-  strm.next_out = out_buffer;
-
-  int ret;
-  inflateInit(&strm);
-  ret = inflate(&strm, Z_NO_FLUSH);
-
-  if (strm.avail_in != 0 || strm.avail_out != 0) {
-    return Z_DATA_ERROR;
-  }
-  inflateEnd(&strm);
-  return ret;
-}
-
-bool ProfileCompilationInfo::MergeWith(const ProfileCompilationInfo& other,
-                                       bool merge_classes) {
-  // First verify that all checksums match. This will avoid adding garbage to
-  // the current profile info.
-  // Note that the number of elements should be very small, so this should not
-  // be a performance issue.
-  for (const DexFileData* other_dex_data : other.info_) {
-    // verify_checksum is false because we want to differentiate between a missing dex data and
-    // a mismatched checksum.
-    const DexFileData* dex_data = FindDexData(other_dex_data->profile_key,
-                                              0u,
-                                              /* verify_checksum */ false);
-    if ((dex_data != nullptr) && (dex_data->checksum != other_dex_data->checksum)) {
-      LOG(WARNING) << "Checksum mismatch for dex " << other_dex_data->profile_key;
-      return false;
-    }
-  }
-  // All checksums match. Import the data.
-
-  // The other profile might have a different indexing of dex files.
-  // That is because each dex files gets a 'dex_profile_index' on a first come first served basis.
-  // That means that the order in with the methods are added to the profile matters for the
-  // actual indices.
-  // The reason we cannot rely on the actual multidex index is that a single profile may store
-  // data from multiple splits. This means that a profile may contain a classes2.dex from split-A
-  // and one from split-B.
-
-  // First, build a mapping from other_dex_profile_index to this_dex_profile_index.
-  // This will make sure that the ClassReferences  will point to the correct dex file.
-  SafeMap<uint8_t, uint8_t> dex_profile_index_remap;
-  for (const DexFileData* other_dex_data : other.info_) {
-    const DexFileData* dex_data = GetOrAddDexFileData(other_dex_data->profile_key,
-                                                      other_dex_data->checksum,
-                                                      other_dex_data->num_method_ids);
-    if (dex_data == nullptr) {
-      return false;  // Could happen if we exceed the number of allowed dex files.
-    }
-    dex_profile_index_remap.Put(other_dex_data->profile_index, dex_data->profile_index);
-  }
-
-  // Merge the actual profile data.
-  for (const DexFileData* other_dex_data : other.info_) {
-    DexFileData* dex_data = const_cast<DexFileData*>(FindDexData(other_dex_data->profile_key,
-                                                                 other_dex_data->checksum));
-    DCHECK(dex_data != nullptr);
-
-    // Merge the classes.
-    if (merge_classes) {
-      dex_data->class_set.insert(other_dex_data->class_set.begin(),
-                                 other_dex_data->class_set.end());
-    }
-
-    // Merge the methods and the inline caches.
-    for (const auto& other_method_it : other_dex_data->method_map) {
-      uint16_t other_method_index = other_method_it.first;
-      InlineCacheMap* inline_cache = dex_data->FindOrAddMethod(other_method_index);
-      if (inline_cache == nullptr) {
-        return false;
-      }
-      const auto& other_inline_cache = other_method_it.second;
-      for (const auto& other_ic_it : other_inline_cache) {
-        uint16_t other_dex_pc = other_ic_it.first;
-        const ClassSet& other_class_set = other_ic_it.second.classes;
-        DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, other_dex_pc);
-        if (other_ic_it.second.is_missing_types) {
-          dex_pc_data->SetIsMissingTypes();
-        } else if (other_ic_it.second.is_megamorphic) {
-          dex_pc_data->SetIsMegamorphic();
-        } else {
-          for (const auto& class_it : other_class_set) {
-            dex_pc_data->AddClass(dex_profile_index_remap.Get(
-                class_it.dex_profile_index), class_it.type_index);
-          }
-        }
-      }
-    }
-
-    // Merge the method bitmaps.
-    dex_data->MergeBitmap(*other_dex_data);
-  }
-  return true;
-}
-
-const ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::FindDexData(
-    const DexFile* dex_file) const {
-  return FindDexData(GetProfileDexFileKey(dex_file->GetLocation()),
-                     dex_file->GetLocationChecksum());
-}
-
-ProfileCompilationInfo::MethodHotness ProfileCompilationInfo::GetMethodHotness(
-    const MethodReference& method_ref) const {
-  const DexFileData* dex_data = FindDexData(method_ref.dex_file);
-  return dex_data != nullptr
-      ? dex_data->GetHotnessInfo(method_ref.index)
-      : MethodHotness();
-}
-
-bool ProfileCompilationInfo::AddMethodHotness(const MethodReference& method_ref,
-                                              const MethodHotness& hotness) {
-  DexFileData* dex_data = GetOrAddDexFileData(method_ref.dex_file);
-  if (dex_data != nullptr) {
-    // TODO: Add inline caches.
-    return dex_data->AddMethod(
-        static_cast<MethodHotness::Flag>(hotness.GetFlags()), method_ref.index);
-  }
-  return false;
-}
-
-ProfileCompilationInfo::MethodHotness ProfileCompilationInfo::GetMethodHotness(
-    const std::string& dex_location,
-    uint32_t dex_checksum,
-    uint16_t dex_method_index) const {
-  const DexFileData* dex_data = FindDexData(GetProfileDexFileKey(dex_location), dex_checksum);
-  return dex_data != nullptr ? dex_data->GetHotnessInfo(dex_method_index) : MethodHotness();
-}
-
-
-std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> ProfileCompilationInfo::GetMethod(
-    const std::string& dex_location,
-    uint32_t dex_checksum,
-    uint16_t dex_method_index) const {
-  MethodHotness hotness(GetMethodHotness(dex_location, dex_checksum, dex_method_index));
-  if (!hotness.IsHot()) {
-    return nullptr;
-  }
-  const InlineCacheMap* inline_caches = hotness.GetInlineCacheMap();
-  DCHECK(inline_caches != nullptr);
-  std::unique_ptr<OfflineProfileMethodInfo> pmi(new OfflineProfileMethodInfo(inline_caches));
-
-  pmi->dex_references.resize(info_.size());
-  for (const DexFileData* dex_data : info_) {
-    pmi->dex_references[dex_data->profile_index].dex_location = dex_data->profile_key;
-    pmi->dex_references[dex_data->profile_index].dex_checksum = dex_data->checksum;
-    pmi->dex_references[dex_data->profile_index].num_method_ids = dex_data->num_method_ids;
-  }
-
-  return pmi;
-}
-
-
-bool ProfileCompilationInfo::ContainsClass(const DexFile& dex_file, dex::TypeIndex type_idx) const {
-  const DexFileData* dex_data = FindDexData(&dex_file);
-  if (dex_data != nullptr) {
-    const ArenaSet<dex::TypeIndex>& classes = dex_data->class_set;
-    return classes.find(type_idx) != classes.end();
-  }
-  return false;
-}
-
-uint32_t ProfileCompilationInfo::GetNumberOfMethods() const {
-  uint32_t total = 0;
-  for (const DexFileData* dex_data : info_) {
-    total += dex_data->method_map.size();
-  }
-  return total;
-}
-
-uint32_t ProfileCompilationInfo::GetNumberOfResolvedClasses() const {
-  uint32_t total = 0;
-  for (const DexFileData* dex_data : info_) {
-    total += dex_data->class_set.size();
-  }
-  return total;
-}
-
-// Produce a non-owning vector from a vector.
-template<typename T>
-const std::vector<T*>* MakeNonOwningVector(const std::vector<std::unique_ptr<T>>* owning_vector) {
-  auto non_owning_vector = new std::vector<T*>();
-  for (auto& element : *owning_vector) {
-    non_owning_vector->push_back(element.get());
-  }
-  return non_owning_vector;
-}
-
-std::string ProfileCompilationInfo::DumpInfo(
-    const std::vector<std::unique_ptr<const DexFile>>* dex_files,
-    bool print_full_dex_location) const {
-  std::unique_ptr<const std::vector<const DexFile*>> non_owning_dex_files(
-      MakeNonOwningVector(dex_files));
-  return DumpInfo(non_owning_dex_files.get(), print_full_dex_location);
-}
-
-std::string ProfileCompilationInfo::DumpInfo(const std::vector<const DexFile*>* dex_files,
-                                             bool print_full_dex_location) const {
-  std::ostringstream os;
-  if (info_.empty()) {
-    return "ProfileInfo: empty";
-  }
-
-  os << "ProfileInfo:";
-
-  const std::string kFirstDexFileKeySubstitute = "!classes.dex";
-
-  for (const DexFileData* dex_data : info_) {
-    os << "\n";
-    if (print_full_dex_location) {
-      os << dex_data->profile_key;
-    } else {
-      // Replace the (empty) multidex suffix of the first key with a substitute for easier reading.
-      std::string multidex_suffix = DexFileLoader::GetMultiDexSuffix(dex_data->profile_key);
-      os << (multidex_suffix.empty() ? kFirstDexFileKeySubstitute : multidex_suffix);
-    }
-    os << " [index=" << static_cast<uint32_t>(dex_data->profile_index) << "]";
-    os << " [checksum=" << std::hex << dex_data->checksum << "]" << std::dec;
-    const DexFile* dex_file = nullptr;
-    if (dex_files != nullptr) {
-      for (size_t i = 0; i < dex_files->size(); i++) {
-        if (dex_data->profile_key == (*dex_files)[i]->GetLocation()) {
-          dex_file = (*dex_files)[i];
-        }
-      }
-    }
-    os << "\n\thot methods: ";
-    for (const auto& method_it : dex_data->method_map) {
-      if (dex_file != nullptr) {
-        os << "\n\t\t" << dex_file->PrettyMethod(method_it.first, true);
-      } else {
-        os << method_it.first;
-      }
-
-      os << "[";
-      for (const auto& inline_cache_it : method_it.second) {
-        os << "{" << std::hex << inline_cache_it.first << std::dec << ":";
-        if (inline_cache_it.second.is_missing_types) {
-          os << "MT";
-        } else if (inline_cache_it.second.is_megamorphic) {
-          os << "MM";
-        } else {
-          for (const ClassReference& class_ref : inline_cache_it.second.classes) {
-            os << "(" << static_cast<uint32_t>(class_ref.dex_profile_index)
-               << "," << class_ref.type_index.index_ << ")";
-          }
-        }
-        os << "}";
-      }
-      os << "], ";
-    }
-    bool startup = true;
-    while (true) {
-      os << "\n\t" << (startup ? "startup methods: " : "post startup methods: ");
-      for (uint32_t method_idx = 0; method_idx < dex_data->num_method_ids; ++method_idx) {
-        MethodHotness hotness_info(dex_data->GetHotnessInfo(method_idx));
-        if (startup ? hotness_info.IsStartup() : hotness_info.IsPostStartup()) {
-          if (dex_file != nullptr) {
-            os << "\n\t\t" << dex_file->PrettyMethod(method_idx, true);
-          } else {
-            os << method_idx << ", ";
-          }
-        }
-      }
-      if (startup == false) {
-        break;
-      }
-      startup = false;
-    }
-    os << "\n\tclasses: ";
-    for (const auto class_it : dex_data->class_set) {
-      if (dex_file != nullptr) {
-        os << "\n\t\t" << dex_file->PrettyType(class_it);
-      } else {
-        os << class_it.index_ << ",";
-      }
-    }
-  }
-  return os.str();
-}
-
-bool ProfileCompilationInfo::GetClassesAndMethods(
-    const DexFile& dex_file,
-    /*out*/std::set<dex::TypeIndex>* class_set,
-    /*out*/std::set<uint16_t>* hot_method_set,
-    /*out*/std::set<uint16_t>* startup_method_set,
-    /*out*/std::set<uint16_t>* post_startup_method_method_set) const {
-  std::set<std::string> ret;
-  const DexFileData* dex_data = FindDexData(&dex_file);
-  if (dex_data == nullptr) {
-    return false;
-  }
-  for (const auto& it : dex_data->method_map) {
-    hot_method_set->insert(it.first);
-  }
-  for (uint32_t method_idx = 0; method_idx < dex_data->num_method_ids; ++method_idx) {
-    MethodHotness hotness = dex_data->GetHotnessInfo(method_idx);
-    if (hotness.IsStartup()) {
-      startup_method_set->insert(method_idx);
-    }
-    if (hotness.IsPostStartup()) {
-      post_startup_method_method_set->insert(method_idx);
-    }
-  }
-  for (const dex::TypeIndex& type_index : dex_data->class_set) {
-    class_set->insert(type_index);
-  }
-  return true;
-}
-
-bool ProfileCompilationInfo::Equals(const ProfileCompilationInfo& other) {
-  // No need to compare profile_key_map_. That's only a cache for fast search.
-  // All the information is already in the info_ vector.
-  if (info_.size() != other.info_.size()) {
-    return false;
-  }
-  for (size_t i = 0; i < info_.size(); i++) {
-    const DexFileData& dex_data = *info_[i];
-    const DexFileData& other_dex_data = *other.info_[i];
-    if (!(dex_data == other_dex_data)) {
-      return false;
-    }
-  }
-  return true;
-}
-
-std::set<DexCacheResolvedClasses> ProfileCompilationInfo::GetResolvedClasses(
-    const std::vector<const DexFile*>& dex_files) const {
-  std::unordered_map<std::string, const DexFile* > key_to_dex_file;
-  for (const DexFile* dex_file : dex_files) {
-    key_to_dex_file.emplace(GetProfileDexFileKey(dex_file->GetLocation()), dex_file);
-  }
-  std::set<DexCacheResolvedClasses> ret;
-  for (const DexFileData* dex_data : info_) {
-    const auto it = key_to_dex_file.find(dex_data->profile_key);
-    if (it != key_to_dex_file.end()) {
-      const DexFile* dex_file = it->second;
-      const std::string& dex_location = dex_file->GetLocation();
-      if (dex_data->checksum != it->second->GetLocationChecksum()) {
-        LOG(ERROR) << "Dex checksum mismatch when getting resolved classes from profile for "
-            << "location " << dex_location << " (checksum=" << dex_file->GetLocationChecksum()
-            << ", profile checksum=" << dex_data->checksum;
-        return std::set<DexCacheResolvedClasses>();
-      }
-      DexCacheResolvedClasses classes(dex_location,
-                                      dex_location,
-                                      dex_data->checksum,
-                                      dex_data->num_method_ids);
-      classes.AddClasses(dex_data->class_set.begin(), dex_data->class_set.end());
-      ret.insert(classes);
-    }
-  }
-  return ret;
-}
-
-// Naive implementation to generate a random profile file suitable for testing.
-bool ProfileCompilationInfo::GenerateTestProfile(int fd,
-                                                 uint16_t number_of_dex_files,
-                                                 uint16_t method_percentage,
-                                                 uint16_t class_percentage,
-                                                 uint32_t random_seed) {
-  const std::string base_dex_location = "base.apk";
-  ProfileCompilationInfo info;
-  // The limits are defined by the dex specification.
-  const uint16_t max_method = std::numeric_limits<uint16_t>::max();
-  const uint16_t max_classes = std::numeric_limits<uint16_t>::max();
-  uint16_t number_of_methods = max_method * method_percentage / 100;
-  uint16_t number_of_classes = max_classes * class_percentage / 100;
-
-  std::srand(random_seed);
-
-  // Make sure we generate more samples with a low index value.
-  // This makes it more likely to hit valid method/class indices in small apps.
-  const uint16_t kFavorFirstN = 10000;
-  const uint16_t kFavorSplit = 2;
-
-  for (uint16_t i = 0; i < number_of_dex_files; i++) {
-    std::string dex_location = DexFileLoader::GetMultiDexLocation(i, base_dex_location.c_str());
-    std::string profile_key = GetProfileDexFileKey(dex_location);
-
-    for (uint16_t m = 0; m < number_of_methods; m++) {
-      uint16_t method_idx = rand() % max_method;
-      if (m < (number_of_methods / kFavorSplit)) {
-        method_idx %= kFavorFirstN;
-      }
-      // Alternate between startup and post startup.
-      uint32_t flags = MethodHotness::kFlagHot;
-      flags |= ((m & 1) != 0) ? MethodHotness::kFlagPostStartup : MethodHotness::kFlagStartup;
-      info.AddMethodIndex(static_cast<MethodHotness::Flag>(flags),
-                          profile_key,
-                          /*method_idx*/ 0,
-                          method_idx,
-                          max_method);
-    }
-
-    for (uint16_t c = 0; c < number_of_classes; c++) {
-      uint16_t type_idx = rand() % max_classes;
-      if (c < (number_of_classes / kFavorSplit)) {
-        type_idx %= kFavorFirstN;
-      }
-      info.AddClassIndex(profile_key, 0, dex::TypeIndex(type_idx), max_method);
-    }
-  }
-  return info.Save(fd);
-}
-
-// Naive implementation to generate a random profile file suitable for testing.
-// Description of random selection:
-// * Select a random starting point S.
-// * For every index i, add (S+i) % (N - total number of methods/classes) to profile with the
-//   probably of 1/(N - i - number of methods/classes needed to add in profile).
-bool ProfileCompilationInfo::GenerateTestProfile(
-    int fd,
-    std::vector<std::unique_ptr<const DexFile>>& dex_files,
-    uint16_t method_percentage,
-    uint16_t class_percentage,
-    uint32_t random_seed) {
-  std::srand(random_seed);
-  ProfileCompilationInfo info;
-  for (std::unique_ptr<const DexFile>& dex_file : dex_files) {
-    const std::string& location = dex_file->GetLocation();
-    uint32_t checksum = dex_file->GetLocationChecksum();
-
-    uint32_t number_of_classes = dex_file->NumClassDefs();
-    uint32_t classes_required_in_profile = (number_of_classes * class_percentage) / 100;
-    uint32_t class_start_index = rand() % number_of_classes;
-    for (uint32_t i = 0; i < number_of_classes && classes_required_in_profile; ++i) {
-      if (number_of_classes - i == classes_required_in_profile ||
-          std::rand() % (number_of_classes - i - classes_required_in_profile) == 0) {
-        uint32_t class_index = (i + class_start_index) % number_of_classes;
-        info.AddClassIndex(location,
-                           checksum,
-                           dex_file->GetClassDef(class_index).class_idx_,
-                           dex_file->NumMethodIds());
-        classes_required_in_profile--;
-      }
-    }
-
-    uint32_t number_of_methods = dex_file->NumMethodIds();
-    uint32_t methods_required_in_profile = (number_of_methods * method_percentage) / 100;
-    uint32_t method_start_index = rand() % number_of_methods;
-    for (uint32_t i = 0; i < number_of_methods && methods_required_in_profile; ++i) {
-      if (number_of_methods - i == methods_required_in_profile ||
-          std::rand() % (number_of_methods - i - methods_required_in_profile) == 0) {
-        uint32_t method_index = (method_start_index + i) % number_of_methods;
-        // Alternate between startup and post startup.
-        uint32_t flags = MethodHotness::kFlagHot;
-        flags |= ((method_index & 1) != 0)
-            ? MethodHotness::kFlagPostStartup
-            : MethodHotness::kFlagStartup;
-        info.AddMethodIndex(static_cast<MethodHotness::Flag>(flags),
-                            MethodReference(dex_file.get(), method_index));
-        methods_required_in_profile--;
-      }
-    }
-  }
-  return info.Save(fd);
-}
-
-bool ProfileCompilationInfo::OfflineProfileMethodInfo::operator==(
-      const OfflineProfileMethodInfo& other) const {
-  if (inline_caches->size() != other.inline_caches->size()) {
-    return false;
-  }
-
-  // We can't use a simple equality test because we need to match the dex files
-  // of the inline caches which might have different profile indexes.
-  for (const auto& inline_cache_it : *inline_caches) {
-    uint16_t dex_pc = inline_cache_it.first;
-    const DexPcData dex_pc_data = inline_cache_it.second;
-    const auto& other_it = other.inline_caches->find(dex_pc);
-    if (other_it == other.inline_caches->end()) {
-      return false;
-    }
-    const DexPcData& other_dex_pc_data = other_it->second;
-    if (dex_pc_data.is_megamorphic != other_dex_pc_data.is_megamorphic ||
-        dex_pc_data.is_missing_types != other_dex_pc_data.is_missing_types) {
-      return false;
-    }
-    for (const ClassReference& class_ref : dex_pc_data.classes) {
-      bool found = false;
-      for (const ClassReference& other_class_ref : other_dex_pc_data.classes) {
-        CHECK_LE(class_ref.dex_profile_index, dex_references.size());
-        CHECK_LE(other_class_ref.dex_profile_index, other.dex_references.size());
-        const DexReference& dex_ref = dex_references[class_ref.dex_profile_index];
-        const DexReference& other_dex_ref = other.dex_references[other_class_ref.dex_profile_index];
-        if (class_ref.type_index == other_class_ref.type_index &&
-            dex_ref == other_dex_ref) {
-          found = true;
-          break;
-        }
-      }
-      if (!found) {
-        return false;
-      }
-    }
-  }
-  return true;
-}
-
-bool ProfileCompilationInfo::IsEmpty() const {
-  DCHECK_EQ(info_.empty(), profile_key_map_.empty());
-  return info_.empty();
-}
-
-ProfileCompilationInfo::InlineCacheMap*
-ProfileCompilationInfo::DexFileData::FindOrAddMethod(uint16_t method_index) {
-  if (method_index >= num_method_ids) {
-    LOG(ERROR) << "Invalid method index " << method_index << ". num_method_ids=" << num_method_ids;
-    return nullptr;
-  }
-  return &(method_map.FindOrAdd(
-      method_index,
-      InlineCacheMap(std::less<uint16_t>(), allocator_->Adapter(kArenaAllocProfile)))->second);
-}
-
-// Mark a method as executed at least once.
-bool ProfileCompilationInfo::DexFileData::AddMethod(MethodHotness::Flag flags, size_t index) {
-  if (index >= num_method_ids) {
-    LOG(ERROR) << "Invalid method index " << index << ". num_method_ids=" << num_method_ids;
-    return false;
-  }
-
-  SetMethodHotness(index, flags);
-
-  if ((flags & MethodHotness::kFlagHot) != 0) {
-    method_map.FindOrAdd(
-        index,
-        InlineCacheMap(std::less<uint16_t>(), allocator_->Adapter(kArenaAllocProfile)));
-  }
-  return true;
-}
-
-void ProfileCompilationInfo::DexFileData::SetMethodHotness(size_t index,
-                                                           MethodHotness::Flag flags) {
-  DCHECK_LT(index, num_method_ids);
-  if ((flags & MethodHotness::kFlagStartup) != 0) {
-    method_bitmap.StoreBit(MethodBitIndex(/*startup*/ true, index), /*value*/ true);
-  }
-  if ((flags & MethodHotness::kFlagPostStartup) != 0) {
-    method_bitmap.StoreBit(MethodBitIndex(/*startup*/ false, index), /*value*/ true);
-  }
-}
-
-ProfileCompilationInfo::MethodHotness ProfileCompilationInfo::DexFileData::GetHotnessInfo(
-    uint32_t dex_method_index) const {
-  MethodHotness ret;
-  if (method_bitmap.LoadBit(MethodBitIndex(/*startup*/ true, dex_method_index))) {
-    ret.AddFlag(MethodHotness::kFlagStartup);
-  }
-  if (method_bitmap.LoadBit(MethodBitIndex(/*startup*/ false, dex_method_index))) {
-    ret.AddFlag(MethodHotness::kFlagPostStartup);
-  }
-  auto it = method_map.find(dex_method_index);
-  if (it != method_map.end()) {
-    ret.SetInlineCacheMap(&it->second);
-    ret.AddFlag(MethodHotness::kFlagHot);
-  }
-  return ret;
-}
-
-ProfileCompilationInfo::DexPcData*
-ProfileCompilationInfo::FindOrAddDexPc(InlineCacheMap* inline_cache, uint32_t dex_pc) {
-  return &(inline_cache->FindOrAdd(dex_pc, DexPcData(&allocator_))->second);
-}
-
-std::unordered_set<std::string> ProfileCompilationInfo::GetClassDescriptors(
-    const std::vector<const DexFile*>& dex_files) {
-  std::unordered_set<std::string> ret;
-  for (const DexFile* dex_file : dex_files) {
-    const DexFileData* data = FindDexData(dex_file);
-    if (data != nullptr) {
-      for (dex::TypeIndex type_idx : data->class_set) {
-        if (!dex_file->IsTypeIndexValid(type_idx)) {
-          // Something went bad. The profile is probably corrupted. Abort and return an emtpy set.
-          LOG(WARNING) << "Corrupted profile: invalid type index "
-              << type_idx.index_ << " in dex " << dex_file->GetLocation();
-          return std::unordered_set<std::string>();
-        }
-        const DexFile::TypeId& type_id = dex_file->GetTypeId(type_idx);
-        ret.insert(dex_file->GetTypeDescriptor(type_id));
-      }
-    } else {
-      VLOG(compiler) << "Failed to find profile data for " << dex_file->GetLocation();
-    }
-  }
-  return ret;
-}
-
-bool ProfileCompilationInfo::IsProfileFile(int fd) {
-  // First check if it's an empty file as we allow empty profile files.
-  // Profiles may be created by ActivityManager or installd before we manage to
-  // process them in the runtime or profman.
-  struct stat stat_buffer;
-  if (fstat(fd, &stat_buffer) != 0) {
-    return false;
-  }
-
-  if (stat_buffer.st_size == 0) {
-    return true;
-  }
-
-  // The files is not empty. Check if it contains the profile magic.
-  size_t byte_count = sizeof(kProfileMagic);
-  uint8_t buffer[sizeof(kProfileMagic)];
-  if (!android::base::ReadFully(fd, buffer, byte_count)) {
-    return false;
-  }
-
-  // Reset the offset to prepare the file for reading.
-  off_t rc =  TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_SET));
-  if (rc == static_cast<off_t>(-1)) {
-    PLOG(ERROR) << "Failed to reset the offset";
-    return false;
-  }
-
-  return memcmp(buffer, kProfileMagic, byte_count) == 0;
-}
-
-bool ProfileCompilationInfo::UpdateProfileKeys(
-      const std::vector<std::unique_ptr<const DexFile>>& dex_files) {
-  for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
-    for (DexFileData* dex_data : info_) {
-      if (dex_data->checksum == dex_file->GetLocationChecksum()
-          && dex_data->num_method_ids == dex_file->NumMethodIds()) {
-        std::string new_profile_key = GetProfileDexFileKey(dex_file->GetLocation());
-        if (dex_data->profile_key != new_profile_key) {
-          if (profile_key_map_.find(new_profile_key) != profile_key_map_.end()) {
-            // We can't update the key if the new key belongs to a different dex file.
-            LOG(ERROR) << "Cannot update profile key to " << new_profile_key
-                << " because the new key belongs to another dex file.";
-            return false;
-          }
-          profile_key_map_.erase(dex_data->profile_key);
-          profile_key_map_.Put(new_profile_key, dex_data->profile_index);
-          dex_data->profile_key = new_profile_key;
-        }
-      }
-    }
-  }
-  return true;
-}
-
-bool ProfileCompilationInfo::ProfileFilterFnAcceptAll(
-    const std::string& dex_location ATTRIBUTE_UNUSED,
-    uint32_t checksum ATTRIBUTE_UNUSED) {
-  return true;
-}
-
-}  // namespace art
diff --git a/runtime/jit/profile_compilation_info.h b/runtime/jit/profile_compilation_info.h
deleted file mode 100644
index f4c8c72..0000000
--- a/runtime/jit/profile_compilation_info.h
+++ /dev/null
@@ -1,812 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_JIT_PROFILE_COMPILATION_INFO_H_
-#define ART_RUNTIME_JIT_PROFILE_COMPILATION_INFO_H_
-
-#include <set>
-#include <vector>
-
-#include "base/arena_containers.h"
-#include "base/arena_object.h"
-#include "base/atomic.h"
-#include "base/bit_memory_region.h"
-#include "base/malloc_arena_pool.h"
-#include "base/mem_map.h"
-#include "base/safe_map.h"
-#include "dex/dex_cache_resolved_classes.h"
-#include "dex/dex_file.h"
-#include "dex/dex_file_types.h"
-#include "dex/method_reference.h"
-#include "dex/type_reference.h"
-
-namespace art {
-
-/**
- *  Convenient class to pass around profile information (including inline caches)
- *  without the need to hold GC-able objects.
- */
-struct ProfileMethodInfo {
-  struct ProfileInlineCache {
-    ProfileInlineCache(uint32_t pc,
-                       bool missing_types,
-                       const std::vector<TypeReference>& profile_classes)
-        : dex_pc(pc), is_missing_types(missing_types), classes(profile_classes) {}
-
-    const uint32_t dex_pc;
-    const bool is_missing_types;
-    const std::vector<TypeReference> classes;
-  };
-
-  explicit ProfileMethodInfo(MethodReference reference) : ref(reference) {}
-
-  ProfileMethodInfo(MethodReference reference, const std::vector<ProfileInlineCache>& caches)
-      : ref(reference),
-        inline_caches(caches) {}
-
-  MethodReference ref;
-  std::vector<ProfileInlineCache> inline_caches;
-};
-
-/**
- * Profile information in a format suitable to be queried by the compiler and
- * performing profile guided compilation.
- * It is a serialize-friendly format based on information collected by the
- * interpreter (ProfileInfo).
- * Currently it stores only the hot compiled methods.
- */
-class ProfileCompilationInfo {
- public:
-  static const uint8_t kProfileMagic[];
-  static const uint8_t kProfileVersion[];
-
-  static const char* kDexMetadataProfileEntry;
-
-  // Data structures for encoding the offline representation of inline caches.
-  // This is exposed as public in order to make it available to dex2oat compilations
-  // (see compiler/optimizing/inliner.cc).
-
-  // A dex location together with its checksum.
-  struct DexReference {
-    DexReference() : dex_checksum(0), num_method_ids(0) {}
-
-    DexReference(const std::string& location, uint32_t checksum, uint32_t num_methods)
-        : dex_location(location), dex_checksum(checksum), num_method_ids(num_methods) {}
-
-    bool operator==(const DexReference& other) const {
-      return dex_checksum == other.dex_checksum &&
-          dex_location == other.dex_location &&
-          num_method_ids == other.num_method_ids;
-    }
-
-    bool MatchesDex(const DexFile* dex_file) const {
-      return dex_checksum == dex_file->GetLocationChecksum() &&
-           dex_location == GetProfileDexFileKey(dex_file->GetLocation());
-    }
-
-    std::string dex_location;
-    uint32_t dex_checksum;
-    uint32_t num_method_ids;
-  };
-
-  // Encodes a class reference in the profile.
-  // The owning dex file is encoded as the index (dex_profile_index) it has in the
-  // profile rather than as a full DexRefence(location,checksum).
-  // This avoids excessive string copying when managing the profile data.
-  // The dex_profile_index is an index in either of:
-  //  - OfflineProfileMethodInfo#dex_references vector (public use)
-  //  - DexFileData#profile_index (internal use).
-  // Note that the dex_profile_index is not necessary the multidex index.
-  // We cannot rely on the actual multidex index because a single profile may store
-  // data from multiple splits. This means that a profile may contain a classes2.dex from split-A
-  // and one from split-B.
-  struct ClassReference : public ValueObject {
-    ClassReference(uint8_t dex_profile_idx, const dex::TypeIndex type_idx) :
-      dex_profile_index(dex_profile_idx), type_index(type_idx) {}
-
-    bool operator==(const ClassReference& other) const {
-      return dex_profile_index == other.dex_profile_index && type_index == other.type_index;
-    }
-    bool operator<(const ClassReference& other) const {
-      return dex_profile_index == other.dex_profile_index
-          ? type_index < other.type_index
-          : dex_profile_index < other.dex_profile_index;
-    }
-
-    uint8_t dex_profile_index;  // the index of the owning dex in the profile info
-    dex::TypeIndex type_index;  // the type index of the class
-  };
-
-  // The set of classes that can be found at a given dex pc.
-  using ClassSet = ArenaSet<ClassReference>;
-
-  // Encodes the actual inline cache for a given dex pc (whether or not the receiver is
-  // megamorphic and its possible types).
-  // If the receiver is megamorphic or is missing types the set of classes will be empty.
-  struct DexPcData : public ArenaObject<kArenaAllocProfile> {
-    explicit DexPcData(ArenaAllocator* allocator)
-        : is_missing_types(false),
-          is_megamorphic(false),
-          classes(std::less<ClassReference>(), allocator->Adapter(kArenaAllocProfile)) {}
-    void AddClass(uint16_t dex_profile_idx, const dex::TypeIndex& type_idx);
-    void SetIsMegamorphic() {
-      if (is_missing_types) return;
-      is_megamorphic = true;
-      classes.clear();
-    }
-    void SetIsMissingTypes() {
-      is_megamorphic = false;
-      is_missing_types = true;
-      classes.clear();
-    }
-    bool operator==(const DexPcData& other) const {
-      return is_megamorphic == other.is_megamorphic &&
-          is_missing_types == other.is_missing_types &&
-          classes == other.classes;
-    }
-
-    // Not all runtime types can be encoded in the profile. For example if the receiver
-    // type is in a dex file which is not tracked for profiling its type cannot be
-    // encoded. When types are missing this field will be set to true.
-    bool is_missing_types;
-    bool is_megamorphic;
-    ClassSet classes;
-  };
-
-  // The inline cache map: DexPc -> DexPcData.
-  using InlineCacheMap = ArenaSafeMap<uint16_t, DexPcData>;
-
-  // Maps a method dex index to its inline cache.
-  using MethodMap = ArenaSafeMap<uint16_t, InlineCacheMap>;
-
-  // Profile method hotness information for a single method. Also includes a pointer to the inline
-  // cache map.
-  class MethodHotness {
-   public:
-    enum Flag {
-      kFlagHot = 0x1,
-      kFlagStartup = 0x2,
-      kFlagPostStartup = 0x4,
-    };
-
-    bool IsHot() const {
-      return (flags_ & kFlagHot) != 0;
-    }
-
-    bool IsStartup() const {
-      return (flags_ & kFlagStartup) != 0;
-    }
-
-    bool IsPostStartup() const {
-      return (flags_ & kFlagPostStartup) != 0;
-    }
-
-    void AddFlag(Flag flag) {
-      flags_ |= flag;
-    }
-
-    uint8_t GetFlags() const {
-      return flags_;
-    }
-
-    bool IsInProfile() const {
-      return flags_ != 0;
-    }
-
-   private:
-    const InlineCacheMap* inline_cache_map_ = nullptr;
-    uint8_t flags_ = 0;
-
-    const InlineCacheMap* GetInlineCacheMap() const {
-      return inline_cache_map_;
-    }
-
-    void SetInlineCacheMap(const InlineCacheMap* info) {
-      inline_cache_map_ = info;
-    }
-
-    friend class ProfileCompilationInfo;
-  };
-
-  // Encodes the full set of inline caches for a given method.
-  // The dex_references vector is indexed according to the ClassReference::dex_profile_index.
-  // i.e. the dex file of any ClassReference present in the inline caches can be found at
-  // dex_references[ClassReference::dex_profile_index].
-  struct OfflineProfileMethodInfo {
-    explicit OfflineProfileMethodInfo(const InlineCacheMap* inline_cache_map)
-        : inline_caches(inline_cache_map) {}
-
-    bool operator==(const OfflineProfileMethodInfo& other) const;
-
-    const InlineCacheMap* const inline_caches;
-    std::vector<DexReference> dex_references;
-  };
-
-  // Public methods to create, extend or query the profile.
-  ProfileCompilationInfo();
-  explicit ProfileCompilationInfo(ArenaPool* arena_pool);
-
-  ~ProfileCompilationInfo();
-
-  // Add the given methods to the current profile object.
-  bool AddMethods(const std::vector<ProfileMethodInfo>& methods, MethodHotness::Flag flags);
-
-  // Add the given classes to the current profile object.
-  bool AddClasses(const std::set<DexCacheResolvedClasses>& resolved_classes);
-
-  // Add multiple type ids for classes in a single dex file. Iterator is for type_ids not
-  // class_defs.
-  template <class Iterator>
-  bool AddClassesForDex(const DexFile* dex_file, Iterator index_begin, Iterator index_end) {
-    DexFileData* data = GetOrAddDexFileData(dex_file);
-    if (data == nullptr) {
-      return false;
-    }
-    data->class_set.insert(index_begin, index_end);
-    return true;
-  }
-  // Add a single type id for a dex file.
-  bool AddClassForDex(const TypeReference& ref) {
-    DexFileData* data = GetOrAddDexFileData(ref.dex_file);
-    if (data == nullptr) {
-      return false;
-    }
-    data->class_set.insert(ref.TypeIndex());
-    return true;
-  }
-
-
-  // Add a method index to the profile (without inline caches). The method flags determine if it is
-  // hot, startup, or post startup, or a combination of the previous.
-  bool AddMethodIndex(MethodHotness::Flag flags,
-                      const std::string& dex_location,
-                      uint32_t checksum,
-                      uint16_t method_idx,
-                      uint32_t num_method_ids);
-  bool AddMethodIndex(MethodHotness::Flag flags, const MethodReference& ref);
-
-  // Add a method to the profile using its online representation (containing runtime structures).
-  bool AddMethod(const ProfileMethodInfo& pmi, MethodHotness::Flag flags);
-
-  // Bulk add sampled methods and/or hot methods for a single dex, fast since it only has one
-  // GetOrAddDexFileData call.
-  template <class Iterator>
-  bool AddMethodsForDex(MethodHotness::Flag flags,
-                        const DexFile* dex_file,
-                        Iterator index_begin,
-                        Iterator index_end) {
-    DexFileData* data = GetOrAddDexFileData(dex_file);
-    if (data == nullptr) {
-      return false;
-    }
-    for (Iterator it = index_begin; it != index_end; ++it) {
-      DCHECK_LT(*it, data->num_method_ids);
-      if (!data->AddMethod(flags, *it)) {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  // Add hotness flags for a simple method.
-  bool AddMethodHotness(const MethodReference& method_ref, const MethodHotness& hotness);
-
-  // Load or Merge profile information from the given file descriptor.
-  // If the current profile is non-empty the load will fail.
-  // If merge_classes is set to false, classes will not be merged/loaded.
-  // If filter_fn is present, it will be used to filter out profile data belonging
-  // to dex file which do not comply with the filter
-  // (i.e. for which filter_fn(dex_location, dex_checksum) is false).
-  using ProfileLoadFilterFn = std::function<bool(const std::string&, uint32_t)>;
-  // Profile filter method which accepts all dex locations.
-  // This is convenient to use when we need to accept all locations without repeating the same
-  // lambda.
-  static bool ProfileFilterFnAcceptAll(const std::string& dex_location, uint32_t checksum);
-
-  bool Load(
-      int fd,
-      bool merge_classes = true,
-      const ProfileLoadFilterFn& filter_fn = ProfileFilterFnAcceptAll);
-
-  // Verify integrity of the profile file with the provided dex files.
-  // If there exists a DexData object which maps to a dex_file, then it verifies that:
-  // - The checksums of the DexData and dex_file are equals.
-  // - No method id exceeds NumMethodIds corresponding to the dex_file.
-  // - No class id exceeds NumTypeIds corresponding to the dex_file.
-  // - For every inline_caches, class_ids does not exceed NumTypeIds corresponding to
-  //   the dex_file they are in.
-  bool VerifyProfileData(const std::vector<const DexFile *> &dex_files);
-
-  // Load profile information from the given file
-  // If the current profile is non-empty the load will fail.
-  // If clear_if_invalid is true and the file is invalid the method clears the
-  // the file and returns true.
-  bool Load(const std::string& filename, bool clear_if_invalid);
-
-  // Merge the data from another ProfileCompilationInfo into the current object. Only merges
-  // classes if merge_classes is true. This is used for creating the boot profile since
-  // we don't want all of the classes to be image classes.
-  bool MergeWith(const ProfileCompilationInfo& info, bool merge_classes = true);
-
-  // Merge profile information from the given file descriptor.
-  bool MergeWith(const std::string& filename);
-
-  // Save the profile data to the given file descriptor.
-  bool Save(int fd);
-
-  // Save the current profile into the given file. The file will be cleared before saving.
-  bool Save(const std::string& filename, uint64_t* bytes_written);
-
-  // Return the number of methods that were profiled.
-  uint32_t GetNumberOfMethods() const;
-
-  // Return the number of resolved classes that were profiled.
-  uint32_t GetNumberOfResolvedClasses() const;
-
-  // Returns the profile method info for a given method reference.
-  MethodHotness GetMethodHotness(const MethodReference& method_ref) const;
-  MethodHotness GetMethodHotness(const std::string& dex_location,
-                                 uint32_t dex_checksum,
-                                 uint16_t dex_method_index) const;
-
-  // Return true if the class's type is present in the profiling info.
-  bool ContainsClass(const DexFile& dex_file, dex::TypeIndex type_idx) const;
-
-  // Return the method data for the given location and index from the profiling info.
-  // If the method index is not found or the checksum doesn't match, null is returned.
-  // Note: the inline cache map is a pointer to the map stored in the profile and
-  // its allocation will go away if the profile goes out of scope.
-  std::unique_ptr<OfflineProfileMethodInfo> GetMethod(const std::string& dex_location,
-                                                      uint32_t dex_checksum,
-                                                      uint16_t dex_method_index) const;
-
-  // Dump all the loaded profile info into a string and returns it.
-  // If dex_files is not null then the method indices will be resolved to their
-  // names.
-  // This is intended for testing and debugging.
-  std::string DumpInfo(const std::vector<std::unique_ptr<const DexFile>>* dex_files,
-                       bool print_full_dex_location = true) const;
-  std::string DumpInfo(const std::vector<const DexFile*>* dex_files,
-                       bool print_full_dex_location = true) const;
-
-  // Return the classes and methods for a given dex file through out args. The out args are the set
-  // of class as well as the methods and their associated inline caches. Returns true if the dex
-  // file is register and has a matching checksum, false otherwise.
-  bool GetClassesAndMethods(const DexFile& dex_file,
-                            /*out*/std::set<dex::TypeIndex>* class_set,
-                            /*out*/std::set<uint16_t>* hot_method_set,
-                            /*out*/std::set<uint16_t>* startup_method_set,
-                            /*out*/std::set<uint16_t>* post_startup_method_method_set) const;
-
-  // Perform an equality test with the `other` profile information.
-  bool Equals(const ProfileCompilationInfo& other);
-
-  // Return the class descriptors for all of the classes in the profiles' class sets.
-  std::set<DexCacheResolvedClasses> GetResolvedClasses(
-      const std::vector<const DexFile*>& dex_files_) const;
-
-  // Return the profile key associated with the given dex location.
-  static std::string GetProfileDexFileKey(const std::string& dex_location);
-
-  // Generate a test profile which will contain a percentage of the total maximum
-  // number of methods and classes (method_ratio and class_ratio).
-  static bool GenerateTestProfile(int fd,
-                                  uint16_t number_of_dex_files,
-                                  uint16_t method_ratio,
-                                  uint16_t class_ratio,
-                                  uint32_t random_seed);
-
-  // Generate a test profile which will randomly contain classes and methods from
-  // the provided list of dex files.
-  static bool GenerateTestProfile(int fd,
-                                  std::vector<std::unique_ptr<const DexFile>>& dex_files,
-                                  uint16_t method_percentage,
-                                  uint16_t class_percentage,
-                                  uint32_t random_seed);
-
-  // Check that the given profile method info contain the same data.
-  static bool Equals(const ProfileCompilationInfo::OfflineProfileMethodInfo& pmi1,
-                     const ProfileCompilationInfo::OfflineProfileMethodInfo& pmi2);
-
-  ArenaAllocator* GetAllocator() { return &allocator_; }
-
-  // Return all of the class descriptors in the profile for a set of dex files.
-  std::unordered_set<std::string> GetClassDescriptors(const std::vector<const DexFile*>& dex_files);
-
-  // Return true if the fd points to a profile file.
-  bool IsProfileFile(int fd);
-
-  // Update the profile keys corresponding to the given dex files based on their current paths.
-  // This method allows fix-ups in the profile for dex files that might have been renamed.
-  // The new profile key will be constructed based on the current dex location.
-  //
-  // The matching [profile key <-> dex_file] is done based on the dex checksum and the number of
-  // methods ids. If neither is a match then the profile key is not updated.
-  //
-  // If the new profile key would collide with an existing key (for a different dex)
-  // the method returns false. Otherwise it returns true.
-  bool UpdateProfileKeys(const std::vector<std::unique_ptr<const DexFile>>& dex_files);
-
-  // Checks if the profile is empty.
-  bool IsEmpty() const;
-
- private:
-  enum ProfileLoadStatus {
-    kProfileLoadWouldOverwiteData,
-    kProfileLoadIOError,
-    kProfileLoadVersionMismatch,
-    kProfileLoadBadData,
-    kProfileLoadSuccess
-  };
-
-  const uint32_t kProfileSizeWarningThresholdInBytes = 500000U;
-  const uint32_t kProfileSizeErrorThresholdInBytes = 1000000U;
-
-  // Internal representation of the profile information belonging to a dex file.
-  // Note that we could do without profile_key (the key used to encode the dex
-  // file in the profile) and profile_index (the index of the dex file in the
-  // profile) fields in this struct because we can infer them from
-  // profile_key_map_ and info_. However, it makes the profiles logic much
-  // simpler if we have references here as well.
-  struct DexFileData : public DeletableArenaObject<kArenaAllocProfile> {
-    DexFileData(ArenaAllocator* allocator,
-                const std::string& key,
-                uint32_t location_checksum,
-                uint16_t index,
-                uint32_t num_methods)
-        : allocator_(allocator),
-          profile_key(key),
-          profile_index(index),
-          checksum(location_checksum),
-          method_map(std::less<uint16_t>(), allocator->Adapter(kArenaAllocProfile)),
-          class_set(std::less<dex::TypeIndex>(), allocator->Adapter(kArenaAllocProfile)),
-          num_method_ids(num_methods),
-          bitmap_storage(allocator->Adapter(kArenaAllocProfile)) {
-      bitmap_storage.resize(ComputeBitmapStorage(num_method_ids));
-      if (!bitmap_storage.empty()) {
-        method_bitmap =
-            BitMemoryRegion(MemoryRegion(
-                &bitmap_storage[0], bitmap_storage.size()), 0, ComputeBitmapBits(num_method_ids));
-      }
-    }
-
-    static size_t ComputeBitmapBits(uint32_t num_method_ids) {
-      return num_method_ids * kBitmapIndexCount;
-    }
-    static size_t ComputeBitmapStorage(uint32_t num_method_ids) {
-      return RoundUp(ComputeBitmapBits(num_method_ids), kBitsPerByte) / kBitsPerByte;
-    }
-
-    bool operator==(const DexFileData& other) const {
-      return checksum == other.checksum && method_map == other.method_map;
-    }
-
-    // Mark a method as executed at least once.
-    bool AddMethod(MethodHotness::Flag flags, size_t index);
-
-    void MergeBitmap(const DexFileData& other) {
-      DCHECK_EQ(bitmap_storage.size(), other.bitmap_storage.size());
-      for (size_t i = 0; i < bitmap_storage.size(); ++i) {
-        bitmap_storage[i] |= other.bitmap_storage[i];
-      }
-    }
-
-    void SetMethodHotness(size_t index, MethodHotness::Flag flags);
-    MethodHotness GetHotnessInfo(uint32_t dex_method_index) const;
-
-    // The allocator used to allocate new inline cache maps.
-    ArenaAllocator* const allocator_;
-    // The profile key this data belongs to.
-    std::string profile_key;
-    // The profile index of this dex file (matches ClassReference#dex_profile_index).
-    uint8_t profile_index;
-    // The dex checksum.
-    uint32_t checksum;
-    // The methonds' profile information.
-    MethodMap method_map;
-    // The classes which have been profiled. Note that these don't necessarily include
-    // all the classes that can be found in the inline caches reference.
-    ArenaSet<dex::TypeIndex> class_set;
-    // Find the inline caches of the the given method index. Add an empty entry if
-    // no previous data is found.
-    InlineCacheMap* FindOrAddMethod(uint16_t method_index);
-    // Num method ids.
-    uint32_t num_method_ids;
-    ArenaVector<uint8_t> bitmap_storage;
-    BitMemoryRegion method_bitmap;
-
-   private:
-    enum BitmapIndex {
-      kBitmapIndexStartup,
-      kBitmapIndexPostStartup,
-      kBitmapIndexCount,
-    };
-
-    size_t MethodBitIndex(bool startup, size_t index) const {
-      DCHECK_LT(index, num_method_ids);
-      // The format is [startup bitmap][post startup bitmap]
-      // This compresses better than ([startup bit][post statup bit])*
-
-      return index + (startup
-          ? kBitmapIndexStartup * num_method_ids
-          : kBitmapIndexPostStartup * num_method_ids);
-    }
-  };
-
-  // Return the profile data for the given profile key or null if the dex location
-  // already exists but has a different checksum
-  DexFileData* GetOrAddDexFileData(const std::string& profile_key,
-                                   uint32_t checksum,
-                                   uint32_t num_method_ids);
-
-  DexFileData* GetOrAddDexFileData(const DexFile* dex_file) {
-    return GetOrAddDexFileData(GetProfileDexFileKey(dex_file->GetLocation()),
-                               dex_file->GetLocationChecksum(),
-                               dex_file->NumMethodIds());
-  }
-
-  // Add a method to the profile using its offline representation.
-  // This is mostly used to facilitate testing.
-  bool AddMethod(const std::string& dex_location,
-                 uint32_t dex_checksum,
-                 uint16_t method_index,
-                 uint32_t num_method_ids,
-                 const OfflineProfileMethodInfo& pmi,
-                 MethodHotness::Flag flags);
-
-  // Add a class index to the profile.
-  bool AddClassIndex(const std::string& dex_location,
-                     uint32_t checksum,
-                     dex::TypeIndex type_idx,
-                     uint32_t num_method_ids);
-
-  // Add all classes from the given dex cache to the the profile.
-  bool AddResolvedClasses(const DexCacheResolvedClasses& classes);
-
-  // Encode the known dex_files into a vector. The index of a dex_reference will
-  // be the same as the profile index of the dex file (used to encode the ClassReferences).
-  void DexFileToProfileIndex(/*out*/std::vector<DexReference>* dex_references) const;
-
-  // Return the dex data associated with the given profile key or null if the profile
-  // doesn't contain the key.
-  const DexFileData* FindDexData(const std::string& profile_key,
-                                 uint32_t checksum,
-                                 bool verify_checksum = true) const;
-
-  // Return the dex data associated with the given dex file or null if the profile doesn't contain
-  // the key or the checksum mismatches.
-  const DexFileData* FindDexData(const DexFile* dex_file) const;
-
-  // Inflate the input buffer (in_buffer) of size in_size. It returns a buffer of
-  // compressed data for the input buffer of "compressed_data_size" size.
-  std::unique_ptr<uint8_t[]> DeflateBuffer(const uint8_t* in_buffer,
-                                           uint32_t in_size,
-                                           /*out*/uint32_t* compressed_data_size);
-
-  // Inflate the input buffer(in_buffer) of size in_size. out_size is the expected output
-  // size of the buffer. It puts the output in out_buffer. It returns Z_STREAM_END on
-  // success. On error, it returns Z_STREAM_ERROR if the compressed data is inconsistent
-  // and Z_DATA_ERROR if the stream ended prematurely or the stream has extra data.
-  int InflateBuffer(const uint8_t* in_buffer,
-                    uint32_t in_size,
-                    uint32_t out_size,
-                    /*out*/uint8_t* out_buffer);
-
-  // Parsing functionality.
-
-  // The information present in the header of each profile line.
-  struct ProfileLineHeader {
-    std::string dex_location;
-    uint16_t class_set_size;
-    uint32_t method_region_size_bytes;
-    uint32_t checksum;
-    uint32_t num_method_ids;
-  };
-
-  /**
-   * Encapsulate the source of profile data for loading.
-   * The source can be either a plain file or a zip file.
-   * For zip files, the profile entry will be extracted to
-   * the memory map.
-   */
-  class ProfileSource {
-   public:
-    /**
-     * Create a profile source for the given fd. The ownership of the fd
-     * remains to the caller; as this class will not attempt to close it at any
-     * point.
-     */
-    static ProfileSource* Create(int32_t fd) {
-      DCHECK_GT(fd, -1);
-      return new ProfileSource(fd, /*map*/ nullptr);
-    }
-
-    /**
-     * Create a profile source backed by a memory map. The map can be null in
-     * which case it will the treated as an empty source.
-     */
-    static ProfileSource* Create(std::unique_ptr<MemMap>&& mem_map) {
-      return new ProfileSource(/*fd*/ -1, std::move(mem_map));
-    }
-
-    /**
-     * Read bytes from this source.
-     * Reading will advance the current source position so subsequent
-     * invocations will read from the las position.
-     */
-    ProfileLoadStatus Read(uint8_t* buffer,
-                           size_t byte_count,
-                           const std::string& debug_stage,
-                           std::string* error);
-
-    /** Return true if the source has 0 data. */
-    bool HasEmptyContent() const;
-    /** Return true if all the information from this source has been read. */
-    bool HasConsumedAllData() const;
-
-   private:
-    ProfileSource(int32_t fd, std::unique_ptr<MemMap>&& mem_map)
-        : fd_(fd), mem_map_(std::move(mem_map)), mem_map_cur_(0) {}
-
-    bool IsMemMap() const { return fd_ == -1; }
-
-    int32_t fd_;  // The fd is not owned by this class.
-    std::unique_ptr<MemMap> mem_map_;
-    size_t mem_map_cur_;  // Current position in the map to read from.
-  };
-
-  // A helper structure to make sure we don't read past our buffers in the loops.
-  struct SafeBuffer {
-   public:
-    explicit SafeBuffer(size_t size) : storage_(new uint8_t[size]) {
-      ptr_current_ = storage_.get();
-      ptr_end_ = ptr_current_ + size;
-    }
-
-    // Reads the content of the descriptor at the current position.
-    ProfileLoadStatus Fill(ProfileSource& source,
-                           const std::string& debug_stage,
-                           /*out*/std::string* error);
-
-    // Reads an uint value (high bits to low bits) and advances the current pointer
-    // with the number of bits read.
-    template <typename T> bool ReadUintAndAdvance(/*out*/ T* value);
-
-    // Compares the given data with the content current pointer. If the contents are
-    // equal it advances the current pointer by data_size.
-    bool CompareAndAdvance(const uint8_t* data, size_t data_size);
-
-    // Advances current pointer by data_size.
-    void Advance(size_t data_size);
-
-    // Returns the count of unread bytes.
-    size_t CountUnreadBytes();
-
-    // Returns the current pointer.
-    const uint8_t* GetCurrentPtr();
-
-    // Get the underlying raw buffer.
-    uint8_t* Get() { return storage_.get(); }
-
-   private:
-    std::unique_ptr<uint8_t[]> storage_;
-    uint8_t* ptr_end_;
-    uint8_t* ptr_current_;
-  };
-
-  ProfileLoadStatus OpenSource(int32_t fd,
-                               /*out*/ std::unique_ptr<ProfileSource>* source,
-                               /*out*/ std::string* error);
-
-  // Entry point for profile loading functionality.
-  ProfileLoadStatus LoadInternal(
-      int32_t fd,
-      std::string* error,
-      bool merge_classes = true,
-      const ProfileLoadFilterFn& filter_fn = ProfileFilterFnAcceptAll);
-
-  // Read the profile header from the given fd and store the number of profile
-  // lines into number_of_dex_files.
-  ProfileLoadStatus ReadProfileHeader(ProfileSource& source,
-                                      /*out*/uint8_t* number_of_dex_files,
-                                      /*out*/uint32_t* size_uncompressed_data,
-                                      /*out*/uint32_t* size_compressed_data,
-                                      /*out*/std::string* error);
-
-  // Read the header of a profile line from the given fd.
-  ProfileLoadStatus ReadProfileLineHeader(SafeBuffer& buffer,
-                                          /*out*/ProfileLineHeader* line_header,
-                                          /*out*/std::string* error);
-
-  // Read individual elements from the profile line header.
-  bool ReadProfileLineHeaderElements(SafeBuffer& buffer,
-                                     /*out*/uint16_t* dex_location_size,
-                                     /*out*/ProfileLineHeader* line_header,
-                                     /*out*/std::string* error);
-
-  // Read a single profile line from the given fd.
-  ProfileLoadStatus ReadProfileLine(SafeBuffer& buffer,
-                                    uint8_t number_of_dex_files,
-                                    const ProfileLineHeader& line_header,
-                                    const SafeMap<uint8_t, uint8_t>& dex_profile_index_remap,
-                                    bool merge_classes,
-                                    /*out*/std::string* error);
-
-  // Read all the classes from the buffer into the profile `info_` structure.
-  bool ReadClasses(SafeBuffer& buffer,
-                   const ProfileLineHeader& line_header,
-                   /*out*/std::string* error);
-
-  // Read all the methods from the buffer into the profile `info_` structure.
-  bool ReadMethods(SafeBuffer& buffer,
-                   uint8_t number_of_dex_files,
-                   const ProfileLineHeader& line_header,
-                   const SafeMap<uint8_t, uint8_t>& dex_profile_index_remap,
-                   /*out*/std::string* error);
-
-  // The method generates mapping of profile indices while merging a new profile
-  // data into current data. It returns true, if the mapping was successful.
-  bool RemapProfileIndex(const std::vector<ProfileLineHeader>& profile_line_headers,
-                         const ProfileLoadFilterFn& filter_fn,
-                         /*out*/SafeMap<uint8_t, uint8_t>* dex_profile_index_remap);
-
-  // Read the inline cache encoding from line_bufer into inline_cache.
-  bool ReadInlineCache(SafeBuffer& buffer,
-                       uint8_t number_of_dex_files,
-                       const SafeMap<uint8_t, uint8_t>& dex_profile_index_remap,
-                       /*out*/InlineCacheMap* inline_cache,
-                       /*out*/std::string* error);
-
-  // Encode the inline cache into the given buffer.
-  void AddInlineCacheToBuffer(std::vector<uint8_t>* buffer,
-                              const InlineCacheMap& inline_cache);
-
-  // Return the number of bytes needed to encode the profile information
-  // for the methods in dex_data.
-  uint32_t GetMethodsRegionSize(const DexFileData& dex_data);
-
-  // Group `classes` by their owning dex profile index and put the result in
-  // `dex_to_classes_map`.
-  void GroupClassesByDex(
-      const ClassSet& classes,
-      /*out*/SafeMap<uint8_t, std::vector<dex::TypeIndex>>* dex_to_classes_map);
-
-  // Find the data for the dex_pc in the inline cache. Adds an empty entry
-  // if no previous data exists.
-  DexPcData* FindOrAddDexPc(InlineCacheMap* inline_cache, uint32_t dex_pc);
-
-  friend class ProfileCompilationInfoTest;
-  friend class CompilerDriverProfileTest;
-  friend class ProfileAssistantTest;
-  friend class Dex2oatLayoutTest;
-
-  MallocArenaPool default_arena_pool_;
-  ArenaAllocator allocator_;
-
-  // Vector containing the actual profile info.
-  // The vector index is the profile index of the dex data and
-  // matched DexFileData::profile_index.
-  ArenaVector<DexFileData*> info_;
-
-  // Cache mapping profile keys to profile index.
-  // This is used to speed up searches since it avoids iterating
-  // over the info_ vector when searching by profile key.
-  ArenaSafeMap<const std::string, uint8_t> profile_key_map_;
-};
-
-}  // namespace art
-
-#endif  // ART_RUNTIME_JIT_PROFILE_COMPILATION_INFO_H_
diff --git a/runtime/jit/profile_compilation_info_test.cc b/runtime/jit/profile_compilation_info_test.cc
deleted file mode 100644
index 0ebadc0..0000000
--- a/runtime/jit/profile_compilation_info_test.cc
+++ /dev/null
@@ -1,1342 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <gtest/gtest.h>
-#include <stdio.h>
-
-#include "art_method-inl.h"
-#include "base/unix_file/fd_file.h"
-#include "class_linker-inl.h"
-#include "common_runtime_test.h"
-#include "dex/dex_file.h"
-#include "dex/dex_file_loader.h"
-#include "dex/method_reference.h"
-#include "dex/type_reference.h"
-#include "handle_scope-inl.h"
-#include "jit/profile_compilation_info.h"
-#include "linear_alloc.h"
-#include "mirror/class-inl.h"
-#include "mirror/class_loader.h"
-#include "scoped_thread_state_change-inl.h"
-#include "ziparchive/zip_writer.h"
-
-namespace art {
-
-using Hotness = ProfileCompilationInfo::MethodHotness;
-
-static constexpr size_t kMaxMethodIds = 65535;
-
-class ProfileCompilationInfoTest : public CommonRuntimeTest {
- public:
-  void PostRuntimeCreate() OVERRIDE {
-    allocator_.reset(new ArenaAllocator(Runtime::Current()->GetArenaPool()));
-  }
-
- protected:
-  std::vector<ArtMethod*> GetVirtualMethods(jobject class_loader,
-                                            const std::string& clazz) {
-    ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-    Thread* self = Thread::Current();
-    ScopedObjectAccess soa(self);
-    StackHandleScope<1> hs(self);
-    Handle<mirror::ClassLoader> h_loader(
-        hs.NewHandle(self->DecodeJObject(class_loader)->AsClassLoader()));
-    mirror::Class* klass = class_linker->FindClass(self, clazz.c_str(), h_loader);
-
-    const auto pointer_size = class_linker->GetImagePointerSize();
-    std::vector<ArtMethod*> methods;
-    for (auto& m : klass->GetVirtualMethods(pointer_size)) {
-      methods.push_back(&m);
-    }
-    return methods;
-  }
-
-  bool AddMethod(const std::string& dex_location,
-                 uint32_t checksum,
-                 uint16_t method_index,
-                 ProfileCompilationInfo* info) {
-    return info->AddMethodIndex(Hotness::kFlagHot,
-                                dex_location,
-                                checksum,
-                                method_index,
-                                kMaxMethodIds);
-  }
-
-  bool AddMethod(const std::string& dex_location,
-                 uint32_t checksum,
-                 uint16_t method_index,
-                 const ProfileCompilationInfo::OfflineProfileMethodInfo& pmi,
-                 ProfileCompilationInfo* info) {
-    return info->AddMethod(
-        dex_location, checksum, method_index, kMaxMethodIds, pmi, Hotness::kFlagPostStartup);
-  }
-
-  bool AddClass(const std::string& dex_location,
-                uint32_t checksum,
-                dex::TypeIndex type_index,
-                ProfileCompilationInfo* info) {
-    DexCacheResolvedClasses classes(dex_location, dex_location, checksum, kMaxMethodIds);
-    classes.AddClass(type_index);
-    return info->AddClasses({classes});
-  }
-
-  uint32_t GetFd(const ScratchFile& file) {
-    return static_cast<uint32_t>(file.GetFd());
-  }
-
-  bool SaveProfilingInfo(
-      const std::string& filename,
-      const std::vector<ArtMethod*>& methods,
-      const std::set<DexCacheResolvedClasses>& resolved_classes,
-      Hotness::Flag flags) {
-    ProfileCompilationInfo info;
-    std::vector<ProfileMethodInfo> profile_methods;
-    ScopedObjectAccess soa(Thread::Current());
-    for (ArtMethod* method : methods) {
-      profile_methods.emplace_back(
-          MethodReference(method->GetDexFile(), method->GetDexMethodIndex()));
-    }
-    if (!info.AddMethods(profile_methods, flags) || !info.AddClasses(resolved_classes)) {
-      return false;
-    }
-    if (info.GetNumberOfMethods() != profile_methods.size()) {
-      return false;
-    }
-    ProfileCompilationInfo file_profile;
-    if (!file_profile.Load(filename, false)) {
-      return false;
-    }
-    if (!info.MergeWith(file_profile)) {
-      return false;
-    }
-
-    return info.Save(filename, nullptr);
-  }
-
-  // Saves the given art methods to a profile backed by 'filename' and adds
-  // some fake inline caches to it. The added inline caches are returned in
-  // the out map `profile_methods_map`.
-  bool SaveProfilingInfoWithFakeInlineCaches(
-      const std::string& filename,
-      const std::vector<ArtMethod*>& methods,
-      Hotness::Flag flags,
-      /*out*/ SafeMap<ArtMethod*, ProfileMethodInfo>* profile_methods_map) {
-    ProfileCompilationInfo info;
-    std::vector<ProfileMethodInfo> profile_methods;
-    ScopedObjectAccess soa(Thread::Current());
-    for (ArtMethod* method : methods) {
-      std::vector<ProfileMethodInfo::ProfileInlineCache> caches;
-      // Monomorphic
-      for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) {
-        std::vector<TypeReference> classes;
-        classes.emplace_back(method->GetDexFile(), dex::TypeIndex(0));
-        caches.emplace_back(dex_pc, /*is_missing_types*/false, classes);
-      }
-      // Polymorphic
-      for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) {
-        std::vector<TypeReference> classes;
-        for (uint16_t k = 0; k < InlineCache::kIndividualCacheSize / 2; k++) {
-          classes.emplace_back(method->GetDexFile(), dex::TypeIndex(k));
-        }
-        caches.emplace_back(dex_pc, /*is_missing_types*/false, classes);
-      }
-      // Megamorphic
-      for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) {
-        std::vector<TypeReference> classes;
-        for (uint16_t k = 0; k < 2 * InlineCache::kIndividualCacheSize; k++) {
-          classes.emplace_back(method->GetDexFile(), dex::TypeIndex(k));
-        }
-        caches.emplace_back(dex_pc, /*is_missing_types*/false, classes);
-      }
-      // Missing types
-      for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) {
-        std::vector<TypeReference> classes;
-        caches.emplace_back(dex_pc, /*is_missing_types*/true, classes);
-      }
-      ProfileMethodInfo pmi(MethodReference(method->GetDexFile(),
-                                            method->GetDexMethodIndex()),
-                            caches);
-      profile_methods.push_back(pmi);
-      profile_methods_map->Put(method, pmi);
-    }
-
-    if (!info.AddMethods(profile_methods, flags)
-        || info.GetNumberOfMethods() != profile_methods.size()) {
-      return false;
-    }
-    return info.Save(filename, nullptr);
-  }
-
-  // Creates an inline cache which will be destructed at the end of the test.
-  ProfileCompilationInfo::InlineCacheMap* CreateInlineCacheMap() {
-    used_inline_caches.emplace_back(new ProfileCompilationInfo::InlineCacheMap(
-        std::less<uint16_t>(), allocator_->Adapter(kArenaAllocProfile)));
-    return used_inline_caches.back().get();
-  }
-
-  ProfileCompilationInfo::OfflineProfileMethodInfo ConvertProfileMethodInfo(
-        const ProfileMethodInfo& pmi) {
-    ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
-    ProfileCompilationInfo::OfflineProfileMethodInfo offline_pmi(ic_map);
-    SafeMap<DexFile*, uint8_t> dex_map;  // dex files to profile index
-    for (const auto& inline_cache : pmi.inline_caches) {
-      ProfileCompilationInfo::DexPcData& dex_pc_data =
-          ic_map->FindOrAdd(
-              inline_cache.dex_pc, ProfileCompilationInfo::DexPcData(allocator_.get()))->second;
-      if (inline_cache.is_missing_types) {
-        dex_pc_data.SetIsMissingTypes();
-      }
-      for (const auto& class_ref : inline_cache.classes) {
-        uint8_t dex_profile_index = dex_map.FindOrAdd(const_cast<DexFile*>(class_ref.dex_file),
-                                                      static_cast<uint8_t>(dex_map.size()))->second;
-        dex_pc_data.AddClass(dex_profile_index, class_ref.TypeIndex());
-        if (dex_profile_index >= offline_pmi.dex_references.size()) {
-          // This is a new dex.
-          const std::string& dex_key = ProfileCompilationInfo::GetProfileDexFileKey(
-              class_ref.dex_file->GetLocation());
-          offline_pmi.dex_references.emplace_back(dex_key,
-                                                  class_ref.dex_file->GetLocationChecksum(),
-                                                  class_ref.dex_file->NumMethodIds());
-        }
-      }
-    }
-    return offline_pmi;
-  }
-
-  // Creates an offline profile used for testing inline caches.
-  ProfileCompilationInfo::OfflineProfileMethodInfo GetOfflineProfileMethodInfo() {
-    ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
-
-    // Monomorphic
-    for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) {
-      ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
-      dex_pc_data.AddClass(0, dex::TypeIndex(0));
-      ic_map->Put(dex_pc, dex_pc_data);
-    }
-    // Polymorphic
-    for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) {
-      ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
-      dex_pc_data.AddClass(0, dex::TypeIndex(0));
-      dex_pc_data.AddClass(1, dex::TypeIndex(1));
-      dex_pc_data.AddClass(2, dex::TypeIndex(2));
-
-      ic_map->Put(dex_pc, dex_pc_data);
-    }
-    // Megamorphic
-    for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) {
-      ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
-      dex_pc_data.SetIsMegamorphic();
-      ic_map->Put(dex_pc, dex_pc_data);
-    }
-    // Missing types
-    for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) {
-      ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
-      dex_pc_data.SetIsMissingTypes();
-      ic_map->Put(dex_pc, dex_pc_data);
-    }
-
-    ProfileCompilationInfo::OfflineProfileMethodInfo pmi(ic_map);
-
-    pmi.dex_references.emplace_back("dex_location1", /* checksum */1, kMaxMethodIds);
-    pmi.dex_references.emplace_back("dex_location2", /* checksum */2, kMaxMethodIds);
-    pmi.dex_references.emplace_back("dex_location3", /* checksum */3, kMaxMethodIds);
-
-    return pmi;
-  }
-
-  void MakeMegamorphic(/*out*/ProfileCompilationInfo::OfflineProfileMethodInfo* pmi) {
-    ProfileCompilationInfo::InlineCacheMap* ic_map =
-        const_cast<ProfileCompilationInfo::InlineCacheMap*>(pmi->inline_caches);
-    for (auto it : *ic_map) {
-      for (uint16_t k = 0; k <= 2 * InlineCache::kIndividualCacheSize; k++) {
-        it.second.AddClass(0, dex::TypeIndex(k));
-      }
-    }
-  }
-
-  void SetIsMissingTypes(/*out*/ProfileCompilationInfo::OfflineProfileMethodInfo* pmi) {
-    ProfileCompilationInfo::InlineCacheMap* ic_map =
-        const_cast<ProfileCompilationInfo::InlineCacheMap*>(pmi->inline_caches);
-    for (auto it : *ic_map) {
-      it.second.SetIsMissingTypes();
-    }
-  }
-
-  void TestProfileLoadFromZip(const char* zip_entry,
-                              size_t zip_flags,
-                              bool should_succeed,
-                              bool should_succeed_with_empty_profile = false) {
-    // Create a valid profile.
-    ScratchFile profile;
-    ProfileCompilationInfo saved_info;
-    for (uint16_t i = 0; i < 10; i++) {
-      ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, /* method_idx */ i, &saved_info));
-      ASSERT_TRUE(AddMethod("dex_location2", /* checksum */ 2, /* method_idx */ i, &saved_info));
-    }
-    ASSERT_TRUE(saved_info.Save(GetFd(profile)));
-    ASSERT_EQ(0, profile.GetFile()->Flush());
-
-    // Prepare the profile content for zipping.
-    ASSERT_TRUE(profile.GetFile()->ResetOffset());
-    std::vector<uint8_t> data(profile.GetFile()->GetLength());
-    ASSERT_TRUE(profile.GetFile()->ReadFully(data.data(), data.size()));
-
-    // Zip the profile content.
-    ScratchFile zip;
-    FILE* file = fopen(zip.GetFile()->GetPath().c_str(), "wb");
-    ZipWriter writer(file);
-    writer.StartEntry(zip_entry, zip_flags);
-    writer.WriteBytes(data.data(), data.size());
-    writer.FinishEntry();
-    writer.Finish();
-    fflush(file);
-    fclose(file);
-
-    // Verify loading from the zip archive.
-    ProfileCompilationInfo loaded_info;
-    ASSERT_TRUE(zip.GetFile()->ResetOffset());
-    ASSERT_EQ(should_succeed, loaded_info.Load(zip.GetFile()->GetPath(), false));
-    if (should_succeed) {
-      if (should_succeed_with_empty_profile) {
-        ASSERT_TRUE(loaded_info.IsEmpty());
-      } else {
-        ASSERT_TRUE(loaded_info.Equals(saved_info));
-      }
-    }
-  }
-
-  bool IsEmpty(const ProfileCompilationInfo& info) {
-    return info.IsEmpty();
-  }
-
-  // Cannot sizeof the actual arrays so hard code the values here.
-  // They should not change anyway.
-  static constexpr int kProfileMagicSize = 4;
-  static constexpr int kProfileVersionSize = 4;
-
-  std::unique_ptr<ArenaAllocator> allocator_;
-
-  // Cache of inline caches generated during tests.
-  // This makes it easier to pass data between different utilities and ensure that
-  // caches are destructed at the end of the test.
-  std::vector<std::unique_ptr<ProfileCompilationInfo::InlineCacheMap>> used_inline_caches;
-};
-
-TEST_F(ProfileCompilationInfoTest, SaveArtMethods) {
-  ScratchFile profile;
-
-  Thread* self = Thread::Current();
-  jobject class_loader;
-  {
-    ScopedObjectAccess soa(self);
-    class_loader = LoadDex("ProfileTestMultiDex");
-  }
-  ASSERT_NE(class_loader, nullptr);
-
-  // Save virtual methods from Main.
-  std::set<DexCacheResolvedClasses> resolved_classes;
-  std::vector<ArtMethod*> main_methods = GetVirtualMethods(class_loader, "LMain;");
-  ASSERT_TRUE(SaveProfilingInfo(
-      profile.GetFilename(), main_methods, resolved_classes, Hotness::kFlagPostStartup));
-
-  // Check that what we saved is in the profile.
-  ProfileCompilationInfo info1;
-  ASSERT_TRUE(info1.Load(GetFd(profile)));
-  ASSERT_EQ(info1.GetNumberOfMethods(), main_methods.size());
-  {
-    ScopedObjectAccess soa(self);
-    for (ArtMethod* m : main_methods) {
-      Hotness h = info1.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex()));
-      ASSERT_TRUE(h.IsHot());
-      ASSERT_TRUE(h.IsPostStartup());
-    }
-  }
-
-  // Save virtual methods from Second.
-  std::vector<ArtMethod*> second_methods = GetVirtualMethods(class_loader, "LSecond;");
-  ASSERT_TRUE(SaveProfilingInfo(
-    profile.GetFilename(), second_methods, resolved_classes, Hotness::kFlagStartup));
-
-  // Check that what we saved is in the profile (methods form Main and Second).
-  ProfileCompilationInfo info2;
-  ASSERT_TRUE(profile.GetFile()->ResetOffset());
-  ASSERT_TRUE(info2.Load(GetFd(profile)));
-  ASSERT_EQ(info2.GetNumberOfMethods(), main_methods.size() + second_methods.size());
-  {
-    ScopedObjectAccess soa(self);
-    for (ArtMethod* m : main_methods) {
-      Hotness h = info2.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex()));
-      ASSERT_TRUE(h.IsHot());
-      ASSERT_TRUE(h.IsPostStartup());
-    }
-    for (ArtMethod* m : second_methods) {
-      Hotness h = info2.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex()));
-      ASSERT_TRUE(h.IsHot());
-      ASSERT_TRUE(h.IsStartup());
-    }
-  }
-}
-
-TEST_F(ProfileCompilationInfoTest, SaveFd) {
-  ScratchFile profile;
-
-  ProfileCompilationInfo saved_info;
-  // Save a few methods.
-  for (uint16_t i = 0; i < 10; i++) {
-    ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, /* method_idx */ i, &saved_info));
-    ASSERT_TRUE(AddMethod("dex_location2", /* checksum */ 2, /* method_idx */ i, &saved_info));
-  }
-  ASSERT_TRUE(saved_info.Save(GetFd(profile)));
-  ASSERT_EQ(0, profile.GetFile()->Flush());
-
-  // Check that we get back what we saved.
-  ProfileCompilationInfo loaded_info;
-  ASSERT_TRUE(profile.GetFile()->ResetOffset());
-  ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
-  ASSERT_TRUE(loaded_info.Equals(saved_info));
-
-  // Save more methods.
-  for (uint16_t i = 0; i < 100; i++) {
-    ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, /* method_idx */ i, &saved_info));
-    ASSERT_TRUE(AddMethod("dex_location2", /* checksum */ 2, /* method_idx */ i, &saved_info));
-    ASSERT_TRUE(AddMethod("dex_location3", /* checksum */ 3, /* method_idx */ i, &saved_info));
-  }
-  ASSERT_TRUE(profile.GetFile()->ResetOffset());
-  ASSERT_TRUE(saved_info.Save(GetFd(profile)));
-  ASSERT_EQ(0, profile.GetFile()->Flush());
-
-  // Check that we get back everything we saved.
-  ProfileCompilationInfo loaded_info2;
-  ASSERT_TRUE(profile.GetFile()->ResetOffset());
-  ASSERT_TRUE(loaded_info2.Load(GetFd(profile)));
-  ASSERT_TRUE(loaded_info2.Equals(saved_info));
-}
-
-TEST_F(ProfileCompilationInfoTest, AddMethodsAndClassesFail) {
-  ScratchFile profile;
-
-  ProfileCompilationInfo info;
-  ASSERT_TRUE(AddMethod("dex_location", /* checksum */ 1, /* method_idx */ 1, &info));
-  // Trying to add info for an existing file but with a different checksum.
-  ASSERT_FALSE(AddMethod("dex_location", /* checksum */ 2, /* method_idx */ 2, &info));
-}
-
-TEST_F(ProfileCompilationInfoTest, MergeFail) {
-  ScratchFile profile;
-
-  ProfileCompilationInfo info1;
-  ASSERT_TRUE(AddMethod("dex_location", /* checksum */ 1, /* method_idx */ 1, &info1));
-  // Use the same file, change the checksum.
-  ProfileCompilationInfo info2;
-  ASSERT_TRUE(AddMethod("dex_location", /* checksum */ 2, /* method_idx */ 2, &info2));
-
-  ASSERT_FALSE(info1.MergeWith(info2));
-}
-
-
-TEST_F(ProfileCompilationInfoTest, MergeFdFail) {
-  ScratchFile profile;
-
-  ProfileCompilationInfo info1;
-  ASSERT_TRUE(AddMethod("dex_location", /* checksum */ 1, /* method_idx */ 1, &info1));
-  // Use the same file, change the checksum.
-  ProfileCompilationInfo info2;
-  ASSERT_TRUE(AddMethod("dex_location", /* checksum */ 2, /* method_idx */ 2, &info2));
-
-  ASSERT_TRUE(info1.Save(profile.GetFd()));
-  ASSERT_EQ(0, profile.GetFile()->Flush());
-  ASSERT_TRUE(profile.GetFile()->ResetOffset());
-
-  ASSERT_FALSE(info2.Load(profile.GetFd()));
-}
-
-TEST_F(ProfileCompilationInfoTest, SaveMaxMethods) {
-  ScratchFile profile;
-
-  ProfileCompilationInfo saved_info;
-  // Save the maximum number of methods
-  for (uint16_t i = 0; i < std::numeric_limits<uint16_t>::max(); i++) {
-    ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, /* method_idx */ i, &saved_info));
-    ASSERT_TRUE(AddMethod("dex_location2", /* checksum */ 2, /* method_idx */ i, &saved_info));
-  }
-  // Save the maximum number of classes
-  for (uint16_t i = 0; i < std::numeric_limits<uint16_t>::max(); i++) {
-    ASSERT_TRUE(AddClass("dex_location1", /* checksum */ 1, dex::TypeIndex(i), &saved_info));
-    ASSERT_TRUE(AddClass("dex_location2", /* checksum */ 2, dex::TypeIndex(i), &saved_info));
-  }
-
-  ASSERT_TRUE(saved_info.Save(GetFd(profile)));
-  ASSERT_EQ(0, profile.GetFile()->Flush());
-
-  // Check that we get back what we saved.
-  ProfileCompilationInfo loaded_info;
-  ASSERT_TRUE(profile.GetFile()->ResetOffset());
-  ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
-  ASSERT_TRUE(loaded_info.Equals(saved_info));
-}
-
-TEST_F(ProfileCompilationInfoTest, SaveEmpty) {
-  ScratchFile profile;
-
-  ProfileCompilationInfo saved_info;
-  ASSERT_TRUE(saved_info.Save(GetFd(profile)));
-  ASSERT_EQ(0, profile.GetFile()->Flush());
-
-  // Check that we get back what we saved.
-  ProfileCompilationInfo loaded_info;
-  ASSERT_TRUE(profile.GetFile()->ResetOffset());
-  ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
-  ASSERT_TRUE(loaded_info.Equals(saved_info));
-}
-
-TEST_F(ProfileCompilationInfoTest, LoadEmpty) {
-  ScratchFile profile;
-
-  ProfileCompilationInfo empty_info;
-
-  ProfileCompilationInfo loaded_info;
-  ASSERT_TRUE(profile.GetFile()->ResetOffset());
-  ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
-  ASSERT_TRUE(loaded_info.Equals(empty_info));
-}
-
-TEST_F(ProfileCompilationInfoTest, BadMagic) {
-  ScratchFile profile;
-  uint8_t buffer[] = { 1, 2, 3, 4 };
-  ASSERT_TRUE(profile.GetFile()->WriteFully(buffer, sizeof(buffer)));
-  ProfileCompilationInfo loaded_info;
-  ASSERT_TRUE(profile.GetFile()->ResetOffset());
-  ASSERT_FALSE(loaded_info.Load(GetFd(profile)));
-}
-
-TEST_F(ProfileCompilationInfoTest, BadVersion) {
-  ScratchFile profile;
-
-  ASSERT_TRUE(profile.GetFile()->WriteFully(
-      ProfileCompilationInfo::kProfileMagic, kProfileMagicSize));
-  uint8_t version[] = { 'v', 'e', 'r', 's', 'i', 'o', 'n' };
-  ASSERT_TRUE(profile.GetFile()->WriteFully(version, sizeof(version)));
-  ASSERT_EQ(0, profile.GetFile()->Flush());
-
-  ProfileCompilationInfo loaded_info;
-  ASSERT_TRUE(profile.GetFile()->ResetOffset());
-  ASSERT_FALSE(loaded_info.Load(GetFd(profile)));
-}
-
-TEST_F(ProfileCompilationInfoTest, Incomplete) {
-  ScratchFile profile;
-  ASSERT_TRUE(profile.GetFile()->WriteFully(
-      ProfileCompilationInfo::kProfileMagic, kProfileMagicSize));
-  ASSERT_TRUE(profile.GetFile()->WriteFully(
-      ProfileCompilationInfo::kProfileVersion, kProfileVersionSize));
-  // Write that we have at least one line.
-  uint8_t line_number[] = { 0, 1 };
-  ASSERT_TRUE(profile.GetFile()->WriteFully(line_number, sizeof(line_number)));
-  ASSERT_EQ(0, profile.GetFile()->Flush());
-
-  ProfileCompilationInfo loaded_info;
-  ASSERT_TRUE(profile.GetFile()->ResetOffset());
-  ASSERT_FALSE(loaded_info.Load(GetFd(profile)));
-}
-
-TEST_F(ProfileCompilationInfoTest, TooLongDexLocation) {
-  ScratchFile profile;
-  ASSERT_TRUE(profile.GetFile()->WriteFully(
-      ProfileCompilationInfo::kProfileMagic, kProfileMagicSize));
-  ASSERT_TRUE(profile.GetFile()->WriteFully(
-      ProfileCompilationInfo::kProfileVersion, kProfileVersionSize));
-  // Write that we have at least one line.
-  uint8_t line_number[] = { 0, 1 };
-  ASSERT_TRUE(profile.GetFile()->WriteFully(line_number, sizeof(line_number)));
-
-  // dex_location_size, methods_size, classes_size, checksum.
-  // Dex location size is too big and should be rejected.
-  uint8_t line[] = { 255, 255, 0, 1, 0, 1, 0, 0, 0, 0 };
-  ASSERT_TRUE(profile.GetFile()->WriteFully(line, sizeof(line)));
-  ASSERT_EQ(0, profile.GetFile()->Flush());
-
-  ProfileCompilationInfo loaded_info;
-  ASSERT_TRUE(profile.GetFile()->ResetOffset());
-  ASSERT_FALSE(loaded_info.Load(GetFd(profile)));
-}
-
-TEST_F(ProfileCompilationInfoTest, UnexpectedContent) {
-  ScratchFile profile;
-
-  ProfileCompilationInfo saved_info;
-  // Save the maximum number of methods
-  for (uint16_t i = 0; i < 10; i++) {
-    ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, /* method_idx */ i, &saved_info));
-  }
-  ASSERT_TRUE(saved_info.Save(GetFd(profile)));
-
-  uint8_t random_data[] = { 1, 2, 3};
-  ASSERT_TRUE(profile.GetFile()->WriteFully(random_data, sizeof(random_data)));
-
-  ASSERT_EQ(0, profile.GetFile()->Flush());
-
-  // Check that we fail because of unexpected data at the end of the file.
-  ProfileCompilationInfo loaded_info;
-  ASSERT_TRUE(profile.GetFile()->ResetOffset());
-  ASSERT_FALSE(loaded_info.Load(GetFd(profile)));
-}
-
-TEST_F(ProfileCompilationInfoTest, SaveInlineCaches) {
-  ScratchFile profile;
-
-  ProfileCompilationInfo saved_info;
-  ProfileCompilationInfo::OfflineProfileMethodInfo pmi = GetOfflineProfileMethodInfo();
-
-  // Add methods with inline caches.
-  for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
-    // Add a method which is part of the same dex file as one of the
-    // class from the inline caches.
-    ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &saved_info));
-    // Add a method which is outside the set of dex files.
-    ASSERT_TRUE(AddMethod("dex_location4", /* checksum */ 4, method_idx, pmi, &saved_info));
-  }
-
-  ASSERT_TRUE(saved_info.Save(GetFd(profile)));
-  ASSERT_EQ(0, profile.GetFile()->Flush());
-
-  // Check that we get back what we saved.
-  ProfileCompilationInfo loaded_info;
-  ASSERT_TRUE(profile.GetFile()->ResetOffset());
-  ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
-
-  ASSERT_TRUE(loaded_info.Equals(saved_info));
-
-  std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi1 =
-      loaded_info.GetMethod("dex_location1", /* checksum */ 1, /* method_idx */ 3);
-  ASSERT_TRUE(loaded_pmi1 != nullptr);
-  ASSERT_TRUE(*loaded_pmi1 == pmi);
-  std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi2 =
-      loaded_info.GetMethod("dex_location4", /* checksum */ 4, /* method_idx */ 3);
-  ASSERT_TRUE(loaded_pmi2 != nullptr);
-  ASSERT_TRUE(*loaded_pmi2 == pmi);
-}
-
-TEST_F(ProfileCompilationInfoTest, MegamorphicInlineCaches) {
-  ScratchFile profile;
-
-  ProfileCompilationInfo saved_info;
-  ProfileCompilationInfo::OfflineProfileMethodInfo pmi = GetOfflineProfileMethodInfo();
-
-  // Add methods with inline caches.
-  for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
-    ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &saved_info));
-  }
-
-  ASSERT_TRUE(saved_info.Save(GetFd(profile)));
-  ASSERT_EQ(0, profile.GetFile()->Flush());
-
-  // Make the inline caches megamorphic and add them to the profile again.
-  ProfileCompilationInfo saved_info_extra;
-  ProfileCompilationInfo::OfflineProfileMethodInfo pmi_extra = GetOfflineProfileMethodInfo();
-  MakeMegamorphic(&pmi_extra);
-  for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
-    ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &saved_info_extra));
-  }
-
-  ASSERT_TRUE(profile.GetFile()->ResetOffset());
-  ASSERT_TRUE(saved_info_extra.Save(GetFd(profile)));
-  ASSERT_EQ(0, profile.GetFile()->Flush());
-
-  // Merge the profiles so that we have the same view as the file.
-  ASSERT_TRUE(saved_info.MergeWith(saved_info_extra));
-
-  // Check that we get back what we saved.
-  ProfileCompilationInfo loaded_info;
-  ASSERT_TRUE(profile.GetFile()->ResetOffset());
-  ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
-
-  ASSERT_TRUE(loaded_info.Equals(saved_info));
-
-  std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi1 =
-      loaded_info.GetMethod("dex_location1", /* checksum */ 1, /* method_idx */ 3);
-
-  ASSERT_TRUE(loaded_pmi1 != nullptr);
-  ASSERT_TRUE(*loaded_pmi1 == pmi_extra);
-}
-
-TEST_F(ProfileCompilationInfoTest, MissingTypesInlineCaches) {
-  ScratchFile profile;
-
-  ProfileCompilationInfo saved_info;
-  ProfileCompilationInfo::OfflineProfileMethodInfo pmi = GetOfflineProfileMethodInfo();
-
-  // Add methods with inline caches.
-  for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
-    ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &saved_info));
-  }
-
-  ASSERT_TRUE(saved_info.Save(GetFd(profile)));
-  ASSERT_EQ(0, profile.GetFile()->Flush());
-
-  // Make some inline caches megamorphic and add them to the profile again.
-  ProfileCompilationInfo saved_info_extra;
-  ProfileCompilationInfo::OfflineProfileMethodInfo pmi_extra = GetOfflineProfileMethodInfo();
-  MakeMegamorphic(&pmi_extra);
-  for (uint16_t method_idx = 5; method_idx < 10; method_idx++) {
-    ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &saved_info_extra));
-  }
-
-  // Mark all inline caches with missing types and add them to the profile again.
-  // This will verify that all inline caches (megamorphic or not) should be marked as missing types.
-  ProfileCompilationInfo::OfflineProfileMethodInfo missing_types = GetOfflineProfileMethodInfo();
-  SetIsMissingTypes(&missing_types);
-  for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
-    ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &saved_info_extra));
-  }
-
-  ASSERT_TRUE(profile.GetFile()->ResetOffset());
-  ASSERT_TRUE(saved_info_extra.Save(GetFd(profile)));
-  ASSERT_EQ(0, profile.GetFile()->Flush());
-
-  // Merge the profiles so that we have the same view as the file.
-  ASSERT_TRUE(saved_info.MergeWith(saved_info_extra));
-
-  // Check that we get back what we saved.
-  ProfileCompilationInfo loaded_info;
-  ASSERT_TRUE(profile.GetFile()->ResetOffset());
-  ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
-
-  ASSERT_TRUE(loaded_info.Equals(saved_info));
-
-  std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi1 =
-      loaded_info.GetMethod("dex_location1", /* checksum */ 1, /* method_idx */ 3);
-  ASSERT_TRUE(loaded_pmi1 != nullptr);
-  ASSERT_TRUE(*loaded_pmi1 == pmi_extra);
-}
-
-TEST_F(ProfileCompilationInfoTest, SaveArtMethodsWithInlineCaches) {
-  ScratchFile profile;
-
-  Thread* self = Thread::Current();
-  jobject class_loader;
-  {
-    ScopedObjectAccess soa(self);
-    class_loader = LoadDex("ProfileTestMultiDex");
-  }
-  ASSERT_NE(class_loader, nullptr);
-
-  // Save virtual methods from Main.
-  std::set<DexCacheResolvedClasses> resolved_classes;
-  std::vector<ArtMethod*> main_methods = GetVirtualMethods(class_loader, "LMain;");
-
-  SafeMap<ArtMethod*, ProfileMethodInfo> profile_methods_map;
-  ASSERT_TRUE(SaveProfilingInfoWithFakeInlineCaches(
-      profile.GetFilename(), main_methods, Hotness::kFlagStartup, &profile_methods_map));
-
-  // Check that what we saved is in the profile.
-  ProfileCompilationInfo info;
-  ASSERT_TRUE(info.Load(GetFd(profile)));
-  ASSERT_EQ(info.GetNumberOfMethods(), main_methods.size());
-  {
-    ScopedObjectAccess soa(self);
-    for (ArtMethod* m : main_methods) {
-      Hotness h = info.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex()));
-      ASSERT_TRUE(h.IsHot());
-      ASSERT_TRUE(h.IsStartup());
-      const ProfileMethodInfo& pmi = profile_methods_map.find(m)->second;
-      std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> offline_pmi =
-          info.GetMethod(m->GetDexFile()->GetLocation(),
-                         m->GetDexFile()->GetLocationChecksum(),
-                         m->GetDexMethodIndex());
-      ASSERT_TRUE(offline_pmi != nullptr);
-      ProfileCompilationInfo::OfflineProfileMethodInfo converted_pmi =
-          ConvertProfileMethodInfo(pmi);
-      ASSERT_EQ(converted_pmi, *offline_pmi);
-    }
-  }
-}
-
-TEST_F(ProfileCompilationInfoTest, InvalidChecksumInInlineCache) {
-  ScratchFile profile;
-
-  ProfileCompilationInfo info;
-  ProfileCompilationInfo::OfflineProfileMethodInfo pmi1 = GetOfflineProfileMethodInfo();
-  ProfileCompilationInfo::OfflineProfileMethodInfo pmi2 = GetOfflineProfileMethodInfo();
-  // Modify the checksum to trigger a mismatch.
-  pmi2.dex_references[0].dex_checksum++;
-
-  ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, /*method_idx*/ 0, pmi1, &info));
-  ASSERT_FALSE(AddMethod("dex_location2", /* checksum */ 2, /*method_idx*/ 0, pmi2, &info));
-}
-
-// Verify that profiles behave correctly even if the methods are added in a different
-// order and with a different dex profile indices for the dex files.
-TEST_F(ProfileCompilationInfoTest, MergeInlineCacheTriggerReindex) {
-  ScratchFile profile;
-
-  ProfileCompilationInfo info;
-  ProfileCompilationInfo info_reindexed;
-
-  ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
-  ProfileCompilationInfo::OfflineProfileMethodInfo pmi(ic_map);
-  pmi.dex_references.emplace_back("dex_location1", /* checksum */ 1, kMaxMethodIds);
-  pmi.dex_references.emplace_back("dex_location2", /* checksum */ 2, kMaxMethodIds);
-  for (uint16_t dex_pc = 1; dex_pc < 5; dex_pc++) {
-    ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
-    dex_pc_data.AddClass(0, dex::TypeIndex(0));
-    dex_pc_data.AddClass(1, dex::TypeIndex(1));
-    ic_map->Put(dex_pc, dex_pc_data);
-  }
-
-  ProfileCompilationInfo::InlineCacheMap* ic_map_reindexed = CreateInlineCacheMap();
-  ProfileCompilationInfo::OfflineProfileMethodInfo pmi_reindexed(ic_map_reindexed);
-  pmi_reindexed.dex_references.emplace_back("dex_location2", /* checksum */ 2, kMaxMethodIds);
-  pmi_reindexed.dex_references.emplace_back("dex_location1", /* checksum */ 1, kMaxMethodIds);
-  for (uint16_t dex_pc = 1; dex_pc < 5; dex_pc++) {
-    ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
-    dex_pc_data.AddClass(1, dex::TypeIndex(0));
-    dex_pc_data.AddClass(0, dex::TypeIndex(1));
-    ic_map_reindexed->Put(dex_pc, dex_pc_data);
-  }
-
-  // Profile 1 and Profile 2 get the same methods but in different order.
-  // This will trigger a different dex numbers.
-  for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
-    ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &info));
-    ASSERT_TRUE(AddMethod("dex_location2", /* checksum */ 2, method_idx, pmi, &info));
-  }
-
-  for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
-    ASSERT_TRUE(AddMethod(
-      "dex_location2", /* checksum */ 2, method_idx, pmi_reindexed, &info_reindexed));
-    ASSERT_TRUE(AddMethod(
-      "dex_location1", /* checksum */ 1, method_idx, pmi_reindexed, &info_reindexed));
-  }
-
-  ProfileCompilationInfo info_backup;
-  info_backup.MergeWith(info);
-  ASSERT_TRUE(info.MergeWith(info_reindexed));
-  // Merging should have no effect as we're adding the exact same stuff.
-  ASSERT_TRUE(info.Equals(info_backup));
-  for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
-    std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi1 =
-        info.GetMethod("dex_location1", /* checksum */ 1, method_idx);
-    ASSERT_TRUE(loaded_pmi1 != nullptr);
-    ASSERT_TRUE(*loaded_pmi1 == pmi);
-    std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi2 =
-        info.GetMethod("dex_location2", /* checksum */ 2, method_idx);
-    ASSERT_TRUE(loaded_pmi2 != nullptr);
-    ASSERT_TRUE(*loaded_pmi2 == pmi);
-  }
-}
-
-TEST_F(ProfileCompilationInfoTest, AddMoreDexFileThanLimit) {
-  ProfileCompilationInfo info;
-  // Save a few methods.
-  for (uint16_t i = 0; i < std::numeric_limits<uint8_t>::max(); i++) {
-    std::string dex_location = std::to_string(i);
-    ASSERT_TRUE(AddMethod(dex_location, /* checksum */ 1, /* method_idx */ i, &info));
-  }
-  // We only support at most 255 dex files.
-  ASSERT_FALSE(AddMethod(
-      /*dex_location*/ "256", /* checksum */ 1, /* method_idx */ 0, &info));
-}
-
-TEST_F(ProfileCompilationInfoTest, MegamorphicInlineCachesMerge) {
-  // Create a megamorphic inline cache.
-  ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
-  ProfileCompilationInfo::OfflineProfileMethodInfo pmi(ic_map);
-  pmi.dex_references.emplace_back("dex_location1", /* checksum */ 1, kMaxMethodIds);
-  ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
-  dex_pc_data.SetIsMegamorphic();
-  ic_map->Put(/*dex_pc*/ 0, dex_pc_data);
-
-  ProfileCompilationInfo info_megamorphic;
-  ASSERT_TRUE(AddMethod("dex_location1",
-                        /*checksum*/ 1,
-                        /*method_idx*/ 0,
-                        pmi,
-                        &info_megamorphic));
-
-  // Create a profile with no inline caches (for the same method).
-  ProfileCompilationInfo info_no_inline_cache;
-  ASSERT_TRUE(AddMethod("dex_location1",
-                        /*checksum*/ 1,
-                        /*method_idx*/ 0,
-                        &info_no_inline_cache));
-
-  // Merge the megamorphic cache into the empty one.
-  ASSERT_TRUE(info_no_inline_cache.MergeWith(info_megamorphic));
-  ScratchFile profile;
-  // Saving profile should work without crashing (b/35644850).
-  ASSERT_TRUE(info_no_inline_cache.Save(GetFd(profile)));
-}
-
-TEST_F(ProfileCompilationInfoTest, MissingTypesInlineCachesMerge) {
-  // Create an inline cache with missing types
-  ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
-  ProfileCompilationInfo::OfflineProfileMethodInfo pmi(ic_map);
-  pmi.dex_references.emplace_back("dex_location1", /* checksum */ 1, kMaxMethodIds);
-  ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
-  dex_pc_data.SetIsMissingTypes();
-  ic_map->Put(/*dex_pc*/ 0, dex_pc_data);
-
-  ProfileCompilationInfo info_megamorphic;
-  ASSERT_TRUE(AddMethod("dex_location1",
-                        /*checksum*/ 1,
-                        /*method_idx*/ 0,
-                        pmi,
-                        &info_megamorphic));
-
-  // Create a profile with no inline caches (for the same method).
-  ProfileCompilationInfo info_no_inline_cache;
-  ASSERT_TRUE(AddMethod("dex_location1",
-                        /*checksum*/ 1,
-                        /*method_idx*/ 0,
-                        &info_no_inline_cache));
-
-  // Merge the missing type cache into the empty one.
-  // Everything should be saved without errors.
-  ASSERT_TRUE(info_no_inline_cache.MergeWith(info_megamorphic));
-  ScratchFile profile;
-  ASSERT_TRUE(info_no_inline_cache.Save(GetFd(profile)));
-}
-
-TEST_F(ProfileCompilationInfoTest, SampledMethodsTest) {
-  ProfileCompilationInfo test_info;
-  static constexpr size_t kNumMethods = 1000;
-  static constexpr size_t kChecksum1 = 1234;
-  static constexpr size_t kChecksum2 = 4321;
-  static const std::string kDex1 = "dex1";
-  static const std::string kDex2 = "dex2";
-  test_info.AddMethodIndex(Hotness::kFlagStartup, kDex1, kChecksum1, 1, kNumMethods);
-  test_info.AddMethodIndex(Hotness::kFlagPostStartup, kDex1, kChecksum1, 5, kNumMethods);
-  test_info.AddMethodIndex(Hotness::kFlagStartup, kDex2, kChecksum2, 2, kNumMethods);
-  test_info.AddMethodIndex(Hotness::kFlagPostStartup, kDex2, kChecksum2, 4, kNumMethods);
-  auto run_test = [](const ProfileCompilationInfo& info) {
-    EXPECT_FALSE(info.GetMethodHotness(kDex1, kChecksum1, 2).IsInProfile());
-    EXPECT_FALSE(info.GetMethodHotness(kDex1, kChecksum1, 4).IsInProfile());
-    EXPECT_TRUE(info.GetMethodHotness(kDex1, kChecksum1, 1).IsStartup());
-    EXPECT_FALSE(info.GetMethodHotness(kDex1, kChecksum1, 3).IsStartup());
-    EXPECT_TRUE(info.GetMethodHotness(kDex1, kChecksum1, 5).IsPostStartup());
-    EXPECT_FALSE(info.GetMethodHotness(kDex1, kChecksum1, 6).IsStartup());
-    EXPECT_TRUE(info.GetMethodHotness(kDex2, kChecksum2, 2).IsStartup());
-    EXPECT_TRUE(info.GetMethodHotness(kDex2, kChecksum2, 4).IsPostStartup());
-  };
-  run_test(test_info);
-
-  // Save the profile.
-  ScratchFile profile;
-  ASSERT_TRUE(test_info.Save(GetFd(profile)));
-  ASSERT_EQ(0, profile.GetFile()->Flush());
-  ASSERT_TRUE(profile.GetFile()->ResetOffset());
-
-  // Load the profile and make sure we can read the data and it matches what we expect.
-  ProfileCompilationInfo loaded_info;
-  ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
-  run_test(loaded_info);
-
-  // Test that the bitmap gets merged properly.
-  EXPECT_FALSE(test_info.GetMethodHotness(kDex1, kChecksum1, 11).IsStartup());
-  {
-    ProfileCompilationInfo merge_info;
-    merge_info.AddMethodIndex(Hotness::kFlagStartup, kDex1, kChecksum1, 11, kNumMethods);
-    test_info.MergeWith(merge_info);
-  }
-  EXPECT_TRUE(test_info.GetMethodHotness(kDex1, kChecksum1, 11).IsStartup());
-
-  // Test bulk adding.
-  {
-    std::unique_ptr<const DexFile> dex(OpenTestDexFile("ManyMethods"));
-    ProfileCompilationInfo info;
-    std::vector<uint16_t> hot_methods = {1, 3, 5};
-    std::vector<uint16_t> startup_methods = {1, 2};
-    std::vector<uint16_t> post_methods = {0, 2, 6};
-    ASSERT_GE(dex->NumMethodIds(), 7u);
-    info.AddMethodsForDex(static_cast<Hotness::Flag>(Hotness::kFlagHot | Hotness::kFlagStartup),
-                          dex.get(),
-                          hot_methods.begin(),
-                          hot_methods.end());
-    info.AddMethodsForDex(Hotness::kFlagStartup,
-                          dex.get(),
-                          startup_methods.begin(),
-                          startup_methods.end());
-    info.AddMethodsForDex(Hotness::kFlagPostStartup,
-                          dex.get(),
-                          post_methods.begin(),
-                          post_methods.end());
-    for (uint16_t id : hot_methods) {
-      EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), id)).IsHot());
-      EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), id)).IsStartup());
-    }
-    for (uint16_t id : startup_methods) {
-      EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), id)).IsStartup());
-    }
-    for (uint16_t id : post_methods) {
-      EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), id)).IsPostStartup());
-    }
-    EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), 6)).IsPostStartup());
-    // Check that methods that shouldn't have been touched are OK.
-    EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), 0)).IsInProfile());
-    EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex.get(), 4)).IsInProfile());
-    EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex.get(), 7)).IsInProfile());
-    EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex.get(), 1)).IsPostStartup());
-    EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex.get(), 4)).IsStartup());
-    EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex.get(), 6)).IsStartup());
-  }
-}
-
-TEST_F(ProfileCompilationInfoTest, LoadFromZipCompress) {
-  TestProfileLoadFromZip("primary.prof",
-                         ZipWriter::kCompress | ZipWriter::kAlign32,
-                         /*should_succeed*/true);
-}
-
-TEST_F(ProfileCompilationInfoTest, LoadFromZipUnCompress) {
-  TestProfileLoadFromZip("primary.prof",
-                         ZipWriter::kAlign32,
-                         /*should_succeed*/true);
-}
-
-TEST_F(ProfileCompilationInfoTest, LoadFromZipUnAligned) {
-  TestProfileLoadFromZip("primary.prof",
-                         0,
-                         /*should_succeed*/true);
-}
-
-TEST_F(ProfileCompilationInfoTest, LoadFromZipFailBadZipEntry) {
-  TestProfileLoadFromZip("invalid.profile.entry",
-                         0,
-                         /*should_succeed*/true,
-                         /*should_succeed_with_empty_profile*/true);
-}
-
-TEST_F(ProfileCompilationInfoTest, LoadFromZipFailBadProfile) {
-  // Create a bad profile.
-  ScratchFile profile;
-  ASSERT_TRUE(profile.GetFile()->WriteFully(
-      ProfileCompilationInfo::kProfileMagic, kProfileMagicSize));
-  ASSERT_TRUE(profile.GetFile()->WriteFully(
-      ProfileCompilationInfo::kProfileVersion, kProfileVersionSize));
-  // Write that we have at least one line.
-  uint8_t line_number[] = { 0, 1 };
-  ASSERT_TRUE(profile.GetFile()->WriteFully(line_number, sizeof(line_number)));
-  ASSERT_EQ(0, profile.GetFile()->Flush());
-
-  // Prepare the profile content for zipping.
-  ASSERT_TRUE(profile.GetFile()->ResetOffset());
-  std::vector<uint8_t> data(profile.GetFile()->GetLength());
-  ASSERT_TRUE(profile.GetFile()->ReadFully(data.data(), data.size()));
-
-  // Zip the profile content.
-  ScratchFile zip;
-  FILE* file = fopen(zip.GetFile()->GetPath().c_str(), "wb");
-  ZipWriter writer(file);
-  writer.StartEntry("primary.prof", ZipWriter::kAlign32);
-  writer.WriteBytes(data.data(), data.size());
-  writer.FinishEntry();
-  writer.Finish();
-  fflush(file);
-  fclose(file);
-
-  // Check that we failed to load.
-  ProfileCompilationInfo loaded_info;
-  ASSERT_TRUE(zip.GetFile()->ResetOffset());
-  ASSERT_FALSE(loaded_info.Load(GetFd(zip)));
-}
-
-TEST_F(ProfileCompilationInfoTest, UpdateProfileKeyOk) {
-  std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("MultiDex");
-
-  ProfileCompilationInfo info;
-  for (const std::unique_ptr<const DexFile>& dex : dex_files) {
-    // Create the profile with a different location so that we can update it to the
-    // real dex location later.
-    std::string base_location = DexFileLoader::GetBaseLocation(dex->GetLocation());
-    std::string multidex_suffix = DexFileLoader::GetMultiDexSuffix(dex->GetLocation());
-    std::string old_name = base_location + "-old" + multidex_suffix;
-    info.AddMethodIndex(Hotness::kFlagHot,
-                        old_name,
-                        dex->GetLocationChecksum(),
-                        /* method_idx */ 0,
-                        dex->NumMethodIds());
-  }
-
-  // Update the profile keys based on the original dex files
-  ASSERT_TRUE(info.UpdateProfileKeys(dex_files));
-
-  // Verify that we find the methods when searched with the original dex files.
-  for (const std::unique_ptr<const DexFile>& dex : dex_files) {
-    std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi =
-        info.GetMethod(dex->GetLocation(), dex->GetLocationChecksum(), /* method_idx */ 0);
-    ASSERT_TRUE(loaded_pmi != nullptr);
-  }
-}
-
-TEST_F(ProfileCompilationInfoTest, UpdateProfileKeyOkButNoUpdate) {
-  std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("MultiDex");
-
-  ProfileCompilationInfo info;
-  info.AddMethodIndex(Hotness::kFlagHot,
-                      "my.app",
-                      /* checksum */ 123,
-                      /* method_idx */ 0,
-                      /* num_method_ids */ 10);
-
-  // Update the profile keys based on the original dex files
-  ASSERT_TRUE(info.UpdateProfileKeys(dex_files));
-
-  // Verify that we did not perform any update and that we cannot find anything with the new
-  // location.
-  for (const std::unique_ptr<const DexFile>& dex : dex_files) {
-    std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi =
-        info.GetMethod(dex->GetLocation(), dex->GetLocationChecksum(), /* method_idx */ 0);
-    ASSERT_TRUE(loaded_pmi == nullptr);
-  }
-
-  // Verify that we can find the original entry.
-  std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi =
-        info.GetMethod("my.app", /* checksum */ 123, /* method_idx */ 0);
-  ASSERT_TRUE(loaded_pmi != nullptr);
-}
-
-TEST_F(ProfileCompilationInfoTest, UpdateProfileKeyFail) {
-  std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("MultiDex");
-
-
-  ProfileCompilationInfo info;
-  // Add all dex
-  for (const std::unique_ptr<const DexFile>& dex : dex_files) {
-    // Create the profile with a different location so that we can update it to the
-    // real dex location later.
-    std::string base_location = DexFileLoader::GetBaseLocation(dex->GetLocation());
-    std::string multidex_suffix = DexFileLoader::GetMultiDexSuffix(dex->GetLocation());
-    std::string old_name = base_location + "-old" + multidex_suffix;
-    info.AddMethodIndex(Hotness::kFlagHot,
-                        old_name,
-                        dex->GetLocationChecksum(),
-                        /* method_idx */ 0,
-                        dex->NumMethodIds());
-  }
-
-  // Add a method index using the location we want to rename to.
-  // This will cause the rename to fail because an existing entry would already have that name.
-  info.AddMethodIndex(Hotness::kFlagHot,
-                      dex_files[0]->GetLocation(),
-                      /* checksum */ 123,
-                      /* method_idx */ 0,
-                      dex_files[0]->NumMethodIds());
-
-  ASSERT_FALSE(info.UpdateProfileKeys(dex_files));
-}
-
-TEST_F(ProfileCompilationInfoTest, FilteredLoading) {
-  ScratchFile profile;
-
-  ProfileCompilationInfo saved_info;
-  ProfileCompilationInfo::OfflineProfileMethodInfo pmi = GetOfflineProfileMethodInfo();
-
-  // Add methods with inline caches.
-  for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
-    // Add a method which is part of the same dex file as one of the class from the inline caches.
-    ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &saved_info));
-    ASSERT_TRUE(AddMethod("dex_location2", /* checksum */ 2, method_idx, pmi, &saved_info));
-    // Add a method which is outside the set of dex files.
-    ASSERT_TRUE(AddMethod("dex_location4", /* checksum */ 4, method_idx, pmi, &saved_info));
-  }
-
-  ASSERT_TRUE(saved_info.Save(GetFd(profile)));
-  ASSERT_EQ(0, profile.GetFile()->Flush());
-
-  // Check that we get back what we saved.
-  ProfileCompilationInfo loaded_info;
-  ASSERT_TRUE(profile.GetFile()->ResetOffset());
-
-  // Filter out dex locations. Keep only dex_location1 and dex_location3.
-  ProfileCompilationInfo::ProfileLoadFilterFn filter_fn =
-      [](const std::string& dex_location, uint32_t checksum) -> bool {
-          return (dex_location == "dex_location1" && checksum == 1)
-              || (dex_location == "dex_location3" && checksum == 3);
-        };
-  ASSERT_TRUE(loaded_info.Load(GetFd(profile), true, filter_fn));
-
-  // Verify that we filtered out locations during load.
-
-  // Dex location 2 and 4 should have been filtered out
-  for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
-    ASSERT_TRUE(nullptr == loaded_info.GetMethod("dex_location2", /* checksum */ 2, method_idx));
-    ASSERT_TRUE(nullptr == loaded_info.GetMethod("dex_location4", /* checksum */ 4, method_idx));
-  }
-
-  // Dex location 1 should have all all the inline caches referencing dex location 2 set to
-  // missing types.
-  for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
-    // The methods for dex location 1 should be in the profile data.
-    std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi1 =
-      loaded_info.GetMethod("dex_location1", /* checksum */ 1, /* method_idx */ method_idx);
-    ASSERT_TRUE(loaded_pmi1 != nullptr);
-
-    // Verify the inline cache.
-    // Everything should be as constructed by GetOfflineProfileMethodInfo with the exception
-    // of the inline caches referring types from dex_location2.
-    // These should be set to IsMissingType.
-    ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
-
-    // Monomorphic types should remain the same as dex_location1 was kept.
-    for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) {
-      ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
-      dex_pc_data.AddClass(0, dex::TypeIndex(0));
-      ic_map->Put(dex_pc, dex_pc_data);
-    }
-    // Polymorphic inline cache should have been transformed to IsMissingType due to
-    // the removal of dex_location2.
-    for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) {
-      ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
-      dex_pc_data.SetIsMissingTypes();
-      ic_map->Put(dex_pc, dex_pc_data);
-    }
-
-    // Megamorphic are not affected by removal of dex files.
-    for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) {
-      ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
-      dex_pc_data.SetIsMegamorphic();
-      ic_map->Put(dex_pc, dex_pc_data);
-    }
-    // Missing types are not affected be removal of dex files.
-    for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) {
-      ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
-      dex_pc_data.SetIsMissingTypes();
-      ic_map->Put(dex_pc, dex_pc_data);
-    }
-
-    ProfileCompilationInfo::OfflineProfileMethodInfo expected_pmi(ic_map);
-
-    // The dex references should not have  dex_location2 in the list.
-    expected_pmi.dex_references.emplace_back("dex_location1", /* checksum */1, kMaxMethodIds);
-    expected_pmi.dex_references.emplace_back("dex_location3", /* checksum */3, kMaxMethodIds);
-
-    // Now check that we get back what we expect.
-    ASSERT_TRUE(*loaded_pmi1 == expected_pmi);
-  }
-}
-
-TEST_F(ProfileCompilationInfoTest, FilteredLoadingRemoveAll) {
-  ScratchFile profile;
-
-  ProfileCompilationInfo saved_info;
-  ProfileCompilationInfo::OfflineProfileMethodInfo pmi = GetOfflineProfileMethodInfo();
-
-  // Add methods with inline caches.
-  for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
-    // Add a method which is part of the same dex file as one of the class from the inline caches.
-    ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &saved_info));
-    ASSERT_TRUE(AddMethod("dex_location2", /* checksum */ 2, method_idx, pmi, &saved_info));
-    // Add a method which is outside the set of dex files.
-    ASSERT_TRUE(AddMethod("dex_location4", /* checksum */ 4, method_idx, pmi, &saved_info));
-  }
-
-  ASSERT_TRUE(saved_info.Save(GetFd(profile)));
-  ASSERT_EQ(0, profile.GetFile()->Flush());
-
-  // Check that we get back what we saved.
-  ProfileCompilationInfo loaded_info;
-  ASSERT_TRUE(profile.GetFile()->ResetOffset());
-
-  // Remove all elements.
-  ProfileCompilationInfo::ProfileLoadFilterFn filter_fn =
-      [](const std::string&, uint32_t) -> bool { return false; };
-  ASSERT_TRUE(loaded_info.Load(GetFd(profile), true, filter_fn));
-
-  // Verify that we filtered out everything.
-  ASSERT_TRUE(IsEmpty(loaded_info));
-}
-
-TEST_F(ProfileCompilationInfoTest, FilteredLoadingKeepAll) {
-  ScratchFile profile;
-
-  ProfileCompilationInfo saved_info;
-  ProfileCompilationInfo::OfflineProfileMethodInfo pmi = GetOfflineProfileMethodInfo();
-
-  // Add methods with inline caches.
-  for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
-    // Add a method which is part of the same dex file as one of the
-    // class from the inline caches.
-    ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &saved_info));
-    // Add a method which is outside the set of dex files.
-    ASSERT_TRUE(AddMethod("dex_location4", /* checksum */ 4, method_idx, pmi, &saved_info));
-  }
-
-  ASSERT_TRUE(saved_info.Save(GetFd(profile)));
-  ASSERT_EQ(0, profile.GetFile()->Flush());
-
-  // Check that we get back what we saved.
-  ProfileCompilationInfo loaded_info;
-  ASSERT_TRUE(profile.GetFile()->ResetOffset());
-
-  // Keep all elements.
-  ProfileCompilationInfo::ProfileLoadFilterFn filter_fn =
-      [](const std::string&, uint32_t) -> bool { return true; };
-  ASSERT_TRUE(loaded_info.Load(GetFd(profile), true, filter_fn));
-
-
-  ASSERT_TRUE(loaded_info.Equals(saved_info));
-
-  for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
-    std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi1 =
-        loaded_info.GetMethod("dex_location1", /* checksum */ 1, method_idx);
-    ASSERT_TRUE(loaded_pmi1 != nullptr);
-    ASSERT_TRUE(*loaded_pmi1 == pmi);
-  }
-  for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
-    std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi2 =
-        loaded_info.GetMethod("dex_location4", /* checksum */ 4, method_idx);
-    ASSERT_TRUE(loaded_pmi2 != nullptr);
-    ASSERT_TRUE(*loaded_pmi2 == pmi);
-  }
-}
-
-// Regression test: we were failing to do a filtering loading when the filtered dex file
-// contained profiled classes.
-TEST_F(ProfileCompilationInfoTest, FilteredLoadingWithClasses) {
-  ScratchFile profile;
-
-  // Save a profile with 2 dex files containing just classes.
-  ProfileCompilationInfo saved_info;
-  uint16_t item_count = 1000;
-  for (uint16_t i = 0; i < item_count; i++) {
-    ASSERT_TRUE(AddClass("dex_location1", /* checksum */ 1, dex::TypeIndex(i), &saved_info));
-    ASSERT_TRUE(AddClass("dex_location2", /* checksum */ 2, dex::TypeIndex(i), &saved_info));
-  }
-
-  ASSERT_TRUE(saved_info.Save(GetFd(profile)));
-  ASSERT_EQ(0, profile.GetFile()->Flush());
-
-
-  // Filter out dex locations: kepp only dex_location2.
-  ProfileCompilationInfo loaded_info;
-  ASSERT_TRUE(profile.GetFile()->ResetOffset());
-  ProfileCompilationInfo::ProfileLoadFilterFn filter_fn =
-      [](const std::string& dex_location, uint32_t checksum) -> bool {
-          return (dex_location == "dex_location2" && checksum == 2);
-        };
-  ASSERT_TRUE(loaded_info.Load(GetFd(profile), true, filter_fn));
-
-  // Compute the expectation.
-  ProfileCompilationInfo expected_info;
-  for (uint16_t i = 0; i < item_count; i++) {
-    ASSERT_TRUE(AddClass("dex_location2", /* checksum */ 2, dex::TypeIndex(i), &expected_info));
-  }
-
-  // Validate the expectation.
-  ASSERT_TRUE(loaded_info.Equals(expected_info));
-}
-
-}  // namespace art
diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc
index 53f4864..618fde8 100644
--- a/runtime/jit/profile_saver.cc
+++ b/runtime/jit/profile_saver.cc
@@ -37,8 +37,9 @@
 #include "gc/collector_type.h"
 #include "gc/gc_cause.h"
 #include "gc/scoped_gc_critical_section.h"
-#include "jit/profile_compilation_info.h"
+#include "jit/profiling_info.h"
 #include "oat_file_manager.h"
+#include "profile/profile_compilation_info.h"
 #include "scoped_thread_state_change-inl.h"
 
 namespace art {
@@ -46,6 +47,10 @@
 ProfileSaver* ProfileSaver::instance_ = nullptr;
 pthread_t ProfileSaver::profiler_pthread_ = 0U;
 
+static_assert(ProfileCompilationInfo::kIndividualInlineCacheSize ==
+              InlineCache::kIndividualCacheSize,
+              "InlineCache and ProfileCompilationInfo do not agree on kIndividualCacheSize");
+
 // At what priority to schedule the saver threads. 9 is the lowest foreground priority on device.
 static constexpr int kProfileSaverPthreadPriority = 9;
 
diff --git a/runtime/jit/profile_saver.h b/runtime/jit/profile_saver.h
index afbb3c1..02c8cd1 100644
--- a/runtime/jit/profile_saver.h
+++ b/runtime/jit/profile_saver.h
@@ -21,7 +21,7 @@
 #include "base/safe_map.h"
 #include "dex/method_reference.h"
 #include "jit_code_cache.h"
-#include "profile_compilation_info.h"
+#include "profile/profile_compilation_info.h"
 #include "profile_saver_options.h"
 
 namespace art {