// Copyright 2011 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. #include "src/heap/objects-visiting.h" #include "src/heap/heap-inl.h" #include "src/heap/mark-compact-inl.h" #include "src/heap/objects-visiting-inl.h" namespace v8 { namespace internal { // We don't record weak slots during marking or scavenges. Instead we do it // once when we complete mark-compact cycle. Note that write barrier has no // effect if we are already in the middle of compacting mark-sweep cycle and we // have to record slots manually. static bool MustRecordSlots(Heap* heap) { return heap->gc_state() == Heap::MARK_COMPACT && heap->mark_compact_collector()->is_compacting(); } template struct WeakListVisitor; template Object* VisitWeakList(Heap* heap, Object* list, WeakObjectRetainer* retainer) { Object* undefined = heap->undefined_value(); Object* head = undefined; T* tail = nullptr; bool record_slots = MustRecordSlots(heap); while (list != undefined) { // Check whether to keep the candidate in the list. T* candidate = reinterpret_cast(list); Object* retained = retainer->RetainAs(list); // Move to the next element before the WeakNext is cleared. list = WeakListVisitor::WeakNext(candidate); if (retained != nullptr) { if (head == undefined) { // First element in the list. head = retained; } else { // Subsequent elements in the list. DCHECK_NOT_NULL(tail); WeakListVisitor::SetWeakNext(tail, retained); if (record_slots) { HeapObject* slot_holder = WeakListVisitor::WeakNextHolder(tail); int slot_offset = WeakListVisitor::WeakNextOffset(); Object** slot = HeapObject::RawField(slot_holder, slot_offset); MarkCompactCollector::RecordSlot(slot_holder, slot, retained); } } // Retained object is new tail. DCHECK(!retained->IsUndefined(heap->isolate())); candidate = reinterpret_cast(retained); tail = candidate; // tail is a live object, visit it. WeakListVisitor::VisitLiveObject(heap, tail, retainer); } else { WeakListVisitor::VisitPhantomObject(heap, candidate); } } // Terminate the list if there is one or more elements. if (tail != nullptr) WeakListVisitor::SetWeakNext(tail, undefined); return head; } template static void ClearWeakList(Heap* heap, Object* list) { Object* undefined = heap->undefined_value(); while (list != undefined) { T* candidate = reinterpret_cast(list); list = WeakListVisitor::WeakNext(candidate); WeakListVisitor::SetWeakNext(candidate, undefined); } } template <> struct WeakListVisitor { static void SetWeakNext(Code* code, Object* next) { code->code_data_container()->set_next_code_link(next, UPDATE_WEAK_WRITE_BARRIER); } static Object* WeakNext(Code* code) { return code->code_data_container()->next_code_link(); } static HeapObject* WeakNextHolder(Code* code) { return code->code_data_container(); } static int WeakNextOffset() { return CodeDataContainer::kNextCodeLinkOffset; } static void VisitLiveObject(Heap*, Code*, WeakObjectRetainer*) {} static void VisitPhantomObject(Heap* heap, Code* code) { // Even though the code is dying, its code_data_container can still be // alive. Clear the next_code_link slot to avoid a dangling pointer. SetWeakNext(code, heap->undefined_value()); } }; template <> struct WeakListVisitor { static void SetWeakNext(Context* context, Object* next) { context->set(Context::NEXT_CONTEXT_LINK, next, UPDATE_WEAK_WRITE_BARRIER); } static Object* WeakNext(Context* context) { return context->next_context_link(); } static HeapObject* WeakNextHolder(Context* context) { return context; } static int WeakNextOffset() { return FixedArray::SizeFor(Context::NEXT_CONTEXT_LINK); } static void VisitLiveObject(Heap* heap, Context* context, WeakObjectRetainer* retainer) { if (heap->gc_state() == Heap::MARK_COMPACT) { // Record the slots of the weak entries in the native context. for (int idx = Context::FIRST_WEAK_SLOT; idx < Context::NATIVE_CONTEXT_SLOTS; ++idx) { Object** slot = Context::cast(context)->RawFieldOfElementAt(idx); MarkCompactCollector::RecordSlot(context, slot, *slot); } // Code objects are always allocated in Code space, we do not have to // visit them during scavenges. DoWeakList(heap, context, retainer, Context::OPTIMIZED_CODE_LIST); DoWeakList(heap, context, retainer, Context::DEOPTIMIZED_CODE_LIST); } } template static void DoWeakList(Heap* heap, Context* context, WeakObjectRetainer* retainer, int index) { // Visit the weak list, removing dead intermediate elements. Object* list_head = VisitWeakList(heap, context->get(index), retainer); // Update the list head. context->set(index, list_head, UPDATE_WRITE_BARRIER); if (MustRecordSlots(heap)) { // Record the updated slot if necessary. Object** head_slot = HeapObject::RawField(context, FixedArray::SizeFor(index)); heap->mark_compact_collector()->RecordSlot(context, head_slot, list_head); } } static void VisitPhantomObject(Heap* heap, Context* context) { ClearWeakList(heap, context->get(Context::OPTIMIZED_CODE_LIST)); ClearWeakList(heap, context->get(Context::DEOPTIMIZED_CODE_LIST)); } }; template <> struct WeakListVisitor { static void SetWeakNext(AllocationSite* obj, Object* next) { obj->set_weak_next(next, UPDATE_WEAK_WRITE_BARRIER); } static Object* WeakNext(AllocationSite* obj) { return obj->weak_next(); } static HeapObject* WeakNextHolder(AllocationSite* obj) { return obj; } static int WeakNextOffset() { return AllocationSite::kWeakNextOffset; } static void VisitLiveObject(Heap*, AllocationSite*, WeakObjectRetainer*) {} static void VisitPhantomObject(Heap*, AllocationSite*) {} }; template Object* VisitWeakList(Heap* heap, Object* list, WeakObjectRetainer* retainer); template Object* VisitWeakList(Heap* heap, Object* list, WeakObjectRetainer* retainer); } // namespace internal } // namespace v8