Commit 94a2a095 authored by antonm@chromium.org's avatar antonm@chromium.org

Add a test to verify correctness of remembered set update for Heap::CopyJSObject.

Review URL: http://codereview.chromium.org/1256002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4286 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 27663efb
......@@ -2663,7 +2663,7 @@ Object* Heap::CopyJSObject(JSObject* source) {
FixedArray* elements = FixedArray::cast(source->elements());
FixedArray* properties = FixedArray::cast(source->properties());
// Update elements if necessary.
if (elements->length()> 0) {
if (elements->length() > 0) {
Object* elem = CopyFixedArray(elements);
if (elem->IsFailure()) return elem;
JSObject::cast(clone)->set_elements(FixedArray::cast(elem));
......
......@@ -938,6 +938,8 @@ class Heap : public AllStatic {
static void RecordStats(HeapStats* stats);
static int MaxObjectSizeInNewSpace() { return kMaxObjectSizeInNewSpace; }
private:
static int reserved_semispace_size_;
static int max_semispace_size_;
......
......@@ -868,3 +868,99 @@ TEST(EmptyHandleEscapeFrom) {
CHECK(runaway.is_null());
}
static int LenFromSize(int size) {
return (size - FixedArray::kHeaderSize) / kPointerSize;
}
TEST(Regression39128) {
// Test case for crbug.com/39128.
InitializeVM();
// Increase the chance of 'bump-the-pointer' allocation in old space.
bool force_compaction = true;
Heap::CollectAllGarbage(force_compaction);
v8::HandleScope scope;
// The plan: create JSObject which references objects in new space.
// Then clone this object (forcing it to go into old space) and check
// that only bits pertaining to the object are updated in remembered set.
// Step 1: prepare a map for the object. We add 1 inobject property to it.
Handle<JSFunction> object_ctor(Top::global_context()->object_function());
CHECK(object_ctor->has_initial_map());
Handle<Map> object_map(object_ctor->initial_map());
// Create a map with single inobject property.
Handle<Map> my_map = Factory::CopyMap(object_map, 1);
int n_properties = my_map->inobject_properties();
CHECK_GT(n_properties, 0);
int object_size = my_map->instance_size();
// Step 2: allocate a lot of objects so to almost fill new space: we need
// just enough room to allocate JSObject and thus fill the newspace.
int allocation_amount = Min(FixedArray::kMaxSize,
Heap::MaxObjectSizeInNewSpace());
int allocation_len = LenFromSize(allocation_amount);
NewSpace* new_space = Heap::new_space();
Address* top_addr = new_space->allocation_top_address();
Address* limit_addr = new_space->allocation_limit_address();
while ((*limit_addr - *top_addr) > allocation_amount) {
CHECK(!Heap::always_allocate());
Object* array = Heap::AllocateFixedArray(allocation_len);
CHECK(!array->IsFailure());
CHECK(new_space->Contains(array));
}
// Step 3: now allocate fixed array and JSObject to fill the whole new space.
int to_fill = *limit_addr - *top_addr - object_size;
int fixed_array_len = LenFromSize(to_fill);
CHECK(fixed_array_len < FixedArray::kMaxLength);
CHECK(!Heap::always_allocate());
Object* array = Heap::AllocateFixedArray(fixed_array_len);
CHECK(!array->IsFailure());
CHECK(new_space->Contains(array));
Object* object = Heap::AllocateJSObjectFromMap(*my_map);
CHECK(!object->IsFailure());
CHECK(new_space->Contains(object));
JSObject* jsobject = JSObject::cast(object);
CHECK_EQ(0, jsobject->elements()->length());
CHECK_EQ(0, jsobject->properties()->length());
// Create a reference to object in new space in jsobject.
jsobject->FastPropertyAtPut(-1, array);
CHECK_EQ(0L, (*limit_addr - *top_addr));
// Step 4: clone jsobject, but force always allocate first to create a clone
// in old pointer space.
Address old_pointer_space_top = Heap::old_pointer_space()->top();
AlwaysAllocateScope aa_scope;
Object* clone_obj = Heap::CopyJSObject(jsobject);
CHECK(!object->IsFailure());
JSObject* clone = JSObject::cast(clone_obj);
if (clone->address() != old_pointer_space_top) {
// Alas, got allocated from free list, we cannot do checks.
return;
}
CHECK(Heap::old_pointer_space()->Contains(clone->address()));
// Step 5: verify validity of remembered set.
Address clone_addr = clone->address();
Page* page = Page::FromAddress(clone_addr);
// Check that remembered set tracks a reference from inobject property 1.
CHECK(page->IsRSetSet(clone_addr, object_size - kPointerSize));
// Probe several addresses after the object.
for (int i = 0; i < 7; i++) {
int offset = object_size + i * kPointerSize;
if (clone_addr + offset >= page->ObjectAreaEnd()) {
break;
}
CHECK(!page->IsRSetSet(clone_addr, offset));
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment