Revision: 22134
Author: [email protected]
Date: Tue Jul 1 18:48:02 2014 UTC
Log: Added a promotion queue unit test that test promotion queue
memory corruption
by semi-space evacuation.
BUG=
[email protected]
Review URL: https://codereview.chromium.org/362723003
http://code.google.com/p/v8/source/detail?r=22134
Modified:
/branches/bleeding_edge/src/heap.cc
/branches/bleeding_edge/src/heap.h
/branches/bleeding_edge/test/cctest/test-heap.cc
=======================================
--- /branches/bleeding_edge/src/heap.cc Tue Jul 1 15:02:31 2014 UTC
+++ /branches/bleeding_edge/src/heap.cc Tue Jul 1 18:48:02 2014 UTC
@@ -1950,6 +1950,19 @@
HeapObject* source,
HeapObject* target,
int size)) {
+ // If we migrate into to-space, then the to-space top pointer should be
+ // right after the target object. Incorporate double alignment
+ // over-allocation.
+ ASSERT(!heap->InToSpace(target) ||
+ target->address() + size == heap->new_space()->top() ||
+ target->address() + size + kPointerSize ==
heap->new_space()->top());
+
+ // Make sure that we do not overwrite the promotion queue which is at
+ // the end of to-space.
+ ASSERT(!heap->InToSpace(target) ||
+ heap->promotion_queue()->IsBelowPromotionQueue(
+ heap->new_space()->top()));
+
// Copy the content of source to target.
heap->CopyBlock(target->address(), source->address(), size);
=======================================
--- /branches/bleeding_edge/src/heap.h Tue Jul 1 15:02:31 2014 UTC
+++ /branches/bleeding_edge/src/heap.h Tue Jul 1 18:48:02 2014 UTC
@@ -426,6 +426,18 @@
RelocateQueueHead();
}
+
+ bool IsBelowPromotionQueue(Address to_space_top) {
+ // If the given to-space top pointer and the head of the promotion
queue
+ // are not on the same page, then the to-space objects are below the
+ // promotion queue.
+ if (GetHeadPage() != Page::FromAddress(to_space_top)) {
+ return true;
+ }
+ // If the to space top pointer is smaller or equal than the promotion
+ // queue head, then the to-space objects are below the promotion queue.
+ return reinterpret_cast<intptr_t*>(to_space_top) <= rear_;
+ }
bool is_empty() {
return (front_ == rear_) &&
=======================================
--- /branches/bleeding_edge/test/cctest/test-heap.cc Mon Jun 23 08:50:54
2014 UTC
+++ /branches/bleeding_edge/test/cctest/test-heap.cc Tue Jul 1 18:48:02
2014 UTC
@@ -4327,6 +4327,81 @@
CHECK(page->WasSwept() ||
Marking::IsBlack(Marking::MarkBitFrom(o->elements())));
}
+
+
+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
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.