mirror of
https://github.com/dart-lang/sdk
synced 2024-10-03 01:14:16 +00:00
[vm, gc] Verify remembered cards when verifying the store buffer.
TEST=ci Change-Id: I004a55902c65d89915ea79c141270a2c2670e53c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/199363 Reviewed-by: Liam Appelbe <liama@google.com> Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
parent
3a3b3e480b
commit
634cccccc6
|
@ -145,6 +145,17 @@ class OldPage {
|
||||||
ASSERT((index >= 0) && (index < card_table_size()));
|
ASSERT((index >= 0) && (index < card_table_size()));
|
||||||
card_table_[index] = 1;
|
card_table_[index] = 1;
|
||||||
}
|
}
|
||||||
|
bool IsCardRemembered(ObjectPtr const* slot) {
|
||||||
|
ASSERT(Contains(reinterpret_cast<uword>(slot)));
|
||||||
|
if (card_table_ == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
intptr_t offset =
|
||||||
|
reinterpret_cast<uword>(slot) - reinterpret_cast<uword>(this);
|
||||||
|
intptr_t index = offset >> kBytesPerCardLog2;
|
||||||
|
ASSERT((index >= 0) && (index < card_table_size()));
|
||||||
|
return card_table_[index] != 0;
|
||||||
|
}
|
||||||
#if defined(DART_COMPRESSED_POINTERS)
|
#if defined(DART_COMPRESSED_POINTERS)
|
||||||
void RememberCard(CompressedObjectPtr const* slot) {
|
void RememberCard(CompressedObjectPtr const* slot) {
|
||||||
ASSERT(Contains(reinterpret_cast<uword>(slot)));
|
ASSERT(Contains(reinterpret_cast<uword>(slot)));
|
||||||
|
@ -158,6 +169,17 @@ class OldPage {
|
||||||
ASSERT((index >= 0) && (index < card_table_size()));
|
ASSERT((index >= 0) && (index < card_table_size()));
|
||||||
card_table_[index] = 1;
|
card_table_[index] = 1;
|
||||||
}
|
}
|
||||||
|
bool IsCardRemembered(CompressedObjectPtr const* slot) {
|
||||||
|
ASSERT(Contains(reinterpret_cast<uword>(slot)));
|
||||||
|
if (card_table_ == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
intptr_t offset =
|
||||||
|
reinterpret_cast<uword>(slot) - reinterpret_cast<uword>(this);
|
||||||
|
intptr_t index = offset >> kBytesPerCardLog2;
|
||||||
|
ASSERT((index >= 0) && (index < card_table_size()));
|
||||||
|
return card_table_[index] != 0;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
void VisitRememberedCards(ObjectPointerVisitor* visitor);
|
void VisitRememberedCards(ObjectPointerVisitor* visitor);
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "vm/dart_api_state.h"
|
#include "vm/dart_api_state.h"
|
||||||
#include "vm/flag_list.h"
|
#include "vm/flag_list.h"
|
||||||
#include "vm/heap/become.h"
|
#include "vm/heap/become.h"
|
||||||
|
#include "vm/heap/pages.h"
|
||||||
#include "vm/heap/pointer_block.h"
|
#include "vm/heap/pointer_block.h"
|
||||||
#include "vm/heap/safepoint.h"
|
#include "vm/heap/safepoint.h"
|
||||||
#include "vm/heap/verifier.h"
|
#include "vm/heap/verifier.h"
|
||||||
|
@ -867,17 +868,15 @@ class CheckStoreBufferVisitor : public ObjectVisitor,
|
||||||
if (raw_obj->IsPseudoObject()) return;
|
if (raw_obj->IsPseudoObject()) return;
|
||||||
RELEASE_ASSERT(raw_obj->IsOldObject());
|
RELEASE_ASSERT(raw_obj->IsOldObject());
|
||||||
|
|
||||||
if (raw_obj->untag()->IsCardRemembered()) {
|
|
||||||
RELEASE_ASSERT(!raw_obj->untag()->IsRemembered());
|
|
||||||
// TODO(rmacnak): Verify card tables.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
RELEASE_ASSERT(raw_obj->untag()->IsRemembered() ==
|
RELEASE_ASSERT(raw_obj->untag()->IsRemembered() ==
|
||||||
in_store_buffer_->Contains(raw_obj));
|
in_store_buffer_->Contains(raw_obj));
|
||||||
|
|
||||||
visiting_ = raw_obj;
|
visiting_ = raw_obj;
|
||||||
is_remembered_ = raw_obj->untag()->IsRemembered();
|
is_remembered_ = raw_obj->untag()->IsRemembered();
|
||||||
|
is_card_remembered_ = raw_obj->untag()->IsCardRemembered();
|
||||||
|
if (is_card_remembered_) {
|
||||||
|
RELEASE_ASSERT(!is_remembered_);
|
||||||
|
}
|
||||||
raw_obj->untag()->VisitPointers(this);
|
raw_obj->untag()->VisitPointers(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -885,12 +884,24 @@ class CheckStoreBufferVisitor : public ObjectVisitor,
|
||||||
for (ObjectPtr* ptr = from; ptr <= to; ptr++) {
|
for (ObjectPtr* ptr = from; ptr <= to; ptr++) {
|
||||||
ObjectPtr raw_obj = *ptr;
|
ObjectPtr raw_obj = *ptr;
|
||||||
if (raw_obj->IsHeapObject() && raw_obj->IsNewObject()) {
|
if (raw_obj->IsHeapObject() && raw_obj->IsNewObject()) {
|
||||||
if (!is_remembered_) {
|
if (is_card_remembered_) {
|
||||||
|
if (!OldPage::Of(visiting_)->IsCardRemembered(ptr)) {
|
||||||
|
FATAL3(
|
||||||
|
"Old object %#" Px " references new object %#" Px
|
||||||
|
", but the "
|
||||||
|
"slot's card is not remembered. Consider using rr to watch the "
|
||||||
|
"slot %p and reverse-continue to find the store with a missing "
|
||||||
|
"barrier.\n",
|
||||||
|
static_cast<uword>(visiting_), static_cast<uword>(raw_obj),
|
||||||
|
ptr);
|
||||||
|
}
|
||||||
|
} else if (!is_remembered_) {
|
||||||
FATAL3(
|
FATAL3(
|
||||||
"Old object %#" Px " references new object %#" Px
|
"Old object %#" Px " references new object %#" Px
|
||||||
", but it is not"
|
", but it is "
|
||||||
" in any store buffer. Consider using rr to watch the slot %p and"
|
"not in any store buffer. Consider using rr to watch the "
|
||||||
" reverse-continue to find the store with a missing barrier.\n",
|
"slot %p and reverse-continue to find the store with a missing "
|
||||||
|
"barrier.\n",
|
||||||
static_cast<uword>(visiting_), static_cast<uword>(raw_obj), ptr);
|
static_cast<uword>(visiting_), static_cast<uword>(raw_obj), ptr);
|
||||||
}
|
}
|
||||||
RELEASE_ASSERT(to_->Contains(UntaggedObject::ToAddr(raw_obj)));
|
RELEASE_ASSERT(to_->Contains(UntaggedObject::ToAddr(raw_obj)));
|
||||||
|
@ -904,12 +915,24 @@ class CheckStoreBufferVisitor : public ObjectVisitor,
|
||||||
for (CompressedObjectPtr* ptr = from; ptr <= to; ptr++) {
|
for (CompressedObjectPtr* ptr = from; ptr <= to; ptr++) {
|
||||||
ObjectPtr raw_obj = ptr->Decompress(heap_base);
|
ObjectPtr raw_obj = ptr->Decompress(heap_base);
|
||||||
if (raw_obj->IsHeapObject() && raw_obj->IsNewObject()) {
|
if (raw_obj->IsHeapObject() && raw_obj->IsNewObject()) {
|
||||||
if (!is_remembered_) {
|
if (is_card_remembered_) {
|
||||||
|
if (!OldPage::Of(visiting_)->IsCardRemembered(ptr)) {
|
||||||
|
FATAL3(
|
||||||
|
"Old object %#" Px " references new object %#" Px
|
||||||
|
", but the "
|
||||||
|
"slot's card is not remembered. Consider using rr to watch the "
|
||||||
|
"slot %p and reverse-continue to find the store with a missing "
|
||||||
|
"barrier.\n",
|
||||||
|
static_cast<uword>(visiting_), static_cast<uword>(raw_obj),
|
||||||
|
ptr);
|
||||||
|
}
|
||||||
|
} else if (!is_remembered_) {
|
||||||
FATAL3(
|
FATAL3(
|
||||||
"Old object %#" Px " references new object %#" Px
|
"Old object %#" Px " references new object %#" Px
|
||||||
", but it is not"
|
", but it is "
|
||||||
" in any store buffer. Consider using rr to watch the slot %p and"
|
"not in any store buffer. Consider using rr to watch the "
|
||||||
" reverse-continue to find the store with a missing barrier.\n",
|
"slot %p and reverse-continue to find the store with a missing "
|
||||||
|
"barrier.\n",
|
||||||
static_cast<uword>(visiting_), static_cast<uword>(raw_obj), ptr);
|
static_cast<uword>(visiting_), static_cast<uword>(raw_obj), ptr);
|
||||||
}
|
}
|
||||||
RELEASE_ASSERT(to_->Contains(UntaggedObject::ToAddr(raw_obj)));
|
RELEASE_ASSERT(to_->Contains(UntaggedObject::ToAddr(raw_obj)));
|
||||||
|
@ -922,6 +945,7 @@ class CheckStoreBufferVisitor : public ObjectVisitor,
|
||||||
const SemiSpace* const to_;
|
const SemiSpace* const to_;
|
||||||
ObjectPtr visiting_;
|
ObjectPtr visiting_;
|
||||||
bool is_remembered_;
|
bool is_remembered_;
|
||||||
|
bool is_card_remembered_;
|
||||||
};
|
};
|
||||||
|
|
||||||
void Scavenger::VerifyStoreBuffers() {
|
void Scavenger::VerifyStoreBuffers() {
|
||||||
|
|
Loading…
Reference in a new issue