inlinevoidoperator()(uint8_t* card,
uint8_t expected_value,
[[maybe_unused]] uint8_t new_value) const { if (expected_value == CardTable::kCardDirty) { // We want the address the card represents, not the address of the card.
bitmap_->Set(reinterpret_cast<uintptr_t>(card_table_->AddrFromCard(card)));
}
}
// Extra parameters are required since we use this same visitor signature for checking objects. voidoperator()(mirror::Object* obj, MemberOffset offset, [[maybe_unused]] bool is_static) const
REQUIRES_SHARED(Locks::mutator_lock_) {
MarkReference(obj->GetFieldObjectReferenceAddr(offset));
}
private: template<typename CompressedReferenceType> void MarkReference(CompressedReferenceType* obj_ptr) const
REQUIRES_SHARED(Locks::mutator_lock_) { // Only add the reference if it is non null and fits our criteria.
mirror::Object* ref = obj_ptr->AsMirrorPtr(); if (ref != nullptr && !from_space_->HasAddress(ref) && !immune_space_->HasAddress(ref)) {
*contains_reference_to_other_space_ = true;
mirror::Object* new_object = visitor_->MarkObject(ref); if (ref != new_object) {
obj_ptr->Assign(new_object);
}
}
}
MarkObjectVisitor* const visitor_; // Space which we are scanning
space::ContinuousSpace* const from_space_;
space::ContinuousSpace* const immune_space_; // Set if we have any references to another space. bool* const contains_reference_to_other_space_;
};
class ModUnionScanImageRootVisitor { public: // Immune space is any other space which we don't care about references to. Currently this is // the image space in the case of the zygote mod union table.
ModUnionScanImageRootVisitor(MarkObjectVisitor* visitor,
space::ContinuousSpace* from_space,
space::ContinuousSpace* immune_space, bool* contains_reference_to_other_space)
: visitor_(visitor),
from_space_(from_space),
immune_space_(immune_space),
contains_reference_to_other_space_(contains_reference_to_other_space) {}
private:
MarkObjectVisitor* const visitor_; // Space which we are scanning
space::ContinuousSpace* const from_space_;
space::ContinuousSpace* const immune_space_; // Set if we have any references to another space. bool* const contains_reference_to_other_space_;
};
void ModUnionTableReferenceCache::ProcessCards() {
CardTable* card_table = GetHeap()->GetCardTable();
ModUnionAddToCardSetVisitor visitor(&cleared_cards_); // Clear dirty cards in the this space and update the corresponding mod-union bits.
card_table->ModifyCardsAtomic(space_->Begin(), space_->End(), AgeCardVisitor(), visitor);
}
// Extra parameters are required since we use this same visitor signature for checking objects. voidoperator()(mirror::Object* obj, MemberOffset offset, [[maybe_unused]] bool is_static) const
REQUIRES_SHARED(Locks::mutator_lock_) {
mirror::HeapReference<mirror::Object>* ref_ptr = obj->GetFieldObjectReferenceAddr(offset);
mirror::Object* ref = ref_ptr->AsMirrorPtr(); // Only add the reference if it is non null and fits our criteria. if (ref != nullptr && mod_union_table_->ShouldAddReference(ref)) { // Push the adddress of the reference.
references_->push_back(ref_ptr);
}
}
voidoperator()(mirror::Object* obj) const
REQUIRES_SHARED(Locks::heap_bitmap_lock_, Locks::mutator_lock_) { // We don't have an early exit since we use the visitor pattern, an early // exit should significantly speed this up.
AddToReferenceArrayVisitor visitor(mod_union_table_,
visitor_,
references_,
has_target_reference_);
obj->VisitReferences(visitor, VoidFunctor());
}
class EmptyMarkObjectVisitor : public MarkObjectVisitor { public:
mirror::Object* MarkObject(mirror::Object* obj) override {return obj;} void MarkHeapReference(mirror::HeapReference<mirror::Object>*, bool) override {}
};
void ModUnionTable::FilterCards() {
EmptyMarkObjectVisitor visitor; // Use empty visitor since filtering is automatically done by UpdateAndMarkReferences.
UpdateAndMarkReferences(&visitor);
}
void ModUnionTableReferenceCache::Verify() { // Start by checking that everything in the mod union table is marked. for (constauto& ref_pair : references_) { for (mirror::HeapReference<mirror::Object>* ref : ref_pair.second) {
CHECK(heap_->IsLiveObjectLocked(ref->AsMirrorPtr()));
}
}
// Check the references of each clean card which is also in the mod union table.
CardTable* card_table = heap_->GetCardTable();
ContinuousSpaceBitmap* live_bitmap = space_->GetLiveBitmap(); for (constauto& ref_pair : references_) { const uint8_t* card = ref_pair.first; if (*card == CardTable::kCardClean) {
std::set<mirror::Object*> reference_set; for (mirror::HeapReference<mirror::Object>* obj_ptr : ref_pair.second) {
reference_set.insert(obj_ptr->AsMirrorPtr());
}
ModUnionCheckReferences visitor(this, reference_set);
uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
live_bitmap->VisitMarkedRange(start, start + CardTable::kCardSize, visitor);
}
}
}
void ModUnionTableReferenceCache::Dump(std::ostream& os) {
CardTable* card_table = heap_->GetCardTable();
os << "ModUnionTable cleared cards: ["; for (uint8_t* card_addr : cleared_cards_) {
uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card_addr));
uintptr_t end = start + CardTable::kCardSize;
os << reinterpret_cast<void*>(start) << "-" << reinterpret_cast<void*>(end) << ",";
}
os << "]\nModUnionTable references: ["; for (constauto& ref_pair : references_) { const uint8_t* card_addr = ref_pair.first;
uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card_addr));
uintptr_t end = start + CardTable::kCardSize;
os << reinterpret_cast<void*>(start) << "-" << reinterpret_cast<void*>(end) << "->{"; for (mirror::HeapReference<mirror::Object>* ref : ref_pair.second) {
os << reinterpret_cast<constvoid*>(ref->AsMirrorPtr()) << ",";
}
os << "},";
}
}
void ModUnionTableReferenceCache::VisitObjects(ObjectCallback callback, void* arg) {
CardTable* const card_table = heap_->GetCardTable();
ContinuousSpaceBitmap* live_bitmap = space_->GetLiveBitmap(); // Use an unordered_set for constant time search of card in the second loop. // We don't want to change cleared_cards_ to unordered so that traversals are // sequential in address order. // TODO: Optimize this.
std::unordered_set<const uint8_t*> card_lookup_map; for (uint8_t* card : cleared_cards_) {
uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
uintptr_t end = start + CardTable::kCardSize;
live_bitmap->VisitMarkedRange(start,
end,
[callback, arg](mirror::Object* obj) {
callback(obj, arg);
});
card_lookup_map.insert(card);
} for (constauto& pair : references_) { const uint8_t* card = pair.first; if (card_lookup_map.find(card) != card_lookup_map.end()) { continue;
}
uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
uintptr_t end = start + CardTable::kCardSize;
live_bitmap->VisitMarkedRange(start,
end,
[callback, arg](mirror::Object* obj) {
callback(obj, arg);
});
}
}
void ModUnionTableReferenceCache::UpdateAndMarkReferences(MarkObjectVisitor* visitor) {
CardTable* const card_table = heap_->GetCardTable();
std::vector<mirror::HeapReference<mirror::Object>*> cards_references; // If has_target_reference is true then there was a GcRoot compressed reference which wasn't // added. In this case we need to keep the card dirty. // We don't know if the GcRoot addresses will remain constant, for example, classloaders have a // hash set of GcRoot which may be resized or modified. bool has_target_reference;
ModUnionReferenceVisitor add_visitor(this, visitor, &cards_references, &has_target_reference);
CardSet new_cleared_cards; for (uint8_t* card : cleared_cards_) { // Clear and re-compute alloc space references associated with this card.
cards_references.clear();
has_target_reference = false;
uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
uintptr_t end = start + CardTable::kCardSize;
space::ContinuousSpace* space =
heap_->FindContinuousSpaceFromObject(reinterpret_cast<mirror::Object*>(start), false);
DCHECK(space != nullptr);
ContinuousSpaceBitmap* live_bitmap = space->GetLiveBitmap();
live_bitmap->VisitMarkedRange(start, end, add_visitor); // Update the corresponding references for the card. auto found = references_.find(card); if (found == references_.end()) { // Don't add card for an empty reference array. if (!cards_references.empty()) {
references_.Put(card, cards_references);
}
} else { if (cards_references.empty()) {
references_.erase(found);
} else {
found->second = cards_references;
}
} if (has_target_reference) { // Keep this card for next time since it contains a GcRoot which matches the // ShouldAddReference criteria. This usually occurs for class loaders.
new_cleared_cards.insert(card);
}
}
cleared_cards_ = std::move(new_cleared_cards);
size_t count = 0; for (auto it = references_.begin(); it != references_.end();) {
std::vector<mirror::HeapReference<mirror::Object>*>& references = it->second; // Since there is no card mark for setting a reference to null, we check each reference. // If all of the references of a card are null then we can remove that card. This is racy // with the mutators, but handled by rescanning dirty cards. bool all_null = true; for (mirror::HeapReference<mirror::Object>* obj_ptr : references) { if (obj_ptr->AsMirrorPtr() != nullptr) {
all_null = false;
visitor->MarkHeapReference(obj_ptr, /*do_atomic_update=*/ false);
}
}
count += references.size(); if (!all_null) {
++it;
} else { // All null references, erase the array from the set.
it = references_.erase(it);
}
} if (VLOG_IS_ON(heap)) {
VLOG(gc) << "Marked " << count << " references in mod union table";
}
}
ModUnionTableCardCache::ModUnionTableCardCache(const std::string& name,
Heap* heap,
space::ContinuousSpace* space)
: ModUnionTable(name, heap, space) { // Normally here we could use End() instead of Limit(), but for testing we may want to have a // mod-union table for a space which can still grow. if (!space->IsImageSpace()) {
CHECK_ALIGNED(reinterpret_cast<uintptr_t>(space->Limit()), CardTable::kCardSize);
}
card_bitmap_.reset(CardBitmap::Create( "mod union bitmap", reinterpret_cast<uintptr_t>(space->Begin()),
RoundUp(reinterpret_cast<uintptr_t>(space->Limit()), CardTable::kCardSize)));
}
void ModUnionTableCardCache::ProcessCards() {
CardTable* const card_table = GetHeap()->GetCardTable();
ModUnionAddToCardBitmapVisitor visitor(card_bitmap_.get(), card_table); // Clear dirty cards in the this space and update the corresponding mod-union bits.
card_table->ModifyCardsAtomic(space_->Begin(), space_->End(), AgeCardVisitor(), visitor);
}
// Mark all references to the alloc space(s). void ModUnionTableCardCache::UpdateAndMarkReferences(MarkObjectVisitor* visitor) { // TODO: Needs better support for multi-images? b/26317072
space::ImageSpace* image_space =
heap_->GetBootImageSpaces().empty() ? nullptr : heap_->GetBootImageSpaces()[0]; // If we don't have an image space, just pass in space_ as the immune space. Pass in the same // space_ instead of image_space to avoid a null check in ModUnionUpdateObjectReferencesVisitor.
CardBitVisitor bit_visitor(visitor, space_, image_space != nullptr ? image_space : space_,
card_bitmap_.get());
card_bitmap_->VisitSetBits( 0, RoundUp(space_->Size(), CardTable::kCardSize) / CardTable::kCardSize, bit_visitor);
}
void ModUnionTableCardCache::Dump(std::ostream& os) {
os << "ModUnionTable dirty cards: ["; // TODO: Find cleaner way of doing this. for (uint8_t* addr = space_->Begin(); addr < AlignUp(space_->End(), CardTable::kCardSize);
addr += CardTable::kCardSize) { if (card_bitmap_->Test(reinterpret_cast<uintptr_t>(addr))) {
os << reinterpret_cast<void*>(addr) << "-"
<< reinterpret_cast<void*>(addr + CardTable::kCardSize) << "\n";
}
}
os << "]";
}
void ModUnionTableCardCache::SetCards() { // Only clean up to the end since there cannot be any objects past the End() of the space. for (uint8_t* addr = space_->Begin(); addr < AlignUp(space_->End(), CardTable::kCardSize);
addr += CardTable::kCardSize) {
card_bitmap_->Set(reinterpret_cast<uintptr_t>(addr));
}
}
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.