| Index: src/mark-compact.cc
|
| ===================================================================
|
| --- src/mark-compact.cc (revision 4248)
|
| +++ 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_ = 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;
|
| +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;
|
| #endif
|
|
|
| void MarkCompactCollector::CollectGarbage() {
|
| @@ -136,13 +136,13 @@
|
|
|
| #ifdef DEBUG
|
| live_bytes_ = 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;
|
| + 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;
|
| #endif
|
| }
|
|
|
| @@ -742,21 +742,21 @@
|
| void MarkCompactCollector::UpdateLiveObjectCount(HeapObject* obj) {
|
| live_bytes_ += obj->Size();
|
| if (Heap::new_space()->Contains(obj)) {
|
| - live_young_objects_++;
|
| + live_young_objects_size_ += obj->Size();
|
| } else if (Heap::map_space()->Contains(obj)) {
|
| ASSERT(obj->IsMap());
|
| - live_map_objects_++;
|
| + live_map_objects_size_ += obj->Size();
|
| } else if (Heap::cell_space()->Contains(obj)) {
|
| ASSERT(obj->IsJSGlobalPropertyCell());
|
| - live_cell_objects_++;
|
| + live_cell_objects_size_ += obj->Size();
|
| } else if (Heap::old_pointer_space()->Contains(obj)) {
|
| - live_old_pointer_objects_++;
|
| + live_old_pointer_objects_size_ += obj->Size();
|
| } else if (Heap::old_data_space()->Contains(obj)) {
|
| - live_old_data_objects_++;
|
| + live_old_data_objects_size_ += obj->Size();
|
| } else if (Heap::code_space()->Contains(obj)) {
|
| - live_code_objects_++;
|
| + live_code_objects_size_ += obj->Size();
|
| } else if (Heap::lo_space()->Contains(obj)) {
|
| - live_lo_objects_++;
|
| + live_lo_objects_size_ += obj->Size();
|
| } else {
|
| UNREACHABLE();
|
| }
|
| @@ -1068,31 +1068,210 @@
|
| }
|
|
|
|
|
| -static void SweepSpace(NewSpace* space) {
|
| +// 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.
|
| HeapObject* object;
|
| for (Address current = space->bottom();
|
| current < space->top();
|
| current += object->Size()) {
|
| object = HeapObject::FromAddress(current);
|
| - 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);
|
| +
|
| + 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));
|
| }
|
| - // 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());
|
| }
|
|
|
|
|
| @@ -1382,10 +1561,12 @@
|
| ASSERT(FreeListNode::IsFreeListNode(vacant_map));
|
| ASSERT(map_to_evacuate->IsMap());
|
|
|
| - memcpy(
|
| - reinterpret_cast<void*>(vacant_map->address()),
|
| - reinterpret_cast<void*>(map_to_evacuate->address()),
|
| - Map::kSize);
|
| + ASSERT(Map::kSize % 4 == 0);
|
| +
|
| + Heap::CopyBlock(reinterpret_cast<Object**>(vacant_map->address()),
|
| + reinterpret_cast<Object**>(map_to_evacuate->address()),
|
| + Map::kSize);
|
| +
|
| ASSERT(vacant_map->IsMap()); // Due to memcpy above.
|
|
|
| MapWord forwarding_map_word = MapWord::FromMap(vacant_map);
|
| @@ -1465,10 +1646,11 @@
|
| SweepSpace(Heap::old_data_space(), &DeallocateOldDataBlock);
|
| SweepSpace(Heap::code_space(), &DeallocateCodeBlock);
|
| SweepSpace(Heap::cell_space(), &DeallocateCellBlock);
|
| - SweepSpace(Heap::new_space());
|
| + SweepNewSpace(Heap::new_space());
|
| SweepSpace(Heap::map_space(), &DeallocateMapBlock);
|
| - int live_maps = Heap::map_space()->Size() / Map::kSize;
|
| - ASSERT(live_map_objects_ == live_maps);
|
| + int live_maps_size = Heap::map_space()->Size();
|
| + int live_maps = live_maps_size / Map::kSize;
|
| + ASSERT(live_map_objects_size_ == live_maps_size);
|
|
|
| if (Heap::map_space()->NeedsCompaction(live_maps)) {
|
| MapCompact map_compact(live_maps);
|
| @@ -1500,7 +1682,7 @@
|
| Address start,
|
| Address end,
|
| HeapObjectCallback size_func) {
|
| - int live_objects = 0;
|
| + int live_objects_size = 0;
|
| Address current = start;
|
| while (current < end) {
|
| uint32_t encoded_map = Memory::uint32_at(current);
|
| @@ -1509,11 +1691,12 @@
|
| } else if (encoded_map == kMultiFreeEncoding) {
|
| current += Memory::int_at(current + kIntSize);
|
| } else {
|
| - live_objects++;
|
| - current += size_func(HeapObject::FromAddress(current));
|
| + int size = size_func(HeapObject::FromAddress(current));
|
| + current += size;
|
| + live_objects_size += size;
|
| }
|
| }
|
| - return live_objects;
|
| + return live_objects_size;
|
| }
|
|
|
|
|
| @@ -1639,36 +1822,36 @@
|
| Heap::IterateRoots(&updating_visitor, VISIT_ONLY_STRONG);
|
| GlobalHandles::IterateWeakRoots(&updating_visitor);
|
|
|
| - 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(),
|
| + int live_maps_size = IterateLiveObjects(Heap::map_space(),
|
| &UpdatePointersInOldObject);
|
| - int live_codes = IterateLiveObjects(Heap::code_space(),
|
| - &UpdatePointersInOldObject);
|
| - int live_cells = IterateLiveObjects(Heap::cell_space(),
|
| - &UpdatePointersInOldObject);
|
| - int live_news = IterateLiveObjects(Heap::new_space(),
|
| - &UpdatePointersInNewObject);
|
| + 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);
|
|
|
| // 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);
|
| - 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_);
|
| + 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_);
|
| }
|
|
|
|
|
| @@ -1783,27 +1966,31 @@
|
| #endif
|
| // Relocates objects, always relocate map objects first. Relocating
|
| // objects in other space relies on map objects to get object size.
|
| - 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);
|
| + 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);
|
|
|
| - 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_);
|
| + 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_);
|
|
|
| // Flip from and to spaces
|
| Heap::new_space()->Flip();
|
| @@ -1821,6 +2008,9 @@
|
| PagedSpaces spaces;
|
| for (PagedSpace* space = spaces.next(); space != NULL; space = spaces.next())
|
| space->MCCommitRelocationInfo();
|
| +
|
| + Heap::CheckNewSpaceExpansionCriteria();
|
| + Heap::IncrementYoungSurvivorsCounter(live_news_size);
|
| }
|
|
|
|
|
| @@ -1840,7 +2030,10 @@
|
| Address old_addr = obj->address();
|
|
|
| if (new_addr != old_addr) {
|
| - memmove(new_addr, old_addr, Map::kSize); // copy contents
|
| + // Move contents.
|
| + Heap::MoveBlock(reinterpret_cast<Object**>(new_addr),
|
| + reinterpret_cast<Object**>(old_addr),
|
| + Map::kSize);
|
| }
|
|
|
| #ifdef DEBUG
|
| @@ -1896,7 +2089,10 @@
|
| Address old_addr = obj->address();
|
|
|
| if (new_addr != old_addr) {
|
| - memmove(new_addr, old_addr, obj_size); // Copy contents
|
| + // Move contents.
|
| + Heap::MoveBlock(reinterpret_cast<Object**>(new_addr),
|
| + reinterpret_cast<Object**>(old_addr),
|
| + obj_size);
|
| }
|
|
|
| ASSERT(!HeapObject::FromAddress(new_addr)->IsCode());
|
| @@ -1940,7 +2136,10 @@
|
| Address old_addr = obj->address();
|
|
|
| if (new_addr != old_addr) {
|
| - memmove(new_addr, old_addr, obj_size); // Copy contents.
|
| + // Move contents.
|
| + Heap::MoveBlock(reinterpret_cast<Object**>(new_addr),
|
| + reinterpret_cast<Object**>(old_addr),
|
| + obj_size);
|
| }
|
|
|
| HeapObject* copied_to = HeapObject::FromAddress(new_addr);
|
| @@ -1976,9 +2175,9 @@
|
| #endif
|
|
|
| // New and old addresses cannot overlap.
|
| - memcpy(reinterpret_cast<void*>(new_addr),
|
| - reinterpret_cast<void*>(old_addr),
|
| - obj_size);
|
| + Heap::CopyBlock(reinterpret_cast<Object**>(new_addr),
|
| + reinterpret_cast<Object**>(old_addr),
|
| + obj_size);
|
|
|
| #ifdef DEBUG
|
| if (FLAG_gc_verbose) {
|
|
|