Add read barriers for the class and the intern tables.
Add read barriers for the strong roots in the intern table and the
(strong) roots in the class table to make possible concurrent scanning
of them.
Bug: 12687968
Change-Id: If6edc33a37e65a8494e66dc3b144138b1530367f
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 7385382..d684a50 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1137,8 +1137,10 @@
MoveImageClassesToClassTable();
}
WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
- for (const std::pair<size_t, mirror::Class*>& it : class_table_) {
- if (!visitor(it.second, arg)) {
+ for (std::pair<const size_t, mirror::Class*>& it : class_table_) {
+ mirror::Class** root = &it.second;
+ mirror::Class* c = ReadBarrier::BarrierForRoot<mirror::Class, kWithReadBarrier>(root);
+ if (!visitor(c, arg)) {
return;
}
}
@@ -2353,7 +2355,8 @@
for (auto it = class_table_.lower_bound(hash), end = class_table_.end();
it != end && it->first == hash;
++it) {
- mirror::Class* klass = it->second;
+ mirror::Class** root = &it->second;
+ mirror::Class* klass = ReadBarrier::BarrierForRoot<mirror::Class, kWithReadBarrier>(root);
if (klass->GetClassLoader() == class_loader && klass->DescriptorEquals(descriptor)) {
class_table_.erase(it);
return true;
@@ -2397,12 +2400,14 @@
size_t hash) {
auto end = class_table_.end();
for (auto it = class_table_.lower_bound(hash); it != end && it->first == hash; ++it) {
- mirror::Class* klass = it->second;
+ mirror::Class** root = &it->second;
+ mirror::Class* klass = ReadBarrier::BarrierForRoot<mirror::Class, kWithReadBarrier>(root);
if (klass->GetClassLoader() == class_loader && klass->DescriptorEquals(descriptor)) {
if (kIsDebugBuild) {
// Check for duplicates in the table.
for (++it; it != end && it->first == hash; ++it) {
- mirror::Class* klass2 = it->second;
+ mirror::Class** root2 = &it->second;
+ mirror::Class* klass2 = ReadBarrier::BarrierForRoot<mirror::Class, kWithReadBarrier>(root2);
CHECK(!(klass2->GetClassLoader() == class_loader &&
klass2->DescriptorEquals(descriptor)))
<< PrettyClass(klass) << " " << klass << " " << klass->GetClassLoader() << " "
@@ -2494,7 +2499,8 @@
ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
for (auto it = class_table_.lower_bound(hash), end = class_table_.end();
it != end && it->first == hash; ++it) {
- mirror::Class* klass = it->second;
+ mirror::Class** root = &it->second;
+ mirror::Class* klass = ReadBarrier::BarrierForRoot<mirror::Class, kWithReadBarrier>(root);
if (klass->DescriptorEquals(descriptor)) {
result.push_back(klass);
}
@@ -4362,8 +4368,10 @@
std::vector<mirror::Class*> all_classes;
{
ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
- for (const std::pair<size_t, mirror::Class*>& it : class_table_) {
- all_classes.push_back(it.second);
+ for (std::pair<const size_t, mirror::Class*>& it : class_table_) {
+ mirror::Class** root = &it.second;
+ mirror::Class* klass = ReadBarrier::BarrierForRoot<mirror::Class, kWithReadBarrier>(root);
+ all_classes.push_back(klass);
}
}
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index a1d7bc6..6d96aa2 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -573,6 +573,8 @@
// mirror::Class* instances. Results should be compared for a matching
// Class::descriptor_ and Class::class_loader_.
typedef std::multimap<size_t, mirror::Class*> Table;
+ // This contains strong roots. To enable concurrent root scanning of
+ // the class table, be careful to use a read barrier when accessing this.
Table class_table_ GUARDED_BY(Locks::classlinker_classes_lock_);
std::vector<std::pair<size_t, mirror::Class*>> new_class_roots_;
diff --git a/runtime/indirect_reference_table-inl.h b/runtime/indirect_reference_table-inl.h
index 790f4d0..b787233 100644
--- a/runtime/indirect_reference_table-inl.h
+++ b/runtime/indirect_reference_table-inl.h
@@ -80,7 +80,7 @@
mirror::Object* obj = *root;
if (LIKELY(obj != kClearedJniWeakGlobal)) {
// The read barrier or VerifyObject won't handle kClearedJniWeakGlobal.
- obj = ReadBarrier::BarrierForWeakRoot<mirror::Object, kReadBarrierOption>(root);
+ obj = ReadBarrier::BarrierForRoot<mirror::Object, kReadBarrierOption>(root);
VerifyObject(obj);
}
return obj;
diff --git a/runtime/indirect_reference_table.cc b/runtime/indirect_reference_table.cc
index 756ac96..98e1d21 100644
--- a/runtime/indirect_reference_table.cc
+++ b/runtime/indirect_reference_table.cc
@@ -280,7 +280,7 @@
// We need a read barrier if weak globals. Since this is for
// debugging where performance isn't top priority, we
// unconditionally enable the read barrier, which is conservative.
- obj = ReadBarrier::BarrierForWeakRoot<mirror::Object, kWithReadBarrier>(root);
+ obj = ReadBarrier::BarrierForRoot<mirror::Object, kWithReadBarrier>(root);
entries.push_back(obj);
}
}
diff --git a/runtime/intern_table.cc b/runtime/intern_table.cc
index f12043e..1430500 100644
--- a/runtime/intern_table.cc
+++ b/runtime/intern_table.cc
@@ -38,6 +38,16 @@
return strong_interns_.size() + weak_interns_.size();
}
+size_t InternTable::StrongSize() const {
+ MutexLock mu(Thread::Current(), *Locks::intern_table_lock_);
+ return strong_interns_.size();
+}
+
+size_t InternTable::WeakSize() const {
+ MutexLock mu(Thread::Current(), *Locks::intern_table_lock_);
+ return weak_interns_.size();
+}
+
void InternTable::DumpForSigQuit(std::ostream& os) const {
MutexLock mu(Thread::Current(), *Locks::intern_table_lock_);
os << "Intern table: " << strong_interns_.size() << " strong; "
@@ -83,24 +93,21 @@
}
mirror::String* InternTable::LookupStrong(mirror::String* s, int32_t hash_code) {
- return Lookup<kWithoutReadBarrier>(&strong_interns_, s, hash_code);
+ return Lookup(&strong_interns_, s, hash_code);
}
mirror::String* InternTable::LookupWeak(mirror::String* s, int32_t hash_code) {
// Weak interns need a read barrier because they are weak roots.
- return Lookup<kWithReadBarrier>(&weak_interns_, s, hash_code);
+ return Lookup(&weak_interns_, s, hash_code);
}
-template<ReadBarrierOption kReadBarrierOption>
mirror::String* InternTable::Lookup(Table* table, mirror::String* s, int32_t hash_code) {
- CHECK_EQ(table == &weak_interns_, kReadBarrierOption == kWithReadBarrier)
- << "Only weak_interns_ needs a read barrier.";
Locks::intern_table_lock_->AssertHeld(Thread::Current());
for (auto it = table->lower_bound(hash_code), end = table->end();
it != end && it->first == hash_code; ++it) {
- mirror::String** weak_root = &it->second;
- mirror::String* existing_string =
- ReadBarrier::BarrierForWeakRoot<mirror::String, kReadBarrierOption>(weak_root);
+ mirror::String* existing_string;
+ mirror::String** root = &it->second;
+ existing_string = ReadBarrier::BarrierForRoot<mirror::String, kWithReadBarrier>(root);
if (existing_string->Equals(s)) {
return existing_string;
}
@@ -130,7 +137,7 @@
}
void InternTable::RemoveStrong(mirror::String* s, int32_t hash_code) {
- Remove<kWithoutReadBarrier>(&strong_interns_, s, hash_code);
+ Remove(&strong_interns_, s, hash_code);
}
void InternTable::RemoveWeak(mirror::String* s, int32_t hash_code) {
@@ -138,18 +145,15 @@
if (runtime->IsActiveTransaction()) {
runtime->RecordWeakStringRemoval(s, hash_code);
}
- Remove<kWithReadBarrier>(&weak_interns_, s, hash_code);
+ Remove(&weak_interns_, s, hash_code);
}
-template<ReadBarrierOption kReadBarrierOption>
void InternTable::Remove(Table* table, mirror::String* s, int32_t hash_code) {
- CHECK_EQ(table == &weak_interns_, kReadBarrierOption == kWithReadBarrier)
- << "Only weak_interns_ needs a read barrier.";
for (auto it = table->lower_bound(hash_code), end = table->end();
it != end && it->first == hash_code; ++it) {
- mirror::String** weak_root = &it->second;
- mirror::String* existing_string =
- ReadBarrier::BarrierForWeakRoot<mirror::String, kReadBarrierOption>(weak_root);
+ mirror::String* existing_string;
+ mirror::String** root = &it->second;
+ existing_string = ReadBarrier::BarrierForRoot<mirror::String, kWithReadBarrier>(root);
if (existing_string == s) {
table->erase(it);
return;
diff --git a/runtime/intern_table.h b/runtime/intern_table.h
index 3df2aeb..6dc7f7b 100644
--- a/runtime/intern_table.h
+++ b/runtime/intern_table.h
@@ -64,6 +64,8 @@
bool ContainsWeak(mirror::String* s) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
size_t Size() const;
+ size_t StrongSize() const;
+ size_t WeakSize() const;
void VisitRoots(RootCallback* callback, void* arg, VisitRootFlags flags);
@@ -83,7 +85,6 @@
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
mirror::String* LookupWeak(mirror::String* s, int32_t hash_code)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
mirror::String* Lookup(Table* table, mirror::String* s, int32_t hash_code)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
mirror::String* InsertStrong(mirror::String* s, int32_t hash_code)
@@ -96,7 +97,6 @@
void RemoveWeak(mirror::String* s, int32_t hash_code)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
- template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
void Remove(Table* table, mirror::String* s, int32_t hash_code)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
@@ -117,12 +117,16 @@
bool log_new_roots_ GUARDED_BY(Locks::intern_table_lock_);
bool allow_new_interns_ GUARDED_BY(Locks::intern_table_lock_);
ConditionVariable new_intern_condition_ GUARDED_BY(Locks::intern_table_lock_);
+ // Since this contains (strong) roots, they need a read barrier to
+ // enable concurrent intern table (strong) root scan. Do not
+ // directly access the strings in it. Use functions that contain
+ // read barriers.
Table strong_interns_ GUARDED_BY(Locks::intern_table_lock_);
std::vector<std::pair<int32_t, mirror::String*>> new_strong_intern_roots_
GUARDED_BY(Locks::intern_table_lock_);
- // Since weak_interns_ contain weak roots, they need a read
- // barrier. Do not directly access the strings in it. Use functions
- // that contain read barriers.
+ // Since this contains (weak) roots, they need a read barrier. Do
+ // not directly access the strings in it. Use functions that contain
+ // read barriers.
Table weak_interns_ GUARDED_BY(Locks::intern_table_lock_);
};
diff --git a/runtime/monitor.h b/runtime/monitor.h
index bd0e23c..a28823d 100644
--- a/runtime/monitor.h
+++ b/runtime/monitor.h
@@ -95,7 +95,7 @@
template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
mirror::Object* GetObject() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- return ReadBarrier::BarrierForWeakRoot<mirror::Object, kReadBarrierOption>(&obj_);
+ return ReadBarrier::BarrierForRoot<mirror::Object, kReadBarrierOption>(&obj_);
}
void SetObject(mirror::Object* object);
diff --git a/runtime/read_barrier-inl.h b/runtime/read_barrier-inl.h
index e252b7b..fd43d78 100644
--- a/runtime/read_barrier-inl.h
+++ b/runtime/read_barrier-inl.h
@@ -44,8 +44,8 @@
}
template <typename MirrorType, ReadBarrierOption kReadBarrierOption>
-inline MirrorType* ReadBarrier::BarrierForWeakRoot(MirrorType** weak_root) {
- MirrorType* ref = *weak_root;
+inline MirrorType* ReadBarrier::BarrierForRoot(MirrorType** root) {
+ MirrorType* ref = *root;
const bool with_read_barrier = kReadBarrierOption == kWithReadBarrier;
if (with_read_barrier && kUseBakerReadBarrier) {
// To be implemented.
diff --git a/runtime/read_barrier.h b/runtime/read_barrier.h
index 7232a3f..451d13c 100644
--- a/runtime/read_barrier.h
+++ b/runtime/read_barrier.h
@@ -39,7 +39,7 @@
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
template <typename MirrorType, ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
- ALWAYS_INLINE static MirrorType* BarrierForWeakRoot(MirrorType** weak_root)
+ ALWAYS_INLINE static MirrorType* BarrierForRoot(MirrorType** root)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
};