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