Unit tests for remembered set after removal of the store buffer
Change-Id: Ibbcd91115c21e3513602a039ebb68a0107a4022f Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1829172 Commit-Queue: Irina Yatsenko <irinayat@microsoft.com> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Cr-Commit-Position: refs/heads/master@{#64146}
This commit is contained in:
parent
994b64c024
commit
4f0f635391
@ -235,9 +235,9 @@ class RememberedSet : public AllStatic {
|
||||
});
|
||||
}
|
||||
|
||||
// Iterates and filters typed old to old pointers in the given memory chunk
|
||||
// with the given callback. The callback should take (SlotType slot_type,
|
||||
// Address addr) and return SlotCallbackResult.
|
||||
// Iterates and filters typed pointers in the given memory chunk with the
|
||||
// given callback. The callback should take (SlotType slot_type, Address addr)
|
||||
// and return SlotCallbackResult.
|
||||
template <typename Callback>
|
||||
static void IterateTyped(MemoryChunk* chunk, Callback callback) {
|
||||
TypedSlotSet* slots = chunk->typed_slot_set<type>();
|
||||
@ -260,9 +260,6 @@ class RememberedSet : public AllStatic {
|
||||
chunk->ReleaseInvalidatedSlots<OLD_TO_OLD>();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static bool IsValidSlot(Heap* heap, MemoryChunk* chunk, ObjectSlot slot);
|
||||
};
|
||||
|
||||
class UpdateTypedSlotHelper {
|
||||
|
@ -42,9 +42,6 @@
|
||||
V(Promotion) \
|
||||
V(Regression39128) \
|
||||
V(ResetWeakHandle) \
|
||||
V(StoreBuffer_CreateFromOldToYoung) \
|
||||
V(StoreBuffer_Overflow) \
|
||||
V(StoreBuffer_NotUsedOnAgingObjectWithRefsToYounger) \
|
||||
V(StressHandles) \
|
||||
V(TestMemoryReducerSampleJsCalls) \
|
||||
V(TestSizeOfObjects) \
|
||||
@ -59,7 +56,6 @@
|
||||
V(Regress791582) \
|
||||
V(Regress845060) \
|
||||
V(RegressMissingWriteBarrierInAllocate) \
|
||||
V(RememberedSet_LargePage) \
|
||||
V(WriteBarriersInCopyJSObject)
|
||||
|
||||
#define HEAP_TEST(Name) \
|
||||
|
@ -6016,6 +6016,173 @@ TEST(UncommitUnusedLargeObjectMemory) {
|
||||
CHECK_EQ(shrinked_size, chunk->CommittedPhysicalMemory());
|
||||
}
|
||||
|
||||
template <RememberedSetType direction>
|
||||
static size_t GetRememberedSetSize(HeapObject obj) {
|
||||
size_t count = 0;
|
||||
auto chunk = MemoryChunk::FromHeapObject(obj);
|
||||
RememberedSet<direction>::Iterate(
|
||||
chunk,
|
||||
[&count](MaybeObjectSlot slot) {
|
||||
count++;
|
||||
return KEEP_SLOT;
|
||||
},
|
||||
SlotSet::KEEP_EMPTY_BUCKETS);
|
||||
return count;
|
||||
}
|
||||
|
||||
TEST(RememberedSet_InsertOnWriteBarrier) {
|
||||
CcTest::InitializeVM();
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
Factory* factory = isolate->factory();
|
||||
Heap* heap = isolate->heap();
|
||||
heap::SealCurrentObjects(heap);
|
||||
HandleScope scope(isolate);
|
||||
|
||||
// Allocate an object in old space.
|
||||
Handle<FixedArray> arr = factory->NewFixedArray(3, AllocationType::kOld);
|
||||
|
||||
// Add into 'arr' references to young objects.
|
||||
{
|
||||
HandleScope scope_inner(isolate);
|
||||
Handle<Object> number = factory->NewHeapNumber(42);
|
||||
arr->set(0, *number);
|
||||
arr->set(1, *number);
|
||||
arr->set(2, *number);
|
||||
Handle<Object> number_other = factory->NewHeapNumber(24);
|
||||
arr->set(2, *number_other);
|
||||
}
|
||||
// Remembered sets track *slots* pages with cross-generational pointers, so
|
||||
// must have recorded three of them each exactly once.
|
||||
CHECK_EQ(3, GetRememberedSetSize<OLD_TO_NEW>(*arr));
|
||||
}
|
||||
|
||||
TEST(RememberedSet_InsertInLargePage) {
|
||||
CcTest::InitializeVM();
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
Factory* factory = isolate->factory();
|
||||
Heap* heap = isolate->heap();
|
||||
heap::SealCurrentObjects(heap);
|
||||
HandleScope scope(isolate);
|
||||
|
||||
// Allocate an object in Large space.
|
||||
const int count = Max(FixedArray::kMaxRegularLength + 1, 128 * KB);
|
||||
Handle<FixedArray> arr = factory->NewFixedArray(count, AllocationType::kOld);
|
||||
CHECK(heap->lo_space()->Contains(*arr));
|
||||
CHECK_EQ(0, GetRememberedSetSize<OLD_TO_NEW>(*arr));
|
||||
|
||||
// Create OLD_TO_NEW references from the large object so that the
|
||||
// corresponding slots end up in different SlotSets.
|
||||
{
|
||||
HandleScope short_lived(isolate);
|
||||
Handle<Object> number = factory->NewHeapNumber(42);
|
||||
arr->set(0, *number);
|
||||
arr->set(count - 1, *number);
|
||||
}
|
||||
CHECK_EQ(2, GetRememberedSetSize<OLD_TO_NEW>(*arr));
|
||||
}
|
||||
|
||||
TEST(RememberedSet_InsertOnPromotingObjectToOld) {
|
||||
CcTest::InitializeVM();
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
Factory* factory = isolate->factory();
|
||||
Heap* heap = isolate->heap();
|
||||
heap::SealCurrentObjects(heap);
|
||||
HandleScope scope(isolate);
|
||||
|
||||
// Create a young object and age it one generation inside the new space.
|
||||
Handle<FixedArray> arr = factory->NewFixedArray(1);
|
||||
CcTest::CollectGarbage(i::NEW_SPACE);
|
||||
CHECK(Heap::InYoungGeneration(*arr));
|
||||
|
||||
// Add into 'arr' a reference to an object one generation younger.
|
||||
{
|
||||
HandleScope scope_inner(isolate);
|
||||
Handle<Object> number = factory->NewHeapNumber(42);
|
||||
arr->set(0, *number);
|
||||
}
|
||||
|
||||
// Promote 'arr' into old, its element is still in new, the old to new
|
||||
// refs are inserted into the remembered sets during GC.
|
||||
CcTest::CollectGarbage(i::NEW_SPACE);
|
||||
|
||||
CHECK(heap->InOldSpace(*arr));
|
||||
CHECK_EQ(1, GetRememberedSetSize<OLD_TO_NEW>(*arr));
|
||||
}
|
||||
|
||||
TEST(RememberedSet_RemoveStaleOnScavenge) {
|
||||
CcTest::InitializeVM();
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
Factory* factory = isolate->factory();
|
||||
Heap* heap = isolate->heap();
|
||||
heap::SealCurrentObjects(heap);
|
||||
HandleScope scope(isolate);
|
||||
|
||||
// Allocate an object in old space and add into it references to young.
|
||||
Handle<FixedArray> arr = factory->NewFixedArray(3, AllocationType::kOld);
|
||||
{
|
||||
HandleScope scope_inner(isolate);
|
||||
Handle<Object> number = factory->NewHeapNumber(42);
|
||||
arr->set(0, *number); // will be trimmed away
|
||||
arr->set(1, *number); // will be replaced with #undefined
|
||||
arr->set(2, *number); // will be promoted into old
|
||||
}
|
||||
CHECK_EQ(3, GetRememberedSetSize<OLD_TO_NEW>(*arr));
|
||||
|
||||
// Run scavenger once so the young object becomes ready for promotion on the
|
||||
// next pass.
|
||||
CcTest::CollectGarbage(i::NEW_SPACE);
|
||||
arr->set(1, ReadOnlyRoots(CcTest::heap()).undefined_value());
|
||||
Handle<FixedArrayBase> tail =
|
||||
Handle<FixedArrayBase>(heap->LeftTrimFixedArray(*arr, 1), isolate);
|
||||
|
||||
// None of the actions above should have updated the remembered set.
|
||||
CHECK_EQ(3, GetRememberedSetSize<OLD_TO_NEW>(*tail));
|
||||
|
||||
// Run GC to promote the remaining young object and fixup the stale entries in
|
||||
// the remembered set.
|
||||
CcTest::CollectGarbage(i::NEW_SPACE);
|
||||
CHECK_EQ(0, GetRememberedSetSize<OLD_TO_NEW>(*tail));
|
||||
}
|
||||
|
||||
// The OLD_TO_OLD remembered set is created temporary by GC and is cleared at
|
||||
// the end of the pass. There is no way to observe it so the test only checks
|
||||
// that compaction has happened and otherwise relies on code's self-validation.
|
||||
TEST(RememberedSet_OldToOld) {
|
||||
if (FLAG_stress_incremental_marking) return;
|
||||
|
||||
CcTest::InitializeVM();
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
Factory* factory = isolate->factory();
|
||||
Heap* heap = isolate->heap();
|
||||
heap::SealCurrentObjects(heap);
|
||||
HandleScope scope(isolate);
|
||||
|
||||
Handle<FixedArray> arr = factory->NewFixedArray(10, AllocationType::kOld);
|
||||
{
|
||||
HandleScope short_lived(isolate);
|
||||
factory->NewFixedArray(100, AllocationType::kOld);
|
||||
}
|
||||
Handle<Object> ref = factory->NewFixedArray(100, AllocationType::kOld);
|
||||
arr->set(0, *ref);
|
||||
|
||||
// To force compaction of the old space, fill it with garbage and start a new
|
||||
// page (so that the page with 'arr' becomes subject to compaction).
|
||||
{
|
||||
HandleScope short_lived(isolate);
|
||||
heap::SimulateFullSpace(heap->old_space());
|
||||
factory->NewFixedArray(100, AllocationType::kOld);
|
||||
}
|
||||
|
||||
FLAG_manual_evacuation_candidates_selection = true;
|
||||
heap::ForceEvacuationCandidate(Page::FromHeapObject(*arr));
|
||||
const auto prev_location = *arr;
|
||||
|
||||
// This GC pass will evacuate the page with 'arr'/'ref' so it will have to
|
||||
// create OLD_TO_OLD remembered set to track the reference.
|
||||
CcTest::CollectAllGarbage();
|
||||
CHECK_NE(prev_location, *arr);
|
||||
}
|
||||
|
||||
TEST(RememberedSetRemoveRange) {
|
||||
CcTest::InitializeVM();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
|
@ -465,11 +465,11 @@ function print_objects_in_range(start, end){
|
||||
if (!Number.isSafeInteger(int(start)) || !Number.isSafeInteger(int(end))) {
|
||||
return;
|
||||
}
|
||||
const ptr_size = tagged_size();
|
||||
const ptr_size = pointer_size();
|
||||
if (start < ptr_size || end <= start) return;
|
||||
|
||||
let iters = (end - start) / ptr_size;
|
||||
let cur = start;
|
||||
let cur = start - ptr_size;
|
||||
print(`===============================================`);
|
||||
print(`objects in range ${hex(start)} - ${hex(end)}`);
|
||||
print(`===============================================`);
|
||||
|
Loading…
Reference in New Issue
Block a user