1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_HEAP_MARK_COMPACT_INL_H_ 6 #define V8_HEAP_MARK_COMPACT_INL_H_ 7 8 #include "src/heap/mark-compact.h" 9 #include "src/heap/remembered-set.h" 10 #include "src/isolate.h" 11 12 namespace v8 { 13 namespace internal { 14 15 void MarkCompactCollector::PushBlack(HeapObject* obj) { 16 DCHECK(Marking::IsBlack(ObjectMarking::MarkBitFrom(obj))); 17 if (marking_deque()->Push(obj)) { 18 MemoryChunk::IncrementLiveBytesFromGC(obj, obj->Size()); 19 } else { 20 MarkBit mark_bit = ObjectMarking::MarkBitFrom(obj); 21 Marking::BlackToGrey(mark_bit); 22 } 23 } 24 25 26 void MarkCompactCollector::UnshiftBlack(HeapObject* obj) { 27 DCHECK(Marking::IsBlack(ObjectMarking::MarkBitFrom(obj))); 28 if (!marking_deque()->Unshift(obj)) { 29 MemoryChunk::IncrementLiveBytesFromGC(obj, -obj->Size()); 30 MarkBit mark_bit = ObjectMarking::MarkBitFrom(obj); 31 Marking::BlackToGrey(mark_bit); 32 } 33 } 34 35 36 void MarkCompactCollector::MarkObject(HeapObject* obj, MarkBit mark_bit) { 37 DCHECK(ObjectMarking::MarkBitFrom(obj) == mark_bit); 38 if (Marking::IsWhite(mark_bit)) { 39 Marking::WhiteToBlack(mark_bit); 40 DCHECK(obj->GetIsolate()->heap()->Contains(obj)); 41 PushBlack(obj); 42 } 43 } 44 45 46 void MarkCompactCollector::SetMark(HeapObject* obj, MarkBit mark_bit) { 47 DCHECK(Marking::IsWhite(mark_bit)); 48 DCHECK(ObjectMarking::MarkBitFrom(obj) == mark_bit); 49 Marking::WhiteToBlack(mark_bit); 50 MemoryChunk::IncrementLiveBytesFromGC(obj, obj->Size()); 51 } 52 53 54 bool MarkCompactCollector::IsMarked(Object* obj) { 55 DCHECK(obj->IsHeapObject()); 56 HeapObject* heap_object = HeapObject::cast(obj); 57 return Marking::IsBlackOrGrey(ObjectMarking::MarkBitFrom(heap_object)); 58 } 59 60 61 void MarkCompactCollector::RecordSlot(HeapObject* object, Object** slot, 62 Object* target) { 63 Page* target_page = Page::FromAddress(reinterpret_cast<Address>(target)); 64 Page* source_page = Page::FromAddress(reinterpret_cast<Address>(object)); 65 if (target_page->IsEvacuationCandidate() && 66 !ShouldSkipEvacuationSlotRecording(object)) { 67 DCHECK(Marking::IsBlackOrGrey(ObjectMarking::MarkBitFrom(object))); 68 RememberedSet<OLD_TO_OLD>::Insert(source_page, 69 reinterpret_cast<Address>(slot)); 70 } 71 } 72 73 74 void CodeFlusher::AddCandidate(SharedFunctionInfo* shared_info) { 75 if (GetNextCandidate(shared_info) == nullptr) { 76 SetNextCandidate(shared_info, shared_function_info_candidates_head_); 77 shared_function_info_candidates_head_ = shared_info; 78 } 79 } 80 81 82 void CodeFlusher::AddCandidate(JSFunction* function) { 83 DCHECK(function->code() == function->shared()->code()); 84 if (function->next_function_link()->IsUndefined(isolate_)) { 85 SetNextCandidate(function, jsfunction_candidates_head_); 86 jsfunction_candidates_head_ = function; 87 } 88 } 89 90 91 JSFunction** CodeFlusher::GetNextCandidateSlot(JSFunction* candidate) { 92 return reinterpret_cast<JSFunction**>( 93 HeapObject::RawField(candidate, JSFunction::kNextFunctionLinkOffset)); 94 } 95 96 97 JSFunction* CodeFlusher::GetNextCandidate(JSFunction* candidate) { 98 Object* next_candidate = candidate->next_function_link(); 99 return reinterpret_cast<JSFunction*>(next_candidate); 100 } 101 102 103 void CodeFlusher::SetNextCandidate(JSFunction* candidate, 104 JSFunction* next_candidate) { 105 candidate->set_next_function_link(next_candidate, UPDATE_WEAK_WRITE_BARRIER); 106 } 107 108 109 void CodeFlusher::ClearNextCandidate(JSFunction* candidate, Object* undefined) { 110 DCHECK(undefined->IsUndefined(candidate->GetIsolate())); 111 candidate->set_next_function_link(undefined, SKIP_WRITE_BARRIER); 112 } 113 114 115 SharedFunctionInfo* CodeFlusher::GetNextCandidate( 116 SharedFunctionInfo* candidate) { 117 Object* next_candidate = candidate->code()->gc_metadata(); 118 return reinterpret_cast<SharedFunctionInfo*>(next_candidate); 119 } 120 121 122 void CodeFlusher::SetNextCandidate(SharedFunctionInfo* candidate, 123 SharedFunctionInfo* next_candidate) { 124 candidate->code()->set_gc_metadata(next_candidate); 125 } 126 127 128 void CodeFlusher::ClearNextCandidate(SharedFunctionInfo* candidate) { 129 candidate->code()->set_gc_metadata(NULL, SKIP_WRITE_BARRIER); 130 } 131 132 133 template <LiveObjectIterationMode T> 134 HeapObject* LiveObjectIterator<T>::Next() { 135 while (!it_.Done()) { 136 HeapObject* object = nullptr; 137 while (current_cell_ != 0) { 138 uint32_t trailing_zeros = base::bits::CountTrailingZeros32(current_cell_); 139 Address addr = cell_base_ + trailing_zeros * kPointerSize; 140 141 // Clear the first bit of the found object.. 142 current_cell_ &= ~(1u << trailing_zeros); 143 144 uint32_t second_bit_index = 0; 145 if (trailing_zeros < Bitmap::kBitIndexMask) { 146 second_bit_index = 1u << (trailing_zeros + 1); 147 } else { 148 second_bit_index = 0x1; 149 // The overlapping case; there has to exist a cell after the current 150 // cell. 151 // However, if there is a black area at the end of the page, and the 152 // last word is a one word filler, we are not allowed to advance. In 153 // that case we can return immediately. 154 if (it_.Done()) { 155 DCHECK(HeapObject::FromAddress(addr)->map() == 156 HeapObject::FromAddress(addr) 157 ->GetHeap() 158 ->one_pointer_filler_map()); 159 return nullptr; 160 } 161 it_.Advance(); 162 cell_base_ = it_.CurrentCellBase(); 163 current_cell_ = *it_.CurrentCell(); 164 } 165 166 Map* map = nullptr; 167 if (current_cell_ & second_bit_index) { 168 // We found a black object. If the black object is within a black area, 169 // make sure that we skip all set bits in the black area until the 170 // object ends. 171 HeapObject* black_object = HeapObject::FromAddress(addr); 172 map = base::NoBarrierAtomicValue<Map*>::FromAddress(addr)->Value(); 173 Address end = addr + black_object->SizeFromMap(map) - kPointerSize; 174 // One word filler objects do not borrow the second mark bit. We have 175 // to jump over the advancing and clearing part. 176 // Note that we know that we are at a one word filler when 177 // object_start + object_size - kPointerSize == object_start. 178 if (addr != end) { 179 DCHECK_EQ(chunk_, MemoryChunk::FromAddress(end)); 180 uint32_t end_mark_bit_index = chunk_->AddressToMarkbitIndex(end); 181 unsigned int end_cell_index = 182 end_mark_bit_index >> Bitmap::kBitsPerCellLog2; 183 MarkBit::CellType end_index_mask = 184 1u << Bitmap::IndexInCell(end_mark_bit_index); 185 if (it_.Advance(end_cell_index)) { 186 cell_base_ = it_.CurrentCellBase(); 187 current_cell_ = *it_.CurrentCell(); 188 } 189 190 // Clear all bits in current_cell, including the end index. 191 current_cell_ &= ~(end_index_mask + end_index_mask - 1); 192 } 193 194 if (T == kBlackObjects || T == kAllLiveObjects) { 195 object = black_object; 196 } 197 } else if ((T == kGreyObjects || T == kAllLiveObjects)) { 198 object = HeapObject::FromAddress(addr); 199 } 200 201 // We found a live object. 202 if (object != nullptr) { 203 if (map != nullptr && map == heap()->one_pointer_filler_map()) { 204 // Black areas together with slack tracking may result in black one 205 // word filler objects. We filter these objects out in the iterator. 206 object = nullptr; 207 } else { 208 break; 209 } 210 } 211 } 212 213 if (current_cell_ == 0) { 214 if (!it_.Done()) { 215 it_.Advance(); 216 cell_base_ = it_.CurrentCellBase(); 217 current_cell_ = *it_.CurrentCell(); 218 } 219 } 220 if (object != nullptr) return object; 221 } 222 return nullptr; 223 } 224 225 } // namespace internal 226 } // namespace v8 227 228 #endif // V8_HEAP_MARK_COMPACT_INL_H_ 229