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 <algorithm>
19 #include <stdio.h>
20 
21 #include "base/arena_allocator.h"
22 #include "base/common_art_test.h"
23 #include "base/unix_file/fd_file.h"
24 #include "dex/compact_dex_file.h"
25 #include "dex/dex_file.h"
26 #include "dex/dex_file_loader.h"
27 #include "dex/method_reference.h"
28 #include "dex/type_reference.h"
29 #include "profile/profile_compilation_info.h"
30 #include "ziparchive/zip_writer.h"
31 
32 namespace art {
33 
34 using Hotness = ProfileCompilationInfo::MethodHotness;
35 using ProfileInlineCache = ProfileMethodInfo::ProfileInlineCache;
36 using ProfileSampleAnnotation = ProfileCompilationInfo::ProfileSampleAnnotation;
37 using ProfileIndexType = ProfileCompilationInfo::ProfileIndexType;
38 using ProfileIndexTypeRegular = ProfileCompilationInfo::ProfileIndexTypeRegular;
39 using ItemMetadata = FlattenProfileData::ItemMetadata;
40 
41 static constexpr size_t kMaxMethodIds = 65535;
42 static uint32_t kMaxHotnessFlagBootIndex =
43     WhichPowerOf2(static_cast<uint32_t>(Hotness::kFlagLastBoot));
44 static uint32_t kMaxHotnessFlagRegularIndex =
45     WhichPowerOf2(static_cast<uint32_t>(Hotness::kFlagLastRegular));
46 
47 class ProfileCompilationInfoTest : public CommonArtTest {
48  public:
SetUp()49   void SetUp() override {
50     CommonArtTest::SetUp();
51     allocator_.reset(new ArenaAllocator(&pool_));
52 
53     dex1 = fake_dex_storage.AddFakeDex("location1", /* checksum= */ 1, /* num_method_ids= */ 10001);
54     dex2 = fake_dex_storage.AddFakeDex("location2", /* checksum= */ 2, /* num_method_ids= */ 10002);
55     dex3 = fake_dex_storage.AddFakeDex("location3", /* checksum= */ 3, /* num_method_ids= */ 10003);
56     dex4 = fake_dex_storage.AddFakeDex("location4", /* checksum= */ 4, /* num_method_ids= */ 10004);
57 
58     dex1_checksum_missmatch = fake_dex_storage.AddFakeDex(
59         "location1", /* checksum= */ 12, /* num_method_ids= */ 10001);
60     dex1_renamed = fake_dex_storage.AddFakeDex(
61         "location1-renamed", /* checksum= */ 1, /* num_method_ids= */ 10001);
62     dex2_renamed = fake_dex_storage.AddFakeDex(
63         "location2-renamed", /* checksum= */ 2, /* num_method_ids= */ 10002);
64 
65     dex_max_methods1 = fake_dex_storage.AddFakeDex(
66         "location-max1", /* checksum= */ 5, /* num_method_ids= */ kMaxMethodIds);
67     dex_max_methods2 = fake_dex_storage.AddFakeDex(
68         "location-max2", /* checksum= */ 6, /* num_method_ids= */ kMaxMethodIds);
69   }
70 
71  protected:
AddMethod(ProfileCompilationInfo * info,const DexFile * dex,uint16_t method_idx,Hotness::Flag flags=Hotness::kFlagHot,const ProfileSampleAnnotation & annotation=ProfileSampleAnnotation::kNone)72   bool AddMethod(ProfileCompilationInfo* info,
73                  const DexFile* dex,
74                  uint16_t method_idx,
75                  Hotness::Flag flags = Hotness::kFlagHot,
76                  const ProfileSampleAnnotation& annotation = ProfileSampleAnnotation::kNone) {
77     return info->AddMethod(ProfileMethodInfo(MethodReference(dex, method_idx)),
78                            flags,
79                            annotation);
80   }
81 
AddMethod(ProfileCompilationInfo * info,const DexFile * dex,uint16_t method_idx,const std::vector<ProfileInlineCache> & inline_caches,const ProfileSampleAnnotation & annotation=ProfileSampleAnnotation::kNone)82   bool AddMethod(ProfileCompilationInfo* info,
83                 const DexFile* dex,
84                 uint16_t method_idx,
85                 const std::vector<ProfileInlineCache>& inline_caches,
86                 const ProfileSampleAnnotation& annotation = ProfileSampleAnnotation::kNone) {
87     return info->AddMethod(
88         ProfileMethodInfo(MethodReference(dex, method_idx), inline_caches),
89         Hotness::kFlagHot,
90         annotation);
91   }
92 
AddClass(ProfileCompilationInfo * info,const DexFile * dex,dex::TypeIndex type_index,const ProfileSampleAnnotation & annotation=ProfileSampleAnnotation::kNone)93   bool AddClass(ProfileCompilationInfo* info,
94                 const DexFile* dex,
95                 dex::TypeIndex type_index,
96                 const ProfileSampleAnnotation& annotation = ProfileSampleAnnotation::kNone) {
97     std::vector<dex::TypeIndex> classes = {type_index};
98     return info->AddClassesForDex(dex, classes.begin(), classes.end(), annotation);
99   }
100 
GetFd(const ScratchFile & file)101   uint32_t GetFd(const ScratchFile& file) {
102     return static_cast<uint32_t>(file.GetFd());
103   }
104 
GetMethod(const ProfileCompilationInfo & info,const DexFile * dex,uint16_t method_idx,const ProfileSampleAnnotation & annotation=ProfileSampleAnnotation::kNone)105   std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> GetMethod(
106       const ProfileCompilationInfo& info,
107       const DexFile* dex,
108       uint16_t method_idx,
109       const ProfileSampleAnnotation& annotation = ProfileSampleAnnotation::kNone) {
110     return info.GetHotMethodInfo(MethodReference(dex, method_idx), annotation);
111   }
112 
113   // Creates an inline cache which will be destructed at the end of the test.
CreateInlineCacheMap()114   ProfileCompilationInfo::InlineCacheMap* CreateInlineCacheMap() {
115     used_inline_caches.emplace_back(new ProfileCompilationInfo::InlineCacheMap(
116         std::less<uint16_t>(), allocator_->Adapter(kArenaAllocProfile)));
117     return used_inline_caches.back().get();
118   }
119 
120   // Creates the default inline caches used in tests.
GetTestInlineCaches()121   std::vector<ProfileInlineCache> GetTestInlineCaches() {
122     std::vector<ProfileInlineCache> inline_caches;
123     // Monomorphic
124     for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) {
125       std::vector<TypeReference> types = {TypeReference(dex1, dex::TypeIndex(0))};
126       inline_caches.push_back(ProfileInlineCache(dex_pc, /* missing_types*/ false, types));
127     }
128     // Polymorphic
129     for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) {
130       std::vector<TypeReference> types = {
131           TypeReference(dex1, dex::TypeIndex(0)),
132           TypeReference(dex2, dex::TypeIndex(1)),
133           TypeReference(dex3, dex::TypeIndex(2))};
134       inline_caches.push_back(ProfileInlineCache(dex_pc, /* missing_types*/ false, types));
135     }
136     // Megamorphic
137     for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) {
138       // we need 5 types to make the cache megamorphic
139       std::vector<TypeReference> types = {
140           TypeReference(dex1, dex::TypeIndex(0)),
141           TypeReference(dex1, dex::TypeIndex(1)),
142           TypeReference(dex1, dex::TypeIndex(2)),
143           TypeReference(dex1, dex::TypeIndex(3)),
144           TypeReference(dex1, dex::TypeIndex(4))};
145       inline_caches.push_back(ProfileInlineCache(dex_pc, /* missing_types*/ false, types));
146     }
147     // Missing types
148     for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) {
149       std::vector<TypeReference> types;
150       inline_caches.push_back(ProfileInlineCache(dex_pc, /* missing_types*/ true, types));
151     }
152 
153     return inline_caches;
154   }
155 
MakeMegamorphic(std::vector<ProfileInlineCache> * inline_caches)156   void MakeMegamorphic(/*out*/std::vector<ProfileInlineCache>* inline_caches) {
157     for (ProfileInlineCache& cache : *inline_caches) {
158       uint16_t k = 5;
159       while (cache.classes.size() < ProfileCompilationInfo::kIndividualInlineCacheSize) {
160         TypeReference type_ref(dex1, dex::TypeIndex(k++));
161         if (std::find(cache.classes.begin(), cache.classes.end(), type_ref) ==
162             cache.classes.end()) {
163           const_cast<std::vector<TypeReference>*>(&cache.classes)->push_back(type_ref);
164         }
165       }
166     }
167   }
168 
SetIsMissingTypes(std::vector<ProfileInlineCache> * inline_caches)169   void SetIsMissingTypes(/*out*/std::vector<ProfileInlineCache>* inline_caches) {
170     for (ProfileInlineCache& cache : *inline_caches) {
171       *(const_cast<bool*>(&(cache.is_missing_types))) = true;
172     }
173   }
174 
TestProfileLoadFromZip(const char * zip_entry,size_t zip_flags,bool should_succeed,bool should_succeed_with_empty_profile=false)175   void TestProfileLoadFromZip(const char* zip_entry,
176                               size_t zip_flags,
177                               bool should_succeed,
178                               bool should_succeed_with_empty_profile = false) {
179     // Create a valid profile.
180     ScratchFile profile;
181     ProfileCompilationInfo saved_info;
182     for (uint16_t i = 0; i < 10; i++) {
183       ASSERT_TRUE(AddMethod(&saved_info, dex1, /* method_idx= */ i));
184       ASSERT_TRUE(AddMethod(&saved_info, dex2, /* method_idx= */ i));
185     }
186     ASSERT_TRUE(saved_info.Save(GetFd(profile)));
187     ASSERT_EQ(0, profile.GetFile()->Flush());
188 
189     // Prepare the profile content for zipping.
190     ASSERT_TRUE(profile.GetFile()->ResetOffset());
191     std::vector<uint8_t> data(profile.GetFile()->GetLength());
192     ASSERT_TRUE(profile.GetFile()->ReadFully(data.data(), data.size()));
193 
194     // Zip the profile content.
195     ScratchFile zip;
196     FILE* file = fopen(zip.GetFile()->GetPath().c_str(), "wb");
197     ZipWriter writer(file);
198     writer.StartEntry(zip_entry, zip_flags);
199     writer.WriteBytes(data.data(), data.size());
200     writer.FinishEntry();
201     writer.Finish();
202     fflush(file);
203     fclose(file);
204 
205     // Verify loading from the zip archive.
206     ProfileCompilationInfo loaded_info;
207     ASSERT_TRUE(zip.GetFile()->ResetOffset());
208     ASSERT_EQ(should_succeed, loaded_info.Load(zip.GetFile()->GetPath(), false));
209     if (should_succeed) {
210       if (should_succeed_with_empty_profile) {
211         ASSERT_TRUE(loaded_info.IsEmpty());
212       } else {
213         ASSERT_TRUE(loaded_info.Equals(saved_info));
214       }
215     }
216   }
217 
IsEmpty(const ProfileCompilationInfo & info)218   bool IsEmpty(const ProfileCompilationInfo& info) {
219     return info.IsEmpty();
220   }
221 
SizeStressTest(bool random)222   void SizeStressTest(bool random) {
223     ProfileCompilationInfo boot_profile(/*for_boot_image*/ true);
224     ProfileCompilationInfo reg_profile(/*for_boot_image*/ false);
225 
226     static constexpr size_t kNumDexFiles = 5;
227 
228     FakeDexStorage local_storage;
229     std::vector<const DexFile*> dex_files;
230     for (uint32_t i = 0; i < kNumDexFiles; i++) {
231       dex_files.push_back(local_storage.AddFakeDex(std::to_string(i), i, kMaxMethodIds));
232     }
233 
234     std::srand(0);
235     // Set a few flags on a 2 different methods in each of the profile.
236     for (const DexFile* dex_file : dex_files) {
237       for (uint32_t method_idx = 0; method_idx < kMaxMethodIds; method_idx++) {
238         for (uint32_t flag_index = 0; flag_index <= kMaxHotnessFlagBootIndex; flag_index++) {
239           if (!random || rand() % 2 == 0) {
240             ASSERT_TRUE(AddMethod(
241                 &boot_profile,
242                 dex_file,
243                 method_idx,
244                 static_cast<Hotness::Flag>(1 << flag_index)));
245           }
246         }
247         for (uint32_t flag_index = 0; flag_index <= kMaxHotnessFlagRegularIndex; flag_index++) {
248           if (!random || rand() % 2 == 0) {
249             ASSERT_TRUE(AddMethod(
250                 &reg_profile,
251                 dex_file,
252                 method_idx,
253                 static_cast<Hotness::Flag>(1 << flag_index)));
254           }
255         }
256       }
257     }
258 
259     ScratchFile boot_file;
260     ScratchFile reg_file;
261 
262     ASSERT_TRUE(boot_profile.Save(GetFd(boot_file)));
263     ASSERT_TRUE(reg_profile.Save(GetFd(reg_file)));
264     ASSERT_TRUE(boot_file.GetFile()->ResetOffset());
265     ASSERT_TRUE(reg_file.GetFile()->ResetOffset());
266 
267     ProfileCompilationInfo loaded_boot;
268     ProfileCompilationInfo loaded_reg;
269     ASSERT_TRUE(loaded_boot.Load(GetFd(boot_file)));
270     ASSERT_TRUE(loaded_reg.Load(GetFd(reg_file)));
271   }
272 
273   // Cannot sizeof the actual arrays so hard code the values here.
274   // They should not change anyway.
275   static constexpr int kProfileMagicSize = 4;
276   static constexpr int kProfileVersionSize = 4;
277 
278   MallocArenaPool pool_;
279   std::unique_ptr<ArenaAllocator> allocator_;
280 
281   const DexFile* dex1;
282   const DexFile* dex2;
283   const DexFile* dex3;
284   const DexFile* dex4;
285   const DexFile* dex1_checksum_missmatch;
286   const DexFile* dex1_renamed;
287   const DexFile* dex2_renamed;
288   const DexFile* dex_max_methods1;
289   const DexFile* dex_max_methods2;
290 
291   // Cache of inline caches generated during tests.
292   // This makes it easier to pass data between different utilities and ensure that
293   // caches are destructed at the end of the test.
294   std::vector<std::unique_ptr<ProfileCompilationInfo::InlineCacheMap>> used_inline_caches;
295 
296   FakeDexStorage fake_dex_storage;
297 };
298 
TEST_F(ProfileCompilationInfoTest,SaveFd)299 TEST_F(ProfileCompilationInfoTest, SaveFd) {
300   ScratchFile profile;
301 
302   ProfileCompilationInfo saved_info;
303   // Save a few methods.
304   for (uint16_t i = 0; i < 10; i++) {
305     ASSERT_TRUE(AddMethod(&saved_info, dex1, /* method_idx= */ i));
306     ASSERT_TRUE(AddMethod(&saved_info, dex2, /* method_idx= */ i));
307   }
308   ASSERT_TRUE(saved_info.Save(GetFd(profile)));
309   ASSERT_EQ(0, profile.GetFile()->Flush());
310 
311   // Check that we get back what we saved.
312   ProfileCompilationInfo loaded_info;
313   ASSERT_TRUE(profile.GetFile()->ResetOffset());
314   ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
315   ASSERT_TRUE(loaded_info.Equals(saved_info));
316 
317   // Save more methods.
318   for (uint16_t i = 0; i < 100; i++) {
319     ASSERT_TRUE(AddMethod(&saved_info, dex1, /* method_idx= */ i));
320     ASSERT_TRUE(AddMethod(&saved_info, dex2, /* method_idx= */ i));
321     ASSERT_TRUE(AddMethod(&saved_info, dex3, /* method_idx= */ i));
322   }
323   ASSERT_TRUE(profile.GetFile()->ResetOffset());
324   ASSERT_TRUE(saved_info.Save(GetFd(profile)));
325   ASSERT_EQ(0, profile.GetFile()->Flush());
326 
327   // Check that we get back everything we saved.
328   ProfileCompilationInfo loaded_info2;
329   ASSERT_TRUE(profile.GetFile()->ResetOffset());
330   ASSERT_TRUE(loaded_info2.Load(GetFd(profile)));
331   ASSERT_TRUE(loaded_info2.Equals(saved_info));
332 }
333 
TEST_F(ProfileCompilationInfoTest,AddMethodsAndClassesFail)334 TEST_F(ProfileCompilationInfoTest, AddMethodsAndClassesFail) {
335   ScratchFile profile;
336 
337   ProfileCompilationInfo info;
338   ASSERT_TRUE(AddMethod(&info, dex1, /* method_idx= */ 1));
339   // Trying to add info for an existing file but with a different checksum.
340   ASSERT_FALSE(AddMethod(&info, dex1_checksum_missmatch, /* method_idx= */ 2));
341 }
342 
TEST_F(ProfileCompilationInfoTest,MergeFail)343 TEST_F(ProfileCompilationInfoTest, MergeFail) {
344   ScratchFile profile;
345 
346   ProfileCompilationInfo info1;
347   ASSERT_TRUE(AddMethod(&info1, dex1, /* method_idx= */ 1));
348   // Use the same file, change the checksum.
349   ProfileCompilationInfo info2;
350   ASSERT_TRUE(AddMethod(&info2, dex1_checksum_missmatch, /* method_idx= */ 2));
351 
352   ASSERT_FALSE(info1.MergeWith(info2));
353 }
354 
355 
TEST_F(ProfileCompilationInfoTest,MergeFdFail)356 TEST_F(ProfileCompilationInfoTest, MergeFdFail) {
357   ScratchFile profile;
358 
359   ProfileCompilationInfo info1;
360   ASSERT_TRUE(AddMethod(&info1, dex1, /* method_idx= */ 1));
361   // Use the same file, change the checksum.
362   ProfileCompilationInfo info2;
363   ASSERT_TRUE(AddMethod(&info2, dex1_checksum_missmatch, /* method_idx= */ 2));
364 
365   ASSERT_TRUE(info1.Save(profile.GetFd()));
366   ASSERT_EQ(0, profile.GetFile()->Flush());
367   ASSERT_TRUE(profile.GetFile()->ResetOffset());
368 
369   ASSERT_FALSE(info2.Load(profile.GetFd()));
370 }
371 
TEST_F(ProfileCompilationInfoTest,SaveMaxMethods)372 TEST_F(ProfileCompilationInfoTest, SaveMaxMethods) {
373   ScratchFile profile;
374 
375   ProfileCompilationInfo saved_info;
376   // Save the maximum number of methods
377   for (uint16_t i = 0; i < std::numeric_limits<uint16_t>::max(); i++) {
378     ASSERT_TRUE(AddMethod(&saved_info, dex_max_methods1, /* method_idx= */ i));
379     ASSERT_TRUE(AddMethod(&saved_info, dex_max_methods2, /* method_idx= */ i));
380   }
381   // Save the maximum number of classes
382   for (uint16_t i = 0; i < std::numeric_limits<uint16_t>::max(); i++) {
383     ASSERT_TRUE(AddClass(&saved_info, dex1, dex::TypeIndex(i)));
384     ASSERT_TRUE(AddClass(&saved_info, dex2, dex::TypeIndex(i)));
385   }
386 
387   ASSERT_TRUE(saved_info.Save(GetFd(profile)));
388   ASSERT_EQ(0, profile.GetFile()->Flush());
389 
390   // Check that we get back what we saved.
391   ProfileCompilationInfo loaded_info;
392   ASSERT_TRUE(profile.GetFile()->ResetOffset());
393   ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
394   ASSERT_TRUE(loaded_info.Equals(saved_info));
395 }
396 
TEST_F(ProfileCompilationInfoTest,SaveEmpty)397 TEST_F(ProfileCompilationInfoTest, SaveEmpty) {
398   ScratchFile profile;
399 
400   ProfileCompilationInfo saved_info;
401   ASSERT_TRUE(saved_info.Save(GetFd(profile)));
402   ASSERT_EQ(0, profile.GetFile()->Flush());
403 
404   // Check that we get back what we saved.
405   ProfileCompilationInfo loaded_info;
406   ASSERT_TRUE(profile.GetFile()->ResetOffset());
407   ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
408   ASSERT_TRUE(loaded_info.Equals(saved_info));
409 }
410 
TEST_F(ProfileCompilationInfoTest,LoadEmpty)411 TEST_F(ProfileCompilationInfoTest, LoadEmpty) {
412   ScratchFile profile;
413 
414   ProfileCompilationInfo empty_info;
415 
416   ProfileCompilationInfo loaded_info;
417   ASSERT_TRUE(profile.GetFile()->ResetOffset());
418   ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
419   ASSERT_TRUE(loaded_info.Equals(empty_info));
420 }
421 
TEST_F(ProfileCompilationInfoTest,BadMagic)422 TEST_F(ProfileCompilationInfoTest, BadMagic) {
423   ScratchFile profile;
424   uint8_t buffer[] = { 1, 2, 3, 4 };
425   ASSERT_TRUE(profile.GetFile()->WriteFully(buffer, sizeof(buffer)));
426   ProfileCompilationInfo loaded_info;
427   ASSERT_TRUE(profile.GetFile()->ResetOffset());
428   ASSERT_FALSE(loaded_info.Load(GetFd(profile)));
429 }
430 
TEST_F(ProfileCompilationInfoTest,BadVersion)431 TEST_F(ProfileCompilationInfoTest, BadVersion) {
432   ScratchFile profile;
433 
434   ASSERT_TRUE(profile.GetFile()->WriteFully(
435       ProfileCompilationInfo::kProfileMagic, kProfileMagicSize));
436   uint8_t version[] = { 'v', 'e', 'r', 's', 'i', 'o', 'n' };
437   ASSERT_TRUE(profile.GetFile()->WriteFully(version, sizeof(version)));
438   ASSERT_EQ(0, profile.GetFile()->Flush());
439 
440   ProfileCompilationInfo loaded_info;
441   ASSERT_TRUE(profile.GetFile()->ResetOffset());
442   ASSERT_FALSE(loaded_info.Load(GetFd(profile)));
443 }
444 
TEST_F(ProfileCompilationInfoTest,Incomplete)445 TEST_F(ProfileCompilationInfoTest, Incomplete) {
446   ScratchFile profile;
447   ASSERT_TRUE(profile.GetFile()->WriteFully(
448       ProfileCompilationInfo::kProfileMagic, kProfileMagicSize));
449   ASSERT_TRUE(profile.GetFile()->WriteFully(
450       ProfileCompilationInfo::kProfileVersion, kProfileVersionSize));
451   // Write that we have at least one line.
452   uint8_t line_number[] = { 0, 1 };
453   ASSERT_TRUE(profile.GetFile()->WriteFully(line_number, sizeof(line_number)));
454   ASSERT_EQ(0, profile.GetFile()->Flush());
455 
456   ProfileCompilationInfo loaded_info;
457   ASSERT_TRUE(profile.GetFile()->ResetOffset());
458   ASSERT_FALSE(loaded_info.Load(GetFd(profile)));
459 }
460 
TEST_F(ProfileCompilationInfoTest,TooLongDexLocation)461 TEST_F(ProfileCompilationInfoTest, TooLongDexLocation) {
462   ScratchFile profile;
463   ASSERT_TRUE(profile.GetFile()->WriteFully(
464       ProfileCompilationInfo::kProfileMagic, kProfileMagicSize));
465   ASSERT_TRUE(profile.GetFile()->WriteFully(
466       ProfileCompilationInfo::kProfileVersion, kProfileVersionSize));
467   // Write that we have at least one line.
468   uint8_t line_number[] = { 0, 1 };
469   ASSERT_TRUE(profile.GetFile()->WriteFully(line_number, sizeof(line_number)));
470 
471   // dex_location_size, methods_size, classes_size, checksum.
472   // Dex location size is too big and should be rejected.
473   uint8_t line[] = { 255, 255, 0, 1, 0, 1, 0, 0, 0, 0 };
474   ASSERT_TRUE(profile.GetFile()->WriteFully(line, sizeof(line)));
475   ASSERT_EQ(0, profile.GetFile()->Flush());
476 
477   ProfileCompilationInfo loaded_info;
478   ASSERT_TRUE(profile.GetFile()->ResetOffset());
479   ASSERT_FALSE(loaded_info.Load(GetFd(profile)));
480 }
481 
TEST_F(ProfileCompilationInfoTest,UnexpectedContent)482 TEST_F(ProfileCompilationInfoTest, UnexpectedContent) {
483   ScratchFile profile;
484 
485   ProfileCompilationInfo saved_info;
486   for (uint16_t i = 0; i < 10; i++) {
487     ASSERT_TRUE(AddMethod(&saved_info, dex1, /* method_idx= */ i));
488   }
489   ASSERT_TRUE(saved_info.Save(GetFd(profile)));
490 
491   uint8_t random_data[] = { 1, 2, 3};
492   ASSERT_TRUE(profile.GetFile()->WriteFully(random_data, sizeof(random_data)));
493 
494   ASSERT_EQ(0, profile.GetFile()->Flush());
495 
496   // Check that we fail because of unexpected data at the end of the file.
497   ProfileCompilationInfo loaded_info;
498   ASSERT_TRUE(profile.GetFile()->ResetOffset());
499   ASSERT_FALSE(loaded_info.Load(GetFd(profile)));
500 }
501 
TEST_F(ProfileCompilationInfoTest,SaveInlineCaches)502 TEST_F(ProfileCompilationInfoTest, SaveInlineCaches) {
503   ScratchFile profile;
504 
505   ProfileCompilationInfo saved_info;
506   std::vector<ProfileInlineCache> inline_caches = GetTestInlineCaches();
507 
508   // Add methods with inline caches.
509   for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
510     // Add a method which is part of the same dex file as one of the
511     // class from the inline caches.
512     ASSERT_TRUE(AddMethod(&saved_info, dex1, method_idx, inline_caches));
513     // Add a method which is outside the set of dex files.
514     ASSERT_TRUE(AddMethod(&saved_info, dex4, method_idx, inline_caches));
515   }
516 
517   ASSERT_TRUE(saved_info.Save(GetFd(profile)));
518   ASSERT_EQ(0, profile.GetFile()->Flush());
519 
520   // Check that we get back what we saved.
521   ProfileCompilationInfo loaded_info;
522   ASSERT_TRUE(profile.GetFile()->ResetOffset());
523   ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
524 
525   ASSERT_TRUE(loaded_info.Equals(saved_info));
526 
527   std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi1 =
528       GetMethod(loaded_info, dex1, /* method_idx= */ 3);
529   ASSERT_TRUE(loaded_pmi1 != nullptr);
530   ASSERT_TRUE(*loaded_pmi1 == inline_caches);
531   std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi2 =
532       GetMethod(loaded_info, dex4, /* method_idx= */ 3);
533   ASSERT_TRUE(loaded_pmi2 != nullptr);
534   ASSERT_TRUE(*loaded_pmi2 == inline_caches);
535 }
536 
TEST_F(ProfileCompilationInfoTest,MegamorphicInlineCaches)537 TEST_F(ProfileCompilationInfoTest, MegamorphicInlineCaches) {
538   ProfileCompilationInfo saved_info;
539   std::vector<ProfileInlineCache> inline_caches = GetTestInlineCaches();
540 
541   // Add methods with inline caches.
542   for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
543     ASSERT_TRUE(AddMethod(&saved_info, dex1, method_idx, inline_caches));
544   }
545 
546   ScratchFile profile;
547   ASSERT_TRUE(saved_info.Save(GetFd(profile)));
548   ASSERT_EQ(0, profile.GetFile()->Flush());
549 
550   // Make the inline caches megamorphic and add them to the profile again.
551   ProfileCompilationInfo saved_info_extra;
552   std::vector<ProfileInlineCache> inline_caches_extra = GetTestInlineCaches();
553   MakeMegamorphic(&inline_caches_extra);
554   for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
555     ASSERT_TRUE(AddMethod(&saved_info_extra, dex1, method_idx, inline_caches_extra));
556   }
557 
558   ScratchFile extra_profile;
559   ASSERT_TRUE(saved_info_extra.Save(GetFd(extra_profile)));
560   ASSERT_EQ(0, extra_profile.GetFile()->Flush());
561 
562   // Merge the profiles so that we have the same view as the file.
563   ASSERT_TRUE(saved_info.MergeWith(saved_info_extra));
564 
565   // Check that we get back what we saved.
566   ProfileCompilationInfo loaded_info;
567   ASSERT_TRUE(extra_profile.GetFile()->ResetOffset());
568   ASSERT_TRUE(loaded_info.Load(GetFd(extra_profile)));
569 
570   ASSERT_TRUE(loaded_info.Equals(saved_info));
571 
572   std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi1 =
573       GetMethod(loaded_info, dex1, /* method_idx= */ 3);
574 
575   ASSERT_TRUE(loaded_pmi1 != nullptr);
576   ASSERT_TRUE(*loaded_pmi1 == inline_caches_extra);
577 }
578 
TEST_F(ProfileCompilationInfoTest,MissingTypesInlineCaches)579 TEST_F(ProfileCompilationInfoTest, MissingTypesInlineCaches) {
580   ProfileCompilationInfo saved_info;
581   std::vector<ProfileInlineCache> inline_caches = GetTestInlineCaches();
582 
583   // Add methods with inline caches.
584   for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
585     ASSERT_TRUE(AddMethod(&saved_info, dex1, method_idx, inline_caches));
586   }
587 
588   ScratchFile profile;
589   ASSERT_TRUE(saved_info.Save(GetFd(profile)));
590   ASSERT_EQ(0, profile.GetFile()->Flush());
591 
592   // Make some inline caches megamorphic and add them to the profile again.
593   ProfileCompilationInfo saved_info_extra;
594   std::vector<ProfileInlineCache> inline_caches_extra = GetTestInlineCaches();
595   MakeMegamorphic(&inline_caches_extra);
596   for (uint16_t method_idx = 5; method_idx < 10; method_idx++) {
597     ASSERT_TRUE(AddMethod(&saved_info_extra, dex1, method_idx, inline_caches));
598   }
599 
600   // Mark all inline caches with missing types and add them to the profile again.
601   // This will verify that all inline caches (megamorphic or not) should be marked as missing types.
602   std::vector<ProfileInlineCache> missing_types = GetTestInlineCaches();
603   SetIsMissingTypes(&missing_types);
604   for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
605     ASSERT_TRUE(AddMethod(&saved_info_extra, dex1, method_idx, missing_types));
606   }
607 
608   ScratchFile extra_profile;
609   ASSERT_TRUE(saved_info_extra.Save(GetFd(extra_profile)));
610   ASSERT_EQ(0, extra_profile.GetFile()->Flush());
611 
612   // Merge the profiles so that we have the same view as the file.
613   ASSERT_TRUE(saved_info.MergeWith(saved_info_extra));
614 
615   // Check that we get back what we saved.
616   ProfileCompilationInfo loaded_info;
617   ASSERT_TRUE(extra_profile.GetFile()->ResetOffset());
618   ASSERT_TRUE(loaded_info.Load(GetFd(extra_profile)));
619 
620   ASSERT_TRUE(loaded_info.Equals(saved_info));
621 
622   std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi1 =
623       GetMethod(loaded_info, dex1, /* method_idx= */ 3);
624   ASSERT_TRUE(loaded_pmi1 != nullptr);
625   ASSERT_TRUE(*loaded_pmi1 == missing_types);
626 }
627 
TEST_F(ProfileCompilationInfoTest,InvalidChecksumInInlineCache)628 TEST_F(ProfileCompilationInfoTest, InvalidChecksumInInlineCache) {
629   ScratchFile profile;
630 
631   ProfileCompilationInfo info;
632   std::vector<ProfileInlineCache> inline_caches1 = GetTestInlineCaches();
633   std::vector<ProfileInlineCache> inline_caches2 = GetTestInlineCaches();
634   // Modify the checksum to trigger a mismatch.
635   std::vector<TypeReference>* types = const_cast<std::vector<TypeReference>*>(
636       &inline_caches2[0].classes);
637   types->front().dex_file = dex1_checksum_missmatch;
638 
639   ASSERT_TRUE(AddMethod(&info, dex1, /* method_idx= */ 0, inline_caches1));
640   ASSERT_FALSE(AddMethod(&info, dex2, /* method_idx= */ 0, inline_caches2));
641 }
642 
643 // Verify that profiles behave correctly even if the methods are added in a different
644 // order and with a different dex profile indices for the dex files.
TEST_F(ProfileCompilationInfoTest,MergeInlineCacheTriggerReindex)645 TEST_F(ProfileCompilationInfoTest, MergeInlineCacheTriggerReindex) {
646   ScratchFile profile;
647 
648   ProfileCompilationInfo info;
649   ProfileCompilationInfo info_reindexed;
650 
651   std::vector<ProfileInlineCache> inline_caches;
652   for (uint16_t dex_pc = 1; dex_pc < 5; dex_pc++) {
653     std::vector<TypeReference> types = {
654         TypeReference(dex1, dex::TypeIndex(0)),
655         TypeReference(dex2, dex::TypeIndex(1))};
656     inline_caches.push_back(ProfileInlineCache(dex_pc, /* missing_types*/ false, types));
657   }
658 
659   std::vector<ProfileInlineCache> inline_caches_reindexed;
660   for (uint16_t dex_pc = 1; dex_pc < 5; dex_pc++) {
661     std::vector<TypeReference> types = {
662         TypeReference(dex2, dex::TypeIndex(1)),
663         TypeReference(dex1, dex::TypeIndex(0))};
664     inline_caches_reindexed.push_back(ProfileInlineCache(dex_pc, /* missing_types*/ false, types));
665   }
666   // Profile 1 and Profile 2 get the same methods but in different order.
667   // This will trigger a different dex numbers.
668   for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
669     ASSERT_TRUE(AddMethod(&info, dex1, method_idx, inline_caches));
670     ASSERT_TRUE(AddMethod(&info, dex2, method_idx, inline_caches));
671   }
672 
673   for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
674     ASSERT_TRUE(AddMethod(&info_reindexed, dex2, method_idx, inline_caches_reindexed));
675     ASSERT_TRUE(AddMethod(&info_reindexed, dex1, method_idx, inline_caches_reindexed));
676   }
677 
678   ProfileCompilationInfo info_backup;
679   info_backup.MergeWith(info);
680   ASSERT_TRUE(info.MergeWith(info_reindexed));
681   // Merging should have no effect as we're adding the exact same stuff.
682   ASSERT_TRUE(info.Equals(info_backup));
683   for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
684     std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi1 =
685         GetMethod(info, dex1, method_idx);
686     ASSERT_TRUE(loaded_pmi1 != nullptr);
687     ASSERT_TRUE(*loaded_pmi1 == inline_caches);
688     std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi2 =
689         GetMethod(info, dex2, method_idx);
690     ASSERT_TRUE(loaded_pmi2 != nullptr);
691     ASSERT_TRUE(*loaded_pmi2 == inline_caches);
692   }
693 }
694 
TEST_F(ProfileCompilationInfoTest,AddMoreDexFileThanLimitRegular)695 TEST_F(ProfileCompilationInfoTest, AddMoreDexFileThanLimitRegular) {
696   FakeDexStorage local_storage;
697   ProfileCompilationInfo info;
698   // Save a few methods.
699   for (uint16_t i = 0; i < std::numeric_limits<ProfileIndexTypeRegular>::max(); i++) {
700     std::string location = std::to_string(i);
701     const DexFile* dex = local_storage.AddFakeDex(
702         location, /* checksum= */ 1, /* num_method_ids= */ 1);
703     ASSERT_TRUE(AddMethod(&info, dex, /* method_idx= */ 0));
704   }
705   // Add an extra dex file.
706   const DexFile* dex = local_storage.AddFakeDex("-1", /* checksum= */ 1, /* num_method_ids= */ 1);
707   ASSERT_FALSE(AddMethod(&info, dex, /* method_idx= */ 0));
708 }
709 
TEST_F(ProfileCompilationInfoTest,AddMoreDexFileThanLimitBoot)710 TEST_F(ProfileCompilationInfoTest, AddMoreDexFileThanLimitBoot) {
711   FakeDexStorage local_storage;
712   ProfileCompilationInfo info(/*for_boot_image=*/true);
713   // Save a few methods.
714   for (uint16_t i = 0; i < std::numeric_limits<ProfileIndexType>::max(); i++) {
715     std::string location = std::to_string(i);
716     const DexFile* dex = local_storage.AddFakeDex(
717         location, /* checksum= */ 1, /* num_method_ids= */ 1);
718     ASSERT_TRUE(AddMethod(&info, dex, /* method_idx= */ 0));
719   }
720   // Add an extra dex file.
721   const DexFile* dex = local_storage.AddFakeDex("-1", /* checksum= */ 1, /* num_method_ids= */ 1);
722   ASSERT_FALSE(AddMethod(&info, dex, /* method_idx= */ 0));
723 }
724 
TEST_F(ProfileCompilationInfoTest,MegamorphicInlineCachesMerge)725 TEST_F(ProfileCompilationInfoTest, MegamorphicInlineCachesMerge) {
726   // Create a megamorphic inline cache.
727   std::vector<ProfileInlineCache> inline_caches;
728   std::vector<TypeReference> types = {
729           TypeReference(dex1, dex::TypeIndex(0)),
730           TypeReference(dex1, dex::TypeIndex(1)),
731           TypeReference(dex1, dex::TypeIndex(2)),
732           TypeReference(dex1, dex::TypeIndex(3)),
733           TypeReference(dex1, dex::TypeIndex(4))};
734   inline_caches.push_back(ProfileInlineCache(0, /* missing_types*/ false, types));
735 
736   ProfileCompilationInfo info_megamorphic;
737   ASSERT_TRUE(AddMethod(&info_megamorphic, dex1, 0, inline_caches));
738 
739   // Create a profile with no inline caches (for the same method).
740   ProfileCompilationInfo info_no_inline_cache;
741   ASSERT_TRUE(AddMethod(&info_no_inline_cache, dex1, 0));
742 
743   // Merge the megamorphic cache into the empty one.
744   ASSERT_TRUE(info_no_inline_cache.MergeWith(info_megamorphic));
745   ScratchFile profile;
746   // Saving profile should work without crashing (b/35644850).
747   ASSERT_TRUE(info_no_inline_cache.Save(GetFd(profile)));
748 }
749 
TEST_F(ProfileCompilationInfoTest,MissingTypesInlineCachesMerge)750 TEST_F(ProfileCompilationInfoTest, MissingTypesInlineCachesMerge) {
751   // Create an inline cache with missing types
752   std::vector<ProfileInlineCache> inline_caches;
753   std::vector<TypeReference> types = {};
754   inline_caches.push_back(ProfileInlineCache(0, /* missing_types*/ true, types));
755 
756   ProfileCompilationInfo info_missing_types;
757   ASSERT_TRUE(AddMethod(&info_missing_types, dex1, /*method_idx=*/ 0, inline_caches));
758 
759   // Create a profile with no inline caches (for the same method).
760   ProfileCompilationInfo info_no_inline_cache;
761   ASSERT_TRUE(AddMethod(&info_no_inline_cache, dex1, /*method_idx=*/ 0));
762 
763   // Merge the missing type cache into the empty one.
764   // Everything should be saved without errors.
765   ASSERT_TRUE(info_no_inline_cache.MergeWith(info_missing_types));
766   ScratchFile profile;
767   ASSERT_TRUE(info_no_inline_cache.Save(GetFd(profile)));
768 }
769 
TEST_F(ProfileCompilationInfoTest,SampledMethodsTest)770 TEST_F(ProfileCompilationInfoTest, SampledMethodsTest) {
771   ProfileCompilationInfo test_info;
772   AddMethod(&test_info, dex1, 1, Hotness::kFlagStartup);
773   AddMethod(&test_info, dex1, 5, Hotness::kFlagPostStartup);
774   AddMethod(&test_info, dex2, 2, Hotness::kFlagStartup);
775   AddMethod(&test_info, dex2, 4, Hotness::kFlagPostStartup);
776   auto run_test = [&dex1 = dex1, &dex2 = dex2](const ProfileCompilationInfo& info) {
777     EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex1, 2)).IsInProfile());
778     EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex1, 4)).IsInProfile());
779     EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex1, 1)).IsStartup());
780     EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex1, 3)).IsStartup());
781     EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex1, 5)).IsPostStartup());
782     EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex1, 6)).IsStartup());
783     EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex2, 2)).IsStartup());
784     EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex2, 4)).IsPostStartup());
785   };
786   run_test(test_info);
787 
788   // Save the profile.
789   ScratchFile profile;
790   ASSERT_TRUE(test_info.Save(GetFd(profile)));
791   ASSERT_EQ(0, profile.GetFile()->Flush());
792   ASSERT_TRUE(profile.GetFile()->ResetOffset());
793 
794   // Load the profile and make sure we can read the data and it matches what we expect.
795   ProfileCompilationInfo loaded_info;
796   ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
797   run_test(loaded_info);
798 
799   // Test that the bitmap gets merged properly.
800   EXPECT_FALSE(test_info.GetMethodHotness(MethodReference(dex1, 11)).IsStartup());
801   {
802     ProfileCompilationInfo merge_info;
803     AddMethod(&merge_info, dex1, 11, Hotness::kFlagStartup);
804     test_info.MergeWith(merge_info);
805   }
806   EXPECT_TRUE(test_info.GetMethodHotness(MethodReference(dex1, 11)).IsStartup());
807 
808   // Test bulk adding.
809   {
810     std::unique_ptr<const DexFile> dex(OpenTestDexFile("ManyMethods"));
811     ProfileCompilationInfo info;
812     std::vector<uint16_t> hot_methods = {1, 3, 5};
813     std::vector<uint16_t> startup_methods = {1, 2};
814     std::vector<uint16_t> post_methods = {0, 2, 6};
815     ASSERT_GE(dex->NumMethodIds(), 7u);
816     info.AddMethodsForDex(static_cast<Hotness::Flag>(Hotness::kFlagHot | Hotness::kFlagStartup),
817                           dex.get(),
818                           hot_methods.begin(),
819                           hot_methods.end());
820     info.AddMethodsForDex(Hotness::kFlagStartup,
821                           dex.get(),
822                           startup_methods.begin(),
823                           startup_methods.end());
824     info.AddMethodsForDex(Hotness::kFlagPostStartup,
825                           dex.get(),
826                           post_methods.begin(),
827                           post_methods.end());
828     for (uint16_t id : hot_methods) {
829       EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), id)).IsHot());
830       EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), id)).IsStartup());
831     }
832     for (uint16_t id : startup_methods) {
833       EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), id)).IsStartup());
834     }
835     for (uint16_t id : post_methods) {
836       EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), id)).IsPostStartup());
837     }
838     EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), 6)).IsPostStartup());
839     // Check that methods that shouldn't have been touched are OK.
840     EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), 0)).IsInProfile());
841     EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex.get(), 4)).IsInProfile());
842     EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex.get(), 7)).IsInProfile());
843     EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex.get(), 1)).IsPostStartup());
844     EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex.get(), 4)).IsStartup());
845     EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex.get(), 6)).IsStartup());
846   }
847 }
848 
TEST_F(ProfileCompilationInfoTest,LoadFromZipCompress)849 TEST_F(ProfileCompilationInfoTest, LoadFromZipCompress) {
850   TestProfileLoadFromZip("primary.prof",
851                          ZipWriter::kCompress | ZipWriter::kAlign32,
852                          /*should_succeed=*/true);
853 }
854 
TEST_F(ProfileCompilationInfoTest,LoadFromZipUnCompress)855 TEST_F(ProfileCompilationInfoTest, LoadFromZipUnCompress) {
856   TestProfileLoadFromZip("primary.prof",
857                          ZipWriter::kAlign32,
858                          /*should_succeed=*/true);
859 }
860 
TEST_F(ProfileCompilationInfoTest,LoadFromZipUnAligned)861 TEST_F(ProfileCompilationInfoTest, LoadFromZipUnAligned) {
862   TestProfileLoadFromZip("primary.prof",
863                          0,
864                          /*should_succeed=*/true);
865 }
866 
TEST_F(ProfileCompilationInfoTest,LoadFromZipFailBadZipEntry)867 TEST_F(ProfileCompilationInfoTest, LoadFromZipFailBadZipEntry) {
868   TestProfileLoadFromZip("invalid.profile.entry",
869                          0,
870                          /*should_succeed=*/true,
871                          /*should_succeed_with_empty_profile=*/true);
872 }
873 
TEST_F(ProfileCompilationInfoTest,LoadFromZipFailBadProfile)874 TEST_F(ProfileCompilationInfoTest, LoadFromZipFailBadProfile) {
875   // Create a bad profile.
876   ScratchFile profile;
877   ASSERT_TRUE(profile.GetFile()->WriteFully(
878       ProfileCompilationInfo::kProfileMagic, kProfileMagicSize));
879   ASSERT_TRUE(profile.GetFile()->WriteFully(
880       ProfileCompilationInfo::kProfileVersion, kProfileVersionSize));
881   // Write that we have at least one line.
882   uint8_t line_number[] = { 0, 1 };
883   ASSERT_TRUE(profile.GetFile()->WriteFully(line_number, sizeof(line_number)));
884   ASSERT_EQ(0, profile.GetFile()->Flush());
885 
886   // Prepare the profile content for zipping.
887   ASSERT_TRUE(profile.GetFile()->ResetOffset());
888   std::vector<uint8_t> data(profile.GetFile()->GetLength());
889   ASSERT_TRUE(profile.GetFile()->ReadFully(data.data(), data.size()));
890 
891   // Zip the profile content.
892   ScratchFile zip;
893   FILE* file = fopen(zip.GetFile()->GetPath().c_str(), "wb");
894   ZipWriter writer(file);
895   writer.StartEntry("primary.prof", ZipWriter::kAlign32);
896   writer.WriteBytes(data.data(), data.size());
897   writer.FinishEntry();
898   writer.Finish();
899   fflush(file);
900   fclose(file);
901 
902   // Check that we failed to load.
903   ProfileCompilationInfo loaded_info;
904   ASSERT_TRUE(zip.GetFile()->ResetOffset());
905   ASSERT_FALSE(loaded_info.Load(GetFd(zip)));
906 }
907 
TEST_F(ProfileCompilationInfoTest,UpdateProfileKeyOk)908 TEST_F(ProfileCompilationInfoTest, UpdateProfileKeyOk) {
909   std::vector<std::unique_ptr<const DexFile>> dex_files;
910   dex_files.push_back(std::unique_ptr<const DexFile>(dex1_renamed));
911   dex_files.push_back(std::unique_ptr<const DexFile>(dex2_renamed));
912 
913   ProfileCompilationInfo info;
914   AddMethod(&info, dex1, /* method_idx= */ 0);
915   AddMethod(&info, dex2, /* method_idx= */ 0);
916 
917   // Update the profile keys based on the original dex files
918   ASSERT_TRUE(info.UpdateProfileKeys(dex_files));
919 
920   // Verify that we find the methods when searched with the original dex files.
921   for (const std::unique_ptr<const DexFile>& dex : dex_files) {
922     std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi =
923         GetMethod(info, dex.get(), /* method_idx= */ 0);
924     ASSERT_TRUE(loaded_pmi != nullptr);
925   }
926 
927   // Release the ownership as this is held by the test class;
928   for (std::unique_ptr<const DexFile>& dex : dex_files) {
929     UNUSED(dex.release());
930   }
931 }
932 
TEST_F(ProfileCompilationInfoTest,UpdateProfileKeyOkButNoUpdate)933 TEST_F(ProfileCompilationInfoTest, UpdateProfileKeyOkButNoUpdate) {
934   std::vector<std::unique_ptr<const DexFile>> dex_files;
935   dex_files.push_back(std::unique_ptr<const DexFile>(dex1));
936 
937   ProfileCompilationInfo info;
938   AddMethod(&info, dex2, /* method_idx= */ 0);
939 
940   // Update the profile keys based on the original dex files.
941   ASSERT_TRUE(info.UpdateProfileKeys(dex_files));
942 
943   // Verify that we did not perform any update and that we cannot find anything with the new
944   // location.
945   for (const std::unique_ptr<const DexFile>& dex : dex_files) {
946     std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi =
947         GetMethod(info, dex.get(), /* method_idx= */ 0);
948     ASSERT_TRUE(loaded_pmi == nullptr);
949   }
950 
951   // Verify that we can find the original entry.
952   std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi =
953         GetMethod(info, dex2, /* method_idx= */ 0);
954   ASSERT_TRUE(loaded_pmi != nullptr);
955 
956   // Release the ownership as this is held by the test class;
957   for (std::unique_ptr<const DexFile>& dex : dex_files) {
958     UNUSED(dex.release());
959   }
960 }
961 
TEST_F(ProfileCompilationInfoTest,UpdateProfileKeyFail)962 TEST_F(ProfileCompilationInfoTest, UpdateProfileKeyFail) {
963   std::vector<std::unique_ptr<const DexFile>> dex_files;
964   dex_files.push_back(std::unique_ptr<const DexFile>(dex1_renamed));
965 
966   ProfileCompilationInfo info;
967   AddMethod(&info, dex1, /* method_idx= */ 0);
968 
969   // Add a method index using the location we want to rename to.
970   // This will cause the rename to fail because an existing entry would already have that name.
971   AddMethod(&info, dex1_renamed, /* method_idx= */ 0);
972 
973   ASSERT_FALSE(info.UpdateProfileKeys(dex_files));
974 
975   // Release the ownership as this is held by the test class;
976   for (std::unique_ptr<const DexFile>& dex : dex_files) {
977     UNUSED(dex.release());
978   }
979 }
980 
TEST_F(ProfileCompilationInfoTest,FilteredLoading)981 TEST_F(ProfileCompilationInfoTest, FilteredLoading) {
982   ScratchFile profile;
983 
984   ProfileCompilationInfo saved_info;
985   std::vector<ProfileInlineCache> inline_caches = GetTestInlineCaches();
986 
987   // Add methods with inline caches.
988   for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
989     // Add a method which is part of the same dex file as one of the class from the inline caches.
990     ASSERT_TRUE(AddMethod(&saved_info, dex1, method_idx, inline_caches));
991     ASSERT_TRUE(AddMethod(&saved_info, dex2, method_idx, inline_caches));
992     // Add a method which is outside the set of dex files.
993     ASSERT_TRUE(AddMethod(&saved_info, dex4, method_idx, inline_caches));
994   }
995 
996   ASSERT_TRUE(saved_info.Save(GetFd(profile)));
997   ASSERT_EQ(0, profile.GetFile()->Flush());
998 
999   // Check that we get back what we saved.
1000   ProfileCompilationInfo loaded_info;
1001   ASSERT_TRUE(profile.GetFile()->ResetOffset());
1002 
1003   // Filter out dex locations. Keep only dex_location1 and dex_location3.
1004   ProfileCompilationInfo::ProfileLoadFilterFn filter_fn =
1005       [&dex1 = dex1, &dex3 = dex3](const std::string& dex_location, uint32_t checksum) -> bool {
1006           return (dex_location == dex1->GetLocation() && checksum == dex1->GetLocationChecksum())
1007               || (dex_location == dex3->GetLocation() && checksum == dex3->GetLocationChecksum());
1008         };
1009   ASSERT_TRUE(loaded_info.Load(GetFd(profile), true, filter_fn));
1010 
1011   // Verify that we filtered out locations during load.
1012 
1013   // Dex location 2 and 4 should have been filtered out
1014   for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
1015     ASSERT_TRUE(nullptr == GetMethod(loaded_info, dex2, method_idx));
1016     ASSERT_TRUE(nullptr == GetMethod(loaded_info, dex4, method_idx));
1017   }
1018 
1019   // Dex location 1 should have all all the inline caches referencing dex location 2 set to
1020   // missing types.
1021   for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
1022     // The methods for dex location 1 should be in the profile data.
1023     std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi1 =
1024         GetMethod(loaded_info, dex1, method_idx);
1025     ASSERT_TRUE(loaded_pmi1 != nullptr);
1026 
1027     // Verify the inline cache.
1028     // Everything should be as constructed by GetTestInlineCaches with the exception
1029     // of the inline caches referring types from dex_location2.
1030     // These should be set to IsMissingType.
1031     ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
1032 
1033     // Monomorphic types should remain the same as dex_location1 was kept.
1034     for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) {
1035       ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
1036       dex_pc_data.AddClass(0, dex::TypeIndex(0));
1037       ic_map->Put(dex_pc, dex_pc_data);
1038     }
1039     // Polymorphic inline cache should have been transformed to IsMissingType due to
1040     // the removal of dex_location2.
1041     for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) {
1042       ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
1043       dex_pc_data.SetIsMissingTypes();
1044       ic_map->Put(dex_pc, dex_pc_data);
1045     }
1046 
1047     // Megamorphic are not affected by removal of dex files.
1048     for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) {
1049       ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
1050       dex_pc_data.SetIsMegamorphic();
1051       ic_map->Put(dex_pc, dex_pc_data);
1052     }
1053     // Missing types are not affected be removal of dex files.
1054     for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) {
1055       ProfileCompilationInfo::DexPcData dex_pc_data(allocator_.get());
1056       dex_pc_data.SetIsMissingTypes();
1057       ic_map->Put(dex_pc, dex_pc_data);
1058     }
1059 
1060     ProfileCompilationInfo::OfflineProfileMethodInfo expected_pmi(ic_map);
1061 
1062     // The dex references should not have  dex_location2 in the list.
1063     expected_pmi.dex_references.emplace_back(
1064         dex1->GetLocation(), dex1->GetLocationChecksum(), dex1->NumMethodIds());
1065     expected_pmi.dex_references.emplace_back(
1066         dex3->GetLocation(), dex3->GetLocationChecksum(), dex3->NumMethodIds());
1067 
1068     // Now check that we get back what we expect.
1069     ASSERT_TRUE(*loaded_pmi1 == expected_pmi);
1070   }
1071 }
1072 
TEST_F(ProfileCompilationInfoTest,FilteredLoadingRemoveAll)1073 TEST_F(ProfileCompilationInfoTest, FilteredLoadingRemoveAll) {
1074   ScratchFile profile;
1075 
1076   ProfileCompilationInfo saved_info;
1077   std::vector<ProfileInlineCache> inline_caches = GetTestInlineCaches();
1078 
1079   // Add methods with inline caches.
1080   for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
1081     // Add a method which is part of the same dex file as one of the class from the inline caches.
1082     ASSERT_TRUE(AddMethod(&saved_info, dex1, method_idx, inline_caches));
1083     ASSERT_TRUE(AddMethod(&saved_info, dex2, method_idx, inline_caches));
1084     // Add a method which is outside the set of dex files.
1085     ASSERT_TRUE(AddMethod(&saved_info, dex4, method_idx, inline_caches));
1086   }
1087 
1088   ASSERT_TRUE(saved_info.Save(GetFd(profile)));
1089   ASSERT_EQ(0, profile.GetFile()->Flush());
1090 
1091   // Check that we get back what we saved.
1092   ProfileCompilationInfo loaded_info;
1093   ASSERT_TRUE(profile.GetFile()->ResetOffset());
1094 
1095   // Remove all elements.
1096   ProfileCompilationInfo::ProfileLoadFilterFn filter_fn =
1097       [](const std::string&, uint32_t) -> bool { return false; };
1098   ASSERT_TRUE(loaded_info.Load(GetFd(profile), true, filter_fn));
1099 
1100   // Verify that we filtered out everything.
1101   ASSERT_TRUE(IsEmpty(loaded_info));
1102 }
1103 
TEST_F(ProfileCompilationInfoTest,FilteredLoadingKeepAll)1104 TEST_F(ProfileCompilationInfoTest, FilteredLoadingKeepAll) {
1105   ScratchFile profile;
1106 
1107   ProfileCompilationInfo saved_info;
1108   std::vector<ProfileInlineCache> inline_caches = GetTestInlineCaches();
1109 
1110   // Add methods with inline caches.
1111   for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
1112     // Add a method which is part of the same dex file as one of the
1113     // class from the inline caches.
1114     ASSERT_TRUE(AddMethod(&saved_info, dex1, method_idx, inline_caches));
1115     // Add a method which is outside the set of dex files.
1116     ASSERT_TRUE(AddMethod(&saved_info, dex4, method_idx, inline_caches));
1117   }
1118 
1119   ASSERT_TRUE(saved_info.Save(GetFd(profile)));
1120   ASSERT_EQ(0, profile.GetFile()->Flush());
1121 
1122   // Check that we get back what we saved.
1123   ProfileCompilationInfo loaded_info;
1124   ASSERT_TRUE(profile.GetFile()->ResetOffset());
1125 
1126   // Keep all elements.
1127   ProfileCompilationInfo::ProfileLoadFilterFn filter_fn =
1128       [](const std::string&, uint32_t) -> bool { return true; };
1129   ASSERT_TRUE(loaded_info.Load(GetFd(profile), true, filter_fn));
1130 
1131 
1132   ASSERT_TRUE(loaded_info.Equals(saved_info));
1133 
1134   for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
1135     std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi1 =
1136         GetMethod(loaded_info, dex1, method_idx);
1137     ASSERT_TRUE(loaded_pmi1 != nullptr);
1138     ASSERT_TRUE(*loaded_pmi1 == inline_caches);
1139   }
1140   for (uint16_t method_idx = 0; method_idx < 10; method_idx++) {
1141     std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> loaded_pmi2 =
1142         GetMethod(loaded_info, dex4, method_idx);
1143     ASSERT_TRUE(loaded_pmi2 != nullptr);
1144     ASSERT_TRUE(*loaded_pmi2 == inline_caches);
1145   }
1146 }
1147 
1148 // Regression test: we were failing to do a filtering loading when the filtered dex file
1149 // contained profiled classes.
TEST_F(ProfileCompilationInfoTest,FilteredLoadingWithClasses)1150 TEST_F(ProfileCompilationInfoTest, FilteredLoadingWithClasses) {
1151   ScratchFile profile;
1152 
1153   // Save a profile with 2 dex files containing just classes.
1154   ProfileCompilationInfo saved_info;
1155   uint16_t item_count = 1000;
1156   for (uint16_t i = 0; i < item_count; i++) {
1157     ASSERT_TRUE(AddClass(&saved_info, dex1, dex::TypeIndex(i)));
1158     ASSERT_TRUE(AddClass(&saved_info, dex2, dex::TypeIndex(i)));
1159   }
1160 
1161   ASSERT_TRUE(saved_info.Save(GetFd(profile)));
1162   ASSERT_EQ(0, profile.GetFile()->Flush());
1163 
1164 
1165   // Filter out dex locations: kepp only dex_location2.
1166   ProfileCompilationInfo loaded_info;
1167   ASSERT_TRUE(profile.GetFile()->ResetOffset());
1168   ProfileCompilationInfo::ProfileLoadFilterFn filter_fn =
1169       [&dex2 = dex2](const std::string& dex_location, uint32_t checksum) -> bool {
1170           return (dex_location == dex2->GetLocation() && checksum == dex2->GetLocationChecksum());
1171         };
1172   ASSERT_TRUE(loaded_info.Load(GetFd(profile), true, filter_fn));
1173 
1174   // Compute the expectation.
1175   ProfileCompilationInfo expected_info;
1176   for (uint16_t i = 0; i < item_count; i++) {
1177     ASSERT_TRUE(AddClass(&expected_info, dex2, dex::TypeIndex(i)));
1178   }
1179 
1180   // Validate the expectation.
1181   ASSERT_TRUE(loaded_info.Equals(expected_info));
1182 }
1183 
1184 
TEST_F(ProfileCompilationInfoTest,ClearData)1185 TEST_F(ProfileCompilationInfoTest, ClearData) {
1186   ProfileCompilationInfo info;
1187   for (uint16_t i = 0; i < 10; i++) {
1188     ASSERT_TRUE(AddMethod(&info, dex1, /* method_idx= */ i));
1189   }
1190   ASSERT_FALSE(IsEmpty(info));
1191   info.ClearData();
1192   ASSERT_TRUE(IsEmpty(info));
1193 }
1194 
TEST_F(ProfileCompilationInfoTest,ClearDataAndSave)1195 TEST_F(ProfileCompilationInfoTest, ClearDataAndSave) {
1196   ProfileCompilationInfo info;
1197   for (uint16_t i = 0; i < 10; i++) {
1198     ASSERT_TRUE(AddMethod(&info, dex1, /* method_idx= */ i));
1199   }
1200   info.ClearData();
1201 
1202   ScratchFile profile;
1203   ASSERT_TRUE(info.Save(GetFd(profile)));
1204   ASSERT_EQ(0, profile.GetFile()->Flush());
1205 
1206   // Check that we get back what we saved.
1207   ProfileCompilationInfo loaded_info;
1208   ASSERT_TRUE(profile.GetFile()->ResetOffset());
1209   ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
1210   ASSERT_TRUE(loaded_info.Equals(info));
1211 }
1212 
TEST_F(ProfileCompilationInfoTest,InitProfiles)1213 TEST_F(ProfileCompilationInfoTest, InitProfiles) {
1214   ProfileCompilationInfo info;
1215   ASSERT_EQ(
1216       memcmp(info.GetVersion(),
1217              ProfileCompilationInfo::kProfileVersion,
1218              ProfileCompilationInfo::kProfileVersionSize),
1219       0);
1220   ASSERT_FALSE(info.IsForBootImage());
1221 
1222   ProfileCompilationInfo info1(/*for_boot_image=*/ true);
1223 
1224   ASSERT_EQ(
1225       memcmp(info1.GetVersion(),
1226              ProfileCompilationInfo::kProfileVersionForBootImage,
1227              ProfileCompilationInfo::kProfileVersionSize),
1228       0);
1229   ASSERT_TRUE(info1.IsForBootImage());
1230 }
1231 
TEST_F(ProfileCompilationInfoTest,VersionEquality)1232 TEST_F(ProfileCompilationInfoTest, VersionEquality) {
1233   ProfileCompilationInfo info(/*for_boot_image=*/ false);
1234   ProfileCompilationInfo info1(/*for_boot_image=*/ true);
1235   ASSERT_FALSE(info.Equals(info1));
1236 }
1237 
TEST_F(ProfileCompilationInfoTest,AllMethodFlags)1238 TEST_F(ProfileCompilationInfoTest, AllMethodFlags) {
1239   ProfileCompilationInfo info(/*for_boot_image*/ true);
1240 
1241   for (uint32_t index = 0; index <= kMaxHotnessFlagBootIndex; index++) {
1242     AddMethod(&info, dex1, index, static_cast<Hotness::Flag>(1 << index));
1243   }
1244 
1245   auto run_test = [&dex1 = dex1](const ProfileCompilationInfo& info) {
1246     for (uint32_t index = 0; index <= kMaxHotnessFlagBootIndex; index++) {
1247       EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex1, index)).IsInProfile());
1248       EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex1, index))
1249           .HasFlagSet(static_cast<Hotness::Flag>(1 << index))) << index << " "
1250             << info.GetMethodHotness(MethodReference(dex1, index)).GetFlags();
1251     }
1252   };
1253   run_test(info);
1254 
1255   // Save the profile.
1256   ScratchFile profile;
1257   ASSERT_TRUE(info.Save(GetFd(profile)));
1258   ASSERT_EQ(0, profile.GetFile()->Flush());
1259   ASSERT_TRUE(profile.GetFile()->ResetOffset());
1260 
1261   // Load the profile and make sure we can read the data and it matches what we expect.
1262   ProfileCompilationInfo loaded_info;
1263   ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
1264   run_test(loaded_info);
1265 }
1266 
TEST_F(ProfileCompilationInfoTest,AllMethodFlagsOnOneMethod)1267 TEST_F(ProfileCompilationInfoTest, AllMethodFlagsOnOneMethod) {
1268   ProfileCompilationInfo info(/*for_boot_image*/ true);
1269 
1270   // Set all flags on a single method.
1271   for (uint32_t index = 0; index <= kMaxHotnessFlagBootIndex; index++) {
1272     AddMethod(&info, dex1, 0, static_cast<Hotness::Flag>(1 << index));
1273   }
1274 
1275   auto run_test = [&dex1 = dex1](const ProfileCompilationInfo& info) {
1276     for (uint32_t index = 0; index <= kMaxHotnessFlagBootIndex; index++) {
1277       EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex1, 0)).IsInProfile());
1278       EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex1, 0))
1279           .HasFlagSet(static_cast<Hotness::Flag>(1 << index)));
1280     }
1281   };
1282   run_test(info);
1283 
1284   // Save the profile.
1285   ScratchFile profile;
1286   ASSERT_TRUE(info.Save(GetFd(profile)));
1287   ASSERT_EQ(0, profile.GetFile()->Flush());
1288   ASSERT_TRUE(profile.GetFile()->ResetOffset());
1289 
1290   // Load the profile and make sure we can read the data and it matches what we expect.
1291   ProfileCompilationInfo loaded_info;
1292   ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
1293   run_test(loaded_info);
1294 }
1295 
1296 
TEST_F(ProfileCompilationInfoTest,MethodFlagsMerge)1297 TEST_F(ProfileCompilationInfoTest, MethodFlagsMerge) {
1298   ProfileCompilationInfo info1(/*for_boot_image*/ true);
1299   ProfileCompilationInfo info2(/*for_boot_image*/ true);
1300 
1301   // Set a few flags on a 2 different methods in each of the profile.
1302   for (uint32_t index = 0; index <= kMaxHotnessFlagBootIndex / 4; index++) {
1303     AddMethod(&info1, dex1, 0, static_cast<Hotness::Flag>(1 << index));
1304     AddMethod(&info2, dex1, 1, static_cast<Hotness::Flag>(1 << index));
1305   }
1306 
1307   // Set a few more flags on the method 1.
1308   for (uint32_t index = kMaxHotnessFlagBootIndex / 4 + 1;
1309        index <= kMaxHotnessFlagBootIndex / 2;
1310        index++) {
1311     AddMethod(&info2, dex1, 1, static_cast<Hotness::Flag>(1 << index));
1312   }
1313 
1314   ASSERT_TRUE(info1.MergeWith(info2));
1315 
1316   auto run_test = [&dex1 = dex1](const ProfileCompilationInfo& info) {
1317     // Assert that the flags were merged correctly for both methods.
1318     for (uint32_t index = 0; index <= kMaxHotnessFlagBootIndex / 4; index++) {
1319       EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex1, 0)).IsInProfile());
1320       EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex1, 0))
1321           .HasFlagSet(static_cast<Hotness::Flag>(1 << index)));
1322 
1323       EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex1, 1)).IsInProfile());
1324       EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex1, 1))
1325           .HasFlagSet(static_cast<Hotness::Flag>(1 << index)));
1326     }
1327 
1328     // Assert that no flags were merged unnecessary.
1329     for (uint32_t index = kMaxHotnessFlagBootIndex / 4 + 1;
1330          index <= kMaxHotnessFlagBootIndex / 2;
1331          index++) {
1332       EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex1, 0)).IsInProfile());
1333       EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex1, 0))
1334           .HasFlagSet(static_cast<Hotness::Flag>(1 << index)));
1335 
1336       EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex1, 1)).IsInProfile());
1337       EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex1, 1))
1338           .HasFlagSet(static_cast<Hotness::Flag>(1 << index)));
1339     }
1340 
1341     // Assert that no extra flags were added.
1342     for (uint32_t index = kMaxHotnessFlagBootIndex / 2 + 1;
1343          index <= kMaxHotnessFlagBootIndex;
1344          index++) {
1345       EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex1, 0))
1346           .HasFlagSet(static_cast<Hotness::Flag>(1 << index)));
1347       EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex1, 1))
1348           .HasFlagSet(static_cast<Hotness::Flag>(1 << index)));
1349     }
1350   };
1351 
1352   run_test(info1);
1353 
1354   // Save the profile.
1355   ScratchFile profile;
1356   ASSERT_TRUE(info1.Save(GetFd(profile)));
1357   ASSERT_EQ(0, profile.GetFile()->Flush());
1358   ASSERT_TRUE(profile.GetFile()->ResetOffset());
1359 
1360   // Load the profile and make sure we can read the data and it matches what we expect.
1361   ProfileCompilationInfo loaded_info;
1362   ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
1363   run_test(loaded_info);
1364 }
1365 
TEST_F(ProfileCompilationInfoTest,SizeStressTestAllIn)1366 TEST_F(ProfileCompilationInfoTest, SizeStressTestAllIn) {
1367   SizeStressTest(/*random=*/ false);
1368 }
1369 
TEST_F(ProfileCompilationInfoTest,SizeStressTestAllInRandom)1370 TEST_F(ProfileCompilationInfoTest, SizeStressTestAllInRandom) {
1371   SizeStressTest(/*random=*/ true);
1372 }
1373 
1374 // Verifies that we correctly add methods to the profile according to their flags.
TEST_F(ProfileCompilationInfoTest,AddMethodsProfileMethodInfoBasic)1375 TEST_F(ProfileCompilationInfoTest, AddMethodsProfileMethodInfoBasic) {
1376   std::unique_ptr<const DexFile> dex(OpenTestDexFile("ManyMethods"));
1377 
1378   ProfileCompilationInfo info;
1379 
1380   MethodReference hot(dex.get(), 0);
1381   MethodReference hot_startup(dex.get(), 1);
1382   MethodReference startup(dex.get(), 2);
1383 
1384   // Add methods
1385   ASSERT_TRUE(info.AddMethod(ProfileMethodInfo(hot), Hotness::kFlagHot));
1386   ASSERT_TRUE(info.AddMethod(
1387       ProfileMethodInfo(hot_startup),
1388       static_cast<Hotness::Flag>(Hotness::kFlagHot | Hotness::kFlagStartup)));
1389   ASSERT_TRUE(info.AddMethod(ProfileMethodInfo(startup), Hotness::kFlagStartup));
1390 
1391   // Verify the profile recorded them correctly.
1392   EXPECT_TRUE(info.GetMethodHotness(hot).IsInProfile());
1393   EXPECT_EQ(info.GetMethodHotness(hot).GetFlags(), Hotness::kFlagHot);
1394 
1395   EXPECT_TRUE(info.GetMethodHotness(hot_startup).IsInProfile());
1396   EXPECT_EQ(info.GetMethodHotness(hot_startup).GetFlags(),
1397             static_cast<uint32_t>(Hotness::kFlagHot | Hotness::kFlagStartup));
1398 
1399   EXPECT_TRUE(info.GetMethodHotness(startup).IsInProfile());
1400   EXPECT_EQ(info.GetMethodHotness(startup).GetFlags(), Hotness::kFlagStartup);
1401 }
1402 
1403 // Verifies that we correctly add inline caches to the profile only for hot methods.
TEST_F(ProfileCompilationInfoTest,AddMethodsProfileMethodInfoInlineCaches)1404 TEST_F(ProfileCompilationInfoTest, AddMethodsProfileMethodInfoInlineCaches) {
1405   ProfileCompilationInfo info;
1406   MethodReference hot(dex1, 0);
1407   MethodReference startup(dex1, 2);
1408 
1409   // Add inline caches with the methods. The profile should record only the one for the hot method.
1410   std::vector<TypeReference> types = {};
1411   ProfileMethodInfo::ProfileInlineCache ic(/*dex_pc*/ 0, /*missing_types*/true, types);
1412   std::vector<ProfileMethodInfo::ProfileInlineCache> inline_caches = {ic};
1413   info.AddMethod(ProfileMethodInfo(hot, inline_caches), Hotness::kFlagHot);
1414   info.AddMethod(ProfileMethodInfo(startup, inline_caches), Hotness::kFlagStartup);
1415 
1416   // Check the hot method's inline cache.
1417   std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> hot_pmi =
1418       GetMethod(info, dex1, hot.index);
1419   ASSERT_TRUE(hot_pmi != nullptr);
1420   ASSERT_EQ(hot_pmi->inline_caches->size(), 1u);
1421   ASSERT_TRUE(hot_pmi->inline_caches->Get(0).is_missing_types);
1422 
1423   // Check there's no inline caches for the startup method.
1424   ASSERT_TRUE(GetMethod(info, dex1, startup.index) == nullptr);
1425 }
1426 
1427 // Verifies that we correctly add methods to the profile according to their flags.
TEST_F(ProfileCompilationInfoTest,AddMethodsProfileMethodInfoFail)1428 TEST_F(ProfileCompilationInfoTest, AddMethodsProfileMethodInfoFail) {
1429   ProfileCompilationInfo info;
1430 
1431   MethodReference hot(dex1, 0);
1432   MethodReference bad_ref(dex1, kMaxMethodIds);
1433 
1434   std::vector<ProfileMethodInfo> pmis = {ProfileMethodInfo(hot), ProfileMethodInfo(bad_ref)};
1435   ASSERT_FALSE(info.AddMethods(pmis, Hotness::kFlagHot));
1436 }
1437 
1438 // Verify that we can add methods with annotations.
TEST_F(ProfileCompilationInfoTest,AddAnnotationsToMethods)1439 TEST_F(ProfileCompilationInfoTest, AddAnnotationsToMethods) {
1440   ProfileCompilationInfo info;
1441 
1442   ProfileSampleAnnotation psa1("test1");
1443   ProfileSampleAnnotation psa2("test2");
1444   // Save a few methods using different annotations, some overlapping, some not.
1445   for (uint16_t i = 0; i < 10; i++) {
1446     ASSERT_TRUE(AddMethod(&info, dex1, /* method_idx= */ i, Hotness::kFlagHot, psa1));
1447   }
1448   for (uint16_t i = 5; i < 15; i++) {
1449     ASSERT_TRUE(AddMethod(&info, dex1, /* method_idx= */ i, Hotness::kFlagHot, psa2));
1450   }
1451 
1452   auto run_test = [&dex1 = dex1, &psa1 = psa1, &psa2 = psa2](const ProfileCompilationInfo& info) {
1453     // Check that all methods are in.
1454     for (uint16_t i = 0; i < 10; i++) {
1455       EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex1, i), psa1).IsInProfile());
1456       EXPECT_TRUE(info.GetHotMethodInfo(MethodReference(dex1, i), psa1) != nullptr);
1457     }
1458     for (uint16_t i = 5; i < 15; i++) {
1459       EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex1, i), psa2).IsInProfile());
1460       EXPECT_TRUE(info.GetHotMethodInfo(MethodReference(dex1, i), psa2) != nullptr);
1461     }
1462     // Check that the non-overlapping methods are not added with a wrong annotation.
1463     for (uint16_t i = 10; i < 15; i++) {
1464       EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex1, i), psa1).IsInProfile());
1465       EXPECT_FALSE(info.GetHotMethodInfo(MethodReference(dex1, i), psa1) != nullptr);
1466     }
1467     for (uint16_t i = 0; i < 5; i++) {
1468       EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex1, i), psa2).IsInProfile());
1469       EXPECT_FALSE(info.GetHotMethodInfo(MethodReference(dex1, i), psa2) != nullptr);
1470     }
1471     // Check that when querying without an annotation only the first one is searched.
1472     for (uint16_t i = 0; i < 10; i++) {
1473       EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex1, i)).IsInProfile());
1474       EXPECT_TRUE(info.GetHotMethodInfo(MethodReference(dex1, i)) != nullptr);
1475     }
1476     // ... this should be false because they belong the second appearance of dex1.
1477     for (uint16_t i = 10; i < 15; i++) {
1478       EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex1, i)).IsInProfile());
1479       EXPECT_FALSE(info.GetHotMethodInfo(MethodReference(dex1, i)) != nullptr);
1480     }
1481 
1482     // Check that the methods cannot be found with a non existing annotation.
1483     MethodReference ref(dex1, 0);
1484     ProfileSampleAnnotation not_exisiting("A");
1485     EXPECT_FALSE(info.GetMethodHotness(ref, not_exisiting).IsInProfile());
1486     EXPECT_FALSE(info.GetHotMethodInfo(ref, not_exisiting) != nullptr);
1487   };
1488 
1489   // Run the test before save.
1490   run_test(info);
1491 
1492   ScratchFile profile;
1493   ASSERT_TRUE(info.Save(GetFd(profile)));
1494   ASSERT_EQ(0, profile.GetFile()->Flush());
1495 
1496   // Check that we get back what we saved.
1497   ProfileCompilationInfo loaded_info;
1498   ASSERT_TRUE(profile.GetFile()->ResetOffset());
1499   ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
1500   ASSERT_TRUE(loaded_info.Equals(info));
1501 
1502   // Run the test after save and load.
1503   run_test(loaded_info);
1504 }
1505 
1506 // Verify that we can add classes with annotations.
TEST_F(ProfileCompilationInfoTest,AddAnnotationsToClasses)1507 TEST_F(ProfileCompilationInfoTest, AddAnnotationsToClasses) {
1508   ProfileCompilationInfo info;
1509 
1510   ProfileSampleAnnotation psa1("test1");
1511   ProfileSampleAnnotation psa2("test2");
1512   // Save a few classes using different annotations, some overlapping, some not.
1513   for (uint16_t i = 0; i < 10; i++) {
1514     ASSERT_TRUE(AddClass(&info, dex1, dex::TypeIndex(i), psa1));
1515   }
1516   for (uint16_t i = 5; i < 15; i++) {
1517     ASSERT_TRUE(AddClass(&info, dex1, dex::TypeIndex(i), psa2));
1518   }
1519 
1520   auto run_test = [&dex1 = dex1, &psa1 = psa1, &psa2 = psa2](const ProfileCompilationInfo& info) {
1521     // Check that all classes are in.
1522     for (uint16_t i = 0; i < 10; i++) {
1523       EXPECT_TRUE(info.ContainsClass(*dex1, dex::TypeIndex(i), psa1));
1524     }
1525     for (uint16_t i = 5; i < 15; i++) {
1526       EXPECT_TRUE(info.ContainsClass(*dex1, dex::TypeIndex(i), psa2));
1527     }
1528     // Check that the non-overlapping classes are not added with a wrong annotation.
1529     for (uint16_t i = 10; i < 15; i++) {
1530       EXPECT_FALSE(info.ContainsClass(*dex1, dex::TypeIndex(i), psa1));
1531     }
1532     for (uint16_t i = 0; i < 5; i++) {
1533       EXPECT_FALSE(info.ContainsClass(*dex1, dex::TypeIndex(i), psa2));
1534     }
1535     // Check that when querying without an annotation only the first one is searched.
1536     for (uint16_t i = 0; i < 10; i++) {
1537       EXPECT_TRUE(info.ContainsClass(*dex1, dex::TypeIndex(i)));
1538     }
1539     // ... this should be false because they belong the second appearance of dex1.
1540     for (uint16_t i = 10; i < 15; i++) {
1541       EXPECT_FALSE(info.ContainsClass(*dex1, dex::TypeIndex(i)));
1542     }
1543 
1544     // Check that the classes cannot be found with a non existing annotation.
1545     EXPECT_FALSE(info.ContainsClass(*dex1, dex::TypeIndex(0), ProfileSampleAnnotation("new_test")));
1546   };
1547 
1548   // Run the test before save.
1549   run_test(info);
1550 
1551   ScratchFile profile;
1552   ASSERT_TRUE(info.Save(GetFd(profile)));
1553   ASSERT_EQ(0, profile.GetFile()->Flush());
1554 
1555   // Check that we get back what we saved.
1556   ProfileCompilationInfo loaded_info;
1557   ASSERT_TRUE(profile.GetFile()->ResetOffset());
1558   ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
1559   ASSERT_TRUE(loaded_info.Equals(info));
1560 
1561   // Run the test after save and load.
1562   run_test(loaded_info);
1563 }
1564 
1565 // Verify we can merge samples with annotations.
TEST_F(ProfileCompilationInfoTest,MergeWithAnnotations)1566 TEST_F(ProfileCompilationInfoTest, MergeWithAnnotations) {
1567   ProfileCompilationInfo info1;
1568   ProfileCompilationInfo info2;
1569 
1570   ProfileSampleAnnotation psa1("test1");
1571   ProfileSampleAnnotation psa2("test2");
1572 
1573   for (uint16_t i = 0; i < 10; i++) {
1574     ASSERT_TRUE(AddMethod(&info1, dex1, /* method_idx= */ i, Hotness::kFlagHot, psa1));
1575     ASSERT_TRUE(AddClass(&info1, dex1, dex::TypeIndex(i), psa1));
1576   }
1577   for (uint16_t i = 5; i < 15; i++) {
1578     ASSERT_TRUE(AddMethod(&info2, dex1, /* method_idx= */ i, Hotness::kFlagHot, psa1));
1579     ASSERT_TRUE(AddMethod(&info2, dex1, /* method_idx= */ i, Hotness::kFlagHot, psa2));
1580     ASSERT_TRUE(AddMethod(&info2, dex2, /* method_idx= */ i, Hotness::kFlagHot, psa2));
1581     ASSERT_TRUE(AddClass(&info2, dex1, dex::TypeIndex(i), psa1));
1582     ASSERT_TRUE(AddClass(&info2, dex1, dex::TypeIndex(i), psa2));
1583   }
1584 
1585   ProfileCompilationInfo info;
1586   ASSERT_TRUE(info.MergeWith(info1));
1587   ASSERT_TRUE(info.MergeWith(info2));
1588 
1589   // Check that all items are in.
1590   for (uint16_t i = 0; i < 15; i++) {
1591     EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex1, i), psa1).IsInProfile());
1592     EXPECT_TRUE(info.ContainsClass(*dex1, dex::TypeIndex(i), psa1));
1593   }
1594   for (uint16_t i = 5; i < 15; i++) {
1595     EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex1, i), psa2).IsInProfile());
1596     EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex2, i), psa2).IsInProfile());
1597     EXPECT_TRUE(info.ContainsClass(*dex1, dex::TypeIndex(i), psa2));
1598   }
1599 
1600   // Check that the non-overlapping items are not added with a wrong annotation.
1601   for (uint16_t i = 0; i < 5; i++) {
1602     EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex1, i), psa2).IsInProfile());
1603     EXPECT_FALSE(info.GetMethodHotness(MethodReference(dex2, i), psa2).IsInProfile());
1604     EXPECT_FALSE(info.ContainsClass(*dex1, dex::TypeIndex(i), psa2));
1605   }
1606 }
1607 
1608 // Verify the bulk extraction API.
TEST_F(ProfileCompilationInfoTest,ExtractInfoWithAnnations)1609 TEST_F(ProfileCompilationInfoTest, ExtractInfoWithAnnations) {
1610   ProfileCompilationInfo info;
1611 
1612   ProfileSampleAnnotation psa1("test1");
1613   ProfileSampleAnnotation psa2("test2");
1614 
1615   std::set<dex::TypeIndex> expected_classes;
1616   std::set<uint16_t> expected_hot_methods;
1617   std::set<uint16_t> expected_startup_methods;
1618   std::set<uint16_t> expected_post_startup_methods;
1619 
1620   for (uint16_t i = 0; i < 10; i++) {
1621     ASSERT_TRUE(AddMethod(&info, dex1, /* method_idx= */ i, Hotness::kFlagHot, psa1));
1622     ASSERT_TRUE(AddClass(&info, dex1, dex::TypeIndex(i), psa1));
1623     expected_hot_methods.insert(i);
1624     expected_classes.insert(dex::TypeIndex(i));
1625   }
1626   for (uint16_t i = 5; i < 15; i++) {
1627     ASSERT_TRUE(AddMethod(&info, dex1, /* method_idx= */ i, Hotness::kFlagHot, psa2));
1628     ASSERT_TRUE(AddMethod(&info, dex1, /* method_idx= */ i, Hotness::kFlagStartup, psa1));
1629     expected_startup_methods.insert(i);
1630   }
1631 
1632   std::set<dex::TypeIndex> classes;
1633   std::set<uint16_t> hot_methods;
1634   std::set<uint16_t> startup_methods;
1635   std::set<uint16_t> post_startup_methods;
1636 
1637   EXPECT_TRUE(info.GetClassesAndMethods(
1638       *dex1, &classes, &hot_methods, &startup_methods, &post_startup_methods, psa1));
1639   EXPECT_EQ(expected_classes, classes);
1640   EXPECT_EQ(expected_hot_methods, hot_methods);
1641   EXPECT_EQ(expected_startup_methods, startup_methods);
1642   EXPECT_EQ(expected_post_startup_methods, post_startup_methods);
1643 
1644   EXPECT_FALSE(info.GetClassesAndMethods(
1645       *dex1,
1646       &classes,
1647       &hot_methods,
1648       &startup_methods,
1649       &post_startup_methods,
1650       ProfileSampleAnnotation("new_test")));
1651 }
1652 
1653 // Verify the behavior for adding methods with annotations and different dex checksums.
TEST_F(ProfileCompilationInfoTest,AddMethodsWithAnnotationAndDifferentChecksum)1654 TEST_F(ProfileCompilationInfoTest, AddMethodsWithAnnotationAndDifferentChecksum) {
1655   ProfileCompilationInfo info;
1656 
1657   ProfileSampleAnnotation psa1("test1");
1658   ProfileSampleAnnotation psa2("test2");
1659 
1660   MethodReference ref(dex1, 0);
1661   MethodReference ref_checksum_missmatch(dex1_checksum_missmatch, 1);
1662 
1663   ASSERT_TRUE(info.AddMethod(ProfileMethodInfo(ref), Hotness::kFlagHot, psa1));
1664   // Adding a method with a different dex checksum and the same annotation should fail.
1665   ASSERT_FALSE(info.AddMethod(ProfileMethodInfo(ref_checksum_missmatch), Hotness::kFlagHot, psa1));
1666   // However, a method with a different dex checksum and a different annotation should be ok.
1667   ASSERT_TRUE(info.AddMethod(ProfileMethodInfo(ref_checksum_missmatch), Hotness::kFlagHot, psa2));
1668 }
1669 
1670 // Verify the behavior for searching method with annotations and different dex checksums.
TEST_F(ProfileCompilationInfoTest,FindMethodsWithAnnotationAndDifferentChecksum)1671 TEST_F(ProfileCompilationInfoTest, FindMethodsWithAnnotationAndDifferentChecksum) {
1672   ProfileCompilationInfo info;
1673 
1674   ProfileSampleAnnotation psa1("test1");
1675 
1676   MethodReference ref(dex1, 0);
1677   MethodReference ref_checksum_missmatch(dex1_checksum_missmatch, 0);
1678 
1679   ASSERT_TRUE(info.AddMethod(ProfileMethodInfo(ref), Hotness::kFlagHot, psa1));
1680 
1681   // The method should be in the profile when searched with the correct data.
1682   EXPECT_TRUE(info.GetMethodHotness(ref, psa1).IsInProfile());
1683   // We should get a negative result if the dex checksum  does not match.
1684   EXPECT_FALSE(info.GetMethodHotness(ref_checksum_missmatch, psa1).IsInProfile());
1685 
1686   // If we search without annotation we should have the same behaviour.
1687   EXPECT_TRUE(info.GetMethodHotness(ref).IsInProfile());
1688   EXPECT_FALSE(info.GetMethodHotness(ref_checksum_missmatch).IsInProfile());
1689 }
1690 
TEST_F(ProfileCompilationInfoTest,ClearDataAndAdjustVersionRegularToBoot)1691 TEST_F(ProfileCompilationInfoTest, ClearDataAndAdjustVersionRegularToBoot) {
1692   ProfileCompilationInfo info;
1693 
1694   AddMethod(&info, dex1, /* method_idx= */ 0, Hotness::kFlagHot);
1695 
1696   info.ClearDataAndAdjustVersion(/*for_boot_image=*/true);
1697   ASSERT_TRUE(info.IsEmpty());
1698   ASSERT_TRUE(info.IsForBootImage());
1699 }
1700 
TEST_F(ProfileCompilationInfoTest,ClearDataAndAdjustVersionBootToRegular)1701 TEST_F(ProfileCompilationInfoTest, ClearDataAndAdjustVersionBootToRegular) {
1702   ProfileCompilationInfo info(/*for_boot_image=*/true);
1703 
1704   AddMethod(&info, dex1, /* method_idx= */ 0, Hotness::kFlagHot);
1705 
1706   info.ClearDataAndAdjustVersion(/*for_boot_image=*/false);
1707   ASSERT_TRUE(info.IsEmpty());
1708   ASSERT_FALSE(info.IsForBootImage());
1709 }
1710 
1711 template<class T>
sort(const std::list<T> & list)1712 static std::list<T> sort(const std::list<T>& list) {
1713   std::list<T> copy(list);
1714   copy.sort();
1715   return copy;
1716 }
1717 
1718 // Verify we can extract profile data
TEST_F(ProfileCompilationInfoTest,ExtractProfileData)1719 TEST_F(ProfileCompilationInfoTest, ExtractProfileData) {
1720   // Setup test data
1721   ProfileCompilationInfo info;
1722 
1723   ProfileSampleAnnotation psa1("test1");
1724   ProfileSampleAnnotation psa2("test2");
1725 
1726   for (uint16_t i = 0; i < 10; i++) {
1727     // Add dex1 data with different annotations so that we can check the annotation count.
1728     ASSERT_TRUE(AddMethod(&info, dex1, /* method_idx= */ i, Hotness::kFlagHot, psa1));
1729     ASSERT_TRUE(AddClass(&info, dex1, dex::TypeIndex(i), psa1));
1730     ASSERT_TRUE(AddMethod(&info, dex1, /* method_idx= */ i, Hotness::kFlagStartup, psa2));
1731     ASSERT_TRUE(AddClass(&info, dex1, dex::TypeIndex(i), psa2));
1732     ASSERT_TRUE(AddMethod(&info, dex2, /* method_idx= */ i, Hotness::kFlagHot, psa2));
1733     // dex3 will not be used in the data extraction
1734     ASSERT_TRUE(AddMethod(&info, dex3, /* method_idx= */ i, Hotness::kFlagHot, psa2));
1735   }
1736 
1737   std::vector<std::unique_ptr<const DexFile>> dex_files;
1738   dex_files.push_back(std::unique_ptr<const DexFile>(dex1));
1739   dex_files.push_back(std::unique_ptr<const DexFile>(dex2));
1740 
1741   // Run the test: extract the data for dex1 and dex2
1742   std::unique_ptr<FlattenProfileData> flattenProfileData = info.ExtractProfileData(dex_files);
1743 
1744   // Check the results
1745   ASSERT_TRUE(flattenProfileData != nullptr);
1746   ASSERT_EQ(flattenProfileData->GetMaxAggregationForMethods(), 2u);
1747   ASSERT_EQ(flattenProfileData->GetMaxAggregationForClasses(), 2u);
1748 
1749   const SafeMap<MethodReference, ItemMetadata>& methods = flattenProfileData->GetMethodData();
1750   const SafeMap<TypeReference, ItemMetadata>& classes = flattenProfileData->GetClassData();
1751   ASSERT_EQ(methods.size(), 20u);  // 10 methods in dex1, 10 in dex2
1752   ASSERT_EQ(classes.size(), 10u);  // 10 methods in dex1
1753 
1754   std::list<ProfileSampleAnnotation> expectedAnnotations1({psa1, psa2});
1755   std::list<ProfileSampleAnnotation> expectedAnnotations2({psa2});
1756   for (uint16_t i = 0; i < 10; i++) {
1757     // Check dex1 methods.
1758     auto mIt1 = methods.find(MethodReference(dex1, i));
1759     ASSERT_TRUE(mIt1 != methods.end());
1760     ASSERT_EQ(mIt1->second.GetFlags(), Hotness::kFlagHot | Hotness::kFlagStartup);
1761     ASSERT_EQ(sort(mIt1->second.GetAnnotations()), expectedAnnotations1);
1762     // Check dex1 classes
1763     auto cIt1 = classes.find(TypeReference(dex1, dex::TypeIndex(i)));
1764     ASSERT_TRUE(cIt1 != classes.end());
1765     ASSERT_EQ(cIt1->second.GetFlags(), 0);
1766     ASSERT_EQ(sort(cIt1->second.GetAnnotations()), expectedAnnotations1);
1767     // Check dex2 methods.
1768     auto mIt2 = methods.find(MethodReference(dex2, i));
1769     ASSERT_TRUE(mIt2 != methods.end());
1770     ASSERT_EQ(mIt2->second.GetFlags(), Hotness::kFlagHot);
1771     ASSERT_EQ(sort(mIt2->second.GetAnnotations()), expectedAnnotations2);
1772   }
1773 
1774   // Release the ownership as this is held by the test class;
1775   for (std::unique_ptr<const DexFile>& dex : dex_files) {
1776     UNUSED(dex.release());
1777   }
1778 }
1779 
1780 // Verify we can merge 2 previously flatten data.
TEST_F(ProfileCompilationInfoTest,MergeFlattenData)1781 TEST_F(ProfileCompilationInfoTest, MergeFlattenData) {
1782   // Setup test data: two profiles with different content which will be used
1783   // to extract FlattenProfileData, later to be merged.
1784   ProfileCompilationInfo info1;
1785   ProfileCompilationInfo info2;
1786 
1787   ProfileSampleAnnotation psa1("test1");
1788   ProfileSampleAnnotation psa2("test2");
1789 
1790   for (uint16_t i = 0; i < 10; i++) {
1791     // Add dex1 data with different annotations so that we can check the annotation count.
1792     ASSERT_TRUE(AddMethod(&info1, dex1, /* method_idx= */ i, Hotness::kFlagHot, psa1));
1793     ASSERT_TRUE(AddClass(&info2, dex1, dex::TypeIndex(i), psa1));
1794     ASSERT_TRUE(AddMethod(&info1, dex1, /* method_idx= */ i, Hotness::kFlagStartup, psa2));
1795     ASSERT_TRUE(AddClass(&info1, dex1, dex::TypeIndex(i), psa2));
1796     ASSERT_TRUE(AddMethod(i % 2 == 0 ? &info1 : &info2, dex2,
1797                           /* method_idx= */ i,
1798                           Hotness::kFlagHot,
1799                           psa2));
1800   }
1801 
1802   std::vector<std::unique_ptr<const DexFile>> dex_files;
1803   dex_files.push_back(std::unique_ptr<const DexFile>(dex1));
1804   dex_files.push_back(std::unique_ptr<const DexFile>(dex2));
1805 
1806   // Run the test: extract the data for dex1 and dex2 and then merge it into
1807   std::unique_ptr<FlattenProfileData> flattenProfileData1 = info1.ExtractProfileData(dex_files);
1808   std::unique_ptr<FlattenProfileData> flattenProfileData2 = info2.ExtractProfileData(dex_files);
1809 
1810   flattenProfileData1->MergeData(*flattenProfileData2);
1811   // Check the results
1812   ASSERT_EQ(flattenProfileData1->GetMaxAggregationForMethods(), 2u);
1813   ASSERT_EQ(flattenProfileData1->GetMaxAggregationForClasses(), 2u);
1814 
1815   const SafeMap<MethodReference, ItemMetadata>& methods = flattenProfileData1->GetMethodData();
1816   const SafeMap<TypeReference, ItemMetadata>& classes = flattenProfileData1->GetClassData();
1817   ASSERT_EQ(methods.size(), 20u);  // 10 methods in dex1, 10 in dex2
1818   ASSERT_EQ(classes.size(), 10u);  // 10 methods in dex1
1819 
1820   std::list<ProfileSampleAnnotation> expectedAnnotations1({psa1, psa2});
1821   std::list<ProfileSampleAnnotation> expectedAnnotations2({psa2});
1822   for (uint16_t i = 0; i < 10; i++) {
1823     // Check dex1 methods.
1824     auto mIt1 = methods.find(MethodReference(dex1, i));
1825     ASSERT_TRUE(mIt1 != methods.end());
1826     ASSERT_EQ(mIt1->second.GetFlags(), Hotness::kFlagHot | Hotness::kFlagStartup);
1827     ASSERT_EQ(sort(mIt1->second.GetAnnotations()), expectedAnnotations1);
1828     // Check dex1 classes
1829     auto cIt1 = classes.find(TypeReference(dex1, dex::TypeIndex(i)));
1830     ASSERT_TRUE(cIt1 != classes.end());
1831     ASSERT_EQ(cIt1->second.GetFlags(), 0);
1832     ASSERT_EQ(sort(cIt1->second.GetAnnotations()).size(), expectedAnnotations1.size());
1833     ASSERT_EQ(sort(cIt1->second.GetAnnotations()), expectedAnnotations1);
1834     // Check dex2 methods.
1835     auto mIt2 = methods.find(MethodReference(dex2, i));
1836     ASSERT_TRUE(mIt2 != methods.end());
1837     ASSERT_EQ(mIt2->second.GetFlags(), Hotness::kFlagHot);
1838     ASSERT_EQ(sort(mIt2->second.GetAnnotations()), expectedAnnotations2);
1839   }
1840 
1841   // Release the ownership as this is held by the test class;
1842   for (std::unique_ptr<const DexFile>& dex : dex_files) {
1843     UNUSED(dex.release());
1844   }
1845 }
1846 
1847 }  // namespace art
1848