| Index: src/mark-compact.cc
|
| ===================================================================
|
| --- src/mark-compact.cc (revision 602)
|
| +++ src/mark-compact.cc (working copy)
|
| @@ -78,8 +78,6 @@
|
|
|
| MarkLiveObjects();
|
|
|
| - if (FLAG_collect_maps) ClearNonLiveTransitions();
|
| -
|
| SweepLargeObjectSpace();
|
|
|
| if (compacting_collection_) {
|
| @@ -137,7 +135,6 @@
|
| }
|
|
|
| if (FLAG_never_compact) compacting_collection_ = false;
|
| - if (FLAG_collect_maps) CreateBackPointers();
|
|
|
| #ifdef DEBUG
|
| if (compacting_collection_) {
|
| @@ -325,13 +322,9 @@
|
|
|
| // Visit an unmarked object.
|
| void VisitUnmarkedObject(HeapObject* obj) {
|
| -#ifdef DEBUG
|
| ASSERT(Heap::Contains(obj));
|
| +#ifdef DEBUG
|
| MarkCompactCollector::UpdateLiveObjectCount(obj);
|
| - ASSERT(!obj->IsMarked());
|
| - // ASSERT(!obj->IsMap()); // Some maps are processed here.
|
| - // Their map transitions will be followed. If we do a test
|
| - // here to treat maps separately, will there be a performance impact?
|
| #endif
|
| Map* map = obj->map();
|
| obj->SetMark();
|
| @@ -432,102 +425,17 @@
|
| ASSERT(!object->IsMarked());
|
| if (object->IsJSGlobalObject()) Counters::global_objects.Increment();
|
|
|
| - tracer_->increment_marked_count();
|
| - ASSERT(Heap::Contains(object));
|
| - if (object->IsMap()) {
|
| - if (FLAG_cleanup_caches_in_maps_at_gc) {
|
| - Map::cast(object)->ClearCodeCache();
|
| - }
|
| - object->SetMark();
|
| - if (FLAG_collect_maps) {
|
| - MarkMapContents(reinterpret_cast<Map*>(object));
|
| - } else {
|
| - marking_stack.Push(object);
|
| - }
|
| - } else {
|
| - object->SetMark();
|
| - marking_stack.Push(object);
|
| + if (FLAG_cleanup_caches_in_maps_at_gc && object->IsMap()) {
|
| + Map::cast(object)->ClearCodeCache();
|
| }
|
| -}
|
|
|
| -
|
| -void MarkCompactCollector::MarkMapContents(Map* map) {
|
| - MarkDescriptorArray(reinterpret_cast<DescriptorArray*>(
|
| - HeapObject::RawField(map, Map::kInstanceDescriptorsOffset)));
|
| -
|
| - // Mark the Object* fields of the Map.
|
| - // Since the descriptor array has been marked already, it is fine
|
| - // that one of these fields contains a pointer to it.
|
| - MarkingVisitor visitor; // Has no state or contents.
|
| - visitor.VisitPointers(&HeapObject::RawField(map, Map::kPrototypeOffset),
|
| - &HeapObject::RawField(map, Map::kSize));
|
| -}
|
| -
|
| -
|
| -void MarkCompactCollector::MarkDescriptorArray(
|
| - DescriptorArray *descriptors) {
|
| - if (descriptors->IsMarked()) return;
|
| - // Empty descriptor array is marked as a root before any maps are marked.
|
| - ASSERT(descriptors != Heap::empty_descriptor_array());
|
| -
|
| + object->SetMark();
|
| tracer_->increment_marked_count();
|
| -#ifdef DEBUG
|
| - UpdateLiveObjectCount(descriptors);
|
| -#endif
|
| - descriptors->SetMark();
|
| -
|
| - FixedArray* contents = reinterpret_cast<FixedArray*>(
|
| - descriptors->get(DescriptorArray::kContentArrayIndex));
|
| - ASSERT(contents->IsHeapObject());
|
| - ASSERT(!contents->IsMarked());
|
| - ASSERT(contents->IsFixedArray());
|
| - ASSERT(contents->length() >= 2);
|
| - tracer_->increment_marked_count();
|
| -#ifdef DEBUG
|
| - UpdateLiveObjectCount(contents);
|
| -#endif
|
| - contents->SetMark();
|
| - // Contents contains (value, details) pairs. If the details say
|
| - // that the type of descriptor is MAP_TRANSITION, CONSTANT_TRANSITION,
|
| - // or NULL_DESCRIPTOR, we don't mark the value as live. Only for
|
| - // type MAP_TRANSITION is the value a Object* (a Map*).
|
| - for (int i = 0; i < contents->length(); i += 2) {
|
| - // If the pair (value, details) at index i, i+1 is not
|
| - // a transition or null descriptor, mark the value.
|
| - PropertyDetails details(Smi::cast(contents->get(i + 1)));
|
| - if (details.type() < FIRST_PHANTOM_PROPERTY_TYPE) {
|
| - HeapObject* object = reinterpret_cast<HeapObject*>(contents->get(i));
|
| - if (object->IsHeapObject() && !object->IsMarked()) {
|
| - tracer_->increment_marked_count();
|
| -#ifdef DEBUG
|
| - UpdateLiveObjectCount(object);
|
| -#endif
|
| - object->SetMark();
|
| - marking_stack.Push(object);
|
| - }
|
| - }
|
| - }
|
| - // The DescriptorArray descriptors contains a pointer to its contents array,
|
| - // but the contents array is already marked.
|
| - marking_stack.Push(descriptors);
|
| + ASSERT(Heap::Contains(object));
|
| + marking_stack.Push(object);
|
| }
|
|
|
|
|
| -void MarkCompactCollector::CreateBackPointers() {
|
| - HeapObjectIterator iterator(Heap::map_space());
|
| - while (iterator.has_next()) {
|
| - Object* next_object = iterator.next();
|
| - if (next_object->IsMap()) { // Could also be ByteArray on free list.
|
| - Map* map = Map::cast(next_object);
|
| - if (map->instance_type() >= FIRST_JS_OBJECT_TYPE &&
|
| - map->instance_type() <= LAST_JS_OBJECT_TYPE) {
|
| - map->CreateBackPointers();
|
| - }
|
| - }
|
| - }
|
| -}
|
| -
|
| -
|
| static int OverflowObjectSize(HeapObject* obj) {
|
| // Recover the normal map pointer, it might be marked as live and
|
| // overflowed.
|
| @@ -767,13 +675,6 @@
|
| }
|
|
|
|
|
| -static int CountMarkedCallback(HeapObject* obj) {
|
| - MapWord map_word = obj->map_word();
|
| - map_word.ClearMark();
|
| - return obj->SizeFromMap(map_word.ToMap());
|
| -}
|
| -
|
| -
|
| #ifdef DEBUG
|
| void MarkCompactCollector::UpdateLiveObjectCount(HeapObject* obj) {
|
| live_bytes_ += obj->Size();
|
| @@ -796,6 +697,13 @@
|
| }
|
|
|
|
|
| +static int CountMarkedCallback(HeapObject* obj) {
|
| + MapWord map_word = obj->map_word();
|
| + map_word.ClearMark();
|
| + return obj->SizeFromMap(map_word.ToMap());
|
| +}
|
| +
|
| +
|
| void MarkCompactCollector::VerifyHeapAfterMarkingPhase() {
|
| Heap::new_space()->Verify();
|
| Heap::old_pointer_space()->Verify();
|
| @@ -847,64 +755,7 @@
|
| Heap::lo_space()->FreeUnmarkedObjects();
|
| }
|
|
|
| -// Safe to use during marking phase only.
|
| -bool MarkCompactCollector::SafeIsMap(HeapObject* object) {
|
| - MapWord metamap = object->map_word();
|
| - metamap.ClearMark();
|
| - return metamap.ToMap()->instance_type() == MAP_TYPE;
|
| -}
|
|
|
| -void MarkCompactCollector::ClearNonLiveTransitions() {
|
| - HeapObjectIterator map_iterator(Heap::map_space(), &CountMarkedCallback);
|
| - // Iterate over the map space, setting map transitions that go from
|
| - // a marked map to an unmarked map to null transitions. At the same time,
|
| - // set all the prototype fields of maps back to their original value,
|
| - // dropping the back pointers temporarily stored in the prototype field.
|
| - // Setting the prototype field requires following the linked list of
|
| - // back pointers, reversing them all at once. This allows us to find
|
| - // those maps with map transitions that need to be nulled, and only
|
| - // scan the descriptor arrays of those maps, not all maps.
|
| - // All of these actions are carried out only on maps of JSObects
|
| - // and related subtypes.
|
| - while (map_iterator.has_next()) {
|
| - Map* map = reinterpret_cast<Map*>(map_iterator.next());
|
| - if (!map->IsMarked() && map->IsByteArray()) continue;
|
| -
|
| - ASSERT(SafeIsMap(map));
|
| - // Only JSObject and subtypes have map transitions and back pointers.
|
| - if (map->instance_type() < FIRST_JS_OBJECT_TYPE) continue;
|
| - if (map->instance_type() > LAST_JS_OBJECT_TYPE) continue;
|
| - // Follow the chain of back pointers to find the prototype.
|
| - Map* current = map;
|
| - while (SafeIsMap(current)) {
|
| - current = reinterpret_cast<Map*>(current->prototype());
|
| - ASSERT(current->IsHeapObject());
|
| - }
|
| - Object* real_prototype = current;
|
| -
|
| - // Follow back pointers, setting them to prototype,
|
| - // clearing map transitions when necessary.
|
| - current = map;
|
| - bool on_dead_path = !current->IsMarked();
|
| - Object *next;
|
| - while (SafeIsMap(current)) {
|
| - next = current->prototype();
|
| - // There should never be a dead map above a live map.
|
| - ASSERT(on_dead_path || current->IsMarked());
|
| -
|
| - // A live map above a dead map indicates a dead transition.
|
| - // This test will always be false on the first iteration.
|
| - if (on_dead_path && current->IsMarked()) {
|
| - on_dead_path = false;
|
| - current->ClearNonLiveTransitions(real_prototype);
|
| - }
|
| - HeapObject::RawField(current, Map::kPrototypeOffset) =
|
| - real_prototype;
|
| - current = reinterpret_cast<Map*>(next);
|
| - }
|
| - }
|
| -}
|
| -
|
| // -------------------------------------------------------------------------
|
| // Phase 2: Encode forwarding addresses.
|
| // When compacting, forwarding addresses for objects in old space and map
|
|
|