| 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 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 74 // Prepare has selected whether to compact the old generation or not. | 74 // Prepare has selected whether to compact the old generation or not. |
| 75 // Tell the tracer. | 75 // Tell the tracer. |
| 76 if (IsCompacting()) tracer_->set_is_compacting(); | 76 if (IsCompacting()) tracer_->set_is_compacting(); |
| 77 | 77 |
| 78 MarkLiveObjects(); | 78 MarkLiveObjects(); |
| 79 | 79 |
| 80 if (FLAG_collect_maps) ClearNonLiveTransitions(); | 80 if (FLAG_collect_maps) ClearNonLiveTransitions(); |
| 81 | 81 |
| 82 SweepLargeObjectSpace(); | 82 SweepLargeObjectSpace(); |
| 83 | 83 |
| 84 if (IsCompacting()) { | 84 SweepSpaces(); |
| 85 GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_COMPACT); | 85 PcToCodeCache::FlushPcToCodeCache(); |
| 86 EncodeForwardingAddresses(); | |
| 87 | |
| 88 Heap::MarkMapPointersAsEncoded(true); | |
| 89 UpdatePointers(); | |
| 90 Heap::MarkMapPointersAsEncoded(false); | |
| 91 PcToCodeCache::FlushPcToCodeCache(); | |
| 92 | |
| 93 RelocateObjects(); | |
| 94 } else { | |
| 95 SweepSpaces(); | |
| 96 PcToCodeCache::FlushPcToCodeCache(); | |
| 97 } | |
| 98 | 86 |
| 99 Finish(); | 87 Finish(); |
| 100 | 88 |
| 101 // Save the count of marked objects remaining after the collection and | 89 // Save the count of marked objects remaining after the collection and |
| 102 // null out the GC tracer. | 90 // null out the GC tracer. |
| 103 previous_marked_count_ = tracer_->marked_count(); | 91 previous_marked_count_ = tracer_->marked_count(); |
| 104 ASSERT(previous_marked_count_ == 0); | 92 ASSERT(previous_marked_count_ == 0); |
| 105 tracer_ = NULL; | 93 tracer_ = NULL; |
| 106 } | 94 } |
| 107 | 95 |
| 108 | 96 |
| 109 void MarkCompactCollector::Prepare(GCTracer* tracer) { | 97 void MarkCompactCollector::Prepare(GCTracer* tracer) { |
| 98 FLAG_flush_code = false; |
| 99 FLAG_always_compact = false; |
| 100 FLAG_never_compact = true; |
| 101 |
| 110 // Rather than passing the tracer around we stash it in a static member | 102 // Rather than passing the tracer around we stash it in a static member |
| 111 // variable. | 103 // variable. |
| 112 tracer_ = tracer; | 104 tracer_ = tracer; |
| 113 | 105 |
| 114 #ifdef DEBUG | 106 #ifdef DEBUG |
| 115 ASSERT(state_ == IDLE); | 107 ASSERT(state_ == IDLE); |
| 116 state_ = PREPARE_GC; | 108 state_ = PREPARE_GC; |
| 117 #endif | 109 #endif |
| 118 ASSERT(!FLAG_always_compact || !FLAG_never_compact); | 110 ASSERT(!FLAG_always_compact || !FLAG_never_compact); |
| 119 | 111 |
| (...skipping 1326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1446 on_dead_path = false; | 1438 on_dead_path = false; |
| 1447 current->ClearNonLiveTransitions(real_prototype); | 1439 current->ClearNonLiveTransitions(real_prototype); |
| 1448 } | 1440 } |
| 1449 *HeapObject::RawField(current, Map::kPrototypeOffset) = | 1441 *HeapObject::RawField(current, Map::kPrototypeOffset) = |
| 1450 real_prototype; | 1442 real_prototype; |
| 1451 current = reinterpret_cast<Map*>(next); | 1443 current = reinterpret_cast<Map*>(next); |
| 1452 } | 1444 } |
| 1453 } | 1445 } |
| 1454 } | 1446 } |
| 1455 | 1447 |
| 1456 // ------------------------------------------------------------------------- | |
| 1457 // Phase 2: Encode forwarding addresses. | |
| 1458 // When compacting, forwarding addresses for objects in old space and map | |
| 1459 // space are encoded in their map pointer word (along with an encoding of | |
| 1460 // their map pointers). | |
| 1461 // | |
| 1462 // The excact encoding is described in the comments for class MapWord in | |
| 1463 // objects.h. | |
| 1464 // | |
| 1465 // An address range [start, end) can have both live and non-live objects. | |
| 1466 // Maximal non-live regions are marked so they can be skipped on subsequent | |
| 1467 // sweeps of the heap. A distinguished map-pointer encoding is used to mark | |
| 1468 // free regions of one-word size (in which case the next word is the start | |
| 1469 // of a live object). A second distinguished map-pointer encoding is used | |
| 1470 // to mark free regions larger than one word, and the size of the free | |
| 1471 // region (including the first word) is written to the second word of the | |
| 1472 // region. | |
| 1473 // | |
| 1474 // Any valid map page offset must lie in the object area of the page, so map | |
| 1475 // page offsets less than Page::kObjectStartOffset are invalid. We use a | |
| 1476 // pair of distinguished invalid map encodings (for single word and multiple | |
| 1477 // words) to indicate free regions in the page found during computation of | |
| 1478 // forwarding addresses and skipped over in subsequent sweeps. | |
| 1479 | |
| 1480 | |
| 1481 // Encode a free region, defined by the given start address and size, in the | |
| 1482 // first word or two of the region. | |
| 1483 void EncodeFreeRegion(Address free_start, int free_size) { | |
| 1484 ASSERT(free_size >= kIntSize); | |
| 1485 if (free_size == kIntSize) { | |
| 1486 Memory::uint32_at(free_start) = MarkCompactCollector::kSingleFreeEncoding; | |
| 1487 } else { | |
| 1488 ASSERT(free_size >= 2 * kIntSize); | |
| 1489 Memory::uint32_at(free_start) = MarkCompactCollector::kMultiFreeEncoding; | |
| 1490 Memory::int_at(free_start + kIntSize) = free_size; | |
| 1491 } | |
| 1492 | |
| 1493 #ifdef DEBUG | |
| 1494 // Zap the body of the free region. | |
| 1495 if (FLAG_enable_slow_asserts) { | |
| 1496 for (int offset = 2 * kIntSize; | |
| 1497 offset < free_size; | |
| 1498 offset += kPointerSize) { | |
| 1499 Memory::Address_at(free_start + offset) = kZapValue; | |
| 1500 } | |
| 1501 } | |
| 1502 #endif | |
| 1503 } | |
| 1504 | |
| 1505 | |
| 1506 // Try to promote all objects in new space. Heap numbers and sequential | |
| 1507 // strings are promoted to the code space, large objects to large object space, | |
| 1508 // and all others to the old space. | |
| 1509 inline MaybeObject* MCAllocateFromNewSpace(HeapObject* object, | |
| 1510 int object_size) { | |
| 1511 MaybeObject* forwarded; | |
| 1512 if (object_size > Heap::MaxObjectSizeInPagedSpace()) { | |
| 1513 forwarded = Failure::Exception(); | |
| 1514 } else { | |
| 1515 OldSpace* target_space = Heap::TargetSpace(object); | |
| 1516 ASSERT(target_space == Heap::old_pointer_space() || | |
| 1517 target_space == Heap::old_data_space()); | |
| 1518 forwarded = target_space->MCAllocateRaw(object_size); | |
| 1519 } | |
| 1520 Object* result; | |
| 1521 if (!forwarded->ToObject(&result)) { | |
| 1522 result = Heap::new_space()->MCAllocateRaw(object_size)->ToObjectUnchecked(); | |
| 1523 } | |
| 1524 return result; | |
| 1525 } | |
| 1526 | |
| 1527 | |
| 1528 // Allocation functions for the paged spaces call the space's MCAllocateRaw. | |
| 1529 MUST_USE_RESULT inline MaybeObject* MCAllocateFromOldPointerSpace( | |
| 1530 HeapObject* ignore, | |
| 1531 int object_size) { | |
| 1532 return Heap::old_pointer_space()->MCAllocateRaw(object_size); | |
| 1533 } | |
| 1534 | |
| 1535 | |
| 1536 MUST_USE_RESULT inline MaybeObject* MCAllocateFromOldDataSpace( | |
| 1537 HeapObject* ignore, | |
| 1538 int object_size) { | |
| 1539 return Heap::old_data_space()->MCAllocateRaw(object_size); | |
| 1540 } | |
| 1541 | |
| 1542 | |
| 1543 MUST_USE_RESULT inline MaybeObject* MCAllocateFromCodeSpace( | |
| 1544 HeapObject* ignore, | |
| 1545 int object_size) { | |
| 1546 return Heap::code_space()->MCAllocateRaw(object_size); | |
| 1547 } | |
| 1548 | |
| 1549 | |
| 1550 MUST_USE_RESULT inline MaybeObject* MCAllocateFromMapSpace( | |
| 1551 HeapObject* ignore, | |
| 1552 int object_size) { | |
| 1553 return Heap::map_space()->MCAllocateRaw(object_size); | |
| 1554 } | |
| 1555 | |
| 1556 | |
| 1557 MUST_USE_RESULT inline MaybeObject* MCAllocateFromCellSpace(HeapObject* ignore, | |
| 1558 int object_size) { | |
| 1559 return Heap::cell_space()->MCAllocateRaw(object_size); | |
| 1560 } | |
| 1561 | |
| 1562 | |
| 1563 // The forwarding address is encoded at the same offset as the current | |
| 1564 // to-space object, but in from space. | |
| 1565 inline void EncodeForwardingAddressInNewSpace(HeapObject* old_object, | |
| 1566 int object_size, | |
| 1567 Object* new_object, | |
| 1568 int* ignored) { | |
| 1569 int offset = | |
| 1570 Heap::new_space()->ToSpaceOffsetForAddress(old_object->address()); | |
| 1571 Memory::Address_at(Heap::new_space()->FromSpaceLow() + offset) = | |
| 1572 HeapObject::cast(new_object)->address(); | |
| 1573 } | |
| 1574 | |
| 1575 | |
| 1576 // The forwarding address is encoded in the map pointer of the object as an | |
| 1577 // offset (in terms of live bytes) from the address of the first live object | |
| 1578 // in the page. | |
| 1579 inline void EncodeForwardingAddressInPagedSpace(HeapObject* old_object, | |
| 1580 int object_size, | |
| 1581 Object* new_object, | |
| 1582 int* offset) { | |
| 1583 // Record the forwarding address of the first live object if necessary. | |
| 1584 if (*offset == 0) { | |
| 1585 Page::FromAddress(old_object->address())->mc_first_forwarded = | |
| 1586 HeapObject::cast(new_object)->address(); | |
| 1587 } | |
| 1588 | |
| 1589 MapWord encoding = | |
| 1590 MapWord::EncodeAddress(old_object->map()->address(), *offset); | |
| 1591 old_object->set_map_word(encoding); | |
| 1592 *offset += object_size; | |
| 1593 ASSERT(*offset <= Page::kObjectAreaSize); | |
| 1594 } | |
| 1595 | |
| 1596 | |
| 1597 // Most non-live objects are ignored. | |
| 1598 inline void IgnoreNonLiveObject(HeapObject* object) {} | |
| 1599 | |
| 1600 | |
| 1601 // Function template that, given a range of addresses (eg, a semispace or a | |
| 1602 // paged space page), iterates through the objects in the range to clear | |
| 1603 // mark bits and compute and encode forwarding addresses. As a side effect, | |
| 1604 // maximal free chunks are marked so that they can be skipped on subsequent | |
| 1605 // sweeps. | |
| 1606 // | |
| 1607 // The template parameters are an allocation function, a forwarding address | |
| 1608 // encoding function, and a function to process non-live objects. | |
| 1609 template<MarkCompactCollector::AllocationFunction Alloc, | |
| 1610 MarkCompactCollector::EncodingFunction Encode, | |
| 1611 MarkCompactCollector::ProcessNonLiveFunction ProcessNonLive> | |
| 1612 inline void EncodeForwardingAddressesInRange(Address start, | |
| 1613 Address end, | |
| 1614 int* offset) { | |
| 1615 // The start address of the current free region while sweeping the space. | |
| 1616 // This address is set when a transition from live to non-live objects is | |
| 1617 // encountered. A value (an encoding of the 'next free region' pointer) | |
| 1618 // is written to memory at this address when a transition from non-live to | |
| 1619 // live objects is encountered. | |
| 1620 Address free_start = NULL; | |
| 1621 | |
| 1622 // A flag giving the state of the previously swept object. Initially true | |
| 1623 // to ensure that free_start is initialized to a proper address before | |
| 1624 // trying to write to it. | |
| 1625 bool is_prev_alive = true; | |
| 1626 | |
| 1627 int object_size; // Will be set on each iteration of the loop. | |
| 1628 for (Address current = start; current < end; current += object_size) { | |
| 1629 HeapObject* object = HeapObject::FromAddress(current); | |
| 1630 if (object->IsMarked()) { | |
| 1631 object->ClearMark(); | |
| 1632 MarkCompactCollector::tracer()->decrement_marked_count(); | |
| 1633 object_size = object->Size(); | |
| 1634 | |
| 1635 // Allocation cannot fail, because we are compacting the space. | |
| 1636 Object* forwarded = Alloc(object, object_size)->ToObjectUnchecked(); | |
| 1637 Encode(object, object_size, forwarded, offset); | |
| 1638 | |
| 1639 #ifdef DEBUG | |
| 1640 if (FLAG_gc_verbose) { | |
| 1641 PrintF("forward %p -> %p.\n", object->address(), | |
| 1642 HeapObject::cast(forwarded)->address()); | |
| 1643 } | |
| 1644 #endif | |
| 1645 if (!is_prev_alive) { // Transition from non-live to live. | |
| 1646 EncodeFreeRegion(free_start, static_cast<int>(current - free_start)); | |
| 1647 is_prev_alive = true; | |
| 1648 } | |
| 1649 } else { // Non-live object. | |
| 1650 object_size = object->Size(); | |
| 1651 ProcessNonLive(object); | |
| 1652 if (is_prev_alive) { // Transition from live to non-live. | |
| 1653 free_start = current; | |
| 1654 is_prev_alive = false; | |
| 1655 } | |
| 1656 } | |
| 1657 } | |
| 1658 | |
| 1659 // If we ended on a free region, mark it. | |
| 1660 if (!is_prev_alive) { | |
| 1661 EncodeFreeRegion(free_start, static_cast<int>(end - free_start)); | |
| 1662 } | |
| 1663 } | |
| 1664 | |
| 1665 | |
| 1666 // Functions to encode the forwarding pointers in each compactable space. | |
| 1667 void MarkCompactCollector::EncodeForwardingAddressesInNewSpace() { | |
| 1668 int ignored; | |
| 1669 EncodeForwardingAddressesInRange<MCAllocateFromNewSpace, | |
| 1670 EncodeForwardingAddressInNewSpace, | |
| 1671 IgnoreNonLiveObject>( | |
| 1672 Heap::new_space()->bottom(), | |
| 1673 Heap::new_space()->top(), | |
| 1674 &ignored); | |
| 1675 } | |
| 1676 | |
| 1677 | |
| 1678 template<MarkCompactCollector::AllocationFunction Alloc, | |
| 1679 MarkCompactCollector::ProcessNonLiveFunction ProcessNonLive> | |
| 1680 void MarkCompactCollector::EncodeForwardingAddressesInPagedSpace( | |
| 1681 PagedSpace* space) { | |
| 1682 PageIterator it(space, PageIterator::PAGES_IN_USE); | |
| 1683 while (it.has_next()) { | |
| 1684 Page* p = it.next(); | |
| 1685 | |
| 1686 // The offset of each live object in the page from the first live object | |
| 1687 // in the page. | |
| 1688 int offset = 0; | |
| 1689 EncodeForwardingAddressesInRange<Alloc, | |
| 1690 EncodeForwardingAddressInPagedSpace, | |
| 1691 ProcessNonLive>( | |
| 1692 p->ObjectAreaStart(), | |
| 1693 p->AllocationTop(), | |
| 1694 &offset); | |
| 1695 } | |
| 1696 } | |
| 1697 | |
| 1698 | 1448 |
| 1699 // We scavange new space simultaneously with sweeping. This is done in two | 1449 // We scavange new space simultaneously with sweeping. This is done in two |
| 1700 // passes. | 1450 // passes. |
| 1701 // The first pass migrates all alive objects from one semispace to another or | 1451 // The first pass migrates all alive objects from one semispace to another or |
| 1702 // promotes them to old space. Forwading address is written directly into | 1452 // promotes them to old space. Forwading address is written directly into |
| 1703 // first word of object without any encoding. If object is dead we are writing | 1453 // first word of object without any encoding. If object is dead we are writing |
| 1704 // NULL as a forwarding address. | 1454 // NULL as a forwarding address. |
| 1705 // The second pass updates pointers to new space in all spaces. It is possible | 1455 // The second pass updates pointers to new space in all spaces. It is possible |
| 1706 // to encounter pointers to dead objects during traversal of dirty regions we | 1456 // to encounter pointers to dead objects during traversal of dirty regions we |
| 1707 // should clear them to avoid encountering them during next dirty regions | 1457 // should clear them to avoid encountering them during next dirty regions |
| (...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2061 } else { | 1811 } else { |
| 2062 ASSERT(new_allocation_top_page == first_empty_page); | 1812 ASSERT(new_allocation_top_page == first_empty_page); |
| 2063 } | 1813 } |
| 2064 #endif | 1814 #endif |
| 2065 | 1815 |
| 2066 space->SetTop(new_allocation_top); | 1816 space->SetTop(new_allocation_top); |
| 2067 } | 1817 } |
| 2068 } | 1818 } |
| 2069 | 1819 |
| 2070 | 1820 |
| 2071 void MarkCompactCollector::EncodeForwardingAddresses() { | |
| 2072 ASSERT(state_ == ENCODE_FORWARDING_ADDRESSES); | |
| 2073 // Objects in the active semispace of the young generation may be | |
| 2074 // relocated to the inactive semispace (if not promoted). Set the | |
| 2075 // relocation info to the beginning of the inactive semispace. | |
| 2076 Heap::new_space()->MCResetRelocationInfo(); | |
| 2077 | |
| 2078 // Compute the forwarding pointers in each space. | |
| 2079 EncodeForwardingAddressesInPagedSpace<MCAllocateFromOldPointerSpace, | |
| 2080 ReportDeleteIfNeeded>( | |
| 2081 Heap::old_pointer_space()); | |
| 2082 | |
| 2083 EncodeForwardingAddressesInPagedSpace<MCAllocateFromOldDataSpace, | |
| 2084 IgnoreNonLiveObject>( | |
| 2085 Heap::old_data_space()); | |
| 2086 | |
| 2087 EncodeForwardingAddressesInPagedSpace<MCAllocateFromCodeSpace, | |
| 2088 ReportDeleteIfNeeded>( | |
| 2089 Heap::code_space()); | |
| 2090 | |
| 2091 EncodeForwardingAddressesInPagedSpace<MCAllocateFromCellSpace, | |
| 2092 IgnoreNonLiveObject>( | |
| 2093 Heap::cell_space()); | |
| 2094 | |
| 2095 | |
| 2096 // Compute new space next to last after the old and code spaces have been | |
| 2097 // compacted. Objects in new space can be promoted to old or code space. | |
| 2098 EncodeForwardingAddressesInNewSpace(); | |
| 2099 | |
| 2100 // Compute map space last because computing forwarding addresses | |
| 2101 // overwrites non-live objects. Objects in the other spaces rely on | |
| 2102 // non-live map pointers to get the sizes of non-live objects. | |
| 2103 EncodeForwardingAddressesInPagedSpace<MCAllocateFromMapSpace, | |
| 2104 IgnoreNonLiveObject>( | |
| 2105 Heap::map_space()); | |
| 2106 | |
| 2107 // Write relocation info to the top page, so we can use it later. This is | |
| 2108 // done after promoting objects from the new space so we get the correct | |
| 2109 // allocation top. | |
| 2110 Heap::old_pointer_space()->MCWriteRelocationInfoToPage(); | |
| 2111 Heap::old_data_space()->MCWriteRelocationInfoToPage(); | |
| 2112 Heap::code_space()->MCWriteRelocationInfoToPage(); | |
| 2113 Heap::map_space()->MCWriteRelocationInfoToPage(); | |
| 2114 Heap::cell_space()->MCWriteRelocationInfoToPage(); | |
| 2115 } | |
| 2116 | |
| 2117 | |
| 2118 class MapIterator : public HeapObjectIterator { | |
| 2119 public: | |
| 2120 MapIterator() : HeapObjectIterator(Heap::map_space(), &SizeCallback) { } | |
| 2121 | |
| 2122 explicit MapIterator(Address start) | |
| 2123 : HeapObjectIterator(Heap::map_space(), start, &SizeCallback) { } | |
| 2124 | |
| 2125 private: | |
| 2126 static int SizeCallback(HeapObject* unused) { | |
| 2127 USE(unused); | |
| 2128 return Map::kSize; | |
| 2129 } | |
| 2130 }; | |
| 2131 | |
| 2132 | |
| 2133 class MapCompact { | |
| 2134 public: | |
| 2135 explicit MapCompact(int live_maps) | |
| 2136 : live_maps_(live_maps), | |
| 2137 to_evacuate_start_(Heap::map_space()->TopAfterCompaction(live_maps)), | |
| 2138 map_to_evacuate_it_(to_evacuate_start_), | |
| 2139 first_map_to_evacuate_( | |
| 2140 reinterpret_cast<Map*>(HeapObject::FromAddress(to_evacuate_start_))) { | |
| 2141 } | |
| 2142 | |
| 2143 void CompactMaps() { | |
| 2144 // As we know the number of maps to evacuate beforehand, | |
| 2145 // we stop then there is no more vacant maps. | |
| 2146 for (Map* next_vacant_map = NextVacantMap(); | |
| 2147 next_vacant_map; | |
| 2148 next_vacant_map = NextVacantMap()) { | |
| 2149 EvacuateMap(next_vacant_map, NextMapToEvacuate()); | |
| 2150 } | |
| 2151 | |
| 2152 #ifdef DEBUG | |
| 2153 CheckNoMapsToEvacuate(); | |
| 2154 #endif | |
| 2155 } | |
| 2156 | |
| 2157 void UpdateMapPointersInRoots() { | |
| 2158 Heap::IterateRoots(&map_updating_visitor_, VISIT_ONLY_STRONG); | |
| 2159 GlobalHandles::IterateWeakRoots(&map_updating_visitor_); | |
| 2160 } | |
| 2161 | |
| 2162 void UpdateMapPointersInPagedSpace(PagedSpace* space) { | |
| 2163 ASSERT(space != Heap::map_space()); | |
| 2164 | |
| 2165 PageIterator it(space, PageIterator::PAGES_IN_USE); | |
| 2166 while (it.has_next()) { | |
| 2167 Page* p = it.next(); | |
| 2168 UpdateMapPointersInRange(p->ObjectAreaStart(), p->AllocationTop()); | |
| 2169 } | |
| 2170 } | |
| 2171 | |
| 2172 void UpdateMapPointersInNewSpace() { | |
| 2173 NewSpace* space = Heap::new_space(); | |
| 2174 UpdateMapPointersInRange(space->bottom(), space->top()); | |
| 2175 } | |
| 2176 | |
| 2177 void UpdateMapPointersInLargeObjectSpace() { | |
| 2178 LargeObjectIterator it(Heap::lo_space()); | |
| 2179 for (HeapObject* obj = it.next(); obj != NULL; obj = it.next()) | |
| 2180 UpdateMapPointersInObject(obj); | |
| 2181 } | |
| 2182 | |
| 2183 void Finish() { | |
| 2184 Heap::map_space()->FinishCompaction(to_evacuate_start_, live_maps_); | |
| 2185 } | |
| 2186 | |
| 2187 private: | |
| 2188 int live_maps_; | |
| 2189 Address to_evacuate_start_; | |
| 2190 MapIterator vacant_map_it_; | |
| 2191 MapIterator map_to_evacuate_it_; | |
| 2192 Map* first_map_to_evacuate_; | |
| 2193 | |
| 2194 // Helper class for updating map pointers in HeapObjects. | |
| 2195 class MapUpdatingVisitor: public ObjectVisitor { | |
| 2196 public: | |
| 2197 void VisitPointer(Object** p) { | |
| 2198 UpdateMapPointer(p); | |
| 2199 } | |
| 2200 | |
| 2201 void VisitPointers(Object** start, Object** end) { | |
| 2202 for (Object** p = start; p < end; p++) UpdateMapPointer(p); | |
| 2203 } | |
| 2204 | |
| 2205 private: | |
| 2206 void UpdateMapPointer(Object** p) { | |
| 2207 if (!(*p)->IsHeapObject()) return; | |
| 2208 HeapObject* old_map = reinterpret_cast<HeapObject*>(*p); | |
| 2209 | |
| 2210 // Moved maps are tagged with overflowed map word. They are the only | |
| 2211 // objects those map word is overflowed as marking is already complete. | |
| 2212 MapWord map_word = old_map->map_word(); | |
| 2213 if (!map_word.IsOverflowed()) return; | |
| 2214 | |
| 2215 *p = GetForwardedMap(map_word); | |
| 2216 } | |
| 2217 }; | |
| 2218 | |
| 2219 static MapUpdatingVisitor map_updating_visitor_; | |
| 2220 | |
| 2221 static Map* NextMap(MapIterator* it, HeapObject* last, bool live) { | |
| 2222 while (true) { | |
| 2223 HeapObject* next = it->next(); | |
| 2224 ASSERT(next != NULL); | |
| 2225 if (next == last) | |
| 2226 return NULL; | |
| 2227 ASSERT(!next->IsOverflowed()); | |
| 2228 ASSERT(!next->IsMarked()); | |
| 2229 ASSERT(next->IsMap() || FreeListNode::IsFreeListNode(next)); | |
| 2230 if (next->IsMap() == live) | |
| 2231 return reinterpret_cast<Map*>(next); | |
| 2232 } | |
| 2233 } | |
| 2234 | |
| 2235 Map* NextVacantMap() { | |
| 2236 Map* map = NextMap(&vacant_map_it_, first_map_to_evacuate_, false); | |
| 2237 ASSERT(map == NULL || FreeListNode::IsFreeListNode(map)); | |
| 2238 return map; | |
| 2239 } | |
| 2240 | |
| 2241 Map* NextMapToEvacuate() { | |
| 2242 Map* map = NextMap(&map_to_evacuate_it_, NULL, true); | |
| 2243 ASSERT(map != NULL); | |
| 2244 ASSERT(map->IsMap()); | |
| 2245 return map; | |
| 2246 } | |
| 2247 | |
| 2248 static void EvacuateMap(Map* vacant_map, Map* map_to_evacuate) { | |
| 2249 ASSERT(FreeListNode::IsFreeListNode(vacant_map)); | |
| 2250 ASSERT(map_to_evacuate->IsMap()); | |
| 2251 | |
| 2252 ASSERT(Map::kSize % 4 == 0); | |
| 2253 | |
| 2254 Heap::CopyBlockToOldSpaceAndUpdateRegionMarks(vacant_map->address(), | |
| 2255 map_to_evacuate->address(), | |
| 2256 Map::kSize); | |
| 2257 | |
| 2258 ASSERT(vacant_map->IsMap()); // Due to memcpy above. | |
| 2259 | |
| 2260 MapWord forwarding_map_word = MapWord::FromMap(vacant_map); | |
| 2261 forwarding_map_word.SetOverflow(); | |
| 2262 map_to_evacuate->set_map_word(forwarding_map_word); | |
| 2263 | |
| 2264 ASSERT(map_to_evacuate->map_word().IsOverflowed()); | |
| 2265 ASSERT(GetForwardedMap(map_to_evacuate->map_word()) == vacant_map); | |
| 2266 } | |
| 2267 | |
| 2268 static Map* GetForwardedMap(MapWord map_word) { | |
| 2269 ASSERT(map_word.IsOverflowed()); | |
| 2270 map_word.ClearOverflow(); | |
| 2271 Map* new_map = map_word.ToMap(); | |
| 2272 ASSERT_MAP_ALIGNED(new_map->address()); | |
| 2273 return new_map; | |
| 2274 } | |
| 2275 | |
| 2276 static int UpdateMapPointersInObject(HeapObject* obj) { | |
| 2277 ASSERT(!obj->IsMarked()); | |
| 2278 Map* map = obj->map(); | |
| 2279 ASSERT(Heap::map_space()->Contains(map)); | |
| 2280 MapWord map_word = map->map_word(); | |
| 2281 ASSERT(!map_word.IsMarked()); | |
| 2282 if (map_word.IsOverflowed()) { | |
| 2283 Map* new_map = GetForwardedMap(map_word); | |
| 2284 ASSERT(Heap::map_space()->Contains(new_map)); | |
| 2285 obj->set_map(new_map); | |
| 2286 | |
| 2287 #ifdef DEBUG | |
| 2288 if (FLAG_gc_verbose) { | |
| 2289 PrintF("update %p : %p -> %p\n", | |
| 2290 obj->address(), | |
| 2291 reinterpret_cast<void*>(map), | |
| 2292 reinterpret_cast<void*>(new_map)); | |
| 2293 } | |
| 2294 #endif | |
| 2295 } | |
| 2296 | |
| 2297 int size = obj->SizeFromMap(map); | |
| 2298 obj->IterateBody(map->instance_type(), size, &map_updating_visitor_); | |
| 2299 return size; | |
| 2300 } | |
| 2301 | |
| 2302 static void UpdateMapPointersInRange(Address start, Address end) { | |
| 2303 HeapObject* object; | |
| 2304 int size; | |
| 2305 for (Address current = start; current < end; current += size) { | |
| 2306 object = HeapObject::FromAddress(current); | |
| 2307 size = UpdateMapPointersInObject(object); | |
| 2308 ASSERT(size > 0); | |
| 2309 } | |
| 2310 } | |
| 2311 | |
| 2312 #ifdef DEBUG | |
| 2313 void CheckNoMapsToEvacuate() { | |
| 2314 if (!FLAG_enable_slow_asserts) | |
| 2315 return; | |
| 2316 | |
| 2317 for (HeapObject* obj = map_to_evacuate_it_.next(); | |
| 2318 obj != NULL; obj = map_to_evacuate_it_.next()) | |
| 2319 ASSERT(FreeListNode::IsFreeListNode(obj)); | |
| 2320 } | |
| 2321 #endif | |
| 2322 }; | |
| 2323 | |
| 2324 MapCompact::MapUpdatingVisitor MapCompact::map_updating_visitor_; | |
| 2325 | |
| 2326 | |
| 2327 void MarkCompactCollector::SweepSpaces() { | 1821 void MarkCompactCollector::SweepSpaces() { |
| 2328 GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_SWEEP); | 1822 GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_SWEEP); |
| 2329 | 1823 |
| 2330 ASSERT(state_ == SWEEP_SPACES); | 1824 ASSERT(state_ == SWEEP_SPACES); |
| 2331 ASSERT(!IsCompacting()); | 1825 ASSERT(!IsCompacting()); |
| 2332 // Noncompacting collections simply sweep the spaces to clear the mark | 1826 // Noncompacting collections simply sweep the spaces to clear the mark |
| 2333 // bits and free the nonlive blocks (for old and map spaces). We sweep | 1827 // bits and free the nonlive blocks (for old and map spaces). We sweep |
| 2334 // the map space last because freeing non-live maps overwrites them and | 1828 // the map space last because freeing non-live maps overwrites them and |
| 2335 // the other spaces rely on possibly non-live maps to get the sizes for | 1829 // the other spaces rely on possibly non-live maps to get the sizes for |
| 2336 // non-live objects. | 1830 // non-live objects. |
| 2337 SweepSpace(Heap::old_pointer_space()); | 1831 SweepSpace(Heap::old_pointer_space()); |
| 2338 SweepSpace(Heap::old_data_space()); | 1832 SweepSpace(Heap::old_data_space()); |
| 2339 SweepSpace(Heap::code_space()); | 1833 SweepSpace(Heap::code_space()); |
| 2340 SweepSpace(Heap::cell_space()); | 1834 SweepSpace(Heap::cell_space()); |
| 2341 { GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_SWEEP_NEWSPACE); | 1835 { GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_SWEEP_NEWSPACE); |
| 2342 SweepNewSpace(Heap::new_space()); | 1836 SweepNewSpace(Heap::new_space()); |
| 2343 } | 1837 } |
| 2344 SweepSpace(Heap::map_space()); | 1838 SweepSpace(Heap::map_space()); |
| 2345 | 1839 |
| 2346 Heap::IterateDirtyRegions(Heap::map_space(), | 1840 Heap::IterateDirtyRegions(Heap::map_space(), |
| 2347 &Heap::IteratePointersInDirtyMapsRegion, | 1841 &Heap::IteratePointersInDirtyMapsRegion, |
| 2348 &UpdatePointerToNewGen, | 1842 &UpdatePointerToNewGen, |
| 2349 Heap::WATERMARK_SHOULD_BE_VALID); | 1843 Heap::WATERMARK_SHOULD_BE_VALID); |
| 2350 | 1844 |
| 2351 intptr_t live_maps_size = Heap::map_space()->Size(); | 1845 ASSERT(live_map_objects_size_ == Heap::map_space()->Size()); |
| 2352 int live_maps = static_cast<int>(live_maps_size / Map::kSize); | |
| 2353 ASSERT(live_map_objects_size_ == live_maps_size); | |
| 2354 | |
| 2355 if (Heap::map_space()->NeedsCompaction(live_maps)) { | |
| 2356 MapCompact map_compact(live_maps); | |
| 2357 | |
| 2358 map_compact.CompactMaps(); | |
| 2359 map_compact.UpdateMapPointersInRoots(); | |
| 2360 | |
| 2361 PagedSpaces spaces; | |
| 2362 for (PagedSpace* space = spaces.next(); | |
| 2363 space != NULL; space = spaces.next()) { | |
| 2364 if (space == Heap::map_space()) continue; | |
| 2365 map_compact.UpdateMapPointersInPagedSpace(space); | |
| 2366 } | |
| 2367 map_compact.UpdateMapPointersInNewSpace(); | |
| 2368 map_compact.UpdateMapPointersInLargeObjectSpace(); | |
| 2369 | |
| 2370 map_compact.Finish(); | |
| 2371 } | |
| 2372 } | 1846 } |
| 2373 | 1847 |
| 2374 | 1848 |
| 2375 // Iterate the live objects in a range of addresses (eg, a page or a | 1849 // Iterate the live objects in a range of addresses (eg, a page or a |
| 2376 // semispace). The live regions of the range have been linked into a list. | 1850 // semispace). The live regions of the range have been linked into a list. |
| 2377 // The first live region is [first_live_start, first_live_end), and the last | 1851 // The first live region is [first_live_start, first_live_end), and the last |
| 2378 // address in the range is top. The callback function is used to get the | 1852 // address in the range is top. The callback function is used to get the |
| 2379 // size of each live object. | 1853 // size of each live object. |
| 2380 int MarkCompactCollector::IterateLiveObjectsInRange( | 1854 int MarkCompactCollector::IterateLiveObjectsInRange( |
| 2381 Address start, | 1855 Address start, |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2414 while (it.has_next()) { | 1888 while (it.has_next()) { |
| 2415 Page* p = it.next(); | 1889 Page* p = it.next(); |
| 2416 total += IterateLiveObjectsInRange(p->ObjectAreaStart(), | 1890 total += IterateLiveObjectsInRange(p->ObjectAreaStart(), |
| 2417 p->AllocationTop(), | 1891 p->AllocationTop(), |
| 2418 size_f); | 1892 size_f); |
| 2419 } | 1893 } |
| 2420 return total; | 1894 return total; |
| 2421 } | 1895 } |
| 2422 | 1896 |
| 2423 | 1897 |
| 2424 // ------------------------------------------------------------------------- | |
| 2425 // Phase 3: Update pointers | |
| 2426 | |
| 2427 // Helper class for updating pointers in HeapObjects. | |
| 2428 class UpdatingVisitor: public ObjectVisitor { | |
| 2429 public: | |
| 2430 void VisitPointer(Object** p) { | |
| 2431 UpdatePointer(p); | |
| 2432 } | |
| 2433 | |
| 2434 void VisitPointers(Object** start, Object** end) { | |
| 2435 // Mark all HeapObject pointers in [start, end) | |
| 2436 for (Object** p = start; p < end; p++) UpdatePointer(p); | |
| 2437 } | |
| 2438 | |
| 2439 void VisitCodeTarget(RelocInfo* rinfo) { | |
| 2440 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode())); | |
| 2441 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address()); | |
| 2442 VisitPointer(&target); | |
| 2443 rinfo->set_target_address( | |
| 2444 reinterpret_cast<Code*>(target)->instruction_start()); | |
| 2445 } | |
| 2446 | |
| 2447 void VisitDebugTarget(RelocInfo* rinfo) { | |
| 2448 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) && | |
| 2449 rinfo->IsPatchedReturnSequence()) || | |
| 2450 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) && | |
| 2451 rinfo->IsPatchedDebugBreakSlotSequence())); | |
| 2452 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address()); | |
| 2453 VisitPointer(&target); | |
| 2454 rinfo->set_call_address( | |
| 2455 reinterpret_cast<Code*>(target)->instruction_start()); | |
| 2456 } | |
| 2457 | |
| 2458 private: | |
| 2459 void UpdatePointer(Object** p) { | |
| 2460 if (!(*p)->IsHeapObject()) return; | |
| 2461 | |
| 2462 HeapObject* obj = HeapObject::cast(*p); | |
| 2463 Address old_addr = obj->address(); | |
| 2464 Address new_addr; | |
| 2465 ASSERT(!Heap::InFromSpace(obj)); | |
| 2466 | |
| 2467 if (Heap::new_space()->Contains(obj)) { | |
| 2468 Address forwarding_pointer_addr = | |
| 2469 Heap::new_space()->FromSpaceLow() + | |
| 2470 Heap::new_space()->ToSpaceOffsetForAddress(old_addr); | |
| 2471 new_addr = Memory::Address_at(forwarding_pointer_addr); | |
| 2472 | |
| 2473 #ifdef DEBUG | |
| 2474 ASSERT(Heap::old_pointer_space()->Contains(new_addr) || | |
| 2475 Heap::old_data_space()->Contains(new_addr) || | |
| 2476 Heap::new_space()->FromSpaceContains(new_addr) || | |
| 2477 Heap::lo_space()->Contains(HeapObject::FromAddress(new_addr))); | |
| 2478 | |
| 2479 if (Heap::new_space()->FromSpaceContains(new_addr)) { | |
| 2480 ASSERT(Heap::new_space()->FromSpaceOffsetForAddress(new_addr) <= | |
| 2481 Heap::new_space()->ToSpaceOffsetForAddress(old_addr)); | |
| 2482 } | |
| 2483 #endif | |
| 2484 | |
| 2485 } else if (Heap::lo_space()->Contains(obj)) { | |
| 2486 // Don't move objects in the large object space. | |
| 2487 return; | |
| 2488 | |
| 2489 } else { | |
| 2490 #ifdef DEBUG | |
| 2491 PagedSpaces spaces; | |
| 2492 PagedSpace* original_space = spaces.next(); | |
| 2493 while (original_space != NULL) { | |
| 2494 if (original_space->Contains(obj)) break; | |
| 2495 original_space = spaces.next(); | |
| 2496 } | |
| 2497 ASSERT(original_space != NULL); | |
| 2498 #endif | |
| 2499 new_addr = MarkCompactCollector::GetForwardingAddressInOldSpace(obj); | |
| 2500 ASSERT(original_space->Contains(new_addr)); | |
| 2501 ASSERT(original_space->MCSpaceOffsetForAddress(new_addr) <= | |
| 2502 original_space->MCSpaceOffsetForAddress(old_addr)); | |
| 2503 } | |
| 2504 | |
| 2505 *p = HeapObject::FromAddress(new_addr); | |
| 2506 | |
| 2507 #ifdef DEBUG | |
| 2508 if (FLAG_gc_verbose) { | |
| 2509 PrintF("update %p : %p -> %p\n", | |
| 2510 reinterpret_cast<Address>(p), old_addr, new_addr); | |
| 2511 } | |
| 2512 #endif | |
| 2513 } | |
| 2514 }; | |
| 2515 | |
| 2516 | |
| 2517 void MarkCompactCollector::UpdatePointers() { | |
| 2518 #ifdef DEBUG | |
| 2519 ASSERT(state_ == ENCODE_FORWARDING_ADDRESSES); | |
| 2520 state_ = UPDATE_POINTERS; | |
| 2521 #endif | |
| 2522 UpdatingVisitor updating_visitor; | |
| 2523 Heap::IterateRoots(&updating_visitor, VISIT_ONLY_STRONG); | |
| 2524 GlobalHandles::IterateWeakRoots(&updating_visitor); | |
| 2525 | |
| 2526 // Update the pointer to the head of the weak list of global contexts. | |
| 2527 updating_visitor.VisitPointer(&Heap::global_contexts_list_); | |
| 2528 | |
| 2529 int live_maps_size = IterateLiveObjects(Heap::map_space(), | |
| 2530 &UpdatePointersInOldObject); | |
| 2531 int live_pointer_olds_size = IterateLiveObjects(Heap::old_pointer_space(), | |
| 2532 &UpdatePointersInOldObject); | |
| 2533 int live_data_olds_size = IterateLiveObjects(Heap::old_data_space(), | |
| 2534 &UpdatePointersInOldObject); | |
| 2535 int live_codes_size = IterateLiveObjects(Heap::code_space(), | |
| 2536 &UpdatePointersInOldObject); | |
| 2537 int live_cells_size = IterateLiveObjects(Heap::cell_space(), | |
| 2538 &UpdatePointersInOldObject); | |
| 2539 int live_news_size = IterateLiveObjects(Heap::new_space(), | |
| 2540 &UpdatePointersInNewObject); | |
| 2541 | |
| 2542 // Large objects do not move, the map word can be updated directly. | |
| 2543 LargeObjectIterator it(Heap::lo_space()); | |
| 2544 for (HeapObject* obj = it.next(); obj != NULL; obj = it.next()) { | |
| 2545 UpdatePointersInNewObject(obj); | |
| 2546 } | |
| 2547 | |
| 2548 USE(live_maps_size); | |
| 2549 USE(live_pointer_olds_size); | |
| 2550 USE(live_data_olds_size); | |
| 2551 USE(live_codes_size); | |
| 2552 USE(live_cells_size); | |
| 2553 USE(live_news_size); | |
| 2554 ASSERT(live_maps_size == live_map_objects_size_); | |
| 2555 ASSERT(live_data_olds_size == live_old_data_objects_size_); | |
| 2556 ASSERT(live_pointer_olds_size == live_old_pointer_objects_size_); | |
| 2557 ASSERT(live_codes_size == live_code_objects_size_); | |
| 2558 ASSERT(live_cells_size == live_cell_objects_size_); | |
| 2559 ASSERT(live_news_size == live_young_objects_size_); | |
| 2560 } | |
| 2561 | |
| 2562 | |
| 2563 int MarkCompactCollector::UpdatePointersInNewObject(HeapObject* obj) { | |
| 2564 // Keep old map pointers | |
| 2565 Map* old_map = obj->map(); | |
| 2566 ASSERT(old_map->IsHeapObject()); | |
| 2567 | |
| 2568 Address forwarded = GetForwardingAddressInOldSpace(old_map); | |
| 2569 | |
| 2570 ASSERT(Heap::map_space()->Contains(old_map)); | |
| 2571 ASSERT(Heap::map_space()->Contains(forwarded)); | |
| 2572 #ifdef DEBUG | |
| 2573 if (FLAG_gc_verbose) { | |
| 2574 PrintF("update %p : %p -> %p\n", obj->address(), old_map->address(), | |
| 2575 forwarded); | |
| 2576 } | |
| 2577 #endif | |
| 2578 // Update the map pointer. | |
| 2579 obj->set_map(reinterpret_cast<Map*>(HeapObject::FromAddress(forwarded))); | |
| 2580 | |
| 2581 // We have to compute the object size relying on the old map because | |
| 2582 // map objects are not relocated yet. | |
| 2583 int obj_size = obj->SizeFromMap(old_map); | |
| 2584 | |
| 2585 // Update pointers in the object body. | |
| 2586 UpdatingVisitor updating_visitor; | |
| 2587 obj->IterateBody(old_map->instance_type(), obj_size, &updating_visitor); | |
| 2588 return obj_size; | |
| 2589 } | |
| 2590 | |
| 2591 | |
| 2592 int MarkCompactCollector::UpdatePointersInOldObject(HeapObject* obj) { | |
| 2593 // Decode the map pointer. | |
| 2594 MapWord encoding = obj->map_word(); | |
| 2595 Address map_addr = encoding.DecodeMapAddress(Heap::map_space()); | |
| 2596 ASSERT(Heap::map_space()->Contains(HeapObject::FromAddress(map_addr))); | |
| 2597 | |
| 2598 // At this point, the first word of map_addr is also encoded, cannot | |
| 2599 // cast it to Map* using Map::cast. | |
| 2600 Map* map = reinterpret_cast<Map*>(HeapObject::FromAddress(map_addr)); | |
| 2601 int obj_size = obj->SizeFromMap(map); | |
| 2602 InstanceType type = map->instance_type(); | |
| 2603 | |
| 2604 // Update map pointer. | |
| 2605 Address new_map_addr = GetForwardingAddressInOldSpace(map); | |
| 2606 int offset = encoding.DecodeOffset(); | |
| 2607 obj->set_map_word(MapWord::EncodeAddress(new_map_addr, offset)); | |
| 2608 | |
| 2609 #ifdef DEBUG | |
| 2610 if (FLAG_gc_verbose) { | |
| 2611 PrintF("update %p : %p -> %p\n", obj->address(), | |
| 2612 map_addr, new_map_addr); | |
| 2613 } | |
| 2614 #endif | |
| 2615 | |
| 2616 // Update pointers in the object body. | |
| 2617 UpdatingVisitor updating_visitor; | |
| 2618 obj->IterateBody(type, obj_size, &updating_visitor); | |
| 2619 return obj_size; | |
| 2620 } | |
| 2621 | |
| 2622 | |
| 2623 Address MarkCompactCollector::GetForwardingAddressInOldSpace(HeapObject* obj) { | |
| 2624 // Object should either in old or map space. | |
| 2625 MapWord encoding = obj->map_word(); | |
| 2626 | |
| 2627 // Offset to the first live object's forwarding address. | |
| 2628 int offset = encoding.DecodeOffset(); | |
| 2629 Address obj_addr = obj->address(); | |
| 2630 | |
| 2631 // Find the first live object's forwarding address. | |
| 2632 Page* p = Page::FromAddress(obj_addr); | |
| 2633 Address first_forwarded = p->mc_first_forwarded; | |
| 2634 | |
| 2635 // Page start address of forwarded address. | |
| 2636 Page* forwarded_page = Page::FromAddress(first_forwarded); | |
| 2637 int forwarded_offset = forwarded_page->Offset(first_forwarded); | |
| 2638 | |
| 2639 // Find end of allocation in the page of first_forwarded. | |
| 2640 int mc_top_offset = forwarded_page->AllocationWatermarkOffset(); | |
| 2641 | |
| 2642 // Check if current object's forward pointer is in the same page | |
| 2643 // as the first live object's forwarding pointer | |
| 2644 if (forwarded_offset + offset < mc_top_offset) { | |
| 2645 // In the same page. | |
| 2646 return first_forwarded + offset; | |
| 2647 } | |
| 2648 | |
| 2649 // Must be in the next page, NOTE: this may cross chunks. | |
| 2650 Page* next_page = forwarded_page->next_page(); | |
| 2651 ASSERT(next_page->is_valid()); | |
| 2652 | |
| 2653 offset -= (mc_top_offset - forwarded_offset); | |
| 2654 offset += Page::kObjectStartOffset; | |
| 2655 | |
| 2656 ASSERT_PAGE_OFFSET(offset); | |
| 2657 ASSERT(next_page->OffsetToAddress(offset) < next_page->AllocationTop()); | |
| 2658 | |
| 2659 return next_page->OffsetToAddress(offset); | |
| 2660 } | |
| 2661 | |
| 2662 | |
| 2663 // ------------------------------------------------------------------------- | |
| 2664 // Phase 4: Relocate objects | |
| 2665 | |
| 2666 void MarkCompactCollector::RelocateObjects() { | |
| 2667 #ifdef DEBUG | |
| 2668 ASSERT(state_ == UPDATE_POINTERS); | |
| 2669 state_ = RELOCATE_OBJECTS; | |
| 2670 #endif | |
| 2671 // Relocates objects, always relocate map objects first. Relocating | |
| 2672 // objects in other space relies on map objects to get object size. | |
| 2673 int live_maps_size = IterateLiveObjects(Heap::map_space(), | |
| 2674 &RelocateMapObject); | |
| 2675 int live_pointer_olds_size = IterateLiveObjects(Heap::old_pointer_space(), | |
| 2676 &RelocateOldPointerObject); | |
| 2677 int live_data_olds_size = IterateLiveObjects(Heap::old_data_space(), | |
| 2678 &RelocateOldDataObject); | |
| 2679 int live_codes_size = IterateLiveObjects(Heap::code_space(), | |
| 2680 &RelocateCodeObject); | |
| 2681 int live_cells_size = IterateLiveObjects(Heap::cell_space(), | |
| 2682 &RelocateCellObject); | |
| 2683 int live_news_size = IterateLiveObjects(Heap::new_space(), | |
| 2684 &RelocateNewObject); | |
| 2685 | |
| 2686 USE(live_maps_size); | |
| 2687 USE(live_pointer_olds_size); | |
| 2688 USE(live_data_olds_size); | |
| 2689 USE(live_codes_size); | |
| 2690 USE(live_cells_size); | |
| 2691 USE(live_news_size); | |
| 2692 ASSERT(live_maps_size == live_map_objects_size_); | |
| 2693 ASSERT(live_data_olds_size == live_old_data_objects_size_); | |
| 2694 ASSERT(live_pointer_olds_size == live_old_pointer_objects_size_); | |
| 2695 ASSERT(live_codes_size == live_code_objects_size_); | |
| 2696 ASSERT(live_cells_size == live_cell_objects_size_); | |
| 2697 ASSERT(live_news_size == live_young_objects_size_); | |
| 2698 | |
| 2699 // Flip from and to spaces | |
| 2700 Heap::new_space()->Flip(); | |
| 2701 | |
| 2702 Heap::new_space()->MCCommitRelocationInfo(); | |
| 2703 | |
| 2704 // Set age_mark to bottom in to space | |
| 2705 Address mark = Heap::new_space()->bottom(); | |
| 2706 Heap::new_space()->set_age_mark(mark); | |
| 2707 | |
| 2708 PagedSpaces spaces; | |
| 2709 for (PagedSpace* space = spaces.next(); space != NULL; space = spaces.next()) | |
| 2710 space->MCCommitRelocationInfo(); | |
| 2711 | |
| 2712 Heap::CheckNewSpaceExpansionCriteria(); | |
| 2713 Heap::IncrementYoungSurvivorsCounter(live_news_size); | |
| 2714 } | |
| 2715 | |
| 2716 | |
| 2717 int MarkCompactCollector::RelocateMapObject(HeapObject* obj) { | |
| 2718 // Recover map pointer. | |
| 2719 MapWord encoding = obj->map_word(); | |
| 2720 Address map_addr = encoding.DecodeMapAddress(Heap::map_space()); | |
| 2721 ASSERT(Heap::map_space()->Contains(HeapObject::FromAddress(map_addr))); | |
| 2722 | |
| 2723 // Get forwarding address before resetting map pointer | |
| 2724 Address new_addr = GetForwardingAddressInOldSpace(obj); | |
| 2725 | |
| 2726 // Reset map pointer. The meta map object may not be copied yet so | |
| 2727 // Map::cast does not yet work. | |
| 2728 obj->set_map(reinterpret_cast<Map*>(HeapObject::FromAddress(map_addr))); | |
| 2729 | |
| 2730 Address old_addr = obj->address(); | |
| 2731 | |
| 2732 if (new_addr != old_addr) { | |
| 2733 // Move contents. | |
| 2734 Heap::MoveBlockToOldSpaceAndUpdateRegionMarks(new_addr, | |
| 2735 old_addr, | |
| 2736 Map::kSize); | |
| 2737 } | |
| 2738 | |
| 2739 #ifdef DEBUG | |
| 2740 if (FLAG_gc_verbose) { | |
| 2741 PrintF("relocate %p -> %p\n", old_addr, new_addr); | |
| 2742 } | |
| 2743 #endif | |
| 2744 | |
| 2745 return Map::kSize; | |
| 2746 } | |
| 2747 | |
| 2748 | |
| 2749 static inline int RestoreMap(HeapObject* obj, | |
| 2750 PagedSpace* space, | |
| 2751 Address new_addr, | |
| 2752 Address map_addr) { | |
| 2753 // This must be a non-map object, and the function relies on the | |
| 2754 // assumption that the Map space is compacted before the other paged | |
| 2755 // spaces (see RelocateObjects). | |
| 2756 | |
| 2757 // Reset map pointer. | |
| 2758 obj->set_map(Map::cast(HeapObject::FromAddress(map_addr))); | |
| 2759 | |
| 2760 int obj_size = obj->Size(); | |
| 2761 ASSERT_OBJECT_SIZE(obj_size); | |
| 2762 | |
| 2763 ASSERT(space->MCSpaceOffsetForAddress(new_addr) <= | |
| 2764 space->MCSpaceOffsetForAddress(obj->address())); | |
| 2765 | |
| 2766 #ifdef DEBUG | |
| 2767 if (FLAG_gc_verbose) { | |
| 2768 PrintF("relocate %p -> %p\n", obj->address(), new_addr); | |
| 2769 } | |
| 2770 #endif | |
| 2771 | |
| 2772 return obj_size; | |
| 2773 } | |
| 2774 | |
| 2775 | |
| 2776 int MarkCompactCollector::RelocateOldNonCodeObject(HeapObject* obj, | |
| 2777 PagedSpace* space) { | |
| 2778 // Recover map pointer. | |
| 2779 MapWord encoding = obj->map_word(); | |
| 2780 Address map_addr = encoding.DecodeMapAddress(Heap::map_space()); | |
| 2781 ASSERT(Heap::map_space()->Contains(map_addr)); | |
| 2782 | |
| 2783 // Get forwarding address before resetting map pointer. | |
| 2784 Address new_addr = GetForwardingAddressInOldSpace(obj); | |
| 2785 | |
| 2786 // Reset the map pointer. | |
| 2787 int obj_size = RestoreMap(obj, space, new_addr, map_addr); | |
| 2788 | |
| 2789 Address old_addr = obj->address(); | |
| 2790 | |
| 2791 if (new_addr != old_addr) { | |
| 2792 // Move contents. | |
| 2793 if (space == Heap::old_data_space()) { | |
| 2794 Heap::MoveBlock(new_addr, old_addr, obj_size); | |
| 2795 } else { | |
| 2796 Heap::MoveBlockToOldSpaceAndUpdateRegionMarks(new_addr, | |
| 2797 old_addr, | |
| 2798 obj_size); | |
| 2799 } | |
| 2800 } | |
| 2801 | |
| 2802 ASSERT(!HeapObject::FromAddress(new_addr)->IsCode()); | |
| 2803 | |
| 2804 HeapObject* copied_to = HeapObject::FromAddress(new_addr); | |
| 2805 if (copied_to->IsJSFunction()) { | |
| 2806 PROFILE(FunctionMoveEvent(old_addr, new_addr)); | |
| 2807 PROFILE(FunctionCreateEventFromMove(JSFunction::cast(copied_to))); | |
| 2808 } | |
| 2809 HEAP_PROFILE(ObjectMoveEvent(old_addr, new_addr)); | |
| 2810 | |
| 2811 return obj_size; | |
| 2812 } | |
| 2813 | |
| 2814 | |
| 2815 int MarkCompactCollector::RelocateOldPointerObject(HeapObject* obj) { | |
| 2816 return RelocateOldNonCodeObject(obj, Heap::old_pointer_space()); | |
| 2817 } | |
| 2818 | |
| 2819 | |
| 2820 int MarkCompactCollector::RelocateOldDataObject(HeapObject* obj) { | |
| 2821 return RelocateOldNonCodeObject(obj, Heap::old_data_space()); | |
| 2822 } | |
| 2823 | |
| 2824 | |
| 2825 int MarkCompactCollector::RelocateCellObject(HeapObject* obj) { | |
| 2826 return RelocateOldNonCodeObject(obj, Heap::cell_space()); | |
| 2827 } | |
| 2828 | |
| 2829 | |
| 2830 int MarkCompactCollector::RelocateCodeObject(HeapObject* obj) { | |
| 2831 // Recover map pointer. | |
| 2832 MapWord encoding = obj->map_word(); | |
| 2833 Address map_addr = encoding.DecodeMapAddress(Heap::map_space()); | |
| 2834 ASSERT(Heap::map_space()->Contains(HeapObject::FromAddress(map_addr))); | |
| 2835 | |
| 2836 // Get forwarding address before resetting map pointer | |
| 2837 Address new_addr = GetForwardingAddressInOldSpace(obj); | |
| 2838 | |
| 2839 // Reset the map pointer. | |
| 2840 int obj_size = RestoreMap(obj, Heap::code_space(), new_addr, map_addr); | |
| 2841 | |
| 2842 Address old_addr = obj->address(); | |
| 2843 | |
| 2844 if (new_addr != old_addr) { | |
| 2845 // Move contents. | |
| 2846 Heap::MoveBlock(new_addr, old_addr, obj_size); | |
| 2847 } | |
| 2848 | |
| 2849 HeapObject* copied_to = HeapObject::FromAddress(new_addr); | |
| 2850 if (copied_to->IsCode()) { | |
| 2851 // May also update inline cache target. | |
| 2852 Code::cast(copied_to)->Relocate(new_addr - old_addr); | |
| 2853 // Notify the logger that compiled code has moved. | |
| 2854 PROFILE(CodeMoveEvent(old_addr, new_addr)); | |
| 2855 } | |
| 2856 HEAP_PROFILE(ObjectMoveEvent(old_addr, new_addr)); | |
| 2857 | |
| 2858 return obj_size; | |
| 2859 } | |
| 2860 | |
| 2861 | |
| 2862 int MarkCompactCollector::RelocateNewObject(HeapObject* obj) { | |
| 2863 int obj_size = obj->Size(); | |
| 2864 | |
| 2865 // Get forwarding address | |
| 2866 Address old_addr = obj->address(); | |
| 2867 int offset = Heap::new_space()->ToSpaceOffsetForAddress(old_addr); | |
| 2868 | |
| 2869 Address new_addr = | |
| 2870 Memory::Address_at(Heap::new_space()->FromSpaceLow() + offset); | |
| 2871 | |
| 2872 #ifdef DEBUG | |
| 2873 if (Heap::new_space()->FromSpaceContains(new_addr)) { | |
| 2874 ASSERT(Heap::new_space()->FromSpaceOffsetForAddress(new_addr) <= | |
| 2875 Heap::new_space()->ToSpaceOffsetForAddress(old_addr)); | |
| 2876 } else { | |
| 2877 ASSERT(Heap::TargetSpace(obj) == Heap::old_pointer_space() || | |
| 2878 Heap::TargetSpace(obj) == Heap::old_data_space()); | |
| 2879 } | |
| 2880 #endif | |
| 2881 | |
| 2882 // New and old addresses cannot overlap. | |
| 2883 if (Heap::InNewSpace(HeapObject::FromAddress(new_addr))) { | |
| 2884 Heap::CopyBlock(new_addr, old_addr, obj_size); | |
| 2885 } else { | |
| 2886 Heap::CopyBlockToOldSpaceAndUpdateRegionMarks(new_addr, | |
| 2887 old_addr, | |
| 2888 obj_size); | |
| 2889 } | |
| 2890 | |
| 2891 #ifdef DEBUG | |
| 2892 if (FLAG_gc_verbose) { | |
| 2893 PrintF("relocate %p -> %p\n", old_addr, new_addr); | |
| 2894 } | |
| 2895 #endif | |
| 2896 | |
| 2897 HeapObject* copied_to = HeapObject::FromAddress(new_addr); | |
| 2898 if (copied_to->IsJSFunction()) { | |
| 2899 PROFILE(FunctionMoveEvent(old_addr, new_addr)); | |
| 2900 PROFILE(FunctionCreateEventFromMove(JSFunction::cast(copied_to))); | |
| 2901 } | |
| 2902 HEAP_PROFILE(ObjectMoveEvent(old_addr, new_addr)); | |
| 2903 | |
| 2904 return obj_size; | |
| 2905 } | |
| 2906 | |
| 2907 | |
| 2908 void MarkCompactCollector::ReportDeleteIfNeeded(HeapObject* obj) { | 1898 void MarkCompactCollector::ReportDeleteIfNeeded(HeapObject* obj) { |
| 2909 #ifdef ENABLE_LOGGING_AND_PROFILING | 1899 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 2910 if (obj->IsCode()) { | 1900 if (obj->IsCode()) { |
| 2911 PROFILE(CodeDeleteEvent(obj->address())); | 1901 PROFILE(CodeDeleteEvent(obj->address())); |
| 2912 } else if (obj->IsJSFunction()) { | 1902 } else if (obj->IsJSFunction()) { |
| 2913 PROFILE(FunctionDeleteEvent(obj->address())); | 1903 PROFILE(FunctionDeleteEvent(obj->address())); |
| 2914 } | 1904 } |
| 2915 #endif | 1905 #endif |
| 2916 } | 1906 } |
| 2917 | 1907 |
| 2918 | 1908 |
| 2919 int MarkCompactCollector::SizeOfMarkedObject(HeapObject* obj) { | 1909 int MarkCompactCollector::SizeOfMarkedObject(HeapObject* obj) { |
| 2920 MapWord map_word = obj->map_word(); | 1910 MapWord map_word = obj->map_word(); |
| 2921 map_word.ClearMark(); | 1911 map_word.ClearMark(); |
| 2922 return obj->SizeFromMap(map_word.ToMap()); | 1912 return obj->SizeFromMap(map_word.ToMap()); |
| 2923 } | 1913 } |
| 2924 | 1914 |
| 2925 | 1915 |
| 2926 void MarkCompactCollector::Initialize() { | 1916 void MarkCompactCollector::Initialize() { |
| 2927 StaticPointersToNewGenUpdatingVisitor::Initialize(); | 1917 StaticPointersToNewGenUpdatingVisitor::Initialize(); |
| 2928 StaticMarkingVisitor::Initialize(); | 1918 StaticMarkingVisitor::Initialize(); |
| 2929 } | 1919 } |
| 2930 | 1920 |
| 2931 | 1921 |
| 2932 } } // namespace v8::internal | 1922 } } // namespace v8::internal |
| OLD | NEW |