| Index: src/mark-compact.cc
|
| ===================================================================
|
| --- src/mark-compact.cc (revision 4369)
|
| +++ src/mark-compact.cc (working copy)
|
| @@ -53,13 +53,13 @@
|
| // Counters used for debugging the marking phase of mark-compact or mark-sweep
|
| // collection.
|
| int MarkCompactCollector::live_bytes_ = 0;
|
| -int MarkCompactCollector::live_young_objects_size_ = 0;
|
| -int MarkCompactCollector::live_old_data_objects_size_ = 0;
|
| -int MarkCompactCollector::live_old_pointer_objects_size_ = 0;
|
| -int MarkCompactCollector::live_code_objects_size_ = 0;
|
| -int MarkCompactCollector::live_map_objects_size_ = 0;
|
| -int MarkCompactCollector::live_cell_objects_size_ = 0;
|
| -int MarkCompactCollector::live_lo_objects_size_ = 0;
|
| +int MarkCompactCollector::live_young_objects_ = 0;
|
| +int MarkCompactCollector::live_old_data_objects_ = 0;
|
| +int MarkCompactCollector::live_old_pointer_objects_ = 0;
|
| +int MarkCompactCollector::live_code_objects_ = 0;
|
| +int MarkCompactCollector::live_map_objects_ = 0;
|
| +int MarkCompactCollector::live_cell_objects_ = 0;
|
| +int MarkCompactCollector::live_lo_objects_ = 0;
|
| #endif
|
|
|
| void MarkCompactCollector::CollectGarbage() {
|
| @@ -136,13 +136,13 @@
|
|
|
| #ifdef DEBUG
|
| live_bytes_ = 0;
|
| - live_young_objects_size_ = 0;
|
| - live_old_pointer_objects_size_ = 0;
|
| - live_old_data_objects_size_ = 0;
|
| - live_code_objects_size_ = 0;
|
| - live_map_objects_size_ = 0;
|
| - live_cell_objects_size_ = 0;
|
| - live_lo_objects_size_ = 0;
|
| + live_young_objects_ = 0;
|
| + live_old_pointer_objects_ = 0;
|
| + live_old_data_objects_ = 0;
|
| + live_code_objects_ = 0;
|
| + live_map_objects_ = 0;
|
| + live_cell_objects_ = 0;
|
| + live_lo_objects_ = 0;
|
| #endif
|
| }
|
|
|
| @@ -742,21 +742,21 @@
|
| void MarkCompactCollector::UpdateLiveObjectCount(HeapObject* obj) {
|
| live_bytes_ += obj->Size();
|
| if (Heap::new_space()->Contains(obj)) {
|
| - live_young_objects_size_ += obj->Size();
|
| + live_young_objects_++;
|
| } else if (Heap::map_space()->Contains(obj)) {
|
| ASSERT(obj->IsMap());
|
| - live_map_objects_size_ += obj->Size();
|
| + live_map_objects_++;
|
| } else if (Heap::cell_space()->Contains(obj)) {
|
| ASSERT(obj->IsJSGlobalPropertyCell());
|
| - live_cell_objects_size_ += obj->Size();
|
| + live_cell_objects_++;
|
| } else if (Heap::old_pointer_space()->Contains(obj)) {
|
| - live_old_pointer_objects_size_ += obj->Size();
|
| + live_old_pointer_objects_++;
|
| } else if (Heap::old_data_space()->Contains(obj)) {
|
| - live_old_data_objects_size_ += obj->Size();
|
| + live_old_data_objects_++;
|
| } else if (Heap::code_space()->Contains(obj)) {
|
| - live_code_objects_size_ += obj->Size();
|
| + live_code_objects_++;
|
| } else if (Heap::lo_space()->Contains(obj)) {
|
| - live_lo_objects_size_ += obj->Size();
|
| + live_lo_objects_++;
|
| } else {
|
| UNREACHABLE();
|
| }
|
| @@ -1068,210 +1068,31 @@
|
| }
|
|
|
|
|
| -// We scavange new space simultaneously with sweeping. This is done in two
|
| -// passes.
|
| -// The first pass migrates all alive objects from one semispace to another or
|
| -// promotes them to old space. Forwading address is written directly into
|
| -// first word of object without any encoding. If object is dead we are writing
|
| -// NULL as a forwarding address.
|
| -// The second pass updates pointers to new space in all spaces. It is possible
|
| -// to encounter pointers to dead objects during traversal of remembered set for
|
| -// map space because remembered set bits corresponding to dead maps are cleared
|
| -// later during map space sweeping.
|
| -static void MigrateObject(Address dst, Address src, int size) {
|
| - Heap::CopyBlock(reinterpret_cast<Object**>(dst),
|
| - reinterpret_cast<Object**>(src),
|
| - size);
|
| -
|
| - Memory::Address_at(src) = dst;
|
| -}
|
| -
|
| -
|
| -// Visitor for updating pointers from live objects in old spaces to new space.
|
| -// It does not expect to encounter pointers to dead objects.
|
| -class PointersToNewGenUpdatingVisitor: public ObjectVisitor {
|
| - public:
|
| - void VisitPointer(Object** p) {
|
| - UpdatePointer(p);
|
| - }
|
| -
|
| - void VisitPointers(Object** start, Object** end) {
|
| - for (Object** p = start; p < end; p++) UpdatePointer(p);
|
| - }
|
| -
|
| - void VisitCodeTarget(RelocInfo* rinfo) {
|
| - ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
|
| - Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
|
| - VisitPointer(&target);
|
| - rinfo->set_target_address(Code::cast(target)->instruction_start());
|
| - }
|
| -
|
| - void VisitDebugTarget(RelocInfo* rinfo) {
|
| - ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()) &&
|
| - rinfo->IsPatchedReturnSequence());
|
| - Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
|
| - VisitPointer(&target);
|
| - rinfo->set_call_address(Code::cast(target)->instruction_start());
|
| - }
|
| -
|
| - private:
|
| - void UpdatePointer(Object** p) {
|
| - if (!(*p)->IsHeapObject()) return;
|
| -
|
| - HeapObject* obj = HeapObject::cast(*p);
|
| - Address old_addr = obj->address();
|
| -
|
| - if (Heap::new_space()->Contains(obj)) {
|
| - ASSERT(Heap::InFromSpace(*p));
|
| - *p = HeapObject::FromAddress(Memory::Address_at(old_addr));
|
| - }
|
| - }
|
| -};
|
| -
|
| -// Visitor for updating pointers from live objects in old spaces to new space.
|
| -// It can encounter pointers to dead objects in new space when traversing map
|
| -// space (see comment for MigrateObject).
|
| -static void UpdatePointerToNewGen(HeapObject** p) {
|
| - if (!(*p)->IsHeapObject()) return;
|
| -
|
| - Address old_addr = (*p)->address();
|
| - ASSERT(Heap::InFromSpace(*p));
|
| -
|
| - Address new_addr = Memory::Address_at(old_addr);
|
| -
|
| - // Object pointed by *p is dead. Update is not required.
|
| - if (new_addr == NULL) return;
|
| -
|
| - *p = HeapObject::FromAddress(new_addr);
|
| -}
|
| -
|
| -
|
| -static String* UpdateNewSpaceReferenceInExternalStringTableEntry(Object **p) {
|
| - Address old_addr = HeapObject::cast(*p)->address();
|
| - Address new_addr = Memory::Address_at(old_addr);
|
| - return String::cast(HeapObject::FromAddress(new_addr));
|
| -}
|
| -
|
| -
|
| -static bool TryPromoteObject(HeapObject* object, int object_size) {
|
| - Object* result;
|
| -
|
| - if (object_size > Heap::MaxObjectSizeInPagedSpace()) {
|
| - result = Heap::lo_space()->AllocateRawFixedArray(object_size);
|
| - if (!result->IsFailure()) {
|
| - HeapObject* target = HeapObject::cast(result);
|
| - MigrateObject(target->address(), object->address(), object_size);
|
| - Heap::UpdateRSet(target);
|
| - return true;
|
| - }
|
| - } else {
|
| - OldSpace* target_space = Heap::TargetSpace(object);
|
| -
|
| - ASSERT(target_space == Heap::old_pointer_space() ||
|
| - target_space == Heap::old_data_space());
|
| - result = target_space->AllocateRaw(object_size);
|
| - if (!result->IsFailure()) {
|
| - HeapObject* target = HeapObject::cast(result);
|
| - MigrateObject(target->address(), object->address(), object_size);
|
| - if (target_space == Heap::old_pointer_space()) {
|
| - Heap::UpdateRSet(target);
|
| - }
|
| - return true;
|
| - }
|
| - }
|
| -
|
| - return false;
|
| -}
|
| -
|
| -
|
| -static void SweepNewSpace(NewSpace* space) {
|
| - Heap::CheckNewSpaceExpansionCriteria();
|
| -
|
| - Address from_bottom = space->bottom();
|
| - Address from_top = space->top();
|
| -
|
| - // Flip the semispaces. After flipping, to space is empty, from space has
|
| - // live objects.
|
| - space->Flip();
|
| - space->ResetAllocationInfo();
|
| -
|
| - int size = 0;
|
| - int survivors_size = 0;
|
| -
|
| - // First pass: traverse all objects in inactive semispace, remove marks,
|
| - // migrate live objects and write forwarding addresses.
|
| - for (Address current = from_bottom; current < from_top; current += size) {
|
| - HeapObject* object = HeapObject::FromAddress(current);
|
| -
|
| - if (object->IsMarked()) {
|
| - object->ClearMark();
|
| - MarkCompactCollector::tracer()->decrement_marked_count();
|
| -
|
| - size = object->Size();
|
| - survivors_size += size;
|
| -
|
| - if (Heap::ShouldBePromoted(current, size) &&
|
| - TryPromoteObject(object, size)) {
|
| - continue;
|
| - }
|
| -
|
| - // Promotion either failed or not required.
|
| - // Copy the content of the object.
|
| - Object* target = space->AllocateRaw(size);
|
| -
|
| - // Allocation cannot fail at this point: semispaces are of equal size.
|
| - ASSERT(!target->IsFailure());
|
| -
|
| - MigrateObject(HeapObject::cast(target)->address(), current, size);
|
| - } else {
|
| - size = object->Size();
|
| - Memory::Address_at(current) = NULL;
|
| - }
|
| - }
|
| -
|
| - // Second pass: find pointers to new space and update them.
|
| - PointersToNewGenUpdatingVisitor updating_visitor;
|
| -
|
| - // Update pointers in to space.
|
| +static void SweepSpace(NewSpace* space) {
|
| HeapObject* object;
|
| for (Address current = space->bottom();
|
| current < space->top();
|
| current += object->Size()) {
|
| object = HeapObject::FromAddress(current);
|
| -
|
| - object->IterateBody(object->map()->instance_type(),
|
| - object->Size(),
|
| - &updating_visitor);
|
| - }
|
| -
|
| - // Update roots.
|
| - Heap::IterateRoots(&updating_visitor, VISIT_ALL_IN_SCAVENGE);
|
| -
|
| - // Update pointers in old spaces.
|
| - Heap::IterateRSet(Heap::old_pointer_space(), &UpdatePointerToNewGen);
|
| - Heap::IterateRSet(Heap::map_space(), &UpdatePointerToNewGen);
|
| - Heap::lo_space()->IterateRSet(&UpdatePointerToNewGen);
|
| -
|
| - // Update pointers from cells.
|
| - HeapObjectIterator cell_iterator(Heap::cell_space());
|
| - for (HeapObject* cell = cell_iterator.next();
|
| - cell != NULL;
|
| - cell = cell_iterator.next()) {
|
| - if (cell->IsJSGlobalPropertyCell()) {
|
| - Address value_address =
|
| - reinterpret_cast<Address>(cell) +
|
| - (JSGlobalPropertyCell::kValueOffset - kHeapObjectTag);
|
| - updating_visitor.VisitPointer(reinterpret_cast<Object**>(value_address));
|
| + if (object->IsMarked()) {
|
| + object->ClearMark();
|
| + MarkCompactCollector::tracer()->decrement_marked_count();
|
| + } else {
|
| + // We give non-live objects a map that will correctly give their size,
|
| + // since their existing map might not be live after the collection.
|
| + int size = object->Size();
|
| + if (size >= ByteArray::kHeaderSize) {
|
| + object->set_map(Heap::raw_unchecked_byte_array_map());
|
| + ByteArray::cast(object)->set_length(ByteArray::LengthFor(size));
|
| + } else {
|
| + ASSERT(size == kPointerSize);
|
| + object->set_map(Heap::raw_unchecked_one_pointer_filler_map());
|
| + }
|
| + ASSERT(object->Size() == size);
|
| }
|
| + // The object is now unmarked for the call to Size() at the top of the
|
| + // loop.
|
| }
|
| -
|
| - // Update pointers from external string table.
|
| - Heap::UpdateNewSpaceReferencesInExternalStringTable(
|
| - &UpdateNewSpaceReferenceInExternalStringTableEntry);
|
| -
|
| - // All pointers were updated. Update auxiliary allocation info.
|
| - Heap::IncrementYoungSurvivorsCounter(survivors_size);
|
| - space->set_age_mark(space->top());
|
| }
|
|
|
|
|
| @@ -1561,12 +1382,10 @@
|
| ASSERT(FreeListNode::IsFreeListNode(vacant_map));
|
| ASSERT(map_to_evacuate->IsMap());
|
|
|
| - ASSERT(Map::kSize % 4 == 0);
|
| -
|
| - Heap::CopyBlock(reinterpret_cast<Object**>(vacant_map->address()),
|
| - reinterpret_cast<Object**>(map_to_evacuate->address()),
|
| - Map::kSize);
|
| -
|
| + memcpy(
|
| + reinterpret_cast<void*>(vacant_map->address()),
|
| + reinterpret_cast<void*>(map_to_evacuate->address()),
|
| + Map::kSize);
|
| ASSERT(vacant_map->IsMap()); // Due to memcpy above.
|
|
|
| MapWord forwarding_map_word = MapWord::FromMap(vacant_map);
|
| @@ -1646,11 +1465,10 @@
|
| SweepSpace(Heap::old_data_space(), &DeallocateOldDataBlock);
|
| SweepSpace(Heap::code_space(), &DeallocateCodeBlock);
|
| SweepSpace(Heap::cell_space(), &DeallocateCellBlock);
|
| - SweepNewSpace(Heap::new_space());
|
| + SweepSpace(Heap::new_space());
|
| SweepSpace(Heap::map_space(), &DeallocateMapBlock);
|
| - int live_maps_size = Heap::map_space()->Size();
|
| - int live_maps = live_maps_size / Map::kSize;
|
| - ASSERT(live_map_objects_size_ == live_maps_size);
|
| + int live_maps = Heap::map_space()->Size() / Map::kSize;
|
| + ASSERT(live_map_objects_ == live_maps);
|
|
|
| if (Heap::map_space()->NeedsCompaction(live_maps)) {
|
| MapCompact map_compact(live_maps);
|
| @@ -1682,7 +1500,7 @@
|
| Address start,
|
| Address end,
|
| HeapObjectCallback size_func) {
|
| - int live_objects_size = 0;
|
| + int live_objects = 0;
|
| Address current = start;
|
| while (current < end) {
|
| uint32_t encoded_map = Memory::uint32_at(current);
|
| @@ -1691,12 +1509,11 @@
|
| } else if (encoded_map == kMultiFreeEncoding) {
|
| current += Memory::int_at(current + kIntSize);
|
| } else {
|
| - int size = size_func(HeapObject::FromAddress(current));
|
| - current += size;
|
| - live_objects_size += size;
|
| + live_objects++;
|
| + current += size_func(HeapObject::FromAddress(current));
|
| }
|
| }
|
| - return live_objects_size;
|
| + return live_objects;
|
| }
|
|
|
|
|
| @@ -1822,36 +1639,36 @@
|
| Heap::IterateRoots(&updating_visitor, VISIT_ONLY_STRONG);
|
| GlobalHandles::IterateWeakRoots(&updating_visitor);
|
|
|
| - int live_maps_size = IterateLiveObjects(Heap::map_space(),
|
| + int live_maps = IterateLiveObjects(Heap::map_space(),
|
| + &UpdatePointersInOldObject);
|
| + int live_pointer_olds = IterateLiveObjects(Heap::old_pointer_space(),
|
| + &UpdatePointersInOldObject);
|
| + int live_data_olds = IterateLiveObjects(Heap::old_data_space(),
|
| &UpdatePointersInOldObject);
|
| - int live_pointer_olds_size = IterateLiveObjects(Heap::old_pointer_space(),
|
| - &UpdatePointersInOldObject);
|
| - int live_data_olds_size = IterateLiveObjects(Heap::old_data_space(),
|
| - &UpdatePointersInOldObject);
|
| - int live_codes_size = IterateLiveObjects(Heap::code_space(),
|
| - &UpdatePointersInOldObject);
|
| - int live_cells_size = IterateLiveObjects(Heap::cell_space(),
|
| - &UpdatePointersInOldObject);
|
| - int live_news_size = IterateLiveObjects(Heap::new_space(),
|
| - &UpdatePointersInNewObject);
|
| + int live_codes = IterateLiveObjects(Heap::code_space(),
|
| + &UpdatePointersInOldObject);
|
| + int live_cells = IterateLiveObjects(Heap::cell_space(),
|
| + &UpdatePointersInOldObject);
|
| + int live_news = IterateLiveObjects(Heap::new_space(),
|
| + &UpdatePointersInNewObject);
|
|
|
| // Large objects do not move, the map word can be updated directly.
|
| LargeObjectIterator it(Heap::lo_space());
|
| for (HeapObject* obj = it.next(); obj != NULL; obj = it.next())
|
| UpdatePointersInNewObject(obj);
|
|
|
| - USE(live_maps_size);
|
| - USE(live_pointer_olds_size);
|
| - USE(live_data_olds_size);
|
| - USE(live_codes_size);
|
| - USE(live_cells_size);
|
| - USE(live_news_size);
|
| - ASSERT(live_maps_size == live_map_objects_size_);
|
| - ASSERT(live_data_olds_size == live_old_data_objects_size_);
|
| - ASSERT(live_pointer_olds_size == live_old_pointer_objects_size_);
|
| - ASSERT(live_codes_size == live_code_objects_size_);
|
| - ASSERT(live_cells_size == live_cell_objects_size_);
|
| - ASSERT(live_news_size == live_young_objects_size_);
|
| + USE(live_maps);
|
| + USE(live_pointer_olds);
|
| + USE(live_data_olds);
|
| + USE(live_codes);
|
| + USE(live_cells);
|
| + USE(live_news);
|
| + ASSERT(live_maps == live_map_objects_);
|
| + ASSERT(live_data_olds == live_old_data_objects_);
|
| + ASSERT(live_pointer_olds == live_old_pointer_objects_);
|
| + ASSERT(live_codes == live_code_objects_);
|
| + ASSERT(live_cells == live_cell_objects_);
|
| + ASSERT(live_news == live_young_objects_);
|
| }
|
|
|
|
|
| @@ -1966,31 +1783,27 @@
|
| #endif
|
| // Relocates objects, always relocate map objects first. Relocating
|
| // objects in other space relies on map objects to get object size.
|
| - int live_maps_size = IterateLiveObjects(Heap::map_space(),
|
| - &RelocateMapObject);
|
| - int live_pointer_olds_size = IterateLiveObjects(Heap::old_pointer_space(),
|
| - &RelocateOldPointerObject);
|
| - int live_data_olds_size = IterateLiveObjects(Heap::old_data_space(),
|
| - &RelocateOldDataObject);
|
| - int live_codes_size = IterateLiveObjects(Heap::code_space(),
|
| - &RelocateCodeObject);
|
| - int live_cells_size = IterateLiveObjects(Heap::cell_space(),
|
| - &RelocateCellObject);
|
| - int live_news_size = IterateLiveObjects(Heap::new_space(),
|
| - &RelocateNewObject);
|
| + int live_maps = IterateLiveObjects(Heap::map_space(), &RelocateMapObject);
|
| + int live_pointer_olds = IterateLiveObjects(Heap::old_pointer_space(),
|
| + &RelocateOldPointerObject);
|
| + int live_data_olds = IterateLiveObjects(Heap::old_data_space(),
|
| + &RelocateOldDataObject);
|
| + int live_codes = IterateLiveObjects(Heap::code_space(), &RelocateCodeObject);
|
| + int live_cells = IterateLiveObjects(Heap::cell_space(), &RelocateCellObject);
|
| + int live_news = IterateLiveObjects(Heap::new_space(), &RelocateNewObject);
|
|
|
| - USE(live_maps_size);
|
| - USE(live_pointer_olds_size);
|
| - USE(live_data_olds_size);
|
| - USE(live_codes_size);
|
| - USE(live_cells_size);
|
| - USE(live_news_size);
|
| - ASSERT(live_maps_size == live_map_objects_size_);
|
| - ASSERT(live_data_olds_size == live_old_data_objects_size_);
|
| - ASSERT(live_pointer_olds_size == live_old_pointer_objects_size_);
|
| - ASSERT(live_codes_size == live_code_objects_size_);
|
| - ASSERT(live_cells_size == live_cell_objects_size_);
|
| - ASSERT(live_news_size == live_young_objects_size_);
|
| + USE(live_maps);
|
| + USE(live_data_olds);
|
| + USE(live_pointer_olds);
|
| + USE(live_codes);
|
| + USE(live_cells);
|
| + USE(live_news);
|
| + ASSERT(live_maps == live_map_objects_);
|
| + ASSERT(live_data_olds == live_old_data_objects_);
|
| + ASSERT(live_pointer_olds == live_old_pointer_objects_);
|
| + ASSERT(live_codes == live_code_objects_);
|
| + ASSERT(live_cells == live_cell_objects_);
|
| + ASSERT(live_news == live_young_objects_);
|
|
|
| // Flip from and to spaces
|
| Heap::new_space()->Flip();
|
| @@ -2008,9 +1821,6 @@
|
| PagedSpaces spaces;
|
| for (PagedSpace* space = spaces.next(); space != NULL; space = spaces.next())
|
| space->MCCommitRelocationInfo();
|
| -
|
| - Heap::CheckNewSpaceExpansionCriteria();
|
| - Heap::IncrementYoungSurvivorsCounter(live_news_size);
|
| }
|
|
|
|
|
| @@ -2030,10 +1840,7 @@
|
| Address old_addr = obj->address();
|
|
|
| if (new_addr != old_addr) {
|
| - // Move contents.
|
| - Heap::MoveBlock(reinterpret_cast<Object**>(new_addr),
|
| - reinterpret_cast<Object**>(old_addr),
|
| - Map::kSize);
|
| + memmove(new_addr, old_addr, Map::kSize); // copy contents
|
| }
|
|
|
| #ifdef DEBUG
|
| @@ -2089,10 +1896,7 @@
|
| Address old_addr = obj->address();
|
|
|
| if (new_addr != old_addr) {
|
| - // Move contents.
|
| - Heap::MoveBlock(reinterpret_cast<Object**>(new_addr),
|
| - reinterpret_cast<Object**>(old_addr),
|
| - obj_size);
|
| + memmove(new_addr, old_addr, obj_size); // Copy contents
|
| }
|
|
|
| ASSERT(!HeapObject::FromAddress(new_addr)->IsCode());
|
| @@ -2136,10 +1940,7 @@
|
| Address old_addr = obj->address();
|
|
|
| if (new_addr != old_addr) {
|
| - // Move contents.
|
| - Heap::MoveBlock(reinterpret_cast<Object**>(new_addr),
|
| - reinterpret_cast<Object**>(old_addr),
|
| - obj_size);
|
| + memmove(new_addr, old_addr, obj_size); // Copy contents.
|
| }
|
|
|
| HeapObject* copied_to = HeapObject::FromAddress(new_addr);
|
| @@ -2175,9 +1976,9 @@
|
| #endif
|
|
|
| // New and old addresses cannot overlap.
|
| - Heap::CopyBlock(reinterpret_cast<Object**>(new_addr),
|
| - reinterpret_cast<Object**>(old_addr),
|
| - obj_size);
|
| + memcpy(reinterpret_cast<void*>(new_addr),
|
| + reinterpret_cast<void*>(old_addr),
|
| + obj_size);
|
|
|
| #ifdef DEBUG
|
| if (FLAG_gc_verbose) {
|
|
|