diff --git a/src/execution/isolate.cc b/src/execution/isolate.cc index 220375db86..1870e0295c 100644 --- a/src/execution/isolate.cc +++ b/src/execution/isolate.cc @@ -4026,6 +4026,13 @@ bool Isolate::InitWithoutSnapshot() { return Init(nullptr, nullptr, nullptr, false); } +bool Isolate::InitWithReadOnlySnapshot(SnapshotData* read_only_snapshot_data) { + DCHECK_NOT_NULL(read_only_snapshot_data); + // Without external code space builtin code objects are alocated in ro space + DCHECK(V8_EXTERNAL_CODE_SPACE_BOOL); + return Init(nullptr, read_only_snapshot_data, nullptr, false); +} + bool Isolate::InitWithSnapshot(SnapshotData* startup_snapshot_data, SnapshotData* read_only_snapshot_data, SnapshotData* shared_heap_snapshot_data, @@ -4138,10 +4145,13 @@ bool Isolate::Init(SnapshotData* startup_snapshot_data, CHECK_EQ(V8HeapCompressionScheme::base(), cage_base()); #endif // V8_COMPRESS_POINTERS_IN_SHARED_CAGE - const bool create_heap_objects = (read_only_snapshot_data == nullptr); - // We either have all or none. + const bool create_heap_objects = (shared_heap_snapshot_data == nullptr); + const bool setup_up_existing_read_only_roots = + create_heap_objects && (read_only_snapshot_data != nullptr); + // We either have both or none. DCHECK_EQ(create_heap_objects, startup_snapshot_data == nullptr); - DCHECK_EQ(create_heap_objects, shared_heap_snapshot_data == nullptr); + DCHECK_IMPLIES(setup_up_existing_read_only_roots, + startup_snapshot_data == nullptr); // Code space setup requires the permissions to be set to default state. RwxMemoryWriteScope::SetDefaultPermissionsForNewThread(); @@ -4294,6 +4304,28 @@ bool Isolate::Init(SnapshotData* startup_snapshot_data, string_forwarding_table_ = shared_heap_isolate()->string_forwarding_table_; } + // If we create an isolate from scratch, but based on existing read only + // roots, then we need to populate the string cache with its strings. + if (setup_up_existing_read_only_roots) { + HandleScope scope(this); + ReadOnlyHeapObjectIterator iterator(read_only_heap()); + for (HeapObject object = iterator.Next(); !object.is_null(); + object = iterator.Next()) { + if (object.IsInternalizedString()) { + auto s = String::cast(object); + Handle str(s, this); + StringTableInsertionKey key( + this, str, DeserializingUserCodeOption::kNotDeserializingUserCode); + auto result = string_table()->LookupKey(this, &key); + // Since this is startup, there should be no duplicate entries in the + // string table, and the lookup should unconditionally add the given + // string. + DCHECK_EQ(*result, *str); + USE(result); + } + } + } + if (V8_SHORT_BUILTIN_CALLS_BOOL && v8_flags.short_builtin_calls) { #if defined(V8_OS_ANDROID) // On Android, the check is not operative to detect memory, and re-embedded @@ -4438,7 +4470,9 @@ bool Isolate::Init(SnapshotData* startup_snapshot_data, CodePageCollectionMemoryModificationScope modification_scope(heap()); if (create_heap_objects) { - read_only_heap_->OnCreateHeapObjectsComplete(this); + if (!setup_up_existing_read_only_roots) { + read_only_heap_->OnCreateHeapObjectsComplete(this); + } } else { SharedHeapDeserializer shared_heap_deserializer( this, shared_heap_snapshot_data, can_rehash); diff --git a/src/execution/isolate.h b/src/execution/isolate.h index 5394d6c327..bcb275a91a 100644 --- a/src/execution/isolate.h +++ b/src/execution/isolate.h @@ -661,6 +661,7 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory { bool InitializeCounters(); // Returns false if already initialized. bool InitWithoutSnapshot(); + bool InitWithReadOnlySnapshot(SnapshotData* read_only_snapshot_data); bool InitWithSnapshot(SnapshotData* startup_snapshot_data, SnapshotData* read_only_snapshot_data, SnapshotData* shared_heap_snapshot_data, diff --git a/src/heap/factory.cc b/src/heap/factory.cc index 2038d1db1a..4f6e6ad2a5 100644 --- a/src/heap/factory.cc +++ b/src/heap/factory.cc @@ -2382,9 +2382,13 @@ Handle Factory::CopyFixedDoubleArray( } Handle Factory::NewHeapNumberForCodeAssembler(double value) { - return CanAllocateInReadOnlySpace() - ? NewHeapNumber(value) - : NewHeapNumber(value); + ReadOnlyRoots roots(isolate()); + auto num = roots.FindHeapNumber(value); + if (!num.is_null()) return num; + // Add known HeapNumber constants to the read only roots. This ensures + // r/o snapshots to be deterministic. + DCHECK(!CanAllocateInReadOnlySpace()); + return NewHeapNumber(value); } Handle Factory::NewError(Handle constructor, diff --git a/src/heap/heap.h b/src/heap/heap.h index 73e4a3d541..c9f9ec10b5 100644 --- a/src/heap/heap.h +++ b/src/heap/heap.h @@ -667,7 +667,8 @@ class Heap { // Support for the API. // - void CreateApiObjects(); + void CreateReadOnlyApiObjects(); + void CreateMutableApiObjects(); // Implements the corresponding V8 API function. bool IdleNotification(double deadline_in_seconds); @@ -810,7 +811,8 @@ class Heap { // Bootstraps the object heap with the core set of objects required to run. // Returns whether it succeeded. - bool CreateHeapObjects(); + bool CreateReadOnlyHeapObjects(); + bool CreateMutableHeapObjects(); // Create ObjectStats if live_object_stats_ or dead_object_stats_ are nullptr. void CreateObjectStats(); @@ -1810,9 +1812,10 @@ class Heap { inline void UpdateOldSpaceLimits(); - bool CreateInitialMaps(); + bool CreateInitialReadOnlyMaps(); void CreateInternalAccessorInfoObjects(); - void CreateInitialObjects(); + void CreateInitialMutableObjects(); + void CreateInitialReadOnlyObjects(); // Zaps the memory of a code object. V8_EXPORT_PRIVATE void ZapCodeObject(Address start_address, @@ -2046,7 +2049,8 @@ class Heap { // Allocates a JS Map in the heap. V8_WARN_UNUSED_RESULT AllocationResult - AllocateMap(InstanceType instance_type, int instance_size, + AllocateMap(AllocationType allocation_type, InstanceType instance_type, + int instance_size, ElementsKind elements_kind = TERMINAL_FAST_ELEMENTS_KIND, int inobject_properties = 0); diff --git a/src/heap/read-only-heap.cc b/src/heap/read-only-heap.cc index 07db0d09da..0aab17c54e 100644 --- a/src/heap/read-only-heap.cc +++ b/src/heap/read-only-heap.cc @@ -145,7 +145,8 @@ ReadOnlyHeap* ReadOnlyHeap::CreateInitalHeapForBootstrapping( } else { std::unique_ptr sole_ro_heap( new SoleReadOnlyHeap(ro_space)); - // The global shared ReadOnlyHeap is only used without pointer compression. + // The global shared ReadOnlyHeap is used with shared cage and if pointer + // compression is disabled. SoleReadOnlyHeap::shared_ro_heap_ = sole_ro_heap.get(); ro_heap = std::move(sole_ro_heap); } diff --git a/src/heap/read-only-heap.h b/src/heap/read-only-heap.h index db73d00e58..4c8af51fc9 100644 --- a/src/heap/read-only-heap.h +++ b/src/heap/read-only-heap.h @@ -87,7 +87,7 @@ class ReadOnlyHeap { // Returns whether the ReadOnlySpace will actually be shared taking into // account whether shared memory is available with pointer compression. - static bool IsReadOnlySpaceShared() { + static constexpr bool IsReadOnlySpaceShared() { return V8_SHARED_RO_HEAP_BOOL && (!COMPRESS_POINTERS_BOOL || COMPRESS_POINTERS_IN_SHARED_CAGE_BOOL); } @@ -96,6 +96,8 @@ class ReadOnlyHeap { virtual void InitializeFromIsolateRoots(Isolate* isolate) {} virtual bool IsOwnedByIsolate() { return true; } + bool init_complete() { return init_complete_; } + protected: friend class ReadOnlyArtifacts; friend class PointerCompressedReadOnlyArtifacts; diff --git a/src/heap/setup-heap-internal.cc b/src/heap/setup-heap-internal.cc index cd86a1a37b..3542875b39 100644 --- a/src/heap/setup-heap-internal.cc +++ b/src/heap/setup-heap-internal.cc @@ -66,33 +66,93 @@ Handle CreateSharedFunctionInfo( return shared; } +#ifdef DEBUG +bool IsMutableMap(InstanceType instance_type, ElementsKind elements_kind) { + bool is_js_object = InstanceTypeChecker::IsJSObject(instance_type); + bool is_wasm_object = false; +#if V8_ENABLE_WEBASSEMBLY + is_wasm_object = + instance_type == WASM_STRUCT_TYPE || instance_type == WASM_ARRAY_TYPE; +#endif // V8_ENABLE_WEBASSEMBLY + DCHECK_IMPLIES(is_js_object && + !Map::CanHaveFastTransitionableElementsKind(instance_type), + IsDictionaryElementsKind(elements_kind) || + IsTerminalElementsKind(elements_kind)); + // JSObjects have maps with a mutable prototype_validity_cell, so they cannot + // go in RO_SPACE. Maps for managed Wasm objects have mutable subtype lists. + return is_js_object || is_wasm_object; +} +#endif + } // namespace bool SetupIsolateDelegate::SetupHeapInternal(Isolate* isolate) { - return isolate->heap()->CreateHeapObjects(); + auto heap = isolate->heap(); + if (!isolate->read_only_heap()->init_complete()) { + if (!heap->CreateReadOnlyHeapObjects()) return false; + } +#ifdef DEBUG + auto ro_size = heap->read_only_space()->Size(); +#endif + DCHECK_EQ(heap->old_space()->Size(), 0); + DCHECK_EQ(heap->new_space()->Size(), 0); + auto res = heap->CreateMutableHeapObjects(); + DCHECK_EQ(heap->read_only_space()->Size(), ro_size); + return res; } -bool Heap::CreateHeapObjects() { +bool Heap::CreateReadOnlyHeapObjects() { // Create initial maps. - if (!CreateInitialMaps()) return false; + if (!CreateInitialReadOnlyMaps()) return false; + + CreateReadOnlyApiObjects(); + CreateInitialReadOnlyObjects(); + +#ifdef DEBUG + ReadOnlyRoots roots(isolate()); + for (auto pos = RootIndex::kFirstReadOnlyRoot; + pos <= RootIndex::kLastReadOnlyRoot; ++pos) { + DCHECK(roots.at(pos)); + } +#endif + return true; +} + +bool Heap::CreateMutableHeapObjects() { + ReadOnlyRoots roots(this); + +#define ALLOCATE_MAP(instance_type, size, field_name) \ + { \ + Map map; \ + if (!AllocateMap(AllocationType::kMap, (instance_type), size).To(&map)) \ + return false; \ + set_##field_name##_map(map); \ + } + + { // Map allocation + ALLOCATE_MAP(JS_MESSAGE_OBJECT_TYPE, JSMessageObject::kHeaderSize, + message_object) + ALLOCATE_MAP(JS_EXTERNAL_OBJECT_TYPE, JSExternalObject::kHeaderSize, + external) + external_map().set_is_extensible(false); + } +#undef ALLOCATE_MAP // Ensure that all young generation pages are iterable. It must be after heap // setup, so that the maps have been created. if (new_space()) new_space()->MakeIterable(); - CreateApiObjects(); + CreateMutableApiObjects(); // Create initial objects - CreateInitialObjects(); + CreateInitialMutableObjects(); CreateInternalAccessorInfoObjects(); CHECK_EQ(0u, gc_count_); - set_native_contexts_list(ReadOnlyRoots(this).undefined_value()); - set_allocation_sites_list(ReadOnlyRoots(this).undefined_value()); - set_dirty_js_finalization_registries_list( - ReadOnlyRoots(this).undefined_value()); - set_dirty_js_finalization_registries_list_tail( - ReadOnlyRoots(this).undefined_value()); + set_native_contexts_list(roots.undefined_value()); + set_allocation_sites_list(roots.undefined_value()); + set_dirty_js_finalization_registries_list(roots.undefined_value()); + set_dirty_js_finalization_registries_list_tail(roots.undefined_value()); return true; } @@ -129,28 +189,17 @@ const Heap::StructTable Heap::struct_table[] = { #undef DATA_HANDLER_ELEMENT }; -AllocationResult Heap::AllocateMap(InstanceType instance_type, +AllocationResult Heap::AllocateMap(AllocationType allocation_type, + InstanceType instance_type, int instance_size, ElementsKind elements_kind, int inobject_properties) { static_assert(LAST_JS_OBJECT_TYPE == LAST_TYPE); - bool is_js_object = InstanceTypeChecker::IsJSObject(instance_type); - bool is_wasm_object = false; -#if V8_ENABLE_WEBASSEMBLY - is_wasm_object = - instance_type == WASM_STRUCT_TYPE || instance_type == WASM_ARRAY_TYPE; -#endif // V8_ENABLE_WEBASSEMBLY - DCHECK_IMPLIES(is_js_object && - !Map::CanHaveFastTransitionableElementsKind(instance_type), - IsDictionaryElementsKind(elements_kind) || - IsTerminalElementsKind(elements_kind)); HeapObject result; - // JSObjects have maps with a mutable prototype_validity_cell, so they cannot - // go in RO_SPACE. Maps for managed Wasm objects have mutable subtype lists. - bool is_mutable = is_js_object || is_wasm_object; - AllocationResult allocation = - AllocateRaw(Map::kSize, is_mutable ? AllocationType::kMap - : AllocationType::kReadOnly); + DCHECK_EQ(allocation_type, IsMutableMap(instance_type, elements_kind) + ? AllocationType::kMap + : AllocationType::kReadOnly); + AllocationResult allocation = AllocateRaw(Map::kSize, allocation_type); if (!allocation.To(&result)) return allocation; result.set_map_after_allocation(ReadOnlyRoots(this).meta_map(), @@ -218,7 +267,8 @@ AllocationResult Heap::Allocate(Handle map, return AllocationResult::FromObject(result); } -bool Heap::CreateInitialMaps() { +bool Heap::CreateInitialReadOnlyMaps() { + ReadOnlyRoots roots(this); HeapObject obj; { AllocationResult allocation = AllocatePartialMap(MAP_TYPE, Map::kSize); @@ -229,8 +279,6 @@ bool Heap::CreateInitialMaps() { set_meta_map(new_meta_map); new_meta_map.set_map_after_allocation(new_meta_map); - ReadOnlyRoots roots(this); - { // Partial map allocation #define ALLOCATE_PARTIAL_MAP(instance_type, size, field_name) \ { \ Map map; \ @@ -238,6 +286,7 @@ bool Heap::CreateInitialMaps() { set_##field_name##_map(map); \ } + { // Partial map allocation ALLOCATE_PARTIAL_MAP(FIXED_ARRAY_TYPE, kVariableSizeSentinel, fixed_array); ALLOCATE_PARTIAL_MAP(WEAK_FIXED_ARRAY_TYPE, kVariableSizeSentinel, weak_fixed_array); @@ -360,12 +409,14 @@ bool Heap::CreateInitialMaps() { FinalizePartialMap(Map::cast(Object(roots_table()[entry.index]))); } - { // Map allocation -#define ALLOCATE_MAP(instance_type, size, field_name) \ - { \ - Map map; \ - if (!AllocateMap((instance_type), size).To(&map)) return false; \ - set_##field_name##_map(map); \ +#define ALLOCATE_MAP(instance_type, size, field_name) \ + { \ + Map map; \ + if (!AllocateMap(AllocationType::kReadOnly, (instance_type), size) \ + .To(&map)) { \ + return false; \ + } \ + set_##field_name##_map(map); \ } #define ALLOCATE_VARSIZE_MAP(instance_type, field_name) \ @@ -379,6 +430,7 @@ bool Heap::CreateInitialMaps() { (constructor_function_index)); \ } + { // Map allocation ALLOCATE_VARSIZE_MAP(SCOPE_INFO_TYPE, scope_info) ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, module_info) ALLOCATE_VARSIZE_MAP(CLOSURE_FEEDBACK_CELL_ARRAY_TYPE, @@ -406,7 +458,10 @@ bool Heap::CreateInitialMaps() { for (unsigned i = 0; i < arraysize(string_type_table); i++) { const StringTypeTable& entry = string_type_table[i]; Map map; - if (!AllocateMap(entry.type, entry.size).To(&map)) return false; + if (!AllocateMap(AllocationType::kReadOnly, entry.type, entry.size) + .To(&map)) { + return false; + } map.SetConstructorFunctionIndex(Context::STRING_FUNCTION_INDEX); // Mark cons string maps as unstable, because their objects can change // maps during GC. @@ -533,16 +588,11 @@ bool Heap::CreateInitialMaps() { WasmContinuationObject::kSize, wasm_continuation_object) ALLOCATE_MAP(WEAK_CELL_TYPE, WeakCell::kSize, weak_cell) - - ALLOCATE_MAP(JS_MESSAGE_OBJECT_TYPE, JSMessageObject::kHeaderSize, - message_object) - ALLOCATE_MAP(JS_EXTERNAL_OBJECT_TYPE, JSExternalObject::kHeaderSize, - external) - external_map().set_is_extensible(false); + } #undef ALLOCATE_PRIMITIVE_MAP #undef ALLOCATE_VARSIZE_MAP #undef ALLOCATE_MAP - } + { AllocationResult alloc = AllocateRaw( ArrayList::SizeFor(ArrayList::kFirstIndex), AllocationType::kReadOnly); @@ -656,20 +706,23 @@ bool Heap::CreateInitialMaps() { return true; } -void Heap::CreateApiObjects() { +void Heap::CreateMutableApiObjects() { Isolate* isolate = this->isolate(); HandleScope scope(isolate); set_message_listeners(*TemplateList::New(isolate, 2)); +} +void Heap::CreateReadOnlyApiObjects() { + HandleScope scope(isolate()); Handle info = - Handle::cast(isolate->factory()->NewStruct( + Handle::cast(isolate()->factory()->NewStruct( INTERCEPTOR_INFO_TYPE, AllocationType::kReadOnly)); info->set_flags(0); set_noop_interceptor_info(*info); } -void Heap::CreateInitialObjects() { +void Heap::CreateInitialReadOnlyObjects() { HandleScope initial_objects_handle_scope(isolate()); Factory* factory = isolate()->factory(); ReadOnlyRoots roots(this); @@ -687,15 +740,18 @@ void Heap::CreateInitialObjects() { *factory->NewHeapNumber(V8_INFINITY)); set_minus_infinity_value( *factory->NewHeapNumber(-V8_INFINITY)); + set_max_safe_integer( + *factory->NewHeapNumber(kMaxSafeInteger)); + set_max_uint_32( + *factory->NewHeapNumber(kMaxUInt32)); + set_smi_min_value( + *factory->NewHeapNumber(kSmiMinValue)); + set_smi_max_value_plus_one( + *factory->NewHeapNumber(0.0 - kSmiMinValue)); set_hash_seed(*factory->NewByteArray(kInt64Size, AllocationType::kReadOnly)); InitializeHashSeed(); - // There's no "current microtask" in the beginning. - set_current_microtask(roots.undefined_value()); - - set_weak_refs_keep_during_job(roots.undefined_value()); - // Allocate and initialize table for single character one byte strings. int table_size = String::kMaxOneByteCharCode + 1; set_single_character_string_table( @@ -853,54 +909,13 @@ void Heap::CreateInitialObjects() { Handle empty_symbol_table = RegisteredSymbolTable::New( isolate(), 1, AllocationType::kReadOnly, USE_CUSTOM_MINIMUM_CAPACITY); DCHECK(!empty_symbol_table->HasSufficientCapacityToAdd(1)); - set_public_symbol_table(*empty_symbol_table); - set_api_symbol_table(*empty_symbol_table); - set_api_private_symbol_table(*empty_symbol_table); - - set_number_string_cache(*factory->NewFixedArray( - kInitialNumberStringCacheSize * 2, AllocationType::kOld)); - - set_basic_block_profiling_data(roots.empty_array_list()); - - // Allocate cache for string split and regexp-multiple. - set_string_split_cache(*factory->NewFixedArray( - RegExpResultsCache::kRegExpResultsCacheSize, AllocationType::kOld)); - set_regexp_multiple_cache(*factory->NewFixedArray( - RegExpResultsCache::kRegExpResultsCacheSize, AllocationType::kOld)); - - // Allocate FeedbackCell for builtins. - Handle many_closures_cell = - factory->NewManyClosuresCell(factory->undefined_value()); - set_many_closures_cell(*many_closures_cell); - - set_detached_contexts(roots.empty_weak_array_list()); - set_retaining_path_targets(roots.empty_weak_array_list()); - - set_feedback_vectors_for_profiling_tools(roots.undefined_value()); - set_functions_marked_for_manual_optimization(roots.undefined_value()); - set_shared_wasm_memories(roots.empty_weak_array_list()); - set_locals_block_list_cache(roots.undefined_value()); -#ifdef V8_ENABLE_WEBASSEMBLY - set_active_continuation(roots.undefined_value()); - set_active_suspender(roots.undefined_value()); - set_js_to_wasm_wrappers(roots.empty_weak_array_list()); - set_wasm_canonical_rtts(roots.empty_weak_array_list()); -#endif // V8_ENABLE_WEBASSEMBLY - - set_script_list(roots.empty_weak_array_list()); + set_empty_symbol_table(*empty_symbol_table); Handle slow_element_dictionary = NumberDictionary::New( isolate(), 1, AllocationType::kReadOnly, USE_CUSTOM_MINIMUM_CAPACITY); DCHECK(!slow_element_dictionary->HasSufficientCapacityToAdd(1)); set_empty_slow_element_dictionary(*slow_element_dictionary); - set_materialized_objects(*factory->NewFixedArray(0, AllocationType::kOld)); - - // Handling of script id generation is in Heap::NextScriptId(). - set_last_script_id(Smi::FromInt(v8::UnboundScript::kNoScriptId)); - set_last_debugging_id(Smi::FromInt(DebugInfo::kNoDebuggingId)); - set_next_template_serial_number(Smi::zero()); - // Allocate the empty OrderedHashMap. Handle empty_ordered_hash_map = OrderedHashMap::AllocateEmpty(isolate(), AllocationType::kReadOnly) @@ -942,6 +957,81 @@ void Heap::CreateInitialObjects() { ScopeInfo::CreateForNativeContext(isolate()); set_native_scope_info(*native_scope_info); + // Canonical off-heap trampoline data + set_off_heap_trampoline_relocation_info( + *Builtins::GenerateOffHeapTrampolineRelocInfo(isolate_)); + + if (V8_EXTERNAL_CODE_SPACE_BOOL) { + // These roots will not be used. + HeapObject no_container = *isolate()->factory()->undefined_value(); + set_trampoline_trivial_code_data_container(no_container); + set_trampoline_promise_rejection_code_data_container(no_container); + + } else { + set_trampoline_trivial_code_data_container( + *isolate()->factory()->NewCodeDataContainer(0, + AllocationType::kReadOnly)); + + set_trampoline_promise_rejection_code_data_container( + *isolate()->factory()->NewCodeDataContainer( + Code::IsPromiseRejectionField::encode(true), + AllocationType::kReadOnly)); + } +} + +void Heap::CreateInitialMutableObjects() { + HandleScope initial_objects_handle_scope(isolate()); + Factory* factory = isolate()->factory(); + ReadOnlyRoots roots(this); + + // There's no "current microtask" in the beginning. + set_current_microtask(roots.undefined_value()); + + set_weak_refs_keep_during_job(roots.undefined_value()); + + set_public_symbol_table(roots.empty_symbol_table()); + set_api_symbol_table(roots.empty_symbol_table()); + set_api_private_symbol_table(roots.empty_symbol_table()); + + set_number_string_cache(*factory->NewFixedArray( + kInitialNumberStringCacheSize * 2, AllocationType::kOld)); + + set_basic_block_profiling_data(roots.empty_array_list()); + + // Allocate cache for string split and regexp-multiple. + set_string_split_cache(*factory->NewFixedArray( + RegExpResultsCache::kRegExpResultsCacheSize, AllocationType::kOld)); + set_regexp_multiple_cache(*factory->NewFixedArray( + RegExpResultsCache::kRegExpResultsCacheSize, AllocationType::kOld)); + + // Allocate FeedbackCell for builtins. + Handle many_closures_cell = + factory->NewManyClosuresCell(factory->undefined_value()); + set_many_closures_cell(*many_closures_cell); + + set_detached_contexts(roots.empty_weak_array_list()); + set_retaining_path_targets(roots.empty_weak_array_list()); + + set_feedback_vectors_for_profiling_tools(roots.undefined_value()); + set_functions_marked_for_manual_optimization(roots.undefined_value()); + set_shared_wasm_memories(roots.empty_weak_array_list()); + set_locals_block_list_cache(roots.undefined_value()); +#ifdef V8_ENABLE_WEBASSEMBLY + set_active_continuation(roots.undefined_value()); + set_active_suspender(roots.undefined_value()); + set_js_to_wasm_wrappers(roots.empty_weak_array_list()); + set_wasm_canonical_rtts(roots.empty_weak_array_list()); +#endif // V8_ENABLE_WEBASSEMBLY + + set_script_list(roots.empty_weak_array_list()); + + set_materialized_objects(*factory->NewFixedArray(0, AllocationType::kOld)); + + // Handling of script id generation is in Heap::NextScriptId(). + set_last_script_id(Smi::FromInt(v8::UnboundScript::kNoScriptId)); + set_last_debugging_id(Smi::FromInt(DebugInfo::kNoDebuggingId)); + set_next_template_serial_number(Smi::zero()); + // Allocate the empty script. Handle