ObjPtr<mirror::String> InternTable::Insert(ObjPtr<mirror::String> s,
uint32_t hash, bool is_strong,
size_t num_searched_strong_frozen_tables) {
DCHECK(s != nullptr);
DCHECK_EQ(hash, static_cast<uint32_t>(s->GetStoredHashCode()));
DCHECK_IMPLIES(hash == 0u, s->ComputeHashCode() == 0);
Thread* const self = Thread::Current(); if (kObjPtrPoisoning) {
StackHandleScope<1> hs(self);
HandleWrapperObjPtr<mirror::String> s_wrapper = hs.NewHandleWrapper(&s);
self->PoisonObjectPointers();
}
MutexLock mu(self, *Locks::intern_table_lock_); if (kDebugLocking) {
Locks::mutator_lock_->AssertSharedHeld(self);
CHECK_EQ(2u, self->NumberOfHeldMutexes()) << "may only safely hold the mutator lock";
} while (true) { // Check the strong table for a match.
ObjPtr<mirror::String> strong =
strong_interns_.Find(s, hash, num_searched_strong_frozen_tables); if (strong != nullptr) { return strong;
} if (WeakAccessEnabled(self)) { break;
}
num_searched_strong_frozen_tables = strong_interns_.tables_.size() - 1u; // weak_root_state_ is set to gc::kWeakRootStateNoReadsOrWrites in the GC pause but is only // cleared after SweepSystemWeaks has completed. This is why we need to wait until it is // cleared.
StackHandleScope<1> hs(self); auto h = hs.NewHandleWrapper(&s);
WaitUntilAccessible(self);
} if (!gUseReadBarrier) {
CHECK_EQ(weak_root_state_, gc::kWeakRootStateNormal);
} else {
CHECK(self->GetWeakRefAccessEnabled());
} // There is no match in the strong table, check the weak table.
ObjPtr<mirror::String> weak = weak_interns_.Find(s, hash); if (weak != nullptr) { if (is_strong) { // A match was found in the weak table. Promote to the strong table.
RemoveWeak(weak, hash); return InsertStrong(weak, hash);
} return weak;
} // No match in the strong table or the weak table. Insert into the strong / weak table. return is_strong ? InsertStrong(s, hash) : InsertWeak(s, hash);
}
ObjPtr<mirror::String> InternTable::Intern(
uint32_t utf16_length, constchar* utf8_data, bool is_strong) {
DCHECK(utf8_data != nullptr);
uint32_t hash = Utf8String::Hash(utf16_length, utf8_data);
Thread* self = Thread::Current();
self->PoisonObjectPointers();
ObjPtr<mirror::String> s;
size_t num_searched_strong_frozen_tables;
{ // Try to avoid allocation. If we need to allocate, release the mutex before the allocation.
MutexLock mu(self, *Locks::intern_table_lock_);
DCHECK(!strong_interns_.tables_.empty());
num_searched_strong_frozen_tables = strong_interns_.tables_.size() - 1u;
s = strong_interns_.Find(Utf8String(utf16_length, utf8_data), hash); if (s == nullptr && !is_strong && WeakAccessEnabled(self)) {
s = weak_interns_.Find(Utf8String(utf16_length, utf8_data), hash);
}
} if (s != nullptr) { return s;
} bool is_ascii = (utf8_data[utf16_length] == 0);
int32_t utf8_length = utf16_length + (LIKELY(is_ascii) ? 0 : strlen(utf8_data + utf16_length));
DCHECK_EQ(static_cast<size_t>(utf8_length), strlen(utf8_data));
s = mirror::String::AllocFromModifiedUtf8(self, utf16_length, utf8_data, utf8_length); if (UNLIKELY(s == nullptr)) {
self->AssertPendingOOMException(); return nullptr;
}
s->SetHashCode(static_cast<int32_t>(hash)); return Insert(s, hash, is_strong, num_searched_strong_frozen_tables);
}
void InternTable::Table::Remove(ObjPtr<mirror::String> s, uint32_t hash) {
DCHECK(Locks::mutator_lock_->IsSharedHeld(Thread::Current())); // Note: We can remove weak interns even from frozen tables when promoting to strong interns. // We can remove strong interns only for a transaction rollback. for (InternalTable& table : tables_) { auto it = table.set_.FindWithHash(GcRoot<mirror::String>(s), hash); if (it != table.set_.end()) {
table.set_.erase(it); return;
}
}
LOG(FATAL) << "Attempting to remove non-interned string " << s->ToModifiedUtf8();
}
FLATTEN
ObjPtr<mirror::String> InternTable::Table::Find(ObjPtr<mirror::String> s,
uint32_t hash,
size_t num_searched_frozen_tables) {
DCHECK(Locks::mutator_lock_->IsSharedHeld(Thread::Current())); auto mid = tables_.begin() + num_searched_frozen_tables; for (Table::InternalTable& table : MakeIterationRange(tables_.begin(), mid)) {
DCHECK(table.set_.FindWithHash(GcRoot<mirror::String>(s), hash) == table.set_.end());
} // Search from the last table, assuming that apps shall search for their own // strings more often than for boot image strings. for (Table::InternalTable& table : ReverseRange(MakeIterationRange(mid, tables_.end()))) { auto it = table.set_.FindWithHash(GcRoot<mirror::String>(s), hash); if (it != table.set_.end()) { return it->Read();
}
} return nullptr;
}
FLATTEN
ObjPtr<mirror::String> InternTable::Table::Find(const Utf8String& string, uint32_t hash) {
Locks::intern_table_lock_->AssertHeld(Thread::Current()); // Search from the last table, assuming that apps shall search for their own // strings more often than for boot image strings. for (InternalTable& table : ReverseRange(tables_)) { auto it = table.set_.FindWithHash(string, hash); if (it != table.set_.end()) { return it->Read();
}
} return nullptr;
}
void InternTable::Table::AddNewTable() { // Propagate the min/max load factor from the old active set.
DCHECK(!tables_.empty()); const UnorderedSet& last_set = tables_.back().set_;
InternalTable new_table;
new_table.set_.SetLoadFactor(last_set.GetMinLoadFactor(), last_set.GetMaxLoadFactor());
tables_.push_back(std::move(new_table));
}
void InternTable::Table::Insert(ObjPtr<mirror::String> s, uint32_t hash) {
DCHECK(Locks::mutator_lock_->IsSharedHeld(Thread::Current())); // Always insert the last table, the image tables are before and we avoid inserting into these // to prevent dirty pages.
DCHECK(!tables_.empty());
tables_.back().set_.PutWithHash(GcRoot<mirror::String>(s), hash);
}
void InternTable::Table::SweepWeaks(UnorderedSet* set, IsMarkedVisitor* visitor) { for (auto it = set->begin(), end = set->end(); it != end;) { // This does not need a read barrier because this is called by GC.
mirror::Object* object = it->Read<kWithoutReadBarrier>();
mirror::Object* new_object = visitor->IsMarked(object); if (new_object == nullptr) {
it = set->erase(it);
} else { // Don't use AsString as it does IsString check in debug builds which, in // case of userfaultfd GC, is called when the object's content isn't // thereyet.
*it = GcRoot<mirror::String>(ObjPtr<mirror::String>::DownCast(new_object));
++it;
}
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.