Added a promotion queue unit test that test promotion queue memory corruption

by semi-space evacuation.

BUG=
R=titzer@chromium.org

Review URL: https://codereview.chromium.org/362723003

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22134 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
hpayer@chromium.org 2014-07-01 18:48:02 +00:00
parent e65cc42189
commit 9bc3d1a8fe
3 changed files with 100 additions and 0 deletions

View File

@ -1950,6 +1950,19 @@ class ScavengingVisitor : public StaticVisitorBase {
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);

View File

@ -427,6 +427,18 @@ class PromotionQueue {
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_) &&
(emergency_stack_ == NULL || emergency_stack_->length() == 0);

View File

@ -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();