cached_map,
SKIP_WRITE_BARRIER);
}
+ new_number_of_transitions++;
}
+ }
- // Fill slots that became free with undefined value.
- 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);
- }
+ if (new_number_of_transitions != 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.
Map* current = map;
while (current->IsMap()) {
HEAP->incremental_marking()->set_should_hurry(true);
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());
+ }
+}