Encode inline caches with missing types in the profile
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.
Previously we would just skip over these types but that can lead to
encode a polymorphic inline cache when in fact it should be megamorphic.
With this CL, inline caches for which types are missing are marked in
the profile with a special bit, kIsMissingTypesEncoding.
Also, extend profman to understand text lines which specify an inline
cache with missing types.
Test: test-art-host
Bug: 35927981
Bug: 32434870
Change-Id: I34528a39c227f3133771fd4454701c1ddc234f40
diff --git a/profman/profile_assistant_test.cc b/profman/profile_assistant_test.cc
index 5a758ae..52f3b52 100644
--- a/profman/profile_assistant_test.cc
+++ b/profman/profile_assistant_test.cc
@@ -182,7 +182,8 @@
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 @@
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 @@
"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 @@
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 @@
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 @@
"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 a99a0ea..963622d 100644
--- a/profman/profman.cc
+++ b/profman/profman.cc
@@ -139,6 +139,7 @@
// 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 @@
// 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 @@
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 @@
}
}
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 62acedf..8b2a2b4 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -1262,6 +1262,7 @@
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 @@
}
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 8c5bb0d..b23a863 100644
--- a/runtime/jit/profile_compilation_info.cc
+++ b/runtime/jit/profile_compilation_info.cc
@@ -47,16 +47,19 @@
// 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 @@
* 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 @@
// 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 @@
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);
- if (pmi_ic_dex_pc_data.is_megamorphic) {
- dex_pc_data_it->second.SetMegamorphic();
+ 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.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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
// 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 @@
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 f089dff..6ad528c 100644
--- a/runtime/jit/profile_compilation_info.h
+++ b/runtime/jit/profile_compilation_info.h
@@ -45,10 +45,13 @@
};
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 @@
// 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 332280a..5cd8e8f 100644
--- a/runtime/jit/profile_compilation_info_test.cc
+++ b/runtime/jit/profile_compilation_info_test.cc
@@ -108,26 +108,31 @@
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 @@
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 @@
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 @@
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.is_megamorphic = true;
+ 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.SetIsMissingTypes();
pmi.inline_caches.Put(dex_pc, dex_pc_data);
}
@@ -207,7 +221,13 @@
}
}
- // 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 @@
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, InvalidChecksumInInlineCahce) {
+TEST_F(ProfileCompilationInfoTest, InvalidChecksumInInlineCache) {
ScratchFile profile;
ProfileCompilationInfo info;
@@ -662,7 +734,7 @@
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 @@
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 73fbb00..a8ced54 100644
--- a/test/ProfileTestMultiDex/Main.java
+++ b/test/ProfileTestMultiDex/Main.java
@@ -39,6 +39,10 @@
return s.getValue();
}
+ public int inlineMissingTypes(Super s) {
+ return s.getValue();
+ }
+
public int noInlineCache(Super s) {
return s.getValue();
}