Home | History | Annotate | Download | only in jit
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <gtest/gtest.h>
     18 #include <stdio.h>
     19 
     20 #include "art_method-inl.h"
     21 #include "base/unix_file/fd_file.h"
     22 #include "class_linker-inl.h"
     23 #include "common_runtime_test.h"
     24 #include "dex/dex_file.h"
     25 #include "dex/dex_file_loader.h"
     26 #include "dex/method_reference.h"
     27 #include "dex/type_reference.h"
     28 #include "handle_scope-inl.h"
     29 #include "jit/profile_compilation_info.h"
     30 #include "linear_alloc.h"
     31 #include "mirror/class-inl.h"
     32 #include "mirror/class_loader.h"
     33 #include "scoped_thread_state_change-inl.h"
     34 #include "ziparchive/zip_writer.h"
     35 
     36 namespace art {
     37 
     38 using Hotness = ProfileCompilationInfo::MethodHotness;
     39 
     40 static constexpr size_t kMaxMethodIds = 65535;
     41 
     42 class ProfileCompilationInfoTest : public CommonRuntimeTest {
     43  public:
     44   void PostRuntimeCreate() OVERRIDE {
     45     allocator_.reset(new ArenaAllocator(Runtime::Current()->GetArenaPool()));
     46   }
     47 
     48  protected:
     49   std::vector<ArtMethod*> GetVirtualMethods(jobject class_loader,
     50                                             const std::string& clazz) {
     51     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
     52     Thread* self = Thread::Current();
     53     ScopedObjectAccess soa(self);
     54     StackHandleScope<1> hs(self);
     55     Handle<mirror::ClassLoader> h_loader(
     56         hs.NewHandle(self->DecodeJObject(class_loader)->AsClassLoader()));
     57     mirror::Class* klass = class_linker->FindClass(self, clazz.c_str(), h_loader);
     58 
     59     const auto pointer_size = class_linker->GetImagePointerSize();
     60     std::vector<ArtMethod*> methods;
     61     for (auto& m : klass->GetVirtualMethods(pointer_size)) {
     62       methods.push_back(&m);
     63     }
     64     return methods;
     65   }
     66 
     67   bool AddMethod(const std::string& dex_location,
     68                  uint32_t checksum,
     69                  uint16_t method_index,
     70                  ProfileCompilationInfo* info) {
     71     return info->AddMethodIndex(Hotness::kFlagHot,
     72                                 dex_location,
     73                                 checksum,
     74                                 method_index,
     75                                 kMaxMethodIds);
     76   }
     77 
     78   bool AddMethod(const std::string& dex_location,
     79                  uint32_t checksum,
     80                  uint16_t method_index,
     81                  const ProfileCompilationInfo::OfflineProfileMethodInfo& pmi,
     82                  ProfileCompilationInfo* info) {
     83     return info->AddMethod(
     84         dex_location, checksum, method_index, kMaxMethodIds, pmi, Hotness::kFlagPostStartup);
     85   }
     86 
     87   bool AddClass(const std::string& dex_location,
     88                 uint32_t checksum,
     89                 dex::TypeIndex type_index,
     90                 ProfileCompilationInfo* info) {
     91     DexCacheResolvedClasses classes(dex_location, dex_location, checksum, kMaxMethodIds);
     92     classes.AddClass(type_index);
     93     return info->AddClasses({classes});
     94   }
     95 
     96   uint32_t GetFd(const ScratchFile& file) {
     97     return static_cast<uint32_t>(file.GetFd());
     98   }
     99 
    100   bool SaveProfilingInfo(
    101       const std::string& filename,
    102       const std::vector<ArtMethod*>& methods,
    103       const std::set<DexCacheResolvedClasses>& resolved_classes,
    104       Hotness::Flag flags) {
    105     ProfileCompilationInfo info;
    106     std::vector<ProfileMethodInfo> profile_methods;
    107     ScopedObjectAccess soa(Thread::Current());
    108     for (ArtMethod* method : methods) {
    109       profile_methods.emplace_back(
    110           MethodReference(method->GetDexFile(), method->GetDexMethodIndex()));
    111     }
    112     if (!info.AddMethods(profile_methods, flags) || !info.AddClasses(resolved_classes)) {
    113       return false;
    114     }
    115     if (info.GetNumberOfMethods() != profile_methods.size()) {
    116       return false;
    117     }
    118     ProfileCompilationInfo file_profile;
    119     if (!file_profile.Load(filename, false)) {
    120       return false;
    121     }
    122     if (!info.MergeWith(file_profile)) {
    123       return false;
    124     }
    125 
    126     return info.Save(filename, nullptr);
    127   }
    128 
    129   // Saves the given art methods to a profile backed by 'filename' and adds
    130   // some fake inline caches to it. The added inline caches are returned in
    131   // the out map `profile_methods_map`.
    132   bool SaveProfilingInfoWithFakeInlineCaches(
    133       const std::string& filename,
    134       const std::vector<ArtMethod*>& methods,
    135       Hotness::Flag flags,
    136       /*out*/ SafeMap<ArtMethod*, ProfileMethodInfo>* profile_methods_map) {
    137     ProfileCompilationInfo info;
    138     std::vector<ProfileMethodInfo> profile_methods;
    139     ScopedObjectAccess soa(Thread::Current());
    140     for (ArtMethod* method : methods) {
    141       std::vector<ProfileMethodInfo::ProfileInlineCache> caches;
    142       // Monomorphic
    143       for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) {
    144         std::vector<TypeReference> classes;
    145         classes.emplace_back(method->GetDexFile(), dex::TypeIndex(0));
    146         caches.emplace_back(dex_pc, /*is_missing_types*/false, classes);
    147       }
    148       // Polymorphic
    149       for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) {
    150         std::vector<TypeReference> classes;
    151         for (uint16_t k = 0; k < InlineCache::kIndividualCacheSize / 2; k++) {
    152           classes.emplace_back(method->GetDexFile(), dex::TypeIndex(k));
    153         }
    154         caches.emplace_back(dex_pc, /*is_missing_types*/false, classes);
    155       }
    156       // Megamorphic
    157       for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) {
    158         std::vector<TypeReference> classes;
    159         for (uint16_t k = 0; k < 2 * InlineCache::kIndividualCacheSize; k++) {
    160           classes.emplace_back(method->GetDexFile(), dex::TypeIndex(k));
    161         }
    162         caches.emplace_back(dex_pc, /*is_missing_types*/false, classes);
    163       }
    164       // Missing types
    165       for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) {
    166         std::vector<TypeReference> classes;
    167         caches.emplace_back(dex_pc, /*is_missing_types*/true, classes);
    168       }
    169       ProfileMethodInfo pmi(MethodReference(method->GetDexFile(),
    170                                             method->GetDexMethodIndex()),
    171                             caches);
    172       profile_methods.push_back(pmi);
    173       profile_methods_map->Put(method, pmi);
    174     }
    175 
    176     if (!info.AddMethods(profile_methods, flags)
    177         || info.GetNumberOfMethods() != profile_methods.size()) {
    178       return false;
    179     }
    180     return info.Save(filename, nullptr);
    181   }
    182 
    183   // Creates an inline cache which will be destructed at the end of the test.
    184   ProfileCompilationInfo::InlineCacheMap* CreateInlineCacheMap() {
    185     used_inline_caches.emplace_back(new ProfileCompilationInfo::InlineCacheMap(
    186         std::less<uint16_t>(), allocator_->Adapter(kArenaAllocProfile)));
    187     return used_inline_caches.back().get();
    188   }
    189 
    190   ProfileCompilationInfo::OfflineProfileMethodInfo ConvertProfileMethodInfo(
    191         const ProfileMethodInfo& pmi) {
    192     ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
    193     ProfileCompilationInfo::OfflineProfileMethodInfo offline_pmi(ic_map);
    194     SafeMap<DexFile*, uint8_t> dex_map;  // dex files to profile index
    195     for (const auto& inline_cache : pmi.inline_caches) {
    196       ProfileCompilationInfo::DexPcData& dex_pc_data =
    197           ic_map->FindOrAdd(
    198               inline_cache.dex_pc, ProfileCompilationInfo::DexPcData(allocator_.get()))->second;
    199       if (inline_cache.is_missing_types) {
    200         dex_pc_data.SetIsMissingTypes();
    201       }
    202       for (const auto& class_ref : inline_cache.classes) {
    203         uint8_t dex_profile_index = dex_map.FindOrAdd(const_cast<DexFile*>(class_ref.dex_file),
    204                                                       static_cast<uint8_t>(dex_map.size()))->second;
    205         dex_pc_data.AddClass(dex_profile_index, class_ref.TypeIndex());
    206         if (dex_profile_index >= offline_pmi.dex_references.size()) {
    207           // This is a new dex.
    208           const std::string& dex_key = ProfileCompilationInfo::GetProfileDexFileKey(
    209               class_ref.dex_file->GetLocation());
    210           offline_pmi.dex_references.emplace_back(dex_key,
    211                                                   class_ref.dex_file->GetLocationChecksum(),
    212                                                   class_ref.dex_file->NumMethodIds());
    213         }
    214       }
    215     }
    216     return offline_pmi;
    217   }
    218 
    219   // Creates an offline profile used for testing inline caches.
    220   ProfileCompilationInfo::OfflineProfileMethodInfo GetOfflineProfileMethodInfo() {
    221     ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
    222 
    223     // Monomorphic
    224     for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) {
    225       ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
    226       dex_pc_data.AddClass(0, dex::TypeIndex(0));
    227       ic_map->Put(dex_pc, dex_pc_data);
    228     }
    229     // Polymorphic
    230     for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) {
    231       ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
    232       dex_pc_data.AddClass(0, dex::TypeIndex(0));
    233       dex_pc_data.AddClass(1, dex::TypeIndex(1));
    234       dex_pc_data.AddClass(2, dex::TypeIndex(2));
    235 
    236       ic_map->Put(dex_pc, dex_pc_data);
    237     }
    238     // Megamorphic
    239     for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) {
    240       ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
    241       dex_pc_data.SetIsMegamorphic();
    242       ic_map->Put(dex_pc, dex_pc_data);
    243     }
    244     // Missing types
    245     for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) {
    246       ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
    247       dex_pc_data.SetIsMissingTypes();
    248       ic_map->Put(dex_pc, dex_pc_data);
    249     }
    250 
    251     ProfileCompilationInfo::OfflineProfileMethodInfo pmi(ic_map);
    252 
    253     pmi.dex_references.emplace_back("dex_location1", /* checksum */1, kMaxMethodIds);
    254     pmi.dex_references.emplace_back("dex_location2", /* checksum */2, kMaxMethodIds);
    255     pmi.dex_references.emplace_back("dex_location3", /* checksum */3, kMaxMethodIds);
    256 
    257     return pmi;
    258   }
    259 
    260   void MakeMegamorphic(/*out*/ProfileCompilationInfo::OfflineProfileMethodInfo* pmi) {
    261     ProfileCompilationInfo::InlineCacheMap* ic_map =
    262         const_cast<ProfileCompilationInfo::InlineCacheMap*>(pmi->inline_caches);
    263     for (auto it : *ic_map) {
    264       for (uint16_t k = 0; k <= 2 * InlineCache::kIndividualCacheSize; k++) {
    265         it.second.AddClass(0, dex::TypeIndex(k));
    266       }
    267     }
    268   }
    269 
    270   void SetIsMissingTypes(/*out*/ProfileCompilationInfo::OfflineProfileMethodInfo* pmi) {
    271     ProfileCompilationInfo::InlineCacheMap* ic_map =
    272         const_cast<ProfileCompilationInfo::InlineCacheMap*>(pmi->inline_caches);
    273     for (auto it : *ic_map) {
    274       it.second.SetIsMissingTypes();
    275     }
    276   }
    277 
    278   void TestProfileLoadFromZip(const char* zip_entry,
    279                               size_t zip_flags,
    280                               bool should_succeed,
    281                               bool should_succeed_with_empty_profile = false) {
    282     // Create a valid profile.
    283     ScratchFile profile;
    284     ProfileCompilationInfo saved_info;
    285     for (uint16_t i = 0; i < 10; i++) {
    286       ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, /* method_idx */ i, &saved_info));
    287       ASSERT_TRUE(AddMethod("dex_location2", /* checksum */ 2, /* method_idx */ i, &saved_info));
    288     }
    289     ASSERT_TRUE(saved_info.Save(GetFd(profile)));
    290     ASSERT_EQ(0, profile.GetFile()->Flush());
    291 
    292     // Prepare the profile content for zipping.
    293     ASSERT_TRUE(profile.GetFile()->ResetOffset());
    294     std::vector<uint8_t> data(profile.GetFile()->GetLength());
    295     ASSERT_TRUE(profile.GetFile()->ReadFully(data.data(), data.size()));
    296 
    297     // Zip the profile content.
    298     ScratchFile zip;
    299     FILE* file = fopen(zip.GetFile()->GetPath().c_str(), "wb");
    300     ZipWriter writer(file);
    301     writer.StartEntry(zip_entry, zip_flags);
    302     writer.WriteBytes(data.data(), data.size());
    303     writer.FinishEntry();
    304     writer.Finish();
    305     fflush(file);
    306     fclose(file);
    307 
    308     // Verify loading from the zip archive.
    309     ProfileCompilationInfo loaded_info;
    310     ASSERT_TRUE(zip.GetFile()->ResetOffset());
    311     ASSERT_EQ(should_succeed, loaded_info.Load(zip.GetFile()->GetPath(), false));
    312     if (should_succeed) {
    313       if (should_succeed_with_empty_profile) {
    314         ASSERT_TRUE(loaded_info.IsEmpty());
    315       } else {
    316         ASSERT_TRUE(loaded_info.Equals(saved_info));
    317       }
    318     }
    319   }
    320 
    321   bool IsEmpty(const ProfileCompilationInfo& info) {
    322     return info.IsEmpty();
    323   }
    324 
    325   // Cannot sizeof the actual arrays so hard code the values here.
    326   // They should not change anyway.
    327   static constexpr int kProfileMagicSize = 4;
    328   static constexpr int kProfileVersionSize = 4;
    329 
    330   std::unique_ptr<ArenaAllocator> allocator_;
    331 
    332   // Cache of inline caches generated during tests.
    333   // This makes it easier to pass data between different utilities and ensure that
    334   // caches are destructed at the end of the test.
    335   std::vector<std::unique_ptr<ProfileCompilationInfo::InlineCacheMap>> used_inline_caches;
    336 };
    337 
    338 TEST_F(ProfileCompilationInfoTest, SaveArtMethods) {
    339   ScratchFile profile;
    340 
    341   Thread* self = Thread::Current();
    342   jobject class_loader;
    343   {
    344     ScopedObjectAccess soa(self);
    345     class_loader = LoadDex("ProfileTestMultiDex");
    346   }
    347   ASSERT_NE(class_loader, nullptr);
    348 
    349   // Save virtual methods from Main.
    350   std::set<DexCacheResolvedClasses> resolved_classes;
    351   std::vector<ArtMethod*> main_methods = GetVirtualMethods(class_loader, "LMain;");
    352   ASSERT_TRUE(SaveProfilingInfo(
    353       profile.GetFilename(), main_methods, resolved_classes, Hotness::kFlagPostStartup));
    354 
    355   // Check that what we saved is in the profile.
    356   ProfileCompilationInfo info1;
    357   ASSERT_TRUE(info1.Load(GetFd(profile)));
    358   ASSERT_EQ(info1.GetNumberOfMethods(), main_methods.size());
    359   {
    360     ScopedObjectAccess soa(self);
    361     for (ArtMethod* m : main_methods) {
    362       Hotness h = info1.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex()));
    363       ASSERT_TRUE(h.IsHot());
    364       ASSERT_TRUE(h.IsPostStartup());
    365     }
    366   }
    367 
    368   // Save virtual methods from Second.
    369   std::vector<ArtMethod*> second_methods = GetVirtualMethods(class_loader, "LSecond;");
    370   ASSERT_TRUE(SaveProfilingInfo(
    371     profile.GetFilename(), second_methods, resolved_classes, Hotness::kFlagStartup));
    372 
    373   // Check that what we saved is in the profile (methods form Main and Second).
    374   ProfileCompilationInfo info2;
    375   ASSERT_TRUE(profile.GetFile()->ResetOffset());
    376   ASSERT_TRUE(info2.Load(GetFd(profile)));
    377   ASSERT_EQ(info2.GetNumberOfMethods(), main_methods.size() + second_methods.size());
    378   {
    379     ScopedObjectAccess soa(self);
    380     for (ArtMethod* m : main_methods) {
    381       Hotness h = info2.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex()));
    382       ASSERT_TRUE(h.IsHot());
    383       ASSERT_TRUE(h.IsPostStartup());
    384     }
    385     for (ArtMethod* m : second_methods) {
    386       Hotness h = info2.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex()));
    387       ASSERT_TRUE(h.IsHot());
    388       ASSERT_TRUE(h.IsStartup());
    389     }
    390   }
    391 }
    392 
    393 TEST_F(ProfileCompilationInfoTest, SaveFd) {
    394   ScratchFile profile;
    395 
    396   ProfileCompilationInfo saved_info;
    397   // Save a few methods.
    398   for (uint16_t i = 0; i < 10; i++) {
    399     ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, /* method_idx */ i, &saved_info));
    400     ASSERT_TRUE(AddMethod("dex_location2", /* checksum */ 2, /* method_idx */ i, &saved_info));
    401   }
    402   ASSERT_TRUE(saved_info.Save(GetFd(profile)));
    403   ASSERT_EQ(0, profile.GetFile()->Flush());
    404 
    405   // Check that we get back what we saved.
    406   ProfileCompilationInfo loaded_info;
    407   ASSERT_TRUE(profile.GetFile()->ResetOffset());
    408   ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
    409   ASSERT_TRUE(loaded_info.Equals(saved_info));
    410 
    411   // Save more methods.
    412   for (uint16_t i = 0; i < 100; i++) {
    413     ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, /* method_idx */ i, &saved_info));
    414     ASSERT_TRUE(AddMethod("dex_location2", /* checksum */ 2, /* method_idx */ i, &saved_info));
    415     ASSERT_TRUE(AddMethod("dex_location3", /* checksum */ 3, /* method_idx */ i, &saved_info));
    416   }
    417   ASSERT_TRUE(profile.GetFile()->ResetOffset());
    418   ASSERT_TRUE(saved_info.Save(GetFd(profile)));
    419   ASSERT_EQ(0, profile.GetFile()->Flush());
    420 
    421   // Check that we get back everything we saved.
    422   ProfileCompilationInfo loaded_info2;
    423   ASSERT_TRUE(profile.GetFile()->ResetOffset());
    424   ASSERT_TRUE(loaded_info2.Load(GetFd(profile)));
    425   ASSERT_TRUE(loaded_info2.Equals(saved_info));
    426 }
    427 
    428 TEST_F(ProfileCompilationInfoTest, AddMethodsAndClassesFail) {
    429   ScratchFile profile;
    430 
    431   ProfileCompilationInfo info;
    432   ASSERT_TRUE(AddMethod("dex_location", /* checksum */ 1, /* method_idx */ 1, &info));
    433   // Trying to add info for an existing file but with a different checksum.
    434   ASSERT_FALSE(AddMethod("dex_location", /* checksum */ 2, /* method_idx */ 2, &info));
    435 }
    436 
    437 TEST_F(ProfileCompilationInfoTest, MergeFail) {
    438   ScratchFile profile;
    439 
    440   ProfileCompilationInfo info1;
    441   ASSERT_TRUE(AddMethod("dex_location", /* checksum */ 1, /* method_idx */ 1, &info1));
    442   // Use the same file, change the checksum.
    443   ProfileCompilationInfo info2;
    444   ASSERT_TRUE(AddMethod("dex_location", /* checksum */ 2, /* method_idx */ 2, &info2));
    445 
    446   ASSERT_FALSE(info1.MergeWith(info2));
    447 }
    448 
    449 
    450 TEST_F(ProfileCompilationInfoTest, MergeFdFail) {
    451   ScratchFile profile;
    452 
    453   ProfileCompilationInfo info1;
    454   ASSERT_TRUE(AddMethod("dex_location", /* checksum */ 1, /* method_idx */ 1, &info1));
    455   // Use the same file, change the checksum.
    456   ProfileCompilationInfo info2;
    457   ASSERT_TRUE(AddMethod("dex_location", /* checksum */ 2, /* method_idx */ 2, &info2));
    458 
    459   ASSERT_TRUE(info1.Save(profile.GetFd()));
    460   ASSERT_EQ(0, profile.GetFile()->Flush());
    461   ASSERT_TRUE(profile.GetFile()->ResetOffset());
    462 
    463   ASSERT_FALSE(info2.Load(profile.GetFd()));
    464 }
    465 
    466 TEST_F(ProfileCompilationInfoTest, SaveMaxMethods) {
    467   ScratchFile profile;
    468 
    469   ProfileCompilationInfo saved_info;
    470   // Save the maximum number of methods
    471   for (uint16_t i = 0; i < std::numeric_limits<uint16_t>::max(); i++) {
    472     ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, /* method_idx */ i, &saved_info));
    473     ASSERT_TRUE(AddMethod("dex_location2", /* checksum */ 2, /* method_idx */ i, &saved_info));
    474   }
    475   // Save the maximum number of classes
    476   for (uint16_t i = 0; i < std::numeric_limits<uint16_t>::max(); i++) {
    477     ASSERT_TRUE(AddClass("dex_location1", /* checksum */ 1, dex::TypeIndex(i), &saved_info));
    478     ASSERT_TRUE(AddClass("dex_location2", /* checksum */ 2, dex::TypeIndex(i), &saved_info));
    479   }
    480 
    481   ASSERT_TRUE(saved_info.Save(GetFd(profile)));
    482   ASSERT_EQ(0, profile.GetFile()->Flush());
    483 
    484   // Check that we get back what we saved.
    485   ProfileCompilationInfo loaded_info;
    486   ASSERT_TRUE(profile.GetFile()->ResetOffset());
    487   ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
    488   ASSERT_TRUE(loaded_info.Equals(saved_info));
    489 }
    490 
    491 TEST_F(ProfileCompilationInfoTest, SaveEmpty) {
    492   ScratchFile profile;
    493 
    494   ProfileCompilationInfo saved_info;
    495   ASSERT_TRUE(saved_info.Save(GetFd(profile)));
    496   ASSERT_EQ(0, profile.GetFile()->Flush());
    497 
    498   // Check that we get back what we saved.
    499   ProfileCompilationInfo loaded_info;
    500   ASSERT_TRUE(profile.GetFile()->ResetOffset());
    501   ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
    502   ASSERT_TRUE(loaded_info.Equals(saved_info));
    503 }
    504 
    505 TEST_F(ProfileCompilationInfoTest, LoadEmpty) {
    506   ScratchFile profile;
    507 
    508   ProfileCompilationInfo empty_info;
    509 
    510   ProfileCompilationInfo loaded_info;
    511   ASSERT_TRUE(profile.GetFile()->ResetOffset());
    512   ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
    513   ASSERT_TRUE(loaded_info.Equals(empty_info));
    514 }
    515 
    516 TEST_F(ProfileCompilationInfoTest, BadMagic) {
    517   ScratchFile profile;
    518   uint8_t buffer[] = { 1, 2, 3, 4 };
    519   ASSERT_TRUE(profile.GetFile()->WriteFully(buffer, sizeof(buffer)));
    520   ProfileCompilationInfo loaded_info;
    521   ASSERT_TRUE(profile.GetFile()->ResetOffset());
    522   ASSERT_FALSE(loaded_info.Load(GetFd(profile)));
    523 }
    524 
    525 TEST_F(ProfileCompilationInfoTest, BadVersion) {
    526   ScratchFile profile;
    527 
    528   ASSERT_TRUE(profile.GetFile()->WriteFully(
    529       ProfileCompilationInfo::kProfileMagic, kProfileMagicSize));
    530   uint8_t version[] = { 'v', 'e', 'r', 's', 'i', 'o', 'n' };
    531   ASSERT_TRUE(profile.GetFile()->WriteFully(version, sizeof(version)));
    532   ASSERT_EQ(0, profile.GetFile()->Flush());
    533 
    534   ProfileCompilationInfo loaded_info;
    535   ASSERT_TRUE(profile.GetFile()->ResetOffset());
    536   ASSERT_FALSE(loaded_info.Load(GetFd(profile)));
    537 }
    538 
    539 TEST_F(ProfileCompilationInfoTest, Incomplete) {
    540   ScratchFile profile;
    541   ASSERT_TRUE(profile.GetFile()->WriteFully(
    542       ProfileCompilationInfo::kProfileMagic, kProfileMagicSize));
    543   ASSERT_TRUE(profile.GetFile()->WriteFully(
    544       ProfileCompilationInfo::kProfileVersion, kProfileVersionSize));
    545   // Write that we have at least one line.
    546   uint8_t line_number[] = { 0, 1 };
    547   ASSERT_TRUE(profile.GetFile()->WriteFully(line_number, sizeof(line_number)));
    548   ASSERT_EQ(0, profile.GetFile()->Flush());
    549 
    550   ProfileCompilationInfo loaded_info;
    551   ASSERT_TRUE(profile.GetFile()->ResetOffset());
    552   ASSERT_FALSE(loaded_info.Load(GetFd(profile)));
    553 }
    554 
    555 TEST_F(ProfileCompilationInfoTest, TooLongDexLocation) {
    556   ScratchFile profile;
    557   ASSERT_TRUE(profile.GetFile()->WriteFully(
    558       ProfileCompilationInfo::kProfileMagic, kProfileMagicSize));
    559   ASSERT_TRUE(profile.GetFile()->WriteFully(
    560       ProfileCompilationInfo::kProfileVersion, kProfileVersionSize));
    561   // Write that we have at least one line.
    562   uint8_t line_number[] = { 0, 1 };
    563   ASSERT_TRUE(profile.GetFile()->WriteFully(line_number, sizeof(line_number)));
    564 
    565   // dex_location_size, methods_size, classes_size, checksum.
    566   // Dex location size is too big and should be rejected.
    567   uint8_t line[] = { 255, 255, 0, 1, 0, 1, 0, 0, 0, 0 };
    568   ASSERT_TRUE(profile.GetFile()->WriteFully(line, sizeof(line)));
    569   ASSERT_EQ(0, profile.GetFile()->Flush());
    570 
    571   ProfileCompilationInfo loaded_info;
    572   ASSERT_TRUE(profile.GetFile()->ResetOffset());
    573   ASSERT_FALSE(loaded_info.Load(GetFd(profile)));
    574 }
    575 
    576 TEST_F(ProfileCompilationInfoTest, UnexpectedContent) {
    577   ScratchFile profile;
    578 
    579   ProfileCompilationInfo saved_info;
    580   // Save the maximum number of methods
    581   for (uint16_t i = 0; i < 10; i++) {
    582     ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, /* method_idx */ i, &saved_info));
    583   }
    584   ASSERT_TRUE(saved_info.Save(GetFd(profile)));
    585 
    586   uint8_t random_data[] = { 1, 2, 3};
    587   ASSERT_TRUE(profile.GetFile()->WriteFully(random_data, sizeof(random_data)));
    588 
    589   ASSERT_EQ(0, profile.GetFile()->Flush());
    590 
    591   // Check that we fail because of unexpected data at the end of the file.
    592   ProfileCompilationInfo loaded_info;
    593   ASSERT_TRUE(profile.GetFile()->ResetOffset());
    594   ASSERT_FALSE(loaded_info.Load(GetFd(profile)));
    595 }
    596 
    597 TEST_F(ProfileCompilationInfoTest, SaveInlineCaches) {
    598   ScratchFile profile;
    599 
    600   ProfileCompilationInfo saved_info;
    601   ProfileCompilationInfo::OfflineProfileMethodInfo pmi = GetOfflineProfileMethodInfo();
    602 
    603   // Add methods with inline caches.
    604   for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
    605     // Add a method which is part of the same dex file as one of the
    606     // class from the inline caches.
    607     ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &saved_info));
    608     // Add a method which is outside the set of dex files.
    609     ASSERT_TRUE(AddMethod("dex_location4", /* checksum */ 4, method_idx, pmi, &saved_info));
    610   }
    611 
    612   ASSERT_TRUE(saved_info.Save(GetFd(profile)));
    613   ASSERT_EQ(0, profile.GetFile()->Flush());
    614 
    615   // Check that we get back what we saved.
    616   ProfileCompilationInfo loaded_info;
    617   ASSERT_TRUE(profile.GetFile()->ResetOffset());
    618   ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
    619 
    620   ASSERT_TRUE(loaded_info.Equals(saved_info));
    621 
    622   std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi1 =
    623       loaded_info.GetMethod("dex_location1", /* checksum */ 1, /* method_idx */ 3);
    624   ASSERT_TRUE(loaded_pmi1 != nullptr);
    625   ASSERT_TRUE(*loaded_pmi1 == pmi);
    626   std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi2 =
    627       loaded_info.GetMethod("dex_location4", /* checksum */ 4, /* method_idx */ 3);
    628   ASSERT_TRUE(loaded_pmi2 != nullptr);
    629   ASSERT_TRUE(*loaded_pmi2 == pmi);
    630 }
    631 
    632 TEST_F(ProfileCompilationInfoTest, MegamorphicInlineCaches) {
    633   ScratchFile profile;
    634 
    635   ProfileCompilationInfo saved_info;
    636   ProfileCompilationInfo::OfflineProfileMethodInfo pmi = GetOfflineProfileMethodInfo();
    637 
    638   // Add methods with inline caches.
    639   for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
    640     ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &saved_info));
    641   }
    642 
    643   ASSERT_TRUE(saved_info.Save(GetFd(profile)));
    644   ASSERT_EQ(0, profile.GetFile()->Flush());
    645 
    646   // Make the inline caches megamorphic and add them to the profile again.
    647   ProfileCompilationInfo saved_info_extra;
    648   ProfileCompilationInfo::OfflineProfileMethodInfo pmi_extra = GetOfflineProfileMethodInfo();
    649   MakeMegamorphic(&pmi_extra);
    650   for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
    651     ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &saved_info_extra));
    652   }
    653 
    654   ASSERT_TRUE(profile.GetFile()->ResetOffset());
    655   ASSERT_TRUE(saved_info_extra.Save(GetFd(profile)));
    656   ASSERT_EQ(0, profile.GetFile()->Flush());
    657 
    658   // Merge the profiles so that we have the same view as the file.
    659   ASSERT_TRUE(saved_info.MergeWith(saved_info_extra));
    660 
    661   // Check that we get back what we saved.
    662   ProfileCompilationInfo loaded_info;
    663   ASSERT_TRUE(profile.GetFile()->ResetOffset());
    664   ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
    665 
    666   ASSERT_TRUE(loaded_info.Equals(saved_info));
    667 
    668   std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi1 =
    669       loaded_info.GetMethod("dex_location1", /* checksum */ 1, /* method_idx */ 3);
    670 
    671   ASSERT_TRUE(loaded_pmi1 != nullptr);
    672   ASSERT_TRUE(*loaded_pmi1 == pmi_extra);
    673 }
    674 
    675 TEST_F(ProfileCompilationInfoTest, MissingTypesInlineCaches) {
    676   ScratchFile profile;
    677 
    678   ProfileCompilationInfo saved_info;
    679   ProfileCompilationInfo::OfflineProfileMethodInfo pmi = GetOfflineProfileMethodInfo();
    680 
    681   // Add methods with inline caches.
    682   for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
    683     ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &saved_info));
    684   }
    685 
    686   ASSERT_TRUE(saved_info.Save(GetFd(profile)));
    687   ASSERT_EQ(0, profile.GetFile()->Flush());
    688 
    689   // Make some inline caches megamorphic and add them to the profile again.
    690   ProfileCompilationInfo saved_info_extra;
    691   ProfileCompilationInfo::OfflineProfileMethodInfo pmi_extra = GetOfflineProfileMethodInfo();
    692   MakeMegamorphic(&pmi_extra);
    693   for (uint16_t method_idx = 5; method_idx < 10; method_idx++) {
    694     ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &saved_info_extra));
    695   }
    696 
    697   // Mark all inline caches with missing types and add them to the profile again.
    698   // This will verify that all inline caches (megamorphic or not) should be marked as missing types.
    699   ProfileCompilationInfo::OfflineProfileMethodInfo missing_types = GetOfflineProfileMethodInfo();
    700   SetIsMissingTypes(&missing_types);
    701   for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
    702     ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &saved_info_extra));
    703   }
    704 
    705   ASSERT_TRUE(profile.GetFile()->ResetOffset());
    706   ASSERT_TRUE(saved_info_extra.Save(GetFd(profile)));
    707   ASSERT_EQ(0, profile.GetFile()->Flush());
    708 
    709   // Merge the profiles so that we have the same view as the file.
    710   ASSERT_TRUE(saved_info.MergeWith(saved_info_extra));
    711 
    712   // Check that we get back what we saved.
    713   ProfileCompilationInfo loaded_info;
    714   ASSERT_TRUE(profile.GetFile()->ResetOffset());
    715   ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
    716 
    717   ASSERT_TRUE(loaded_info.Equals(saved_info));
    718 
    719   std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi1 =
    720       loaded_info.GetMethod("dex_location1", /* checksum */ 1, /* method_idx */ 3);
    721   ASSERT_TRUE(loaded_pmi1 != nullptr);
    722   ASSERT_TRUE(*loaded_pmi1 == pmi_extra);
    723 }
    724 
    725 TEST_F(ProfileCompilationInfoTest, SaveArtMethodsWithInlineCaches) {
    726   ScratchFile profile;
    727 
    728   Thread* self = Thread::Current();
    729   jobject class_loader;
    730   {
    731     ScopedObjectAccess soa(self);
    732     class_loader = LoadDex("ProfileTestMultiDex");
    733   }
    734   ASSERT_NE(class_loader, nullptr);
    735 
    736   // Save virtual methods from Main.
    737   std::set<DexCacheResolvedClasses> resolved_classes;
    738   std::vector<ArtMethod*> main_methods = GetVirtualMethods(class_loader, "LMain;");
    739 
    740   SafeMap<ArtMethod*, ProfileMethodInfo> profile_methods_map;
    741   ASSERT_TRUE(SaveProfilingInfoWithFakeInlineCaches(
    742       profile.GetFilename(), main_methods, Hotness::kFlagStartup, &profile_methods_map));
    743 
    744   // Check that what we saved is in the profile.
    745   ProfileCompilationInfo info;
    746   ASSERT_TRUE(info.Load(GetFd(profile)));
    747   ASSERT_EQ(info.GetNumberOfMethods(), main_methods.size());
    748   {
    749     ScopedObjectAccess soa(self);
    750     for (ArtMethod* m : main_methods) {
    751       Hotness h = info.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex()));
    752       ASSERT_TRUE(h.IsHot());
    753       ASSERT_TRUE(h.IsStartup());
    754       const ProfileMethodInfo& pmi = profile_methods_map.find(m)->second;
    755       std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> offline_pmi =
    756           info.GetMethod(m->GetDexFile()->GetLocation(),
    757                          m->GetDexFile()->GetLocationChecksum(),
    758                          m->GetDexMethodIndex());
    759       ASSERT_TRUE(offline_pmi != nullptr);
    760       ProfileCompilationInfo::OfflineProfileMethodInfo converted_pmi =
    761           ConvertProfileMethodInfo(pmi);
    762       ASSERT_EQ(converted_pmi, *offline_pmi);
    763     }
    764   }
    765 }
    766 
    767 TEST_F(ProfileCompilationInfoTest, InvalidChecksumInInlineCache) {
    768   ScratchFile profile;
    769 
    770   ProfileCompilationInfo info;
    771   ProfileCompilationInfo::OfflineProfileMethodInfo pmi1 = GetOfflineProfileMethodInfo();
    772   ProfileCompilationInfo::OfflineProfileMethodInfo pmi2 = GetOfflineProfileMethodInfo();
    773   // Modify the checksum to trigger a mismatch.
    774   pmi2.dex_references[0].dex_checksum++;
    775 
    776   ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, /*method_idx*/ 0, pmi1, &info));
    777   ASSERT_FALSE(AddMethod("dex_location2", /* checksum */ 2, /*method_idx*/ 0, pmi2, &info));
    778 }
    779 
    780 // Verify that profiles behave correctly even if the methods are added in a different
    781 // order and with a different dex profile indices for the dex files.
    782 TEST_F(ProfileCompilationInfoTest, MergeInlineCacheTriggerReindex) {
    783   ScratchFile profile;
    784 
    785   ProfileCompilationInfo info;
    786   ProfileCompilationInfo info_reindexed;
    787 
    788   ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
    789   ProfileCompilationInfo::OfflineProfileMethodInfo pmi(ic_map);
    790   pmi.dex_references.emplace_back("dex_location1", /* checksum */ 1, kMaxMethodIds);
    791   pmi.dex_references.emplace_back("dex_location2", /* checksum */ 2, kMaxMethodIds);
    792   for (uint16_t dex_pc = 1; dex_pc < 5; dex_pc++) {
    793     ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
    794     dex_pc_data.AddClass(0, dex::TypeIndex(0));
    795     dex_pc_data.AddClass(1, dex::TypeIndex(1));
    796     ic_map->Put(dex_pc, dex_pc_data);
    797   }
    798 
    799   ProfileCompilationInfo::InlineCacheMap* ic_map_reindexed = CreateInlineCacheMap();
    800   ProfileCompilationInfo::OfflineProfileMethodInfo pmi_reindexed(ic_map_reindexed);
    801   pmi_reindexed.dex_references.emplace_back("dex_location2", /* checksum */ 2, kMaxMethodIds);
    802   pmi_reindexed.dex_references.emplace_back("dex_location1", /* checksum */ 1, kMaxMethodIds);
    803   for (uint16_t dex_pc = 1; dex_pc < 5; dex_pc++) {
    804     ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
    805     dex_pc_data.AddClass(1, dex::TypeIndex(0));
    806     dex_pc_data.AddClass(0, dex::TypeIndex(1));
    807     ic_map_reindexed->Put(dex_pc, dex_pc_data);
    808   }
    809 
    810   // Profile 1 and Profile 2 get the same methods but in different order.
    811   // This will trigger a different dex numbers.
    812   for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
    813     ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &info));
    814     ASSERT_TRUE(AddMethod("dex_location2", /* checksum */ 2, method_idx, pmi, &info));
    815   }
    816 
    817   for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
    818     ASSERT_TRUE(AddMethod(
    819       "dex_location2", /* checksum */ 2, method_idx, pmi_reindexed, &info_reindexed));
    820     ASSERT_TRUE(AddMethod(
    821       "dex_location1", /* checksum */ 1, method_idx, pmi_reindexed, &info_reindexed));
    822   }
    823 
    824   ProfileCompilationInfo info_backup;
    825   info_backup.MergeWith(info);
    826   ASSERT_TRUE(info.MergeWith(info_reindexed));
    827   // Merging should have no effect as we're adding the exact same stuff.
    828   ASSERT_TRUE(info.Equals(info_backup));
    829   for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
    830     std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi1 =
    831         info.GetMethod("dex_location1", /* checksum */ 1, method_idx);
    832     ASSERT_TRUE(loaded_pmi1 != nullptr);
    833     ASSERT_TRUE(*loaded_pmi1 == pmi);
    834     std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi2 =
    835         info.GetMethod("dex_location2", /* checksum */ 2, method_idx);
    836     ASSERT_TRUE(loaded_pmi2 != nullptr);
    837     ASSERT_TRUE(*loaded_pmi2 == pmi);
    838   }
    839 }
    840 
    841 TEST_F(ProfileCompilationInfoTest, AddMoreDexFileThanLimit) {
    842   ProfileCompilationInfo info;
    843   // Save a few methods.
    844   for (uint16_t i = 0; i < std::numeric_limits<uint8_t>::max(); i++) {
    845     std::string dex_location = std::to_string(i);
    846     ASSERT_TRUE(AddMethod(dex_location, /* checksum */ 1, /* method_idx */ i, &info));
    847   }
    848   // We only support at most 255 dex files.
    849   ASSERT_FALSE(AddMethod(
    850       /*dex_location*/ "256", /* checksum */ 1, /* method_idx */ 0, &info));
    851 }
    852 
    853 TEST_F(ProfileCompilationInfoTest, MegamorphicInlineCachesMerge) {
    854   // Create a megamorphic inline cache.
    855   ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
    856   ProfileCompilationInfo::OfflineProfileMethodInfo pmi(ic_map);
    857   pmi.dex_references.emplace_back("dex_location1", /* checksum */ 1, kMaxMethodIds);
    858   ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
    859   dex_pc_data.SetIsMegamorphic();
    860   ic_map->Put(/*dex_pc*/ 0, dex_pc_data);
    861 
    862   ProfileCompilationInfo info_megamorphic;
    863   ASSERT_TRUE(AddMethod("dex_location1",
    864                         /*checksum*/ 1,
    865                         /*method_idx*/ 0,
    866                         pmi,
    867                         &info_megamorphic));
    868 
    869   // Create a profile with no inline caches (for the same method).
    870   ProfileCompilationInfo info_no_inline_cache;
    871   ASSERT_TRUE(AddMethod("dex_location1",
    872                         /*checksum*/ 1,
    873                         /*method_idx*/ 0,
    874                         &info_no_inline_cache));
    875 
    876   // Merge the megamorphic cache into the empty one.
    877   ASSERT_TRUE(info_no_inline_cache.MergeWith(info_megamorphic));
    878   ScratchFile profile;
    879   // Saving profile should work without crashing (b/35644850).
    880   ASSERT_TRUE(info_no_inline_cache.Save(GetFd(profile)));
    881 }
    882 
    883 TEST_F(ProfileCompilationInfoTest, MissingTypesInlineCachesMerge) {
    884   // Create an inline cache with missing types
    885   ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
    886   ProfileCompilationInfo::OfflineProfileMethodInfo pmi(ic_map);
    887   pmi.dex_references.emplace_back("dex_location1", /* checksum */ 1, kMaxMethodIds);
    888   ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
    889   dex_pc_data.SetIsMissingTypes();
    890   ic_map->Put(/*dex_pc*/ 0, dex_pc_data);
    891 
    892   ProfileCompilationInfo info_megamorphic;
    893   ASSERT_TRUE(AddMethod("dex_location1",
    894                         /*checksum*/ 1,
    895                         /*method_idx*/ 0,
    896                         pmi,
    897                         &info_megamorphic));
    898 
    899   // Create a profile with no inline caches (for the same method).
    900   ProfileCompilationInfo info_no_inline_cache;
    901   ASSERT_TRUE(AddMethod("dex_location1",
    902                         /*checksum*/ 1,
    903                         /*method_idx*/ 0,
    904                         &info_no_inline_cache));
    905 
    906   // Merge the missing type cache into the empty one.
    907   // Everything should be saved without errors.
    908   ASSERT_TRUE(info_no_inline_cache.MergeWith(info_megamorphic));
    909   ScratchFile profile;
    910   ASSERT_TRUE(info_no_inline_cache.Save(GetFd(profile)));
    911 }
    912 
    913 TEST_F(ProfileCompilationInfoTest, SampledMethodsTest) {
    914   ProfileCompilationInfo test_info;
    915   static constexpr size_t kNumMethods = 1000;
    916   static constexpr size_t kChecksum1 = 1234;
    917   static constexpr size_t kChecksum2 = 4321;
    918   static const std::string kDex1 = "dex1";
    919   static const std::string kDex2 = "dex2";
    920   test_info.AddMethodIndex(Hotness::kFlagStartup, kDex1, kChecksum1, 1, kNumMethods);
    921   test_info.AddMethodIndex(Hotness::kFlagPostStartup, kDex1, kChecksum1, 5, kNumMethods);
    922   test_info.AddMethodIndex(Hotness::kFlagStartup, kDex2, kChecksum2, 2, kNumMethods);
    923   test_info.AddMethodIndex(Hotness::kFlagPostStartup, kDex2, kChecksum2, 4, kNumMethods);
    924   auto run_test = [](const ProfileCompilationInfo& info) {
    925     EXPECT_FALSE(info.GetMethodHotness(kDex1, kChecksum1, 2).IsInProfile());
    926     EXPECT_FALSE(info.GetMethodHotness(kDex1, kChecksum1, 4).IsInProfile());
    927     EXPECT_TRUE(info.GetMethodHotness(kDex1, kChecksum1, 1).IsStartup());
    928     EXPECT_FALSE(info.GetMethodHotness(kDex1, kChecksum1, 3).IsStartup());
    929     EXPECT_TRUE(info.GetMethodHotness(kDex1, kChecksum1, 5).IsPostStartup());
    930     EXPECT_FALSE(info.GetMethodHotness(kDex1, kChecksum1, 6).IsStartup());
    931     EXPECT_TRUE(info.GetMethodHotness(kDex2, kChecksum2, 2).IsStartup());
    932     EXPECT_TRUE(info.GetMethodHotness(kDex2, kChecksum2, 4).IsPostStartup());
    933   };
    934   run_test(test_info);
    935 
    936   // Save the profile.
    937   ScratchFile profile;
    938   ASSERT_TRUE(test_info.Save(GetFd(profile)));
    939   ASSERT_EQ(0, profile.GetFile()->Flush());
    940   ASSERT_TRUE(profile.GetFile()->ResetOffset());
    941 
    942   // Load the profile and make sure we can read the data and it matches what we expect.
    943   ProfileCompilationInfo loaded_info;
    944   ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
    945   run_test(loaded_info);
    946 
    947   // Test that the bitmap gets merged properly.
    948   EXPECT_FALSE(test_info.GetMethodHotness(kDex1, kChecksum1, 11).IsStartup());
    949   {
    950     ProfileCompilationInfo merge_info;
    951     merge_info.AddMethodIndex(Hotness::kFlagStartup, kDex1, kChecksum1, 11, kNumMethods);
    952     test_info.MergeWith(merge_info);
    953   }
    954   EXPECT_TRUE(test_info.GetMethodHotness(kDex1, kChecksum1, 11).IsStartup());
    955 
    956   // Test bulk adding.
    957   {
    958     std::unique_ptr<const DexFile> dex(OpenTestDexFile("ManyMethods"));
    959     ProfileCompilationInfo info;
    960     std::vector<uint16_t> hot_methods = {1, 3, 5};
    961     std::vector<uint16_t> startup_methods = {1, 2};
    962     std::vector<uint16_t> post_methods = {0, 2, 6};
    963     ASSERT_GE(dex->NumMethodIds(), 7u);
    964     info.AddMethodsForDex(static_cast<Hotness::Flag>(Hotness::kFlagHot | Hotness::kFlagStartup),
    965                           dex.get(),
    966                           hot_methods.begin(),
    967                           hot_methods.end());
    968     info.AddMethodsForDex(Hotness::kFlagStartup,
    969                           dex.get(),
    970                           startup_methods.begin(),
    971                           startup_methods.end());
    972     info.AddMethodsForDex(Hotness::kFlagPostStartup,
    973                           dex.get(),
    974                           post_methods.begin(),
    975                           post_methods.end());
    976     for (uint16_t id : hot_methods) {
    977       EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), id)).IsHot());
    978       EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), id)).IsStartup());
    979     }
    980     for (uint16_t id : startup_methods) {
    981       EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), id)).IsStartup());
    982     }
    983     for (uint16_t id : post_methods) {
    984       EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), id)).IsPostStartup());
    985     }
    986     EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), 6)).IsPostStartup());
    987     // Check that methods that shouldn't have been touched are OK.
    988     EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), 0)).IsInProfile());
    989     EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex.get(), 4)).IsInProfile());
    990     EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex.get(), 7)).IsInProfile());
    991     EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex.get(), 1)).IsPostStartup());
    992     EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex.get(), 4)).IsStartup());
    993     EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex.get(), 6)).IsStartup());
    994   }
    995 }
    996 
    997 TEST_F(ProfileCompilationInfoTest, LoadFromZipCompress) {
    998   TestProfileLoadFromZip("primary.prof",
    999                          ZipWriter::kCompress | ZipWriter::kAlign32,
   1000                          /*should_succeed*/true);
   1001 }
   1002 
   1003 TEST_F(ProfileCompilationInfoTest, LoadFromZipUnCompress) {
   1004   TestProfileLoadFromZip("primary.prof",
   1005                          ZipWriter::kAlign32,
   1006                          /*should_succeed*/true);
   1007 }
   1008 
   1009 TEST_F(ProfileCompilationInfoTest, LoadFromZipUnAligned) {
   1010   TestProfileLoadFromZip("primary.prof",
   1011                          0,
   1012                          /*should_succeed*/true);
   1013 }
   1014 
   1015 TEST_F(ProfileCompilationInfoTest, LoadFromZipFailBadZipEntry) {
   1016   TestProfileLoadFromZip("invalid.profile.entry",
   1017                          0,
   1018                          /*should_succeed*/true,
   1019                          /*should_succeed_with_empty_profile*/true);
   1020 }
   1021 
   1022 TEST_F(ProfileCompilationInfoTest, LoadFromZipFailBadProfile) {
   1023   // Create a bad profile.
   1024   ScratchFile profile;
   1025   ASSERT_TRUE(profile.GetFile()->WriteFully(
   1026       ProfileCompilationInfo::kProfileMagic, kProfileMagicSize));
   1027   ASSERT_TRUE(profile.GetFile()->WriteFully(
   1028       ProfileCompilationInfo::kProfileVersion, kProfileVersionSize));
   1029   // Write that we have at least one line.
   1030   uint8_t line_number[] = { 0, 1 };
   1031   ASSERT_TRUE(profile.GetFile()->WriteFully(line_number, sizeof(line_number)));
   1032   ASSERT_EQ(0, profile.GetFile()->Flush());
   1033 
   1034   // Prepare the profile content for zipping.
   1035   ASSERT_TRUE(profile.GetFile()->ResetOffset());
   1036   std::vector<uint8_t> data(profile.GetFile()->GetLength());
   1037   ASSERT_TRUE(profile.GetFile()->ReadFully(data.data(), data.size()));
   1038 
   1039   // Zip the profile content.
   1040   ScratchFile zip;
   1041   FILE* file = fopen(zip.GetFile()->GetPath().c_str(), "wb");
   1042   ZipWriter writer(file);
   1043   writer.StartEntry("primary.prof", ZipWriter::kAlign32);
   1044   writer.WriteBytes(data.data(), data.size());
   1045   writer.FinishEntry();
   1046   writer.Finish();
   1047   fflush(file);
   1048   fclose(file);
   1049 
   1050   // Check that we failed to load.
   1051   ProfileCompilationInfo loaded_info;
   1052   ASSERT_TRUE(zip.GetFile()->ResetOffset());
   1053   ASSERT_FALSE(loaded_info.Load(GetFd(zip)));
   1054 }
   1055 
   1056 TEST_F(ProfileCompilationInfoTest, UpdateProfileKeyOk) {
   1057   std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("MultiDex");
   1058 
   1059   ProfileCompilationInfo info;
   1060   for (const std::unique_ptr<const DexFile>& dex : dex_files) {
   1061     // Create the profile with a different location so that we can update it to the
   1062     // real dex location later.
   1063     std::string base_location = DexFileLoader::GetBaseLocation(dex->GetLocation());
   1064     std::string multidex_suffix = DexFileLoader::GetMultiDexSuffix(dex->GetLocation());
   1065     std::string old_name = base_location + "-old" + multidex_suffix;
   1066     info.AddMethodIndex(Hotness::kFlagHot,
   1067                         old_name,
   1068                         dex->GetLocationChecksum(),
   1069                         /* method_idx */ 0,
   1070                         dex->NumMethodIds());
   1071   }
   1072 
   1073   // Update the profile keys based on the original dex files
   1074   ASSERT_TRUE(info.UpdateProfileKeys(dex_files));
   1075 
   1076   // Verify that we find the methods when searched with the original dex files.
   1077   for (const std::unique_ptr<const DexFile>& dex : dex_files) {
   1078     std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi =
   1079         info.GetMethod(dex->GetLocation(), dex->GetLocationChecksum(), /* method_idx */ 0);
   1080     ASSERT_TRUE(loaded_pmi != nullptr);
   1081   }
   1082 }
   1083 
   1084 TEST_F(ProfileCompilationInfoTest, UpdateProfileKeyOkButNoUpdate) {
   1085   std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("MultiDex");
   1086 
   1087   ProfileCompilationInfo info;
   1088   info.AddMethodIndex(Hotness::kFlagHot,
   1089                       "my.app",
   1090                       /* checksum */ 123,
   1091                       /* method_idx */ 0,
   1092                       /* num_method_ids */ 10);
   1093 
   1094   // Update the profile keys based on the original dex files
   1095   ASSERT_TRUE(info.UpdateProfileKeys(dex_files));
   1096 
   1097   // Verify that we did not perform any update and that we cannot find anything with the new
   1098   // location.
   1099   for (const std::unique_ptr<const DexFile>& dex : dex_files) {
   1100     std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi =
   1101         info.GetMethod(dex->GetLocation(), dex->GetLocationChecksum(), /* method_idx */ 0);
   1102     ASSERT_TRUE(loaded_pmi == nullptr);
   1103   }
   1104 
   1105   // Verify that we can find the original entry.
   1106   std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi =
   1107         info.GetMethod("my.app", /* checksum */ 123, /* method_idx */ 0);
   1108   ASSERT_TRUE(loaded_pmi != nullptr);
   1109 }
   1110 
   1111 TEST_F(ProfileCompilationInfoTest, UpdateProfileKeyFail) {
   1112   std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("MultiDex");
   1113 
   1114 
   1115   ProfileCompilationInfo info;
   1116   // Add all dex
   1117   for (const std::unique_ptr<const DexFile>& dex : dex_files) {
   1118     // Create the profile with a different location so that we can update it to the
   1119     // real dex location later.
   1120     std::string base_location = DexFileLoader::GetBaseLocation(dex->GetLocation());
   1121     std::string multidex_suffix = DexFileLoader::GetMultiDexSuffix(dex->GetLocation());
   1122     std::string old_name = base_location + "-old" + multidex_suffix;
   1123     info.AddMethodIndex(Hotness::kFlagHot,
   1124                         old_name,
   1125                         dex->GetLocationChecksum(),
   1126                         /* method_idx */ 0,
   1127                         dex->NumMethodIds());
   1128   }
   1129 
   1130   // Add a method index using the location we want to rename to.
   1131   // This will cause the rename to fail because an existing entry would already have that name.
   1132   info.AddMethodIndex(Hotness::kFlagHot,
   1133                       dex_files[0]->GetLocation(),
   1134                       /* checksum */ 123,
   1135                       /* method_idx */ 0,
   1136                       dex_files[0]->NumMethodIds());
   1137 
   1138   ASSERT_FALSE(info.UpdateProfileKeys(dex_files));
   1139 }
   1140 
   1141 TEST_F(ProfileCompilationInfoTest, FilteredLoading) {
   1142   ScratchFile profile;
   1143 
   1144   ProfileCompilationInfo saved_info;
   1145   ProfileCompilationInfo::OfflineProfileMethodInfo pmi = GetOfflineProfileMethodInfo();
   1146 
   1147   // Add methods with inline caches.
   1148   for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
   1149     // Add a method which is part of the same dex file as one of the class from the inline caches.
   1150     ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &saved_info));
   1151     ASSERT_TRUE(AddMethod("dex_location2", /* checksum */ 2, method_idx, pmi, &saved_info));
   1152     // Add a method which is outside the set of dex files.
   1153     ASSERT_TRUE(AddMethod("dex_location4", /* checksum */ 4, method_idx, pmi, &saved_info));
   1154   }
   1155 
   1156   ASSERT_TRUE(saved_info.Save(GetFd(profile)));
   1157   ASSERT_EQ(0, profile.GetFile()->Flush());
   1158 
   1159   // Check that we get back what we saved.
   1160   ProfileCompilationInfo loaded_info;
   1161   ASSERT_TRUE(profile.GetFile()->ResetOffset());
   1162 
   1163   // Filter out dex locations. Keep only dex_location1 and dex_location3.
   1164   ProfileCompilationInfo::ProfileLoadFilterFn filter_fn =
   1165       [](const std::string& dex_location, uint32_t checksum) -> bool {
   1166           return (dex_location == "dex_location1" && checksum == 1)
   1167               || (dex_location == "dex_location3" && checksum == 3);
   1168         };
   1169   ASSERT_TRUE(loaded_info.Load(GetFd(profile), true, filter_fn));
   1170 
   1171   // Verify that we filtered out locations during load.
   1172 
   1173   // Dex location 2 and 4 should have been filtered out
   1174   for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
   1175     ASSERT_TRUE(nullptr == loaded_info.GetMethod("dex_location2", /* checksum */ 2, method_idx));
   1176     ASSERT_TRUE(nullptr == loaded_info.GetMethod("dex_location4", /* checksum */ 4, method_idx));
   1177   }
   1178 
   1179   // Dex location 1 should have all all the inline caches referencing dex location 2 set to
   1180   // missing types.
   1181   for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
   1182     // The methods for dex location 1 should be in the profile data.
   1183     std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi1 =
   1184       loaded_info.GetMethod("dex_location1", /* checksum */ 1, /* method_idx */ method_idx);
   1185     ASSERT_TRUE(loaded_pmi1 != nullptr);
   1186 
   1187     // Verify the inline cache.
   1188     // Everything should be as constructed by GetOfflineProfileMethodInfo with the exception
   1189     // of the inline caches referring types from dex_location2.
   1190     // These should be set to IsMissingType.
   1191     ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
   1192 
   1193     // Monomorphic types should remain the same as dex_location1 was kept.
   1194     for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) {
   1195       ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
   1196       dex_pc_data.AddClass(0, dex::TypeIndex(0));
   1197       ic_map->Put(dex_pc, dex_pc_data);
   1198     }
   1199     // Polymorphic inline cache should have been transformed to IsMissingType due to
   1200     // the removal of dex_location2.
   1201     for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) {
   1202       ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
   1203       dex_pc_data.SetIsMissingTypes();
   1204       ic_map->Put(dex_pc, dex_pc_data);
   1205     }
   1206 
   1207     // Megamorphic are not affected by removal of dex files.
   1208     for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) {
   1209       ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
   1210       dex_pc_data.SetIsMegamorphic();
   1211       ic_map->Put(dex_pc, dex_pc_data);
   1212     }
   1213     // Missing types are not affected be removal of dex files.
   1214     for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) {
   1215       ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
   1216       dex_pc_data.SetIsMissingTypes();
   1217       ic_map->Put(dex_pc, dex_pc_data);
   1218     }
   1219 
   1220     ProfileCompilationInfo::OfflineProfileMethodInfo expected_pmi(ic_map);
   1221 
   1222     // The dex references should not have  dex_location2 in the list.
   1223     expected_pmi.dex_references.emplace_back("dex_location1", /* checksum */1, kMaxMethodIds);
   1224     expected_pmi.dex_references.emplace_back("dex_location3", /* checksum */3, kMaxMethodIds);
   1225 
   1226     // Now check that we get back what we expect.
   1227     ASSERT_TRUE(*loaded_pmi1 == expected_pmi);
   1228   }
   1229 }
   1230 
   1231 TEST_F(ProfileCompilationInfoTest, FilteredLoadingRemoveAll) {
   1232   ScratchFile profile;
   1233 
   1234   ProfileCompilationInfo saved_info;
   1235   ProfileCompilationInfo::OfflineProfileMethodInfo pmi = GetOfflineProfileMethodInfo();
   1236 
   1237   // Add methods with inline caches.
   1238   for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
   1239     // Add a method which is part of the same dex file as one of the class from the inline caches.
   1240     ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &saved_info));
   1241     ASSERT_TRUE(AddMethod("dex_location2", /* checksum */ 2, method_idx, pmi, &saved_info));
   1242     // Add a method which is outside the set of dex files.
   1243     ASSERT_TRUE(AddMethod("dex_location4", /* checksum */ 4, method_idx, pmi, &saved_info));
   1244   }
   1245 
   1246   ASSERT_TRUE(saved_info.Save(GetFd(profile)));
   1247   ASSERT_EQ(0, profile.GetFile()->Flush());
   1248 
   1249   // Check that we get back what we saved.
   1250   ProfileCompilationInfo loaded_info;
   1251   ASSERT_TRUE(profile.GetFile()->ResetOffset());
   1252 
   1253   // Remove all elements.
   1254   ProfileCompilationInfo::ProfileLoadFilterFn filter_fn =
   1255       [](const std::string&, uint32_t) -> bool { return false; };
   1256   ASSERT_TRUE(loaded_info.Load(GetFd(profile), true, filter_fn));
   1257 
   1258   // Verify that we filtered out everything.
   1259   ASSERT_TRUE(IsEmpty(loaded_info));
   1260 }
   1261 
   1262 TEST_F(ProfileCompilationInfoTest, FilteredLoadingKeepAll) {
   1263   ScratchFile profile;
   1264 
   1265   ProfileCompilationInfo saved_info;
   1266   ProfileCompilationInfo::OfflineProfileMethodInfo pmi = GetOfflineProfileMethodInfo();
   1267 
   1268   // Add methods with inline caches.
   1269   for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
   1270     // Add a method which is part of the same dex file as one of the
   1271     // class from the inline caches.
   1272     ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &saved_info));
   1273     // Add a method which is outside the set of dex files.
   1274     ASSERT_TRUE(AddMethod("dex_location4", /* checksum */ 4, method_idx, pmi, &saved_info));
   1275   }
   1276 
   1277   ASSERT_TRUE(saved_info.Save(GetFd(profile)));
   1278   ASSERT_EQ(0, profile.GetFile()->Flush());
   1279 
   1280   // Check that we get back what we saved.
   1281   ProfileCompilationInfo loaded_info;
   1282   ASSERT_TRUE(profile.GetFile()->ResetOffset());
   1283 
   1284   // Keep all elements.
   1285   ProfileCompilationInfo::ProfileLoadFilterFn filter_fn =
   1286       [](const std::string&, uint32_t) -> bool { return true; };
   1287   ASSERT_TRUE(loaded_info.Load(GetFd(profile), true, filter_fn));
   1288 
   1289 
   1290   ASSERT_TRUE(loaded_info.Equals(saved_info));
   1291 
   1292   for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
   1293     std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi1 =
   1294         loaded_info.GetMethod("dex_location1", /* checksum */ 1, method_idx);
   1295     ASSERT_TRUE(loaded_pmi1 != nullptr);
   1296     ASSERT_TRUE(*loaded_pmi1 == pmi);
   1297   }
   1298   for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
   1299     std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi2 =
   1300         loaded_info.GetMethod("dex_location4", /* checksum */ 4, method_idx);
   1301     ASSERT_TRUE(loaded_pmi2 != nullptr);
   1302     ASSERT_TRUE(*loaded_pmi2 == pmi);
   1303   }
   1304 }
   1305 
   1306 // Regression test: we were failing to do a filtering loading when the filtered dex file
   1307 // contained profiled classes.
   1308 TEST_F(ProfileCompilationInfoTest, FilteredLoadingWithClasses) {
   1309   ScratchFile profile;
   1310 
   1311   // Save a profile with 2 dex files containing just classes.
   1312   ProfileCompilationInfo saved_info;
   1313   uint16_t item_count = 1000;
   1314   for (uint16_t i = 0; i < item_count; i++) {
   1315     ASSERT_TRUE(AddClass("dex_location1", /* checksum */ 1, dex::TypeIndex(i), &saved_info));
   1316     ASSERT_TRUE(AddClass("dex_location2", /* checksum */ 2, dex::TypeIndex(i), &saved_info));
   1317   }
   1318 
   1319   ASSERT_TRUE(saved_info.Save(GetFd(profile)));
   1320   ASSERT_EQ(0, profile.GetFile()->Flush());
   1321 
   1322 
   1323   // Filter out dex locations: kepp only dex_location2.
   1324   ProfileCompilationInfo loaded_info;
   1325   ASSERT_TRUE(profile.GetFile()->ResetOffset());
   1326   ProfileCompilationInfo::ProfileLoadFilterFn filter_fn =
   1327       [](const std::string& dex_location, uint32_t checksum) -> bool {
   1328           return (dex_location == "dex_location2" && checksum == 2);
   1329         };
   1330   ASSERT_TRUE(loaded_info.Load(GetFd(profile), true, filter_fn));
   1331 
   1332   // Compute the expectation.
   1333   ProfileCompilationInfo expected_info;
   1334   for (uint16_t i = 0; i < item_count; i++) {
   1335     ASSERT_TRUE(AddClass("dex_location2", /* checksum */ 2, dex::TypeIndex(i), &expected_info));
   1336   }
   1337 
   1338   // Validate the expectation.
   1339   ASSERT_TRUE(loaded_info.Equals(expected_info));
   1340 }
   1341 
   1342 
   1343 TEST_F(ProfileCompilationInfoTest, ClearData) {
   1344   ProfileCompilationInfo info;
   1345   for (uint16_t i = 0; i < 10; i++) {
   1346     ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, /* method_idx */ i, &info));
   1347   }
   1348   ASSERT_FALSE(IsEmpty(info));
   1349   info.ClearData();
   1350   ASSERT_TRUE(IsEmpty(info));
   1351 }
   1352 
   1353 TEST_F(ProfileCompilationInfoTest, ClearDataAndSave) {
   1354   ProfileCompilationInfo info;
   1355   for (uint16_t i = 0; i < 10; i++) {
   1356     ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, /* method_idx */ i, &info));
   1357   }
   1358   info.ClearData();
   1359 
   1360   ScratchFile profile;
   1361   ASSERT_TRUE(info.Save(GetFd(profile)));
   1362   ASSERT_EQ(0, profile.GetFile()->Flush());
   1363 
   1364   // Check that we get back what we saved.
   1365   ProfileCompilationInfo loaded_info;
   1366   ASSERT_TRUE(profile.GetFile()->ResetOffset());
   1367   ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
   1368   ASSERT_TRUE(loaded_info.Equals(info));
   1369 }
   1370 
   1371 }  // namespace art
   1372