1// Copyright 2020 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#include "src/heap/cppgc/prefinalizer-handler.h" 6 7#include <algorithm> 8#include <memory> 9 10#include "src/base/platform/platform.h" 11#include "src/heap/cppgc/heap-page.h" 12#include "src/heap/cppgc/heap.h" 13#include "src/heap/cppgc/liveness-broker.h" 14#include "src/heap/cppgc/stats-collector.h" 15 16namespace cppgc { 17namespace internal { 18 19PrefinalizerRegistration::PrefinalizerRegistration(void* object, 20 Callback callback) { 21 auto* page = BasePage::FromPayload(object); 22 DCHECK(!page->space().is_compactable()); 23 page->heap().prefinalizer_handler()->RegisterPrefinalizer({object, callback}); 24} 25 26bool PreFinalizer::operator==(const PreFinalizer& other) const { 27 return (object == other.object) && (callback == other.callback); 28} 29 30PreFinalizerHandler::PreFinalizerHandler(HeapBase& heap) 31 : current_ordered_pre_finalizers_(&ordered_pre_finalizers_), 32 heap_(heap) 33#ifdef DEBUG 34 , 35 creation_thread_id_(v8::base::OS::GetCurrentThreadId()) 36#endif // DEBUG 37{ 38} 39 40void PreFinalizerHandler::RegisterPrefinalizer(PreFinalizer pre_finalizer) { 41 DCHECK(CurrentThreadIsCreationThread()); 42 DCHECK_EQ(ordered_pre_finalizers_.end(), 43 std::find(ordered_pre_finalizers_.begin(), 44 ordered_pre_finalizers_.end(), pre_finalizer)); 45 DCHECK_EQ(current_ordered_pre_finalizers_->end(), 46 std::find(current_ordered_pre_finalizers_->begin(), 47 current_ordered_pre_finalizers_->end(), pre_finalizer)); 48 current_ordered_pre_finalizers_->push_back(pre_finalizer); 49} 50 51void PreFinalizerHandler::InvokePreFinalizers() { 52 StatsCollector::EnabledScope stats_scope(heap_.stats_collector(), 53 StatsCollector::kAtomicSweep); 54 StatsCollector::EnabledScope nested_stats_scope( 55 heap_.stats_collector(), StatsCollector::kSweepInvokePreFinalizers); 56 57 DCHECK(CurrentThreadIsCreationThread()); 58 LivenessBroker liveness_broker = LivenessBrokerFactory::Create(); 59 is_invoking_ = true; 60 DCHECK_EQ(0u, bytes_allocated_in_prefinalizers); 61 // Reset all LABs to force allocations to the slow path for black allocation. 62 heap_.object_allocator().ResetLinearAllocationBuffers(); 63 // Prefinalizers can allocate other objects with prefinalizers, which will 64 // modify ordered_pre_finalizers_ and break iterators. 65 std::vector<PreFinalizer> new_ordered_pre_finalizers; 66 current_ordered_pre_finalizers_ = &new_ordered_pre_finalizers; 67 ordered_pre_finalizers_.erase( 68 ordered_pre_finalizers_.begin(), 69 std::remove_if(ordered_pre_finalizers_.rbegin(), 70 ordered_pre_finalizers_.rend(), 71 [liveness_broker](const PreFinalizer& pf) { 72 return (pf.callback)(liveness_broker, pf.object); 73 }) 74 .base()); 75 // Newly added objects with prefinalizers will always survive the current GC 76 // cycle, so it's safe to add them after clearing out the older prefinalizers. 77 ordered_pre_finalizers_.insert(ordered_pre_finalizers_.end(), 78 new_ordered_pre_finalizers.begin(), 79 new_ordered_pre_finalizers.end()); 80 current_ordered_pre_finalizers_ = &ordered_pre_finalizers_; 81 is_invoking_ = false; 82 ordered_pre_finalizers_.shrink_to_fit(); 83} 84 85bool PreFinalizerHandler::CurrentThreadIsCreationThread() { 86#ifdef DEBUG 87 return creation_thread_id_ == v8::base::OS::GetCurrentThreadId(); 88#else 89 return true; 90#endif 91} 92 93void PreFinalizerHandler::NotifyAllocationInPrefinalizer(size_t size) { 94 DCHECK_GT(bytes_allocated_in_prefinalizers + size, 95 bytes_allocated_in_prefinalizers); 96 bytes_allocated_in_prefinalizers += size; 97} 98 99} // namespace internal 100} // namespace cppgc 101