OLD | NEW |
---|---|
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
94 ASSERT(state_ == PREPARE_GC); | 94 ASSERT(state_ == PREPARE_GC); |
95 | 95 |
96 // Prepare has selected whether to compact the old generation or not. | 96 // Prepare has selected whether to compact the old generation or not. |
97 // Tell the tracer. | 97 // Tell the tracer. |
98 if (IsCompacting()) tracer_->set_is_compacting(); | 98 if (IsCompacting()) tracer_->set_is_compacting(); |
99 | 99 |
100 MarkLiveObjects(); | 100 MarkLiveObjects(); |
101 | 101 |
102 if (FLAG_collect_maps) ClearNonLiveTransitions(); | 102 if (FLAG_collect_maps) ClearNonLiveTransitions(); |
103 | 103 |
104 SweepSpaces(); | |
104 SweepLargeObjectSpace(); | 105 SweepLargeObjectSpace(); |
Vyacheslav Egorov (Chromium)
2011/02/02 13:15:47
You can now move SweepLargeObjectSpace into SweepS
Erik Corry
2011/02/03 13:21:17
Done.
| |
105 | 106 |
106 SweepSpaces(); | |
107 PcToCodeCache::FlushPcToCodeCache(); | 107 PcToCodeCache::FlushPcToCodeCache(); |
108 | 108 |
109 Finish(); | 109 Finish(); |
110 | 110 |
111 // Check that swept all marked objects and | 111 // Check that swept all marked objects and |
112 // null out the GC tracer. | 112 // null out the GC tracer. |
113 // TODO(gc) does not work with conservative sweeping. | 113 // TODO(gc) does not work with conservative sweeping. |
114 // ASSERT(tracer_->marked_count() == 0); | 114 // ASSERT(tracer_->marked_count() == 0); |
115 tracer_ = NULL; | 115 tracer_ = NULL; |
116 } | 116 } |
(...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
409 InstanceType type = object->map()->instance_type(); | 409 InstanceType type = object->map()->instance_type(); |
410 if ((type & kShortcutTypeMask) != kShortcutTypeTag) return object; | 410 if ((type & kShortcutTypeMask) != kShortcutTypeTag) return object; |
411 | 411 |
412 Object* second = reinterpret_cast<ConsString*>(object)->unchecked_second(); | 412 Object* second = reinterpret_cast<ConsString*>(object)->unchecked_second(); |
413 if (second != Heap::raw_unchecked_empty_string()) { | 413 if (second != Heap::raw_unchecked_empty_string()) { |
414 return object; | 414 return object; |
415 } | 415 } |
416 | 416 |
417 // Since we don't have the object's start, it is impossible to update the | 417 // Since we don't have the object's start, it is impossible to update the |
418 // page dirty marks. Therefore, we only replace the string with its left | 418 // page dirty marks. Therefore, we only replace the string with its left |
419 // substring when page dirty marks do not change. | 419 // substring when page dirty marks do not change. TODO(gc): Seems like we |
Vyacheslav Egorov (Chromium)
2011/02/02 13:15:47
move todo to the new line
Erik Corry
2011/02/03 13:21:17
Done.
| |
420 // could relax this restriction with store buffers. | |
420 Object* first = reinterpret_cast<ConsString*>(object)->unchecked_first(); | 421 Object* first = reinterpret_cast<ConsString*>(object)->unchecked_first(); |
421 if (!Heap::InNewSpace(object) && Heap::InNewSpace(first)) return object; | 422 if (!Heap::InNewSpace(object) && Heap::InNewSpace(first)) return object; |
422 | 423 |
423 *p = first; | 424 *p = first; |
424 return HeapObject::cast(first); | 425 return HeapObject::cast(first); |
425 } | 426 } |
426 | 427 |
427 | 428 |
428 class StaticMarkingVisitor : public StaticVisitorBase { | 429 class StaticMarkingVisitor : public StaticVisitorBase { |
429 public: | 430 public: |
(...skipping 993 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1423 live_lo_objects_size_ += obj->Size(); | 1424 live_lo_objects_size_ += obj->Size(); |
1424 } else { | 1425 } else { |
1425 UNREACHABLE(); | 1426 UNREACHABLE(); |
1426 } | 1427 } |
1427 } | 1428 } |
1428 #endif // DEBUG | 1429 #endif // DEBUG |
1429 | 1430 |
1430 | 1431 |
1431 void MarkCompactCollector::SweepLargeObjectSpace() { | 1432 void MarkCompactCollector::SweepLargeObjectSpace() { |
1432 #ifdef DEBUG | 1433 #ifdef DEBUG |
1433 ASSERT(state_ == MARK_LIVE_OBJECTS); | 1434 ASSERT(state_ == SWEEP_SPACES); |
1434 state_ = | |
1435 compacting_collection_ ? ENCODE_FORWARDING_ADDRESSES : SWEEP_SPACES; | |
1436 #endif | 1435 #endif |
1437 // Deallocate unmarked objects and clear marked bits for marked objects. | 1436 // Deallocate unmarked objects and clear marked bits for marked objects. |
1438 Heap::lo_space()->FreeUnmarkedObjects(); | 1437 Heap::lo_space()->FreeUnmarkedObjects(); |
1439 } | 1438 } |
1440 | 1439 |
1441 | 1440 |
1442 // Safe to use during marking phase only. | 1441 // Safe to use during marking phase only. |
1443 bool MarkCompactCollector::SafeIsMap(HeapObject* object) { | 1442 bool MarkCompactCollector::SafeIsMap(HeapObject* object) { |
1444 return object->map()->instance_type() == MAP_TYPE; | 1443 return object->map()->instance_type() == MAP_TYPE; |
1445 } | 1444 } |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1502 *HeapObject::RawField(current, Map::kPrototypeOffset) = | 1501 *HeapObject::RawField(current, Map::kPrototypeOffset) = |
1503 real_prototype; | 1502 real_prototype; |
1504 current = reinterpret_cast<Map*>(next); | 1503 current = reinterpret_cast<Map*>(next); |
1505 } | 1504 } |
1506 } | 1505 } |
1507 } | 1506 } |
1508 | 1507 |
1509 | 1508 |
1510 // We scavange new space simultaneously with sweeping. This is done in two | 1509 // We scavange new space simultaneously with sweeping. This is done in two |
1511 // passes. | 1510 // passes. |
1511 // | |
1512 // The first pass migrates all alive objects from one semispace to another or | 1512 // The first pass migrates all alive objects from one semispace to another or |
1513 // promotes them to old space. Forwading address is written directly into | 1513 // promotes them to old space. Forwarding address is written directly into |
1514 // first word of object without any encoding. If object is dead we are writing | 1514 // first word of object without any encoding. If object is dead we write |
1515 // NULL as a forwarding address. | 1515 // NULL as a forwarding address. |
1516 // The second pass updates pointers to new space in all spaces. It is possible | 1516 // |
1517 // to encounter pointers to dead objects during traversal of dirty regions we | 1517 // The second pass updates pointers to new space in all spaces. It is possible |
1518 // should clear them to avoid encountering them during next dirty regions | 1518 // to encounter pointers to dead new space objects during traversal of pointers |
1519 // iteration. | 1519 // to new space. We should clear them to avoid encountering them during next |
1520 // pointer iteration. This is an issue if the store buffer overflows and we | |
1521 // have to scan the entire old space, including dead objects, looking for | |
1522 // pointers to new space. | |
1520 static void MigrateObject(Address dst, | 1523 static void MigrateObject(Address dst, |
1521 Address src, | 1524 Address src, |
1522 int size, | 1525 int size, |
1523 bool to_old_space) { | 1526 bool to_old_space) { |
1524 if (to_old_space) { | 1527 if (to_old_space) { |
1525 Heap::CopyBlockToOldSpaceAndUpdateWriteBarrier(dst, src, size); | 1528 Heap::CopyBlockToOldSpaceAndUpdateWriteBarrier(dst, src, size); |
1526 } else { | 1529 } else { |
1527 Heap::CopyBlock(dst, src, size); | 1530 Heap::CopyBlock(dst, src, size); |
1528 } | 1531 } |
1529 | |
1530 Memory::Address_at(src) = dst; | 1532 Memory::Address_at(src) = dst; |
1531 } | 1533 } |
1532 | 1534 |
1533 | 1535 |
1534 class StaticPointersToNewGenUpdatingVisitor : public | 1536 class StaticPointersToNewGenUpdatingVisitor : public |
1535 StaticNewSpaceVisitor<StaticPointersToNewGenUpdatingVisitor> { | 1537 StaticNewSpaceVisitor<StaticPointersToNewGenUpdatingVisitor> { |
1536 public: | 1538 public: |
1537 static inline void VisitPointer(Object** p) { | 1539 static inline void VisitPointer(Object** p) { |
1538 if (!(*p)->IsHeapObject()) return; | 1540 if (!(*p)->IsHeapObject()) return; |
1539 | 1541 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1574 rinfo->IsPatchedReturnSequence()) || | 1576 rinfo->IsPatchedReturnSequence()) || |
1575 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) && | 1577 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) && |
1576 rinfo->IsPatchedDebugBreakSlotSequence())); | 1578 rinfo->IsPatchedDebugBreakSlotSequence())); |
1577 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address()); | 1579 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address()); |
1578 VisitPointer(&target); | 1580 VisitPointer(&target); |
1579 rinfo->set_call_address(Code::cast(target)->instruction_start()); | 1581 rinfo->set_call_address(Code::cast(target)->instruction_start()); |
1580 } | 1582 } |
1581 }; | 1583 }; |
1582 | 1584 |
1583 | 1585 |
1584 // Visitor for updating pointers from live objects in old spaces to new space. | 1586 static void UpdatePointerToNewGen(HeapObject** p, HeapObject* object) { |
1585 // It can encounter pointers to dead objects in new space when traversing map | 1587 ASSERT(Heap::InFromSpace(object)); |
1586 // space (see comment for MigrateObject). | 1588 ASSERT(*p == object); |
1587 static void UpdatePointerToNewGen(HeapObject** p) { | |
1588 if (!(*p)->IsHeapObject()) return; | |
1589 | 1589 |
1590 Address old_addr = (*p)->address(); | 1590 Address old_addr = object->address(); |
1591 ASSERT(Heap::InFromSpace(*p)); | |
1592 | 1591 |
1593 Address new_addr = Memory::Address_at(old_addr); | 1592 Address new_addr = Memory::Address_at(old_addr); |
1594 | 1593 |
1595 if (new_addr == NULL) { | 1594 // The new space sweep will overwrite the map word of dead objects |
1596 // We encountered pointer to a dead object. Clear it so we will | 1595 // with NULL. In this case we do not need to transfer this entry to |
1597 // not visit it again during next iteration of dirty regions. | 1596 // the store buffer which we are rebuilding. |
1598 *p = NULL; | 1597 if (new_addr != NULL) { |
1598 *p = HeapObject::FromAddress(new_addr); | |
1599 if (Heap::InNewSpace(new_addr)) { | |
1600 StoreBuffer::EnterDirectlyIntoStoreBuffer(reinterpret_cast<Address>(p)); | |
1601 } | |
1599 } else { | 1602 } else { |
1600 *p = HeapObject::FromAddress(new_addr); | 1603 // We have to zap this pointer, because the store buffer may overflow later, |
1604 // and then we have to scan the entire heap and we don't want to find | |
1605 // spurious newspace pointers in the old space. | |
1606 *p = HeapObject::FromAddress(NULL); // Fake heap object not in new space. | |
1601 } | 1607 } |
1602 } | 1608 } |
1603 | 1609 |
1604 | 1610 |
1605 static String* UpdateNewSpaceReferenceInExternalStringTableEntry(Object **p) { | 1611 static String* UpdateNewSpaceReferenceInExternalStringTableEntry(Object **p) { |
1606 Address old_addr = HeapObject::cast(*p)->address(); | 1612 Address old_addr = HeapObject::cast(*p)->address(); |
1607 Address new_addr = Memory::Address_at(old_addr); | 1613 Address new_addr = Memory::Address_at(old_addr); |
1608 return String::cast(HeapObject::FromAddress(new_addr)); | 1614 return String::cast(HeapObject::FromAddress(new_addr)); |
1609 } | 1615 } |
1610 | 1616 |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1678 // Promotion failed. Just migrate object to another semispace. | 1684 // Promotion failed. Just migrate object to another semispace. |
1679 // Allocation cannot fail at this point: semispaces are of equal size. | 1685 // Allocation cannot fail at this point: semispaces are of equal size. |
1680 Object* target = space->AllocateRaw(size)->ToObjectUnchecked(); | 1686 Object* target = space->AllocateRaw(size)->ToObjectUnchecked(); |
1681 | 1687 |
1682 MigrateObject(HeapObject::cast(target)->address(), | 1688 MigrateObject(HeapObject::cast(target)->address(), |
1683 current, | 1689 current, |
1684 size, | 1690 size, |
1685 false); | 1691 false); |
1686 } else { | 1692 } else { |
1687 size = object->Size(); | 1693 size = object->Size(); |
1694 // Mark dead objects in the new space with null in their map field. | |
1688 Memory::Address_at(current) = NULL; | 1695 Memory::Address_at(current) = NULL; |
1689 } | 1696 } |
1690 } | 1697 } |
1691 | 1698 |
1692 // Second pass: find pointers to new space and update them. | 1699 // Second pass: find pointers to new space and update them. |
1693 PointersToNewGenUpdatingVisitor updating_visitor; | 1700 PointersToNewGenUpdatingVisitor updating_visitor; |
1694 | 1701 |
1695 // Update pointers in to space. | 1702 // Update pointers in to space. |
1696 Address current = space->bottom(); | 1703 Address current = space->bottom(); |
1697 while (current < space->top()) { | 1704 while (current < space->top()) { |
1698 HeapObject* object = HeapObject::FromAddress(current); | 1705 HeapObject* object = HeapObject::FromAddress(current); |
1699 current += | 1706 current += |
1700 StaticPointersToNewGenUpdatingVisitor::IterateBody(object->map(), | 1707 StaticPointersToNewGenUpdatingVisitor::IterateBody(object->map(), |
1701 object); | 1708 object); |
1702 } | 1709 } |
1703 | 1710 |
1704 // Update roots. | 1711 // Update roots. |
1705 Heap::IterateRoots(&updating_visitor, VISIT_ALL_IN_SCAVENGE); | 1712 Heap::IterateRoots(&updating_visitor, VISIT_ALL_IN_SCAVENGE); |
1706 | 1713 |
1707 // Update pointers in old spaces. | 1714 { |
1708 Heap::IterateDirtyRegions(Heap::old_pointer_space(), | 1715 StoreBufferRebuildScope scope; |
1709 &Heap::IteratePointersInDirtyRegion, | 1716 StoreBuffer::IteratePointersToNewSpace(&UpdatePointerToNewGen); |
1710 &UpdatePointerToNewGen, | 1717 } |
1711 Heap::WATERMARK_SHOULD_BE_VALID); | |
1712 | |
1713 Heap::lo_space()->IterateDirtyRegions(&UpdatePointerToNewGen); | |
1714 | 1718 |
1715 // Update pointers from cells. | 1719 // Update pointers from cells. |
1716 HeapObjectIterator cell_iterator(Heap::cell_space()); | 1720 HeapObjectIterator cell_iterator(Heap::cell_space()); |
1717 for (HeapObject* cell = cell_iterator.next(); | 1721 for (HeapObject* cell = cell_iterator.next(); |
1718 cell != NULL; | 1722 cell != NULL; |
1719 cell = cell_iterator.next()) { | 1723 cell = cell_iterator.next()) { |
1720 if (cell->IsJSGlobalPropertyCell()) { | 1724 if (cell->IsJSGlobalPropertyCell()) { |
1721 Address value_address = | 1725 Address value_address = |
1722 reinterpret_cast<Address>(cell) + | 1726 reinterpret_cast<Address>(cell) + |
1723 (JSGlobalPropertyCell::kValueOffset - kHeapObjectTag); | 1727 (JSGlobalPropertyCell::kValueOffset - kHeapObjectTag); |
(...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2022 } | 2026 } |
2023 #endif | 2027 #endif |
2024 | 2028 |
2025 space->SetTop(new_allocation_top); | 2029 space->SetTop(new_allocation_top); |
2026 } | 2030 } |
2027 } | 2031 } |
2028 | 2032 |
2029 | 2033 |
2030 void MarkCompactCollector::SweepSpaces() { | 2034 void MarkCompactCollector::SweepSpaces() { |
2031 GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_SWEEP); | 2035 GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_SWEEP); |
2032 | 2036 #ifdef DEBUG |
2033 ASSERT(state_ == SWEEP_SPACES); | 2037 state_ = SWEEP_SPACES; |
2038 #endif | |
2034 ASSERT(!IsCompacting()); | 2039 ASSERT(!IsCompacting()); |
2035 // Noncompacting collections simply sweep the spaces to clear the mark | 2040 // Noncompacting collections simply sweep the spaces to clear the mark |
2036 // bits and free the nonlive blocks (for old and map spaces). We sweep | 2041 // bits and free the nonlive blocks (for old and map spaces). We sweep |
2037 // the map space last because freeing non-live maps overwrites them and | 2042 // the map space last because freeing non-live maps overwrites them and |
2038 // the other spaces rely on possibly non-live maps to get the sizes for | 2043 // the other spaces rely on possibly non-live maps to get the sizes for |
2039 // non-live objects. | 2044 // non-live objects. |
2040 SweepSpace(Heap::old_pointer_space(), CONSERVATIVE); | 2045 SweepSpace(Heap::old_pointer_space(), CONSERVATIVE); |
2041 SweepSpace(Heap::old_data_space(), CONSERVATIVE); | 2046 SweepSpace(Heap::old_data_space(), CONSERVATIVE); |
2042 SweepSpace(Heap::code_space(), PRECISE); | 2047 SweepSpace(Heap::code_space(), PRECISE); |
2043 // TODO(gc): implement specialized sweeper for cell space. | 2048 // TODO(gc): implement specialized sweeper for cell space. |
2044 SweepSpace(Heap::cell_space(), CONSERVATIVE); | 2049 SweepSpace(Heap::cell_space(), CONSERVATIVE); |
2045 { GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_SWEEP_NEWSPACE); | 2050 { GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_SWEEP_NEWSPACE); |
2046 SweepNewSpace(Heap::new_space()); | 2051 SweepNewSpace(Heap::new_space()); |
2047 } | 2052 } |
2048 // TODO(gc): ClearNonLiveTransitions depends on precise sweeping of | 2053 // TODO(gc): ClearNonLiveTransitions depends on precise sweeping of |
2049 // map space to detect whether unmarked map became dead in this | 2054 // map space to detect whether unmarked map became dead in this |
2050 // collection or in one of the previous ones. | 2055 // collection or in one of the previous ones. |
2051 // TODO(gc): Implement specialized sweeper for map space. | 2056 // TODO(gc): Implement specialized sweeper for map space. |
2052 SweepSpace(Heap::map_space(), PRECISE); | 2057 SweepSpace(Heap::map_space(), PRECISE); |
2053 | 2058 |
2054 Heap::IterateDirtyRegions(Heap::map_space(), | |
2055 &Heap::IteratePointersInDirtyMapsRegion, | |
2056 &UpdatePointerToNewGen, | |
2057 Heap::WATERMARK_SHOULD_BE_VALID); | |
2058 | |
2059 ASSERT(live_map_objects_size_ <= Heap::map_space()->Size()); | 2059 ASSERT(live_map_objects_size_ <= Heap::map_space()->Size()); |
2060 } | 2060 } |
2061 | 2061 |
2062 | 2062 |
2063 // Iterate the live objects in a range of addresses (eg, a page or a | 2063 // Iterate the live objects in a range of addresses (eg, a page or a |
2064 // semispace). The live regions of the range have been linked into a list. | 2064 // semispace). The live regions of the range have been linked into a list. |
2065 // The first live region is [first_live_start, first_live_end), and the last | 2065 // The first live region is [first_live_start, first_live_end), and the last |
2066 // address in the range is top. The callback function is used to get the | 2066 // address in the range is top. The callback function is used to get the |
2067 // size of each live object. | 2067 // size of each live object. |
2068 int MarkCompactCollector::IterateLiveObjectsInRange( | 2068 int MarkCompactCollector::IterateLiveObjectsInRange( |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2124 } | 2124 } |
2125 | 2125 |
2126 | 2126 |
2127 void MarkCompactCollector::Initialize() { | 2127 void MarkCompactCollector::Initialize() { |
2128 StaticPointersToNewGenUpdatingVisitor::Initialize(); | 2128 StaticPointersToNewGenUpdatingVisitor::Initialize(); |
2129 StaticMarkingVisitor::Initialize(); | 2129 StaticMarkingVisitor::Initialize(); |
2130 } | 2130 } |
2131 | 2131 |
2132 | 2132 |
2133 } } // namespace v8::internal | 2133 } } // namespace v8::internal |
OLD | NEW |