| Index: test/cctest/test-heap.cc
|
| diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc
|
| index f0682b297c2ac4eb4c5910cb62f8fea8d865c7a4..5d61524d23655b762c78d83ab750cd84ad7fb24a 100644
|
| --- a/test/cctest/test-heap.cc
|
| +++ b/test/cctest/test-heap.cc
|
| @@ -4329,6 +4329,81 @@ TEST(ArrayShiftSweeping) {
|
| }
|
|
|
|
|
| +TEST(PromotionQueue) {
|
| + i::FLAG_expose_gc = true;
|
| + i::FLAG_max_semi_space_size = 2;
|
| + CcTest::InitializeVM();
|
| + v8::HandleScope scope(CcTest::isolate());
|
| + Isolate* isolate = CcTest::i_isolate();
|
| + Heap* heap = isolate->heap();
|
| + NewSpace* new_space = heap->new_space();
|
| +
|
| + // In this test we will try to overwrite the promotion queue which is at the
|
| + // end of to-space. To actually make that possible, we need at least two
|
| + // semi-space pages and take advantage of fragementation.
|
| + // (1) Grow semi-space to two pages.
|
| + // (2) Create a few small long living objects and call the scavenger to
|
| + // move them to the other semi-space.
|
| + // (3) Create a huge object, i.e., remainder of first semi-space page and
|
| + // create another huge object which should be of maximum allocatable memory
|
| + // size of the second semi-space page.
|
| + // (4) Call the scavenger again.
|
| + // What will happen is: the scavenger will promote the objects created in (2)
|
| + // and will create promotion queue entries at the end of the second
|
| + // semi-space page during the next scavenge when it promotes the objects to
|
| + // the old generation. The first allocation of (3) will fill up the first
|
| + // semi-space page. The second allocation in (3) will not fit into the first
|
| + // semi-space page, but it will overwrite the promotion queue which are in
|
| + // the second semi-space page. If the right guards are in place, the promotion
|
| + // queue will be evacuated in that case.
|
| +
|
| + // Grow the semi-space to two pages to make semi-space copy overwrite the
|
| + // promotion queue, which will be at the end of the second page.
|
| + intptr_t old_capacity = new_space->Capacity();
|
| + new_space->Grow();
|
| + CHECK(new_space->IsAtMaximumCapacity());
|
| + CHECK(2 * old_capacity == new_space->Capacity());
|
| +
|
| + // Call the scavenger two times to get an empty new space
|
| + heap->CollectGarbage(NEW_SPACE);
|
| + heap->CollectGarbage(NEW_SPACE);
|
| +
|
| + // First create a few objects which will survive a scavenge, and will get
|
| + // promoted to the old generation later on. These objects will create
|
| + // promotion queue entries at the end of the second semi-space page.
|
| + const int number_handles = 12;
|
| + Handle<FixedArray> handles[number_handles];
|
| + for (int i = 0; i < number_handles; i++) {
|
| + handles[i] = isolate->factory()->NewFixedArray(1, NOT_TENURED);
|
| + }
|
| + heap->CollectGarbage(NEW_SPACE);
|
| +
|
| + // Create the first huge object which will exactly fit the first semi-space
|
| + // page.
|
| + int new_linear_size = static_cast<int>(
|
| + *heap->new_space()->allocation_limit_address() -
|
| + *heap->new_space()->allocation_top_address());
|
| + int length = new_linear_size / kPointerSize - FixedArray::kHeaderSize;
|
| + Handle<FixedArray> first =
|
| + isolate->factory()->NewFixedArray(length, NOT_TENURED);
|
| + CHECK(heap->InNewSpace(*first));
|
| +
|
| + // Create the second huge object of maximum allocatable second semi-space
|
| + // page size.
|
| + new_linear_size = static_cast<int>(
|
| + *heap->new_space()->allocation_limit_address() -
|
| + *heap->new_space()->allocation_top_address());
|
| + length = Page::kMaxRegularHeapObjectSize / kPointerSize -
|
| + FixedArray::kHeaderSize;
|
| + Handle<FixedArray> second =
|
| + isolate->factory()->NewFixedArray(length, NOT_TENURED);
|
| + CHECK(heap->InNewSpace(*second));
|
| +
|
| + // This scavenge will corrupt memory if the promotion queue is not evacuated.
|
| + heap->CollectGarbage(NEW_SPACE);
|
| +}
|
| +
|
| +
|
| #ifdef DEBUG
|
| TEST(PathTracer) {
|
| CcTest::InitializeVM();
|
|
|