[vm, gc] Don't double-visit remembered cards to decide if they should remain remembered.
TEST=ci
Change-Id: Ib92dbbabf90f80c6e984c21b9eaee67fd4205f8f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/365543
Commit-Queue: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Alexander Aprelev <aam@google.com>
diff --git a/runtime/vm/heap/page.cc b/runtime/vm/heap/page.cc
index a0b83b9..08e998e 100644
--- a/runtime/vm/heap/page.cc
+++ b/runtime/vm/heap/page.cc
@@ -207,7 +207,7 @@
ASSERT(obj_addr == end_addr);
}
-void Page::VisitRememberedCards(ObjectPointerVisitor* visitor) {
+void Page::VisitRememberedCards(PredicateObjectPointerVisitor* visitor) {
ASSERT(Thread::Current()->OwnsGCSafepoint() ||
(Thread::Current()->task_kind() == Thread::kScavengerTask));
NoSafepointScope no_safepoint;
@@ -258,15 +258,9 @@
card_to = obj_to;
}
- visitor->VisitCompressedPointers(heap_base, card_from, card_to);
+ bool has_new_target = visitor->PredicateVisitCompressedPointers(
+ heap_base, card_from, card_to);
- bool has_new_target = false;
- for (CompressedObjectPtr* slot = card_from; slot <= card_to; slot++) {
- if ((*slot)->IsNewObjectMayBeSmi()) {
- has_new_target = true;
- break;
- }
- }
if (!has_new_target) {
cell ^= bit_mask;
}
diff --git a/runtime/vm/heap/page.h b/runtime/vm/heap/page.h
index 4be0412..9ecc2ea 100644
--- a/runtime/vm/heap/page.h
+++ b/runtime/vm/heap/page.h
@@ -173,7 +173,7 @@
return IsCardRemembered(reinterpret_cast<uword>(slot));
}
#endif
- void VisitRememberedCards(ObjectPointerVisitor* visitor);
+ void VisitRememberedCards(PredicateObjectPointerVisitor* visitor);
void ResetProgressBar();
Thread* owner() const { return owner_; }
diff --git a/runtime/vm/heap/pages.cc b/runtime/vm/heap/pages.cc
index f929af1..d63bf22 100644
--- a/runtime/vm/heap/pages.cc
+++ b/runtime/vm/heap/pages.cc
@@ -676,7 +676,8 @@
}
}
-void PageSpace::VisitRememberedCards(ObjectPointerVisitor* visitor) const {
+void PageSpace::VisitRememberedCards(
+ PredicateObjectPointerVisitor* visitor) const {
ASSERT(Thread::Current()->OwnsGCSafepoint() ||
(Thread::Current()->task_kind() == Thread::kScavengerTask));
diff --git a/runtime/vm/heap/pages.h b/runtime/vm/heap/pages.h
index 71c5ef1..fe0bc18 100644
--- a/runtime/vm/heap/pages.h
+++ b/runtime/vm/heap/pages.h
@@ -230,7 +230,7 @@
void VisitObjectsUnsafe(ObjectVisitor* visitor) const;
void VisitObjectPointers(ObjectPointerVisitor* visitor) const;
- void VisitRememberedCards(ObjectPointerVisitor* visitor) const;
+ void VisitRememberedCards(PredicateObjectPointerVisitor* visitor) const;
void ResetProgressBars() const;
// Collect the garbage in the page space using mark-sweep or mark-compact.
diff --git a/runtime/vm/heap/scavenger.cc b/runtime/vm/heap/scavenger.cc
index 5f25361..64e96f2 100644
--- a/runtime/vm/heap/scavenger.cc
+++ b/runtime/vm/heap/scavenger.cc
@@ -127,7 +127,8 @@
}
template <bool parallel>
-class ScavengerVisitorBase : public ObjectPointerVisitor {
+class ScavengerVisitorBase : public ObjectPointerVisitor,
+ public PredicateObjectPointerVisitor {
public:
explicit ScavengerVisitorBase(IsolateGroup* isolate_group,
Scavenger* scavenger,
@@ -226,14 +227,35 @@
}
}
+ bool PredicateVisitPointers(ObjectPtr* first, ObjectPtr* last) override {
+ bool has_new_target = false;
+ for (ObjectPtr* current = first; current <= last; current++) {
+ has_new_target |= PredicateScavengePointer(current);
+ }
+ return has_new_target;
+ }
+
#if defined(DART_COMPRESSED_POINTERS)
+ bool PredicateVisitCompressedPointers(uword heap_base,
+ CompressedObjectPtr* first,
+ CompressedObjectPtr* last) override {
+ bool has_new_target = false;
+ for (CompressedObjectPtr* current = first; current <= last; current++) {
+ has_new_target |= PredicateScavengeCompressedPointer(heap_base, current);
+ }
+ return has_new_target;
+ }
+
void VisitCompressedPointers(uword heap_base,
CompressedObjectPtr* first,
CompressedObjectPtr* last) override {
- ASSERT(Utils::IsAligned(first, sizeof(*first)));
- ASSERT(Utils::IsAligned(last, sizeof(*last)));
- for (CompressedObjectPtr* current = first; current <= last; current++) {
- ScavengeCompressedPointer(heap_base, current);
+ if (PredicateVisitCompressedPointers(heap_base, first, last)) {
+ // Update the store buffer as needed.
+ ObjectPtr visiting_object = visiting_old_object_;
+ if (visiting_object != nullptr &&
+ visiting_object->untag()->TryAcquireRememberedBit()) {
+ thread_->StoreBufferAddObjectGC(visiting_object);
+ }
}
}
#endif
@@ -353,19 +375,24 @@
private:
DART_FORCE_INLINE
- void ScavengePointer(ObjectPtr* p) {
+ bool PredicateScavengePointer(ObjectPtr* p) {
// ScavengePointer cannot be called recursively.
ObjectPtr obj = *p;
if (obj->IsImmediateOrOldObject()) {
- return;
+ return false;
}
ObjectPtr new_obj = ScavengeObject(obj);
// Update the reference.
*p = new_obj;
- if (new_obj->IsNewObject()) {
+ return new_obj->IsNewObject();
+ }
+
+ DART_FORCE_INLINE
+ void ScavengePointer(ObjectPtr* p) {
+ if (PredicateScavengePointer(p)) {
// Update the store buffer as needed.
ObjectPtr visiting_object = visiting_old_object_;
if (visiting_object != nullptr &&
@@ -376,20 +403,26 @@
}
DART_FORCE_INLINE
- void ScavengeCompressedPointer(uword heap_base, CompressedObjectPtr* p) {
+ bool PredicateScavengeCompressedPointer(uword heap_base,
+ CompressedObjectPtr* p) {
// ScavengePointer cannot be called recursively.
ObjectPtr obj = p->Decompress(heap_base);
// Could be tested without decompression.
if (obj->IsImmediateOrOldObject()) {
- return;
+ return false;
}
ObjectPtr new_obj = ScavengeObject(obj);
// Update the reference.
*p = new_obj;
- if (new_obj->IsNewObject()) {
+ return new_obj->IsNewObject();
+ }
+
+ DART_FORCE_INLINE
+ void ScavengeCompressedPointer(uword heap_base, CompressedObjectPtr* p) {
+ if (PredicateScavengeCompressedPointer(heap_base, p)) {
// Update the store buffer as needed.
ObjectPtr visiting_object = visiting_old_object_;
if (visiting_object != nullptr &&
diff --git a/runtime/vm/visitor.h b/runtime/vm/visitor.h
index 59790ad..e306164 100644
--- a/runtime/vm/visitor.h
+++ b/runtime/vm/visitor.h
@@ -87,6 +87,24 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(ObjectPointerVisitor);
};
+class PredicateObjectPointerVisitor {
+ public:
+ PredicateObjectPointerVisitor() {}
+ virtual ~PredicateObjectPointerVisitor() {}
+ virtual bool PredicateVisitPointers(ObjectPtr* first, ObjectPtr* last) = 0;
+#if defined(DART_COMPRESSED_POINTERS)
+ virtual bool PredicateVisitCompressedPointers(uword heap_base,
+ CompressedObjectPtr* first,
+ CompressedObjectPtr* last) = 0;
+#else
+ bool PredicateVisitCompressedPointers(uword heap_base,
+ CompressedObjectPtr* first,
+ CompressedObjectPtr* last) {
+ return PredicateVisitPointers(first, last);
+ }
+#endif
+};
+
// An object visitor interface.
class ObjectVisitor {
public: