// Copyright 2012 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_HEAP_MARK_COMPACT_INL_H_ #define V8_HEAP_MARK_COMPACT_INL_H_ #include "src/heap/mark-compact.h" #include "src/heap/remembered-set.h" #include "src/isolate.h" namespace v8 { namespace internal { void MarkCompactCollector::PushBlack(HeapObject* obj) { DCHECK(Marking::IsBlack(ObjectMarking::MarkBitFrom(obj))); if (marking_deque()->Push(obj)) { MemoryChunk::IncrementLiveBytesFromGC(obj, obj->Size()); } else { MarkBit mark_bit = ObjectMarking::MarkBitFrom(obj); Marking::BlackToGrey(mark_bit); } } void MarkCompactCollector::UnshiftBlack(HeapObject* obj) { DCHECK(Marking::IsBlack(ObjectMarking::MarkBitFrom(obj))); if (!marking_deque()->Unshift(obj)) { MemoryChunk::IncrementLiveBytesFromGC(obj, -obj->Size()); MarkBit mark_bit = ObjectMarking::MarkBitFrom(obj); Marking::BlackToGrey(mark_bit); } } void MarkCompactCollector::MarkObject(HeapObject* obj, MarkBit mark_bit) { DCHECK(ObjectMarking::MarkBitFrom(obj) == mark_bit); if (Marking::IsWhite(mark_bit)) { Marking::WhiteToBlack(mark_bit); DCHECK(obj->GetIsolate()->heap()->Contains(obj)); PushBlack(obj); } } void MarkCompactCollector::SetMark(HeapObject* obj, MarkBit mark_bit) { DCHECK(Marking::IsWhite(mark_bit)); DCHECK(ObjectMarking::MarkBitFrom(obj) == mark_bit); Marking::WhiteToBlack(mark_bit); MemoryChunk::IncrementLiveBytesFromGC(obj, obj->Size()); } bool MarkCompactCollector::IsMarked(Object* obj) { DCHECK(obj->IsHeapObject()); HeapObject* heap_object = HeapObject::cast(obj); return Marking::IsBlackOrGrey(ObjectMarking::MarkBitFrom(heap_object)); } void MarkCompactCollector::RecordSlot(HeapObject* object, Object** slot, Object* target) { Page* target_page = Page::FromAddress(reinterpret_cast<Address>(target)); Page* source_page = Page::FromAddress(reinterpret_cast<Address>(object)); if (target_page->IsEvacuationCandidate() && !ShouldSkipEvacuationSlotRecording(object)) { DCHECK(Marking::IsBlackOrGrey(ObjectMarking::MarkBitFrom(object))); RememberedSet<OLD_TO_OLD>::Insert(source_page, reinterpret_cast<Address>(slot)); } } void CodeFlusher::AddCandidate(SharedFunctionInfo* shared_info) { if (GetNextCandidate(shared_info) == nullptr) { SetNextCandidate(shared_info, shared_function_info_candidates_head_); shared_function_info_candidates_head_ = shared_info; } } void CodeFlusher::AddCandidate(JSFunction* function) { DCHECK(function->code() == function->shared()->code()); if (function->next_function_link()->IsUndefined(isolate_)) { SetNextCandidate(function, jsfunction_candidates_head_); jsfunction_candidates_head_ = function; } } JSFunction** CodeFlusher::GetNextCandidateSlot(JSFunction* candidate) { return reinterpret_cast<JSFunction**>( HeapObject::RawField(candidate, JSFunction::kNextFunctionLinkOffset)); } JSFunction* CodeFlusher::GetNextCandidate(JSFunction* candidate) { Object* next_candidate = candidate->next_function_link(); return reinterpret_cast<JSFunction*>(next_candidate); } void CodeFlusher::SetNextCandidate(JSFunction* candidate, JSFunction* next_candidate) { candidate->set_next_function_link(next_candidate, UPDATE_WEAK_WRITE_BARRIER); } void CodeFlusher::ClearNextCandidate(JSFunction* candidate, Object* undefined) { DCHECK(undefined->IsUndefined(candidate->GetIsolate())); candidate->set_next_function_link(undefined, SKIP_WRITE_BARRIER); } SharedFunctionInfo* CodeFlusher::GetNextCandidate( SharedFunctionInfo* candidate) { Object* next_candidate = candidate->code()->gc_metadata(); return reinterpret_cast<SharedFunctionInfo*>(next_candidate); } void CodeFlusher::SetNextCandidate(SharedFunctionInfo* candidate, SharedFunctionInfo* next_candidate) { candidate->code()->set_gc_metadata(next_candidate); } void CodeFlusher::ClearNextCandidate(SharedFunctionInfo* candidate) { candidate->code()->set_gc_metadata(NULL, SKIP_WRITE_BARRIER); } template <LiveObjectIterationMode T> HeapObject* LiveObjectIterator<T>::Next() { while (!it_.Done()) { HeapObject* object = nullptr; while (current_cell_ != 0) { uint32_t trailing_zeros = base::bits::CountTrailingZeros32(current_cell_); Address addr = cell_base_ + trailing_zeros * kPointerSize; // Clear the first bit of the found object.. current_cell_ &= ~(1u << trailing_zeros); uint32_t second_bit_index = 0; if (trailing_zeros < Bitmap::kBitIndexMask) { second_bit_index = 1u << (trailing_zeros + 1); } else { second_bit_index = 0x1; // The overlapping case; there has to exist a cell after the current // cell. // However, if there is a black area at the end of the page, and the // last word is a one word filler, we are not allowed to advance. In // that case we can return immediately. if (it_.Done()) { DCHECK(HeapObject::FromAddress(addr)->map() == HeapObject::FromAddress(addr) ->GetHeap() ->one_pointer_filler_map()); return nullptr; } it_.Advance(); cell_base_ = it_.CurrentCellBase(); current_cell_ = *it_.CurrentCell(); } Map* map = nullptr; if (current_cell_ & second_bit_index) { // We found a black object. If the black object is within a black area, // make sure that we skip all set bits in the black area until the // object ends. HeapObject* black_object = HeapObject::FromAddress(addr); map = base::NoBarrierAtomicValue<Map*>::FromAddress(addr)->Value(); Address end = addr + black_object->SizeFromMap(map) - kPointerSize; // One word filler objects do not borrow the second mark bit. We have // to jump over the advancing and clearing part. // Note that we know that we are at a one word filler when // object_start + object_size - kPointerSize == object_start. if (addr != end) { DCHECK_EQ(chunk_, MemoryChunk::FromAddress(end)); uint32_t end_mark_bit_index = chunk_->AddressToMarkbitIndex(end); unsigned int end_cell_index = end_mark_bit_index >> Bitmap::kBitsPerCellLog2; MarkBit::CellType end_index_mask = 1u << Bitmap::IndexInCell(end_mark_bit_index); if (it_.Advance(end_cell_index)) { cell_base_ = it_.CurrentCellBase(); current_cell_ = *it_.CurrentCell(); } // Clear all bits in current_cell, including the end index. current_cell_ &= ~(end_index_mask + end_index_mask - 1); } if (T == kBlackObjects || T == kAllLiveObjects) { object = black_object; } } else if ((T == kGreyObjects || T == kAllLiveObjects)) { object = HeapObject::FromAddress(addr); } // We found a live object. if (object != nullptr) { if (map != nullptr && map == heap()->one_pointer_filler_map()) { // Black areas together with slack tracking may result in black one // word filler objects. We filter these objects out in the iterator. object = nullptr; } else { break; } } } if (current_cell_ == 0) { if (!it_.Done()) { it_.Advance(); cell_base_ = it_.CurrentCellBase(); current_cell_ = *it_.CurrentCell(); } } if (object != nullptr) return object; } return nullptr; } } // namespace internal } // namespace v8 #endif // V8_HEAP_MARK_COMPACT_INL_H_