41constexpr size_t kBlockSize = 256;
60template <
class _NodeType>
61class GlobalHandles::NodeBlock final {
105template <
class NodeType>
108 const NodeType* firstNode = node - node->index();
110 DCHECK_EQ(node, block->at(node->index()));
114template <
class NodeType>
117 NodeType* firstNode = node - node->index();
119 DCHECK_EQ(node, block->at(node->index()));
123template <
class NodeType>
126 return used_nodes_++ == 0;
129template <
class NodeType>
133 next_used_ = old_top;
134 prev_used_ =
nullptr;
135 if (old_top !=
nullptr) {
140template <
class NodeType>
143 return --used_nodes_ == 0;
146template <
class NodeType>
148 if (next_used_ !=
nullptr) next_used_->prev_used_ = prev_used_;
149 if (prev_used_ !=
nullptr) prev_used_->next_used_ = next_used_;
155template <
class BlockType>
175 return block_ == other.block_;
178 return block_ != other.block_;
182 if (++
index_ < kBlockSize)
return *
this;
196template <
class NodeType>
229template <
class NodeType>
231 auto* block = first_block_;
232 while (block !=
nullptr) {
233 auto* tmp = block->next();
239template <
class NodeType>
241 if (first_free_ ==
nullptr) {
242 first_block_ =
new BlockType(global_handles_,
this, first_block_);
244 PutNodesOnFreeList(first_block_);
247 NodeType* node = first_free_;
248 first_free_ = first_free_->next_free();
249 BlockType* block = BlockType::From(node);
250 if (block->IncreaseUsage()) {
251 block->ListAdd(&first_used_block_);
253 global_handles_->isolate()->counters()->global_handles()->Increment();
255 node->CheckNodeIsFreeNode();
259template <
class NodeType>
261 for (int32_t
i = kBlockSize - 1;
i >= 0; --
i) {
262 NodeType* node = block->at(
i);
263 const uint8_t index =
static_cast<uint8_t
>(
i);
265 node->set_index(index);
266 node->Free(first_free_);
271template <
class NodeType>
273 BlockType* block = BlockType::From(node);
274 block->space()->Free(node);
277template <
class NodeType>
279 CHECK(node->IsInUse());
280 node->Release(first_free_);
282 BlockType* block = BlockType::From(node);
283 if (block->DecreaseUsage()) {
284 block->ListRemove(&first_used_block_);
286 global_handles_->isolate()->counters()->global_handles()->Decrement();
290template <
class Child>
294 return reinterpret_cast<const Child*
>(
location);
298 return reinterpret_cast<Child*
>(
location);
307#ifdef ENABLE_GLOBAL_HANDLE_ZAPPING
310 data_.next_free =
nullptr;
318 data_.next_free = free_list;
324 data_.parameter =
nullptr;
326 reinterpret_cast<std::atomic<Address>*
>(&
object_)->
store(
327 object.ptr(), std::memory_order_release);
354 return data_.next_free;
363 return data_.parameter;
369 AsChild()->CheckNodeIsFreeNodeImpl();
373 Child*
AsChild() {
return reinterpret_cast<Child*
>(
this); }
374 const Child*
AsChild()
const {
return reinterpret_cast<const Child*
>(
this); }
410void ExtractInternalFields(
Tagged<JSObject> jsobject,
void** embedder_fields,
412 int field_count = jsobject->GetEmbedderFieldCount();
414 for (
int i = 0;
i < len; ++
i) {
415 if (field_count ==
i)
break;
417 if (EmbedderDataSlot(jsobject,
i).ToAlignedPointer(isolate, &pointer)) {
418 embedder_fields[
i] = pointer;
491 return data_.next_free;
536 std::vector<std::pair<Node*, PendingPhantomCallback>>*
537 pending_phantom_callbacks) {
545 IsJSObject(
object())) {
553 pending_phantom_callbacks->push_back(std::make_pair(
617template <
typename NodeType>
618bool NeedsTrackingInYoungNodes(
Tagged<Object> value, NodeType* node) {
626 if (NeedsTrackingInYoungNodes(value, node)) {
628 node->set_in_young_list(
true);
646 return global_handles->
Create(*location);
655 if (node->IsWeak() && node->IsPhantomResetHandle()) {
656 node->set_parameter(to);
662 if (location !=
nullptr) {
694 DCHECK(node->IsWeakRetainer());
696 if (!should_reset_handle(
isolate()->
heap(), node->location()))
return false;
698 switch (node->weakness_type()) {
700 node->ResetPhantomHandle();
721 if (node->IsStrongRetainer()) {
731 DCHECK(node->is_in_young_list());
733 if (node->IsWeakRetainer() &&
747 DCHECK(AllowGarbageCollection::IsAllowed());
757 TRACE_EVENT0(
"v8",
"V8.GCPhantomHandleProcessingCallback");
760 GCTracer::Scope::HEAP_EXTERNAL_PROLOGUE);
763 GCTracer::Scope::HEAP_EXTERNAL_SECOND_PASS_CALLBACKS);
772 GCTracer::Scope::HEAP_EXTERNAL_EPILOGUE);
779void UpdateListOfYoungNodesImpl(
Isolate* isolate, std::vector<T*>* node_list) {
781 for (T* node : *node_list) {
782 DCHECK(node->is_in_young_list());
783 if (node->IsInUse() && node->state() != T::NEAR_DEATH) {
785 (*node_list)[last++] =
node;
786 isolate->heap()->IncrementNodesCopiedInNewSpace();
788 node->set_in_young_list(
false);
789 isolate->heap()->IncrementNodesPromoted();
792 node->set_in_young_list(
false);
793 isolate->heap()->IncrementNodesDiedInNewSpace(1);
797 node_list->resize(last);
798 node_list->shrink_to_fit();
802void ClearListOfYoungNodesImpl(Isolate* isolate, std::vector<T*>* node_list) {
803 for (T* node : *node_list) {
804 DCHECK(node->is_in_young_list());
805 node->set_in_young_list(
false);
809 isolate->heap()->IncrementNodesDiedInNewSpace(
810 static_cast<int>(node_list->size()));
812 node_list->shrink_to_fit();
830 GCTracer::Scope::HEAP_EXTERNAL_WEAK_GLOBAL_HANDLES);
832 size_t freed_nodes = 0;
833 std::vector<std::pair<Node*, PendingPhantomCallback>>
834 pending_phantom_callbacks;
837 for (
auto& pair : pending_phantom_callbacks) {
838 Node* node = pair.first;
846 "Handle not reset in first callback. See comments on "
847 "|v8::WeakCallbackInfo|.");
878 const bool synchronous_second_pass =
884 if (synchronous_second_pass) {
896 DisallowJavascriptExecution no_js(
isolate());
904 if (node->IsStrongRetainer()) {
913 if (node->IsWeak()) {
923 if (node->IsWeakOrStrongRetainer()) {
933 if (node->IsWeakOrStrongRetainer()) {
943 Address* value = node->handle().location();
946 node->wrapper_class_id());
952 if (node->IsWeakOrStrongRetainer()) {
959 stats->global_handle_count = 0;
960 stats->weak_global_handle_count = 0;
961 stats->pending_global_handle_count = 0;
962 stats->near_death_global_handle_count = 0;
963 stats->free_global_handle_count = 0;
965 stats->global_handle_count += 1;
967 stats->weak_global_handle_count += 1;
969 stats->near_death_global_handle_count += 1;
971 stats->free_global_handle_count += 1;
978void GlobalHandles::PrintStats() {
991 PrintF(
"Global Handle Statistics:\n");
992 PrintF(
" allocated memory = %zuB\n", total *
sizeof(Node));
993 PrintF(
" # weak = %d\n", weak);
994 PrintF(
" # near_death = %d\n", near_death);
995 PrintF(
" # free = %d\n", destroyed);
996 PrintF(
" # total = %d\n", total);
999void GlobalHandles::Print() {
1000 PrintF(
"Global handles:\n");
1002 PrintF(
" handle %p to %p%s\n", node->location().ToVoidPtr(),
1003 reinterpret_cast<void*
>(node->object().ptr()),
1004 node->IsWeak() ?
" (weak)" :
"");
1026 for (
int index : young_node_indices_) {
1034 for (
int index : young_node_indices_) {
1036 young_node_indices_[last++] =
index;
1039 DCHECK_LE(last, young_node_indices_.size());
1040 young_node_indices_.resize(last);
1049 int block =
size_ >> kShift;
1055 blocks_.push_back(next_block);
1060 young_node_indices_.push_back(
size_);
union v8::internal::@341::BuiltinMetadata::KindSpecificData data
static const uint16_t kPersistentHandleNoClassId
virtual void VisitPersistentHandle(Persistent< Value > *value, uint16_t class_id)
void PostTask(std::unique_ptr< Task > task, const SourceLocation &location=SourceLocation::Current())
void(*)(const WeakCallbackInfo< T > &data) Callback
static constexpr T decode(U value)
static V8_NODISCARD constexpr U update(U previous, T value)
V8_EXPORT_PRIVATE void Create(Isolate *isolate, Tagged< Object > object, int *index)
void IterateAllRoots(RootVisitor *visitor)
void PostGarbageCollectionProcessing()
void IterateYoungRoots(RootVisitor *visitor)
void store(Tagged< Object > value) const
bool CheckReenter() const
GlobalHandles::NodeSpace< NodeType > *const space_
V8_INLINE void ListAdd(NodeBlock **top)
const void * begin_address() const
GlobalHandles * global_handles() const
V8_INLINE void ListRemove(NodeBlock **top)
GlobalHandles *const global_handles_
NodeBlock(GlobalHandles *global_handles, GlobalHandles::NodeSpace< NodeType > *space, NodeBlock *next) V8_NOEXCEPT
NodeBlock & operator=(const NodeBlock &)=delete
const NodeType * at(size_t index) const
static V8_INLINE const NodeBlock * From(const NodeType *node)
GlobalHandles::NodeSpace< NodeType > * space() const
const void * end_address() const
NodeBlock * next_used() const
NodeType nodes_[kBlockSize]
NodeType * at(size_t index)
NodeBlock(const NodeBlock &)=delete
V8_INLINE bool IncreaseUsage()
V8_INLINE bool DecreaseUsage()
NodeIterator & operator=(const NodeIterator &)=delete
NodeIterator(BlockType *block) V8_NOEXCEPT
NodeIterator(const NodeIterator &)=delete
std::forward_iterator_tag iterator_category
bool operator==(const NodeIterator &other) const
NodeIterator(NodeIterator &&other) V8_NOEXCEPT
std::ptrdiff_t difference_type
typename BlockType::NodeType NodeType
bool operator!=(const NodeIterator &other) const
NodeIterator & operator++()
V8_INLINE void Free(NodeType *node)
BlockType * first_used_block_
void PutNodesOnFreeList(BlockType *block)
static void Release(NodeType *node)
V8_INLINE NodeType * Allocate()
size_t handles_count() const
NodeIterator< BlockType > iterator
GlobalHandles *const global_handles_
NodeSpace(GlobalHandles *global_handles) V8_NOEXCEPT
static NodeSpace * From(NodeType *node)
Node(const Node &)=delete
void ResetPhantomHandle()
bool IsWeakRetainer() const
Node & operator=(const Node &)=delete
void MakeWeak(Address **location_addr)
bool is_in_young_list() const
void MakeWeak(void *parameter, WeakCallbackInfo< void >::Callback phantom_callback, v8::WeakCallbackType type)
void set_state(State state)
void set_in_young_list(bool v)
void AnnotateStrongRetainer(const char *label)
bool IsPhantomResetHandle() const
void CheckNodeIsFreeNodeImpl() const
bool IsWeakOrStrongRetainer() const
bool has_callback() const
const char * label() const
void set_weakness_type(WeaknessType weakness_type)
GlobalHandles * global_handles()
bool IsStrongRetainer() const
WeakCallbackInfo< void >::Callback weak_callback_
void CollectPhantomCallbackData(std::vector< std::pair< Node *, PendingPhantomCallback > > *pending_phantom_callbacks)
WeaknessType weakness_type() const
void * embedder_fields_[v8::kEmbedderFieldsInWeakCallback]
void Invoke(Isolate *isolate, InvocationType type)
Data::Callback callback() const
void IterateAllYoungRoots(RootVisitor *v)
void InvokeSecondPassPhantomCallbacks()
void RecordStats(HeapStats *stats)
static void * ClearWeakness(Address *location)
static void Destroy(Address *location)
void UpdateListOfYoungNodes()
void ClearListOfYoungNodes()
static void MakeWeak(Address *location, void *parameter, WeakCallbackInfo< void >::Callback weak_callback, v8::WeakCallbackType type)
static void AnnotateStrongRetainer(Address *location, const char *label)
std::unique_ptr< NodeSpace< Node > > regular_nodes_
IndirectHandle< Object > Create(Tagged< Object > value)
Isolate * isolate() const
std::vector< std::pair< Node *, PendingPhantomCallback > > pending_phantom_callbacks_
void PostGarbageCollectionProcessing(v8::GCCallbackFlags gc_callback_flags)
void IterateYoungStrongAndDependentRoots(RootVisitor *v)
void IterateAllRoots(RootVisitor *v)
std::vector< PendingPhantomCallback > second_pass_callbacks_
static bool IsWeak(Address *location)
bool second_pass_callbacks_task_posted_
static void MoveGlobal(Address **from, Address **to)
size_t last_gc_custom_callbacks_
static IndirectHandle< Object > CopyGlobal(Address *location)
void ApplyPersistentHandleVisitor(v8::PersistentHandleVisitor *visitor, Node *node)
bool ResetWeakNodeIfDead(Node *node, WeakSlotCallbackWithHeap should_reset_node)
void IterateStrongRoots(RootVisitor *v)
size_t InvokeFirstPassWeakCallbacks()
void ProcessWeakYoungObjects(RootVisitor *v, WeakSlotCallbackWithHeap should_reset_handle)
std::vector< Node * > young_nodes_
void IterateWeakRoots(RootVisitor *v)
size_t handles_count() const
GlobalHandles(const GlobalHandles &)=delete
void IterateWeakRootsForPhantomHandles(WeakSlotCallbackWithHeap should_reset_handle)
void IterateAllRootsForTesting(v8::PersistentHandleVisitor *v)
static V8_INLINE bool InYoungGeneration(Tagged< Object > object)
bool IsTearingDown() const
HeapState gc_state() const
void CallGCPrologueCallbacks(GCType gc_type, GCCallbackFlags flags, GCTracer::Scope::ScopeId scope_id)
void CallGCEpilogueCallbacks(GCType gc_type, GCCallbackFlags flags, GCTracer::Scope::ScopeId scope_id)
static const int kNodeStateMask
static const int kNodeStateIsWeakValue
static const int kNodeFlagsOffset
static const int kNodeClassIdOffset
bool MemorySaverModeEnabled()
Address raw_object() const
IndirectHandle< Object > Publish(Tagged< Object > object)
uint16_t wrapper_class_id() const
void set_parameter(void *parameter)
void Free(Child *free_list)
Tagged< Object > object() const
static const Child * FromLocation(const Address *location)
void CheckNodeIsFreeNode() const
FullObjectSlot location()
IndirectHandle< Object > handle()
union v8::internal::NodeBase::@76 data_
bool has_wrapper_class_id() const
static Child * FromLocation(Address *location)
void set_index(uint8_t value)
void Release(Child *free_list)
const Child * AsChild() const
virtual void VisitRootPointers(Root root, const char *description, FullObjectSlot start, FullObjectSlot end)=0
virtual void VisitRootPointer(Root root, const char *description, FullObjectSlot p)
V8_INLINE constexpr StorageType ptr() const
static V8_EXPORT_PRIVATE v8::Platform * GetCurrentPlatform()
#define TRACE_GC(tracer, scope_id)
void PrintF(const char *format,...)
Tagged(T object) -> Tagged< T >
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in allocation gc speed threshold for starting incremental marking via a task in percent of available threshold for starting incremental marking immediately in percent of available Use a single schedule for determining a marking schedule between JS and C objects schedules the minor GC task with kUserVisible priority max worker number of concurrent for NumberOfWorkerThreads start background threads that allocate memory concurrent_array_buffer_sweeping use parallel threads to clear weak refs in the atomic pause trace progress of the incremental marking trace object counts and memory usage report a tick only when allocated zone memory changes by this amount TracingFlags::gc_stats store(v8::tracing::TracingCategoryObserver::ENABLED_BY_NATIVE)) DEFINE_GENERIC_IMPLICATION(trace_gc_object_stats
V8_INLINE IsolateForSandbox GetIsolateForSandbox(Tagged< HeapObject >)
@ kCallbackWithTwoEmbedderFields
Handle< T > IndirectHandle
constexpr uint32_t kGlobalHandleZapValue
V8_EXPORT_PRIVATE FlagValues v8_flags
bool(*)(Heap *heap, FullObjectSlot pointer) WeakSlotCallbackWithHeap
std::unique_ptr< CancelableTask > MakeCancelableTask(Isolate *isolate, std::function< void()> func)
static constexpr Address kNullAddress
v8::WeakCallbackInfo< void >::Callback GenericCallback
void MemsetPointer(FullObjectSlot start, Tagged< Object > value, size_t counter)
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
static constexpr int kEmbedderFieldsInWeakCallback
@ kGCCallbackFlagSynchronousPhantomCallbackProcessing
@ kGCCallbackFlagCollectAllAvailableGarbage
@ kGCTypeProcessWeakCallbacks
std::vector< std::vector< ValueType > > blocks_
#define DCHECK_LE(v1, v2)
#define CHECK_WITH_MSG(condition, message)
#define DCHECK_NOT_NULL(val)
#define DCHECK_IMPLIES(v1, v2)
#define DCHECK_NE(v1, v2)
#define CHECK_NE(lhs, rhs)
#define DCHECK(condition)
#define DCHECK_LT(v1, v2)
#define DCHECK_EQ(v1, v2)
#define DCHECK_GT(v1, v2)
#define TRACE_EVENT0(category_group, name)