diff options
| -rw-r--r-- | profman/profile_assistant_test.cc | 39 | ||||
| -rw-r--r-- | profman/profman.cc | 14 | ||||
| -rw-r--r-- | runtime/jit/jit_code_cache.cc | 6 | ||||
| -rw-r--r-- | runtime/jit/profile_compilation_info.cc | 79 | ||||
| -rw-r--r-- | runtime/jit/profile_compilation_info.h | 27 | ||||
| -rw-r--r-- | runtime/jit/profile_compilation_info_test.cc | 139 | ||||
| -rw-r--r-- | test/ProfileTestMultiDex/Main.java | 4 |
7 files changed, 255 insertions, 53 deletions
diff --git a/profman/profile_assistant_test.cc b/profman/profile_assistant_test.cc index 5a758aedf4..52f3b52ee2 100644 --- a/profman/profile_assistant_test.cc +++ b/profman/profile_assistant_test.cc @@ -182,7 +182,8 @@ class ProfileAssistantTest : public CommonRuntimeTest { void AssertInlineCaches(ArtMethod* method, const std::set<mirror::Class*>& expected_clases, const ProfileCompilationInfo& info, - bool megamorphic) + bool is_megamorphic, + bool is_missing_types) REQUIRES_SHARED(Locks::mutator_lock_) { ProfileCompilationInfo::OfflineProfileMethodInfo pmi; ASSERT_TRUE(info.GetMethod(method->GetDexFile()->GetLocation(), @@ -192,7 +193,8 @@ class ProfileAssistantTest : public CommonRuntimeTest { ASSERT_EQ(pmi.inline_caches.size(), 1u); ProfileCompilationInfo::DexPcData dex_pc_data = pmi.inline_caches.begin()->second; - ASSERT_EQ(dex_pc_data.is_megamorphic, megamorphic); + ASSERT_EQ(dex_pc_data.is_megamorphic, is_megamorphic); + ASSERT_EQ(dex_pc_data.is_missing_types, is_missing_types); ASSERT_EQ(expected_clases.size(), dex_pc_data.classes.size()); size_t found = 0; for (mirror::Class* it : expected_clases) { @@ -482,6 +484,7 @@ TEST_F(ProfileAssistantTest, TestProfileCreateInlineCache) { "LTestInline;->inlineMonomorphic(LSuper;)I+LSubA;", "LTestInline;->inlinePolymorphic(LSuper;)I+LSubA;,LSubB;,LSubC;", "LTestInline;->inlineMegamorphic(LSuper;)I+LSubA;,LSubB;,LSubC;,LSubD;,LSubE;", + "LTestInline;->inlineMissingTypes(LSuper;)I+missing_types", "LTestInline;->noInlineCache(LSuper;)I" }; std::string input_file_contents; @@ -521,7 +524,11 @@ TEST_F(ProfileAssistantTest, TestProfileCreateInlineCache) { ASSERT_TRUE(inline_monomorphic != nullptr); std::set<mirror::Class*> expected_monomorphic; expected_monomorphic.insert(sub_a); - AssertInlineCaches(inline_monomorphic, expected_monomorphic, info, /*megamorphic*/ false); + AssertInlineCaches(inline_monomorphic, + expected_monomorphic, + info, + /*megamorphic*/false, + /*missing_types*/false); } { @@ -534,7 +541,11 @@ TEST_F(ProfileAssistantTest, TestProfileCreateInlineCache) { expected_polymorphic.insert(sub_a); expected_polymorphic.insert(sub_b); expected_polymorphic.insert(sub_c); - AssertInlineCaches(inline_polymorhic, expected_polymorphic, info, /*megamorphic*/ false); + AssertInlineCaches(inline_polymorhic, + expected_polymorphic, + info, + /*megamorphic*/false, + /*missing_types*/false); } { @@ -544,7 +555,25 @@ TEST_F(ProfileAssistantTest, TestProfileCreateInlineCache) { "inlineMegamorphic"); ASSERT_TRUE(inline_megamorphic != nullptr); std::set<mirror::Class*> expected_megamorphic; - AssertInlineCaches(inline_megamorphic, expected_megamorphic, info, /*megamorphic*/ true); + AssertInlineCaches(inline_megamorphic, + expected_megamorphic, + info, + /*megamorphic*/true, + /*missing_types*/false); + } + + { + // Verify that method inlineMegamorphic has the expected inline caches and nothing else. + ArtMethod* inline_missing_types = GetVirtualMethod(class_loader, + "LTestInline;", + "inlineMissingTypes"); + ASSERT_TRUE(inline_missing_types != nullptr); + std::set<mirror::Class*> expected_missing_Types; + AssertInlineCaches(inline_missing_types, + expected_missing_Types, + info, + /*megamorphic*/false, + /*missing_types*/true); } { diff --git a/profman/profman.cc b/profman/profman.cc index 871967d1e3..f7316cc129 100644 --- a/profman/profman.cc +++ b/profman/profman.cc @@ -139,6 +139,7 @@ static constexpr uint16_t kDefaultTestProfileClassRatio = 5; // Separators used when parsing human friendly representation of profiles. static const std::string kMethodSep = "->"; +static const std::string kMissingTypesMarker = "missing_types"; static constexpr char kProfileParsingInlineChacheSep = '+'; static constexpr char kProfileParsingTypeSep = ','; static constexpr char kProfileParsingFirstCharInSignature = '('; @@ -624,8 +625,11 @@ class ProfMan FINAL { // Process a line defining a class or a method and its inline caches. // Upon success return true and add the class or the method info to profile. - // The format of the method line is: + // The possible line formats are: + // "LJustTheCass;". // "LTestInline;->inlinePolymorphic(LSuper;)I+LSubA;,LSubB;,LSubC;". + // "LTestInline;->inlineMissingTypes(LSuper;)I+missing_types". + // "LTestInline;->inlineNoInlineCaches(LSuper;)I". // The method and classes are searched only in the given dex files. bool ProcessLine(const std::vector<std::unique_ptr<const DexFile>>& dex_files, const std::string& line, @@ -664,10 +668,14 @@ class ProfMan FINAL { std::vector<std::string> inline_cache_elems; std::vector<std::string> method_elems; + bool is_missing_types = false; Split(method_str, kProfileParsingInlineChacheSep, &method_elems); if (method_elems.size() == 2) { method_spec = method_elems[0]; - Split(method_elems[1], kProfileParsingTypeSep, &inline_cache_elems); + is_missing_types = method_elems[1] == kMissingTypesMarker; + if (!is_missing_types) { + Split(method_elems[1], kProfileParsingTypeSep, &inline_cache_elems); + } } else if (method_elems.size() == 1) { method_spec = method_elems[0]; } else { @@ -689,7 +697,7 @@ class ProfMan FINAL { } } std::vector<ProfileMethodInfo::ProfileInlineCache> inline_caches; - inline_caches.emplace_back(dex_pc, classes); + inline_caches.emplace_back(dex_pc, is_missing_types, classes); std::vector<ProfileMethodInfo> pmi; pmi.emplace_back(class_ref.dex_file, method_index, inline_caches); diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc index 62acedfb1b..8b2a2b4d13 100644 --- a/runtime/jit/jit_code_cache.cc +++ b/runtime/jit/jit_code_cache.cc @@ -1262,6 +1262,7 @@ void JitCodeCache::GetProfiledMethods(const std::set<std::string>& dex_base_loca for (size_t i = 0; i < info->number_of_inline_caches_; ++i) { std::vector<ProfileMethodInfo::ProfileClassReference> profile_classes; const InlineCache& cache = info->cache_[i]; + bool is_missing_types = false; for (size_t k = 0; k < InlineCache::kIndividualCacheSize; k++) { mirror::Class* cls = cache.classes_[k].Read(); if (cls == nullptr) { @@ -1284,17 +1285,20 @@ void JitCodeCache::GetProfiledMethods(const std::set<std::string>& dex_base_loca } if (!type_index.IsValid()) { // Could be a proxy class or an array for which we couldn't find the type index. + is_missing_types = true; continue; } if (ContainsElement(dex_base_locations, class_dex_file->GetBaseLocation())) { // Only consider classes from the same apk (including multidex). profile_classes.emplace_back(/*ProfileMethodInfo::ProfileClassReference*/ class_dex_file, type_index); + } else { + is_missing_types = true; } } if (!profile_classes.empty()) { inline_caches.emplace_back(/*ProfileMethodInfo::ProfileInlineCache*/ - cache.dex_pc_, profile_classes); + cache.dex_pc_, is_missing_types, profile_classes); } } methods.emplace_back(/*ProfileMethodInfo*/ diff --git a/runtime/jit/profile_compilation_info.cc b/runtime/jit/profile_compilation_info.cc index 8c5bb0d775..b23a86313f 100644 --- a/runtime/jit/profile_compilation_info.cc +++ b/runtime/jit/profile_compilation_info.cc @@ -47,16 +47,19 @@ static constexpr uint16_t kMaxDexFileKeyLength = PATH_MAX; // using the same test profile. static constexpr bool kDebugIgnoreChecksum = false; -static constexpr uint8_t kMegamorphicEncoding = 7; +static constexpr uint8_t kIsMissingTypesEncoding = 6; +static constexpr uint8_t kIsMegamorphicEncoding = 7; static_assert(sizeof(InlineCache::kIndividualCacheSize) == sizeof(uint8_t), "InlineCache::kIndividualCacheSize does not have the expect type size"); -static_assert(InlineCache::kIndividualCacheSize < kMegamorphicEncoding, +static_assert(InlineCache::kIndividualCacheSize < kIsMegamorphicEncoding, + "InlineCache::kIndividualCacheSize is larger than expected"); +static_assert(InlineCache::kIndividualCacheSize < kIsMissingTypesEncoding, "InlineCache::kIndividualCacheSize is larger than expected"); void ProfileCompilationInfo::DexPcData::AddClass(uint16_t dex_profile_idx, const dex::TypeIndex& type_idx) { - if (is_megamorphic) { + if (is_megamorphic || is_missing_types) { return; } classes.emplace(dex_profile_idx, type_idx); @@ -207,7 +210,8 @@ static constexpr size_t kLineHeaderSize = * Classes are grouped per their dex files and the line * `dex_profile_index,class_id1,class_id2...,dex_profile_index2,...` encodes the * mapping from `dex_profile_index` to the set of classes `class_id1,class_id2...` - * M stands for megamorphic and it's encoded as the byte kMegamorphicEncoding. + * M stands for megamorphic or missing types and it's encoded as either + * the byte kIsMegamorphicEncoding or kIsMissingTypesEncoding. * When present, there will be no class ids following. **/ bool ProfileCompilationInfo::Save(int fd) { @@ -298,10 +302,19 @@ void ProfileCompilationInfo::AddInlineCacheToBuffer(std::vector<uint8_t>* buffer // Add the dex pc. AddUintToBuffer(buffer, dex_pc); - if (dex_pc_data.is_megamorphic) { - // Add the megamorphic encoding if needed and continue. - // If megamorphic, we don't add the rest of the classes. - AddUintToBuffer(buffer, kMegamorphicEncoding); + // Add the megamorphic/missing_types encoding if needed and continue. + // In either cases we don't add any classes to the profiles and so there's + // no point to continue. + // TODO(calin): in case we miss types there is still value to add the + // rest of the classes. They can be added without bumping the profile version. + if (dex_pc_data.is_missing_types) { + DCHECK(!dex_pc_data.is_megamorphic); // at this point the megamorphic flag should not be set. + DCHECK_EQ(classes.size(), 0u); + AddUintToBuffer(buffer, kIsMissingTypesEncoding); + continue; + } else if (dex_pc_data.is_megamorphic) { + DCHECK_EQ(classes.size(), 0u); + AddUintToBuffer(buffer, kIsMegamorphicEncoding); continue; } @@ -412,11 +425,21 @@ bool ProfileCompilationInfo::AddMethod(const std::string& dex_location, for (const auto& pmi_inline_cache_it : pmi.inline_caches) { uint16_t pmi_ic_dex_pc = pmi_inline_cache_it.first; const DexPcData& pmi_ic_dex_pc_data = pmi_inline_cache_it.second; - auto dex_pc_data_it = inline_cache_it->second.FindOrAdd(pmi_ic_dex_pc); + DexPcData& dex_pc_data = inline_cache_it->second.FindOrAdd(pmi_ic_dex_pc)->second; + if (dex_pc_data.is_missing_types || dex_pc_data.is_megamorphic) { + // We are already megamorphic or we are missing types; no point in going forward. + continue; + } + + if (pmi_ic_dex_pc_data.is_missing_types) { + dex_pc_data.SetIsMissingTypes(); + continue; + } if (pmi_ic_dex_pc_data.is_megamorphic) { - dex_pc_data_it->second.SetMegamorphic(); + dex_pc_data.SetIsMegamorphic(); continue; } + for (const ClassReference& class_ref : pmi_ic_dex_pc_data.classes) { const DexReference& dex_ref = pmi.dex_references[class_ref.dex_profile_index]; DexFileData* class_dex_data = GetOrAddDexFileData( @@ -425,7 +448,7 @@ bool ProfileCompilationInfo::AddMethod(const std::string& dex_location, if (class_dex_data == nullptr) { // checksum mismatch return false; } - dex_pc_data_it->second.AddClass(class_dex_data->profile_index, class_ref.type_index); + dex_pc_data.AddClass(class_dex_data->profile_index, class_ref.type_index); } } return true; @@ -441,6 +464,11 @@ bool ProfileCompilationInfo::AddMethod(const ProfileMethodInfo& pmi) { auto inline_cache_it = data->method_map.FindOrAdd(pmi.dex_method_index); for (const ProfileMethodInfo::ProfileInlineCache& cache : pmi.inline_caches) { + if (cache.is_missing_types) { + auto dex_pc_data_it = inline_cache_it->second.FindOrAdd(cache.dex_pc); + dex_pc_data_it->second.SetIsMissingTypes(); + continue; + } for (const ProfileMethodInfo::ProfileClassReference& class_ref : cache.classes) { DexFileData* class_dex_data = GetOrAddDexFileData( GetProfileDexFileKey(class_ref.dex_file->GetLocation()), @@ -449,6 +477,10 @@ bool ProfileCompilationInfo::AddMethod(const ProfileMethodInfo& pmi) { return false; } auto dex_pc_data_it = inline_cache_it->second.FindOrAdd(cache.dex_pc); + if (dex_pc_data_it->second.is_missing_types) { + // Don't bother adding classes if we are missing types. + break; + } dex_pc_data_it->second.AddClass(class_dex_data->profile_index, class_ref.type_index); } } @@ -487,8 +519,12 @@ bool ProfileCompilationInfo::ReadInlineCache(SafeBuffer& buffer, READ_UINT(uint16_t, buffer, dex_pc, error); READ_UINT(uint8_t, buffer, dex_to_classes_map_size, error); auto dex_pc_data_it = inline_cache->FindOrAdd(dex_pc); - if (dex_to_classes_map_size == kMegamorphicEncoding) { - dex_pc_data_it->second.SetMegamorphic(); + if (dex_to_classes_map_size == kIsMissingTypesEncoding) { + dex_pc_data_it->second.SetIsMissingTypes(); + continue; + } + if (dex_to_classes_map_size == kIsMegamorphicEncoding) { + dex_pc_data_it->second.SetIsMegamorphic(); continue; } for (; dex_to_classes_map_size > 0; dex_to_classes_map_size--) { @@ -835,8 +871,10 @@ bool ProfileCompilationInfo::MergeWith(const ProfileCompilationInfo& other) { uint16_t other_dex_pc = other_ic_it.first; const ClassSet& other_class_set = other_ic_it.second.classes; auto class_set = method_it->second.FindOrAdd(other_dex_pc); - if (other_ic_it.second.is_megamorphic) { - class_set->second.SetMegamorphic(); + if (other_ic_it.second.is_missing_types) { + class_set->second.SetIsMissingTypes(); + } else if (other_ic_it.second.is_megamorphic) { + class_set->second.SetIsMegamorphic(); } else { for (const auto& class_it : other_class_set) { class_set->second.AddClass(dex_profile_index_remap.Get( @@ -999,8 +1037,10 @@ std::string ProfileCompilationInfo::DumpInfo(const std::vector<const DexFile*>* os << "["; for (const auto& inline_cache_it : method_it.second) { os << "{" << std::hex << inline_cache_it.first << std::dec << ":"; - if (inline_cache_it.second.is_megamorphic) { - os << "M"; + if (inline_cache_it.second.is_missing_types) { + os << "MT"; + } else if (inline_cache_it.second.is_megamorphic) { + os << "MM"; } else { for (const ClassReference& class_ref : inline_cache_it.second.classes) { os << "(" << static_cast<uint32_t>(class_ref.dex_profile_index) @@ -1136,7 +1176,7 @@ bool ProfileCompilationInfo::OfflineProfileMethodInfo::operator==( } // We can't use a simple equality test because we need to match the dex files - // of the inline caches which might have different profile indices. + // of the inline caches which might have different profile indexes. for (const auto& inline_cache_it : inline_caches) { uint16_t dex_pc = inline_cache_it.first; const DexPcData dex_pc_data = inline_cache_it.second; @@ -1145,7 +1185,8 @@ bool ProfileCompilationInfo::OfflineProfileMethodInfo::operator==( return false; } const DexPcData& other_dex_pc_data = other_it->second; - if (dex_pc_data.is_megamorphic != other_dex_pc_data.is_megamorphic) { + if (dex_pc_data.is_megamorphic != other_dex_pc_data.is_megamorphic || + dex_pc_data.is_missing_types != other_dex_pc_data.is_missing_types) { return false; } for (const ClassReference& class_ref : dex_pc_data.classes) { diff --git a/runtime/jit/profile_compilation_info.h b/runtime/jit/profile_compilation_info.h index f089dff898..6ad528c805 100644 --- a/runtime/jit/profile_compilation_info.h +++ b/runtime/jit/profile_compilation_info.h @@ -45,10 +45,13 @@ struct ProfileMethodInfo { }; struct ProfileInlineCache { - ProfileInlineCache(uint32_t pc, const std::vector<ProfileClassReference>& profile_classes) - : dex_pc(pc), classes(profile_classes) {} + ProfileInlineCache(uint32_t pc, + bool missing_types, + const std::vector<ProfileClassReference>& profile_classes) + : dex_pc(pc), is_missing_types(missing_types), classes(profile_classes) {} const uint32_t dex_pc; + const bool is_missing_types; const std::vector<ProfileClassReference> classes; }; @@ -134,18 +137,30 @@ class ProfileCompilationInfo { // Encodes the actual inline cache for a given dex pc (whether or not the receiver is // megamorphic and its possible types). - // If the receiver is megamorphic the set of classes will be empty. + // If the receiver is megamorphic or is missing types the set of classes will be empty. struct DexPcData { - DexPcData() : is_megamorphic(false) {} + DexPcData() : is_missing_types(false), is_megamorphic(false) {} void AddClass(uint16_t dex_profile_idx, const dex::TypeIndex& type_idx); - void SetMegamorphic() { + void SetIsMegamorphic() { + if (is_missing_types) return; is_megamorphic = true; classes.clear(); } + void SetIsMissingTypes() { + is_megamorphic = false; + is_missing_types = true; + classes.clear(); + } bool operator==(const DexPcData& other) const { - return is_megamorphic == other.is_megamorphic && classes == other.classes; + return is_megamorphic == other.is_megamorphic && + is_missing_types == other.is_missing_types && + classes == other.classes; } + // Not all runtime types can be encoded in the profile. For example if the receiver + // type is in a dex file which is not tracked for profiling its type cannot be + // encoded. When types are missing this field will be set to true. + bool is_missing_types; bool is_megamorphic; ClassSet classes; }; diff --git a/runtime/jit/profile_compilation_info_test.cc b/runtime/jit/profile_compilation_info_test.cc index 332280a0e3..5cd8e8fef5 100644 --- a/runtime/jit/profile_compilation_info_test.cc +++ b/runtime/jit/profile_compilation_info_test.cc @@ -108,26 +108,31 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest { for (ArtMethod* method : methods) { std::vector<ProfileMethodInfo::ProfileInlineCache> caches; // Monomorphic - for (uint16_t dex_pc = 0; dex_pc < 1; dex_pc++) { + for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) { std::vector<ProfileMethodInfo::ProfileClassReference> classes; classes.emplace_back(method->GetDexFile(), dex::TypeIndex(0)); - caches.emplace_back(dex_pc, classes); + caches.emplace_back(dex_pc, /*is_missing_types*/false, classes); } // Polymorphic - for (uint16_t dex_pc = 1; dex_pc < 2; dex_pc++) { + for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) { std::vector<ProfileMethodInfo::ProfileClassReference> classes; for (uint16_t k = 0; k < InlineCache::kIndividualCacheSize / 2; k++) { classes.emplace_back(method->GetDexFile(), dex::TypeIndex(k)); } - caches.emplace_back(dex_pc, classes); + caches.emplace_back(dex_pc, /*is_missing_types*/false, classes); } // Megamorphic - for (uint16_t dex_pc = 2; dex_pc < 3; dex_pc++) { + for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) { std::vector<ProfileMethodInfo::ProfileClassReference> classes; for (uint16_t k = 0; k < 2 * InlineCache::kIndividualCacheSize; k++) { classes.emplace_back(method->GetDexFile(), dex::TypeIndex(k)); } - caches.emplace_back(dex_pc, classes); + caches.emplace_back(dex_pc, /*is_missing_types*/false, classes); + } + // Missing types + for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) { + std::vector<ProfileMethodInfo::ProfileClassReference> classes; + caches.emplace_back(dex_pc, /*is_missing_types*/true, classes); } ProfileMethodInfo pmi(method->GetDexFile(), method->GetDexMethodIndex(), caches); profile_methods.push_back(pmi); @@ -148,12 +153,15 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest { ProfileCompilationInfo::OfflineProfileMethodInfo offline_pmi; SafeMap<DexFile*, uint8_t> dex_map; // dex files to profile index for (const auto& inline_cache : pmi.inline_caches) { + ProfileCompilationInfo::DexPcData& dex_pc_data = + offline_pmi.inline_caches.FindOrAdd(inline_cache.dex_pc)->second; + if (inline_cache.is_missing_types) { + dex_pc_data.SetIsMissingTypes(); + } for (const auto& class_ref : inline_cache.classes) { uint8_t dex_profile_index = dex_map.FindOrAdd(const_cast<DexFile*>(class_ref.dex_file), static_cast<uint8_t>(dex_map.size()))->second; - offline_pmi.inline_caches - .FindOrAdd(inline_cache.dex_pc)->second - .AddClass(dex_profile_index, class_ref.type_index); + dex_pc_data.AddClass(dex_profile_index, class_ref.type_index); if (dex_profile_index >= offline_pmi.dex_references.size()) { // This is a new dex. const std::string& dex_key = ProfileCompilationInfo::GetProfileDexFileKey( @@ -170,18 +178,18 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest { ProfileCompilationInfo::OfflineProfileMethodInfo GetOfflineProfileMethodInfo() { ProfileCompilationInfo::OfflineProfileMethodInfo pmi; - pmi.dex_references.emplace_back("dex_location1", /* checksum */ 1); - pmi.dex_references.emplace_back("dex_location2", /* checksum */ 2); - pmi.dex_references.emplace_back("dex_location3", /* checksum */ 3); + pmi.dex_references.emplace_back("dex_location1", /* checksum */1); + pmi.dex_references.emplace_back("dex_location2", /* checksum */2); + pmi.dex_references.emplace_back("dex_location3", /* checksum */3); // Monomorphic - for (uint16_t dex_pc = 0; dex_pc < 10; dex_pc++) { + for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) { ProfileCompilationInfo::DexPcData dex_pc_data; dex_pc_data.AddClass(0, dex::TypeIndex(0)); pmi.inline_caches.Put(dex_pc, dex_pc_data); } // Polymorphic - for (uint16_t dex_pc = 10; dex_pc < 20; dex_pc++) { + for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) { ProfileCompilationInfo::DexPcData dex_pc_data; dex_pc_data.AddClass(0, dex::TypeIndex(0)); dex_pc_data.AddClass(1, dex::TypeIndex(1)); @@ -190,9 +198,15 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest { pmi.inline_caches.Put(dex_pc, dex_pc_data); } // Megamorphic - for (uint16_t dex_pc = 20; dex_pc < 30; dex_pc++) { + for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) { + ProfileCompilationInfo::DexPcData dex_pc_data; + dex_pc_data.SetIsMegamorphic(); + pmi.inline_caches.Put(dex_pc, dex_pc_data); + } + // Missing types + for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) { ProfileCompilationInfo::DexPcData dex_pc_data; - dex_pc_data.is_megamorphic = true; + dex_pc_data.SetIsMissingTypes(); pmi.inline_caches.Put(dex_pc, dex_pc_data); } @@ -207,7 +221,13 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest { } } - // Cannot sizeof the actual arrays so hardcode the values here. + void SetIsMissingTypes(/*out*/ProfileCompilationInfo::OfflineProfileMethodInfo* pmi) { + for (auto it : pmi->inline_caches) { + it.second.SetIsMissingTypes(); + } + } + + // Cannot sizeof the actual arrays so hard code the values here. // They should not change anyway. static constexpr int kProfileMagicSize = 4; static constexpr int kProfileVersionSize = 4; @@ -530,6 +550,58 @@ TEST_F(ProfileCompilationInfoTest, MegamorphicInlineCaches) { ASSERT_TRUE(loaded_pmi1 == pmi_extra); } +TEST_F(ProfileCompilationInfoTest, MissingTypesInlineCaches) { + ScratchFile profile; + + ProfileCompilationInfo saved_info; + ProfileCompilationInfo::OfflineProfileMethodInfo pmi = GetOfflineProfileMethodInfo(); + + // Add methods with inline caches. + for (uint16_t method_idx = 0; method_idx < 10; method_idx++) { + ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &saved_info)); + } + + ASSERT_TRUE(saved_info.Save(GetFd(profile))); + ASSERT_EQ(0, profile.GetFile()->Flush()); + + // Make some inline caches megamorphic and add them to the profile again. + ProfileCompilationInfo saved_info_extra; + ProfileCompilationInfo::OfflineProfileMethodInfo pmi_extra = GetOfflineProfileMethodInfo(); + MakeMegamorphic(&pmi_extra); + for (uint16_t method_idx = 5; method_idx < 10; method_idx++) { + ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &saved_info_extra)); + } + + // Mark all inline caches with missing types and add them to the profile again. + // This will verify that all inline caches (megamorphic or not) should be marked as missing types. + ProfileCompilationInfo::OfflineProfileMethodInfo missing_types = GetOfflineProfileMethodInfo(); + SetIsMissingTypes(&missing_types); + for (uint16_t method_idx = 0; method_idx < 10; method_idx++) { + ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, method_idx, pmi, &saved_info_extra)); + } + + ASSERT_TRUE(profile.GetFile()->ResetOffset()); + ASSERT_TRUE(saved_info_extra.Save(GetFd(profile))); + ASSERT_EQ(0, profile.GetFile()->Flush()); + + // Merge the profiles so that we have the same view as the file. + ASSERT_TRUE(saved_info.MergeWith(saved_info_extra)); + + // Check that we get back what we saved. + ProfileCompilationInfo loaded_info; + ASSERT_TRUE(profile.GetFile()->ResetOffset()); + ASSERT_TRUE(loaded_info.Load(GetFd(profile))); + + ASSERT_TRUE(loaded_info.Equals(saved_info)); + + ProfileCompilationInfo::OfflineProfileMethodInfo loaded_pmi1; + ASSERT_TRUE(loaded_info.GetMethod("dex_location1", + /* checksum */ 1, + /* method_idx */ 3, + &loaded_pmi1)); + ASSERT_TRUE(loaded_pmi1 == pmi_extra); +} + TEST_F(ProfileCompilationInfoTest, SaveArtMethodsWithInlineCaches) { ScratchFile profile; @@ -570,7 +642,7 @@ TEST_F(ProfileCompilationInfoTest, SaveArtMethodsWithInlineCaches) { } } -TEST_F(ProfileCompilationInfoTest, InvalidChecksumInInlineCahce) { +TEST_F(ProfileCompilationInfoTest, InvalidChecksumInInlineCache) { ScratchFile profile; ProfileCompilationInfo info; @@ -662,7 +734,7 @@ TEST_F(ProfileCompilationInfoTest, MegamorphicInlineCachesMerge) { ProfileCompilationInfo::OfflineProfileMethodInfo pmi; pmi.dex_references.emplace_back("dex_location1", /* checksum */ 1); ProfileCompilationInfo::DexPcData dex_pc_data; - dex_pc_data.is_megamorphic = true; + dex_pc_data.SetIsMegamorphic(); pmi.inline_caches.Put(/*dex_pc*/ 0, dex_pc_data); ProfileCompilationInfo info_megamorphic; @@ -686,4 +758,33 @@ TEST_F(ProfileCompilationInfoTest, MegamorphicInlineCachesMerge) { ASSERT_TRUE(info_no_inline_cache.Save(GetFd(profile))); } +TEST_F(ProfileCompilationInfoTest, MissingTypesInlineCachesMerge) { + // Create an inline cache with missing types + ProfileCompilationInfo::OfflineProfileMethodInfo pmi; + pmi.dex_references.emplace_back("dex_location1", /* checksum */ 1); + ProfileCompilationInfo::DexPcData dex_pc_data; + dex_pc_data.SetIsMissingTypes(); + pmi.inline_caches.Put(/*dex_pc*/ 0, dex_pc_data); + + ProfileCompilationInfo info_megamorphic; + ASSERT_TRUE(AddMethod("dex_location1", + /*checksum*/ 1, + /*method_idx*/ 0, + pmi, + &info_megamorphic)); + + // Create a profile with no inline caches (for the same method). + ProfileCompilationInfo info_no_inline_cache; + ASSERT_TRUE(AddMethod("dex_location1", + /*checksum*/ 1, + /*method_idx*/ 0, + &info_no_inline_cache)); + + // Merge the missing type cache into the empty one. + // Everything should be saved without errors. + ASSERT_TRUE(info_no_inline_cache.MergeWith(info_megamorphic)); + ScratchFile profile; + ASSERT_TRUE(info_no_inline_cache.Save(GetFd(profile))); +} + } // namespace art diff --git a/test/ProfileTestMultiDex/Main.java b/test/ProfileTestMultiDex/Main.java index 73fbb00d25..a8ced544c9 100644 --- a/test/ProfileTestMultiDex/Main.java +++ b/test/ProfileTestMultiDex/Main.java @@ -39,6 +39,10 @@ class TestInline { return s.getValue(); } + public int inlineMissingTypes(Super s) { + return s.getValue(); + } + public int noInlineCache(Super s) { return s.getValue(); } |