Simplify CHA dependency tracking data structure.
Change pointer to vector in the map to just vector.
Bug: 37953217
Test: m -j20 test-art-host-run-test test-art-host-gtest
Change-Id: I0e601c69aef99401360cc1a3967c056952a05a0f
diff --git a/runtime/cha.cc b/runtime/cha.cc
index 7948c29..e6bdb84 100644
--- a/runtime/cha.cc
+++ b/runtime/cha.cc
@@ -31,34 +31,24 @@
void ClassHierarchyAnalysis::AddDependency(ArtMethod* method,
ArtMethod* dependent_method,
OatQuickMethodHeader* dependent_header) {
- auto it = cha_dependency_map_.find(method);
- if (it == cha_dependency_map_.end()) {
- cha_dependency_map_[method] =
- new std::vector<std::pair<art::ArtMethod*, art::OatQuickMethodHeader*>>();
- it = cha_dependency_map_.find(method);
- } else {
- DCHECK(it->second != nullptr);
- }
- it->second->push_back(std::make_pair(dependent_method, dependent_header));
+ const auto it = cha_dependency_map_.insert(
+ decltype(cha_dependency_map_)::value_type(method, ListOfDependentPairs())).first;
+ it->second.push_back({dependent_method, dependent_header});
}
-std::vector<std::pair<ArtMethod*, OatQuickMethodHeader*>>*
- ClassHierarchyAnalysis::GetDependents(ArtMethod* method) {
+static const ClassHierarchyAnalysis::ListOfDependentPairs s_empty_vector;
+
+const ClassHierarchyAnalysis::ListOfDependentPairs& ClassHierarchyAnalysis::GetDependents(
+ ArtMethod* method) {
auto it = cha_dependency_map_.find(method);
if (it != cha_dependency_map_.end()) {
- DCHECK(it->second != nullptr);
return it->second;
}
- return nullptr;
+ return s_empty_vector;
}
-void ClassHierarchyAnalysis::RemoveDependencyFor(ArtMethod* method) {
- auto it = cha_dependency_map_.find(method);
- if (it != cha_dependency_map_.end()) {
- auto dependents = it->second;
- cha_dependency_map_.erase(it);
- delete dependents;
- }
+void ClassHierarchyAnalysis::RemoveAllDependenciesFor(ArtMethod* method) {
+ cha_dependency_map_.erase(method);
}
void ClassHierarchyAnalysis::RemoveDependentsWithMethodHeaders(
@@ -66,20 +56,19 @@
// Iterate through all entries in the dependency map and remove any entry that
// contains one of those in method_headers.
for (auto map_it = cha_dependency_map_.begin(); map_it != cha_dependency_map_.end(); ) {
- auto dependents = map_it->second;
- for (auto vec_it = dependents->begin(); vec_it != dependents->end(); ) {
- OatQuickMethodHeader* method_header = vec_it->second;
- auto it = std::find(method_headers.begin(), method_headers.end(), method_header);
- if (it != method_headers.end()) {
- vec_it = dependents->erase(vec_it);
- } else {
- vec_it++;
- }
- }
+ ListOfDependentPairs& dependents = map_it->second;
+ dependents.erase(
+ std::remove_if(
+ dependents.begin(),
+ dependents.end(),
+ [&method_headers](MethodAndMethodHeaderPair& dependent) {
+ return method_headers.find(dependent.second) != method_headers.end();
+ }),
+ dependents.end());
+
// Remove the map entry if there are no more dependents.
- if (dependents->empty()) {
+ if (dependents.empty()) {
map_it = cha_dependency_map_.erase(map_it);
- delete dependents;
} else {
map_it++;
}
@@ -554,11 +543,7 @@
}
// Invalidate all dependents.
- auto dependents = GetDependents(invalidated);
- if (dependents == nullptr) {
- continue;
- }
- for (const auto& dependent : *dependents) {
+ for (const auto& dependent : GetDependents(invalidated)) {
ArtMethod* method = dependent.first;;
OatQuickMethodHeader* method_header = dependent.second;
VLOG(class_linker) << "CHA invalidated compiled code for " << method->PrettyMethod();
@@ -567,7 +552,7 @@
method, method_header);
dependent_method_headers.insert(method_header);
}
- RemoveDependencyFor(invalidated);
+ RemoveAllDependenciesFor(invalidated);
}
}
diff --git a/runtime/cha.h b/runtime/cha.h
index 99c49d2..d9692a6 100644
--- a/runtime/cha.h
+++ b/runtime/cha.h
@@ -94,12 +94,11 @@
OatQuickMethodHeader* dependent_header) REQUIRES(Locks::cha_lock_);
// Return compiled code that assumes that `method` has single-implementation.
- std::vector<MethodAndMethodHeaderPair>* GetDependents(ArtMethod* method)
- REQUIRES(Locks::cha_lock_);
+ const ListOfDependentPairs& GetDependents(ArtMethod* method) REQUIRES(Locks::cha_lock_);
// Remove dependency tracking for compiled code that assumes that
// `method` has single-implementation.
- void RemoveDependencyFor(ArtMethod* method) REQUIRES(Locks::cha_lock_);
+ void RemoveAllDependenciesFor(ArtMethod* method) REQUIRES(Locks::cha_lock_);
// Remove from cha_dependency_map_ all entries that contain OatQuickMethodHeader from
// the given `method_headers` set.
@@ -158,7 +157,7 @@
// A map that maps a method to a set of compiled code that assumes that method has a
// single implementation, which is used to do CHA-based devirtualization.
- std::unordered_map<ArtMethod*, ListOfDependentPairs*> cha_dependency_map_
+ std::unordered_map<ArtMethod*, ListOfDependentPairs> cha_dependency_map_
GUARDED_BY(Locks::cha_lock_);
DISALLOW_COPY_AND_ASSIGN(ClassHierarchyAnalysis);
diff --git a/runtime/cha_test.cc b/runtime/cha_test.cc
index d2f335e..c60720f 100644
--- a/runtime/cha_test.cc
+++ b/runtime/cha_test.cc
@@ -36,58 +36,58 @@
ClassHierarchyAnalysis cha;
MutexLock cha_mu(Thread::Current(), *Locks::cha_lock_);
- ASSERT_EQ(cha.GetDependents(METHOD1), nullptr);
- ASSERT_EQ(cha.GetDependents(METHOD2), nullptr);
- ASSERT_EQ(cha.GetDependents(METHOD3), nullptr);
+ ASSERT_TRUE(cha.GetDependents(METHOD1).empty());
+ ASSERT_TRUE(cha.GetDependents(METHOD2).empty());
+ ASSERT_TRUE(cha.GetDependents(METHOD3).empty());
cha.AddDependency(METHOD1, METHOD2, METHOD_HEADER2);
- ASSERT_EQ(cha.GetDependents(METHOD2), nullptr);
- ASSERT_EQ(cha.GetDependents(METHOD3), nullptr);
+ ASSERT_TRUE(cha.GetDependents(METHOD2).empty());
+ ASSERT_TRUE(cha.GetDependents(METHOD3).empty());
auto dependents = cha.GetDependents(METHOD1);
- ASSERT_EQ(dependents->size(), 1u);
- ASSERT_EQ(dependents->at(0).first, METHOD2);
- ASSERT_EQ(dependents->at(0).second, METHOD_HEADER2);
+ ASSERT_EQ(dependents.size(), 1u);
+ ASSERT_EQ(dependents[0].first, METHOD2);
+ ASSERT_EQ(dependents[0].second, METHOD_HEADER2);
cha.AddDependency(METHOD1, METHOD3, METHOD_HEADER3);
- ASSERT_EQ(cha.GetDependents(METHOD2), nullptr);
- ASSERT_EQ(cha.GetDependents(METHOD3), nullptr);
+ ASSERT_TRUE(cha.GetDependents(METHOD2).empty());
+ ASSERT_TRUE(cha.GetDependents(METHOD3).empty());
dependents = cha.GetDependents(METHOD1);
- ASSERT_EQ(dependents->size(), 2u);
- ASSERT_EQ(dependents->at(0).first, METHOD2);
- ASSERT_EQ(dependents->at(0).second, METHOD_HEADER2);
- ASSERT_EQ(dependents->at(1).first, METHOD3);
- ASSERT_EQ(dependents->at(1).second, METHOD_HEADER3);
+ ASSERT_EQ(dependents.size(), 2u);
+ ASSERT_EQ(dependents[0].first, METHOD2);
+ ASSERT_EQ(dependents[0].second, METHOD_HEADER2);
+ ASSERT_EQ(dependents[1].first, METHOD3);
+ ASSERT_EQ(dependents[1].second, METHOD_HEADER3);
std::unordered_set<OatQuickMethodHeader*> headers;
headers.insert(METHOD_HEADER2);
cha.RemoveDependentsWithMethodHeaders(headers);
- ASSERT_EQ(cha.GetDependents(METHOD2), nullptr);
- ASSERT_EQ(cha.GetDependents(METHOD3), nullptr);
+ ASSERT_TRUE(cha.GetDependents(METHOD2).empty());
+ ASSERT_TRUE(cha.GetDependents(METHOD3).empty());
dependents = cha.GetDependents(METHOD1);
- ASSERT_EQ(dependents->size(), 1u);
- ASSERT_EQ(dependents->at(0).first, METHOD3);
- ASSERT_EQ(dependents->at(0).second, METHOD_HEADER3);
+ ASSERT_EQ(dependents.size(), 1u);
+ ASSERT_EQ(dependents[0].first, METHOD3);
+ ASSERT_EQ(dependents[0].second, METHOD_HEADER3);
cha.AddDependency(METHOD2, METHOD1, METHOD_HEADER1);
- ASSERT_EQ(cha.GetDependents(METHOD3), nullptr);
+ ASSERT_TRUE(cha.GetDependents(METHOD3).empty());
dependents = cha.GetDependents(METHOD1);
- ASSERT_EQ(dependents->size(), 1u);
+ ASSERT_EQ(dependents.size(), 1u);
dependents = cha.GetDependents(METHOD2);
- ASSERT_EQ(dependents->size(), 1u);
+ ASSERT_EQ(dependents.size(), 1u);
headers.insert(METHOD_HEADER3);
cha.RemoveDependentsWithMethodHeaders(headers);
- ASSERT_EQ(cha.GetDependents(METHOD1), nullptr);
- ASSERT_EQ(cha.GetDependents(METHOD3), nullptr);
+ ASSERT_TRUE(cha.GetDependents(METHOD1).empty());
+ ASSERT_TRUE(cha.GetDependents(METHOD3).empty());
dependents = cha.GetDependents(METHOD2);
- ASSERT_EQ(dependents->size(), 1u);
- ASSERT_EQ(dependents->at(0).first, METHOD1);
- ASSERT_EQ(dependents->at(0).second, METHOD_HEADER1);
+ ASSERT_EQ(dependents.size(), 1u);
+ ASSERT_EQ(dependents[0].first, METHOD1);
+ ASSERT_EQ(dependents[0].second, METHOD_HEADER1);
- cha.RemoveDependencyFor(METHOD2);
- ASSERT_EQ(cha.GetDependents(METHOD1), nullptr);
- ASSERT_EQ(cha.GetDependents(METHOD2), nullptr);
- ASSERT_EQ(cha.GetDependents(METHOD3), nullptr);
+ cha.RemoveAllDependenciesFor(METHOD2);
+ ASSERT_TRUE(cha.GetDependents(METHOD1).empty());
+ ASSERT_TRUE(cha.GetDependents(METHOD2).empty());
+ ASSERT_TRUE(cha.GetDependents(METHOD3).empty());
}
} // namespace art