Fix prototype transition clearing during full GC.

R=vegorov@chromium.org

Review URL: https://chromiumcodereview.appspot.com/9195008

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10439 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 504ef4f2
...@@ -2316,28 +2316,21 @@ void MarkCompactCollector::ClearNonLiveTransitions() { ...@@ -2316,28 +2316,21 @@ void MarkCompactCollector::ClearNonLiveTransitions() {
cached_map, cached_map,
SKIP_WRITE_BARRIER); SKIP_WRITE_BARRIER);
} }
new_number_of_transitions++;
} }
}
// Fill slots that became free with undefined value. if (new_number_of_transitions != number_of_transitions) {
Object* undefined = heap()->undefined_value();
for (int i = new_number_of_transitions * step;
i < number_of_transitions * step;
i++) {
// The undefined object is on a page that is never compacted and never
// in new space so it is OK to skip the write barrier. Also it's a
// root.
prototype_transitions->set_unchecked(heap_,
header + i,
undefined,
SKIP_WRITE_BARRIER);
Object** undefined_slot =
prototype_transitions->data_start() + i;
RecordSlot(undefined_slot, undefined_slot, undefined);
}
map->SetNumberOfProtoTransitions(new_number_of_transitions); map->SetNumberOfProtoTransitions(new_number_of_transitions);
} }
// Fill slots that became free with undefined value.
for (int i = new_number_of_transitions * step;
i < number_of_transitions * step;
i++) {
prototype_transitions->set_undefined(heap_, header + i);
}
// Follow the chain of back pointers to find the prototype. // Follow the chain of back pointers to find the prototype.
Map* current = map; Map* current = map;
while (current->IsMap()) { while (current->IsMap()) {
......
...@@ -1572,3 +1572,38 @@ TEST(InstanceOfStubWriteBarrier) { ...@@ -1572,3 +1572,38 @@ TEST(InstanceOfStubWriteBarrier) {
HEAP->incremental_marking()->set_should_hurry(true); HEAP->incremental_marking()->set_should_hurry(true);
HEAP->CollectGarbage(OLD_POINTER_SPACE); HEAP->CollectGarbage(OLD_POINTER_SPACE);
} }
TEST(PrototypeTransitionClearing) {
InitializeVM();
v8::HandleScope scope;
CompileRun(
"var base = {};"
"var live = [];"
"for (var i = 0; i < 10; i++) {"
" var object = {};"
" var prototype = {};"
" object.__proto__ = prototype;"
" if (i >= 3) live.push(object, prototype);"
"}");
Handle<JSObject> baseObject =
v8::Utils::OpenHandle(
*v8::Handle<v8::Object>::Cast(
v8::Context::GetCurrent()->Global()->Get(v8_str("base"))));
// Verify that only dead prototype transitions are cleared.
CHECK_EQ(10, baseObject->map()->NumberOfProtoTransitions());
HEAP->CollectAllGarbage(Heap::kNoGCFlags);
CHECK_EQ(10 - 3, baseObject->map()->NumberOfProtoTransitions());
// Verify that prototype transitions array was compacted.
FixedArray* trans = baseObject->map()->prototype_transitions();
for (int i = 0; i < 10 - 3; i++) {
int j = Map::kProtoTransitionHeaderSize +
i * Map::kProtoTransitionElementsPerEntry;
CHECK(trans->get(j + Map::kProtoTransitionMapOffset)->IsMap());
CHECK(trans->get(j + Map::kProtoTransitionPrototypeOffset)->IsJSObject());
}
}
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