Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(955)

Unified Diff: src/mark-compact.cc

Issue 1217011: Merging scavenge into sweeping phase of mark-sweep(-compact) collector. (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 10 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/mark-compact.h ('k') | src/utils.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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) {
« no previous file with comments | « src/mark-compact.h ('k') | src/utils.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698