diff --git a/BUILD.gn b/BUILD.gn index efd2affd30..6574a6ff38 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -196,6 +196,11 @@ declare_args() { # Sets -dV8_SHORT_BUILTIN_CALLS v8_enable_short_builtin_calls = "" + # Enable support for external code range relative to the pointer compression + # cage. + # Sets -dV8_EXTERNAL_CODE_SPACE + v8_enable_external_code_space = "" + # With post mortem support enabled, metadata is embedded into libv8 that # describes various parameters of the VM for use by debuggers. See # tools/gen-postmortem-metadata.py for details. @@ -391,6 +396,9 @@ if (v8_enable_short_builtin_calls == "") { v8_enable_short_builtin_calls = v8_current_cpu == "x64" || (!is_android && v8_current_cpu == "arm64") } +if (v8_enable_external_code_space == "") { + v8_enable_external_code_space = false +} if (v8_enable_single_generation == "") { v8_enable_single_generation = v8_disable_write_barriers } @@ -471,6 +479,9 @@ assert(!v8_use_multi_snapshots || !v8_control_flow_integrity, assert(!v8_enable_heap_sandbox || v8_enable_pointer_compression, "V8 Heap Sandbox requires pointer compression") +assert(!v8_enable_heap_sandbox || v8_enable_external_code_space, + "V8 Heap Sandbox is not compatible with external code space YET") + assert( !v8_enable_pointer_compression_shared_cage || v8_enable_pointer_compression, "Can't share a pointer compression cage if pointers aren't compressed") @@ -879,6 +890,9 @@ config("features") { if (v8_enable_short_builtin_calls) { defines += [ "V8_SHORT_BUILTIN_CALLS" ] } + if (v8_enable_external_code_space) { + defines += [ "V8_EXTERNAL_CODE_SPACE" ] + } if (v8_enable_swiss_name_dictionary) { defines += [ "V8_ENABLE_SWISS_NAME_DICTIONARY" ] } diff --git a/include/v8-internal.h b/include/v8-internal.h index f289149d8d..1826dd6fca 100644 --- a/include/v8-internal.h +++ b/include/v8-internal.h @@ -146,6 +146,7 @@ enum ExternalPointerTag : uint64_t { kForeignForeignAddressTag = 0x01f7000000000000, // 0b000000111110111 kNativeContextMicrotaskQueueTag = 0x01fb000000000000, // 0b000000111111011 kEmbedderDataSlotPayloadTag = 0x01fd000000000000, // 0b000000111111101 + kCodeEntryPointTag = 0x01fe000000000000, // 0b000000111111110 }; constexpr uint64_t kExternalPointerTagMask = 0xffff000000000000; diff --git a/src/builtins/builtins.cc b/src/builtins/builtins.cc index b7dc552338..0f0dd61bff 100644 --- a/src/builtins/builtins.cc +++ b/src/builtins/builtins.cc @@ -396,7 +396,8 @@ Handle Builtins::GenerateOffHeapTrampolineFor( : TrampolineType::kAbort); return Factory::CodeBuilder(isolate, desc, CodeKind::BUILTIN) - .set_read_only_data_container(kind_specfic_flags) + .set_kind_specific_flags(kind_specfic_flags) + .set_read_only_data_container(!V8_EXTERNAL_CODE_SPACE_BOOL) .set_self_reference(generator.CodeObject()) .set_is_executable(generate_jump_to_instruction_stream) .Build(); diff --git a/src/common/globals.h b/src/common/globals.h index 5ce49f318a..c7358fcd6b 100644 --- a/src/common/globals.h +++ b/src/common/globals.h @@ -126,6 +126,12 @@ const size_t kShortBuiltinCallsOldSpaceSizeThreshold = size_t{2} * GB; #define V8_DICT_PROPERTY_CONST_TRACKING_BOOL false #endif +#ifdef V8_EXTERNAL_CODE_SPACE +#define V8_EXTERNAL_CODE_SPACE_BOOL true +#else +#define V8_EXTERNAL_CODE_SPACE_BOOL false +#endif + // Determine whether tagged pointers are 8 bytes (used in Torque layouts for // choosing where to insert padding). #if V8_TARGET_ARCH_64_BIT && !defined(V8_COMPRESS_POINTERS) diff --git a/src/diagnostics/objects-debug.cc b/src/diagnostics/objects-debug.cc index 5c746da548..064be0f480 100644 --- a/src/diagnostics/objects-debug.cc +++ b/src/diagnostics/objects-debug.cc @@ -969,6 +969,11 @@ void CodeDataContainer::CodeDataContainerVerify(Isolate* isolate) { CHECK(IsCodeDataContainer()); VerifyObjectField(isolate, kNextCodeLinkOffset); CHECK(next_code_link().IsCode() || next_code_link().IsUndefined(isolate)); + if (V8_EXTERNAL_CODE_SPACE_BOOL) { + if (raw_code() != Smi::zero()) { + CHECK_EQ(code().InstructionStart(), code_entry_point()); + } + } } void Code::CodeVerify(Isolate* isolate) { @@ -984,6 +989,9 @@ void Code::CodeVerify(Isolate* isolate) { IsAligned(InstructionStart(), kCodeAlignment)); CHECK_IMPLIES(!ReadOnlyHeap::Contains(*this), IsAligned(raw_instruction_start(), kCodeAlignment)); + if (V8_EXTERNAL_CODE_SPACE_BOOL) { + CHECK_EQ(*this, code_data_container(kAcquireLoad).code()); + } // TODO(delphick): Refactor Factory::CodeBuilder::BuildInternal, so that the // following CHECK works builtin trampolines. It currently fails because // CodeVerify is called halfway through constructing the trampoline and so not diff --git a/src/diagnostics/objects-printer.cc b/src/diagnostics/objects-printer.cc index 1f1afe1af7..186dc3c26e 100644 --- a/src/diagnostics/objects-printer.cc +++ b/src/diagnostics/objects-printer.cc @@ -79,9 +79,11 @@ void PrintDictionaryContents(std::ostream& os, T dict) { return; } +#ifdef V8_ENABLE_SWISS_NAME_DICTIONARY Isolate* isolate = GetIsolateFromWritableObject(dict); // IterateEntries for SwissNameDictionary needs to create a handle. HandleScope scope(isolate); +#endif for (InternalIndex i : dict.IterateEntries()) { Object k; if (!dict.ToKey(roots, i, &k)) continue; @@ -1639,6 +1641,11 @@ void PropertyCell::PropertyCellPrint(std::ostream& os) { void Code::CodePrint(std::ostream& os) { PrintHeader(os, "Code"); + os << "\n - code_data_container: " + << Brief(code_data_container(kAcquireLoad)); + if (is_builtin()) { + os << "\n - builtin_id: " << Builtins::name(builtin_id()); + } os << "\n"; #ifdef ENABLE_DISASSEMBLER Disassemble(nullptr, os, GetIsolate()); @@ -1648,6 +1655,11 @@ void Code::CodePrint(std::ostream& os) { void CodeDataContainer::CodeDataContainerPrint(std::ostream& os) { PrintHeader(os, "CodeDataContainer"); os << "\n - kind_specific_flags: " << kind_specific_flags(); + if (V8_EXTERNAL_CODE_SPACE_BOOL) { + os << "\n - code: " << Brief(code()); + os << "\n - code_entry_point: " + << reinterpret_cast(code_entry_point()); + } os << "\n"; } diff --git a/src/heap/factory.cc b/src/heap/factory.cc index 713f66fe08..6a985f2a7b 100644 --- a/src/heap/factory.cc +++ b/src/heap/factory.cc @@ -96,10 +96,10 @@ MaybeHandle Factory::CodeBuilder::BuildInternal( (kind_specific_flags_ == 0 || kind_specific_flags_ == promise_rejection_flag)) { const ReadOnlyRoots roots(isolate_); - const auto canonical_code_data_container = + const auto canonical_code_data_container = Handle::cast( kind_specific_flags_ == 0 ? roots.trampoline_trivial_code_data_container_handle() - : roots.trampoline_promise_rejection_code_data_container_handle(); + : roots.trampoline_promise_rejection_code_data_container_handle()); DCHECK_EQ(canonical_code_data_container->kind_specific_flags(), kind_specific_flags_); data_container = canonical_code_data_container; @@ -136,7 +136,9 @@ MaybeHandle Factory::CodeBuilder::BuildInternal( CodePageCollectionMemoryModificationScope code_allocation(heap); HeapObject result; AllocationType allocation_type = - is_executable_ ? AllocationType::kCode : AllocationType::kReadOnly; + V8_EXTERNAL_CODE_SPACE_BOOL || is_executable_ + ? AllocationType::kCode + : AllocationType::kReadOnly; if (retry_allocation_or_fail) { result = heap->AllocateRawWith( object_size, allocation_type, AllocationOrigin::kRuntime); @@ -218,6 +220,9 @@ MaybeHandle Factory::CodeBuilder::BuildInternal( raw_code.clear_padding(); + if (V8_EXTERNAL_CODE_SPACE_BOOL) { + data_container->SetCodeAndEntryPoint(isolate_, raw_code); + } #ifdef VERIFY_HEAP if (FLAG_verify_heap) raw_code.ObjectVerify(isolate_); #endif @@ -2078,6 +2083,11 @@ Handle Factory::NewCodeDataContainer( DisallowGarbageCollection no_gc; data_container.set_next_code_link(*undefined_value(), SKIP_WRITE_BARRIER); data_container.set_kind_specific_flags(flags); + if (V8_EXTERNAL_CODE_SPACE_BOOL) { + data_container.AllocateExternalPointerEntries(isolate()); + data_container.set_raw_code(Smi::zero(), SKIP_WRITE_BARRIER); + data_container.set_code_entry_point(isolate(), kNullAddress); + } data_container.clear_padding(); return handle(data_container, isolate()); } @@ -2137,6 +2147,12 @@ Handle Factory::NewOffHeapTrampolineFor(Handle code, } #endif raw_result.set_relocation_info(canonical_reloc_info); + if (V8_EXTERNAL_CODE_SPACE_BOOL) { + // Updating flags (in particular is_off_heap_trampoline one) might change + // the value of the instruction start, so update it here. + raw_result.code_data_container(kAcquireLoad) + .UpdateCodeEntryPoint(isolate(), raw_result); + } } return result; @@ -2173,6 +2189,9 @@ Handle Factory::CopyCode(Handle code) { WriteBarrierForCode(*new_code); #endif } + if (V8_EXTERNAL_CODE_SPACE_BOOL) { + data_container->SetCodeAndEntryPoint(isolate(), *new_code); + } #ifdef VERIFY_HEAP if (FLAG_verify_heap) new_code->ObjectVerify(isolate()); diff --git a/src/heap/factory.h b/src/heap/factory.h index 86d041ae8c..4c9896e66e 100644 --- a/src/heap/factory.h +++ b/src/heap/factory.h @@ -901,8 +901,13 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase { // Indicates the CodeDataContainer should be allocated in read-only space. // As an optimization, if the kind-specific flags match that of a canonical // container, it will be used instead. - CodeBuilder& set_read_only_data_container(int32_t flags) { - read_only_data_container_ = true; + CodeBuilder& set_read_only_data_container(bool read_only) { + CHECK_IMPLIES(V8_EXTERNAL_CODE_SPACE_BOOL, !read_only); + read_only_data_container_ = read_only; + return *this; + } + + CodeBuilder& set_kind_specific_flags(int32_t flags) { kind_specific_flags_ = flags; return *this; } diff --git a/src/heap/heap-inl.h b/src/heap/heap-inl.h index ed4bb63f1c..8ff3c8f13a 100644 --- a/src/heap/heap-inl.h +++ b/src/heap/heap-inl.h @@ -49,6 +49,19 @@ namespace v8 { namespace internal { +template +T ForwardingAddress(T heap_obj) { + MapWord map_word = heap_obj.map_word(kRelaxedLoad); + + if (map_word.IsForwardingAddress()) { + return T::cast(map_word.ToForwardingAddress()); + } else if (Heap::InFromPage(heap_obj)) { + return T(); + } else { + return heap_obj; + } +} + AllocationSpace AllocationResult::RetrySpace() { DCHECK(IsRetry()); return static_cast(Smi::ToInt(object_)); diff --git a/src/heap/heap.h b/src/heap/heap.h index 0aee7e674a..b97b00c4c5 100644 --- a/src/heap/heap.h +++ b/src/heap/heap.h @@ -2735,17 +2735,7 @@ class HeapObjectAllocationTracker { }; template -T ForwardingAddress(T heap_obj) { - MapWord map_word = heap_obj.map_word(kRelaxedLoad); - - if (map_word.IsForwardingAddress()) { - return T::cast(map_word.ToForwardingAddress()); - } else if (Heap::InFromPage(heap_obj)) { - return T(); - } else { - return heap_obj; - } -} +inline T ForwardingAddress(T heap_obj); // Address block allocator compatible with standard containers which registers // its allocated range as strong roots. diff --git a/src/heap/mark-compact.cc b/src/heap/mark-compact.cc index 206c02ca7c..364d156021 100644 --- a/src/heap/mark-compact.cc +++ b/src/heap/mark-compact.cc @@ -1340,10 +1340,19 @@ class EvacuateVisitorBase : public HeapObjectVisitor { } else if (dest == CODE_SPACE) { DCHECK_CODEOBJECT_SIZE(size, base->heap_->code_space()); base->heap_->CopyBlock(dst_addr, src_addr, size); - Code::cast(dst).Relocate(dst_addr - src_addr); + Code code = Code::cast(dst); + code.Relocate(dst_addr - src_addr); if (mode != MigrationMode::kFast) base->ExecuteMigrationObservers(dest, src, dst, size); dst.IterateBodyFast(dst.map(), size, base->record_visitor_); + if (V8_EXTERNAL_CODE_SPACE_BOOL) { + CodeDataContainer code_data_container = + code.GCSafeCodeDataContainer(kAcquireLoad); + Isolate* isolate_for_sandbox = base->heap_->isolate(); + // Update the |code_entry_point| which is a raw interiour or off-heap + // pointer and thus not handled by the regular updating mechanism. + code_data_container.SetCodeAndEntryPoint(isolate_for_sandbox, code); + } } else { DCHECK_OBJECT_SIZE(size); DCHECK(dest == NEW_SPACE); diff --git a/src/heap/setup-heap-internal.cc b/src/heap/setup-heap-internal.cc index e4ce4712d8..08488eacd0 100644 --- a/src/heap/setup-heap-internal.cc +++ b/src/heap/setup-heap-internal.cc @@ -891,14 +891,22 @@ void Heap::CreateInitialObjects() { set_off_heap_trampoline_relocation_info( *Builtins::GenerateOffHeapTrampolineRelocInfo(isolate_)); - set_trampoline_trivial_code_data_container( - *isolate()->factory()->NewCodeDataContainer(0, - AllocationType::kReadOnly)); + 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); - set_trampoline_promise_rejection_code_data_container( - *isolate()->factory()->NewCodeDataContainer( - Code::IsPromiseRejectionField::encode(true), - AllocationType::kReadOnly)); + } 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)); + } // Evaluate the hash values which will then be cached in the strings. isolate()->factory()->zero_string()->EnsureHash(); diff --git a/src/objects/code-inl.h b/src/objects/code-inl.h index 2ea4e6c4f5..0a942195e1 100644 --- a/src/objects/code-inl.h +++ b/src/objects/code-inl.h @@ -10,6 +10,7 @@ #include "src/codegen/code-desc.h" #include "src/common/assert-scope.h" #include "src/execution/isolate.h" +#include "src/heap/heap-inl.h" #include "src/interpreter/bytecode-register.h" #include "src/objects/code.h" #include "src/objects/dictionary.h" @@ -203,6 +204,17 @@ RELEASE_ACQUIRE_CODE_ACCESSORS(code_data_container, CodeDataContainer, #undef CODE_ACCESSORS #undef RELEASE_ACQUIRE_CODE_ACCESSORS +CodeDataContainer Code::GCSafeCodeDataContainer(AcquireLoadTag) const { + PtrComprCageBase cage_base = GetPtrComprCageBase(*this); + HeapObject object = + TaggedField::Acquire_Load(cage_base, + *this); + DCHECK(!ObjectInYoungGeneration(object)); + CodeDataContainer code_data_container = + ForwardingAddress(CodeDataContainer::unchecked_cast(object)); + return code_data_container; +} + void Code::WipeOutHeader() { WRITE_FIELD(*this, kRelocationInfoOffset, Smi::FromInt(0)); WRITE_FIELD(*this, kDeoptimizationDataOffset, Smi::FromInt(0)); @@ -733,8 +745,47 @@ STATIC_ASSERT(FIELD_SIZE(CodeDataContainer::kKindSpecificFlagsOffset) == kInt32Size); RELAXED_INT32_ACCESSORS(CodeDataContainer, kind_specific_flags, kKindSpecificFlagsOffset) +ACCESSORS_CHECKED(CodeDataContainer, raw_code, Object, kCodeOffset, + V8_EXTERNAL_CODE_SPACE_BOOL) ACCESSORS(CodeDataContainer, next_code_link, Object, kNextCodeLinkOffset) +void CodeDataContainer::AllocateExternalPointerEntries(Isolate* isolate) { + CHECK(V8_EXTERNAL_CODE_SPACE_BOOL); + InitExternalPointerField(kCodeEntryPointOffset, isolate); +} + +DEF_GETTER(CodeDataContainer, code, Code) { + CHECK(V8_EXTERNAL_CODE_SPACE_BOOL); + return Code::cast(raw_code(cage_base)); +} + +DEF_GETTER(CodeDataContainer, code_entry_point, Address) { + CHECK(V8_EXTERNAL_CODE_SPACE_BOOL); + Isolate* isolate = GetIsolateForHeapSandbox(*this); + return ReadExternalPointerField(kCodeEntryPointOffset, isolate, + kCodeEntryPointTag); +} + +void CodeDataContainer::set_code_entry_point(Isolate* isolate, Address value) { + CHECK(V8_EXTERNAL_CODE_SPACE_BOOL); + WriteExternalPointerField(kCodeEntryPointOffset, isolate, value, + kCodeEntryPointTag); +} + +void CodeDataContainer::SetCodeAndEntryPoint(Isolate* isolate_for_sandbox, + Code code, WriteBarrierMode mode) { + CHECK(V8_EXTERNAL_CODE_SPACE_BOOL); + set_raw_code(code, mode); + set_code_entry_point(isolate_for_sandbox, code.InstructionStart()); +} + +void CodeDataContainer::UpdateCodeEntryPoint(Isolate* isolate_for_sandbox, + Code code) { + CHECK(V8_EXTERNAL_CODE_SPACE_BOOL); + DCHECK_EQ(raw_code(), code); + set_code_entry_point(isolate_for_sandbox, code.InstructionStart()); +} + void CodeDataContainer::clear_padding() { memset(reinterpret_cast(address() + kUnalignedSize), 0, kSize - kUnalignedSize); diff --git a/src/objects/code.h b/src/objects/code.h index 49aa55af75..96b375400b 100644 --- a/src/objects/code.h +++ b/src/objects/code.h @@ -47,6 +47,23 @@ class CodeDataContainer : public HeapObject { // is deterministic. inline void clear_padding(); + // Back-reference to the Code object. + // Available only when V8_EXTERNAL_CODE_SPACE is defined. + DECL_GETTER(code, Code) + + // Cached value of code().InstructionStart(). + // Available only when V8_EXTERNAL_CODE_SPACE is defined. + DECL_GETTER(code_entry_point, Address) + + inline void SetCodeAndEntryPoint( + Isolate* isolate_for_sandbox, Code code, + WriteBarrierMode mode = UPDATE_WRITE_BARRIER); + // Updates the value of the code entry point. The code must be equal to + // the code() value. + inline void UpdateCodeEntryPoint(Isolate* isolate_for_sandbox, Code code); + + inline void AllocateExternalPointerEntries(Isolate* isolate); + DECL_CAST(CodeDataContainer) // Dispatched behavior. @@ -54,15 +71,19 @@ class CodeDataContainer : public HeapObject { DECL_VERIFIER(CodeDataContainer) // Layout description. -#define CODE_DATA_FIELDS(V) \ - /* Weak pointer fields. */ \ - V(kPointerFieldsStrongEndOffset, 0) \ - V(kNextCodeLinkOffset, kTaggedSize) \ - V(kPointerFieldsWeakEndOffset, 0) \ - /* Raw data fields. */ \ - V(kKindSpecificFlagsOffset, kInt32Size) \ - V(kUnalignedSize, OBJECT_POINTER_PADDING(kUnalignedSize)) \ - /* Total size. */ \ +#define CODE_DATA_FIELDS(V) \ + /* Strong pointer fields. */ \ + V(kCodeOffset, V8_EXTERNAL_CODE_SPACE_BOOL ? kTaggedSize : 0) \ + V(kPointerFieldsStrongEndOffset, 0) \ + /* Weak pointer fields. */ \ + V(kNextCodeLinkOffset, kTaggedSize) \ + V(kPointerFieldsWeakEndOffset, 0) \ + /* Raw data fields. */ \ + V(kCodeEntryPointOffset, \ + V8_EXTERNAL_CODE_SPACE_BOOL ? kExternalPointerSize : 0) \ + V(kKindSpecificFlagsOffset, kInt32Size) \ + V(kUnalignedSize, OBJECT_POINTER_PADDING(kUnalignedSize)) \ + /* Total size. */ \ V(kSize, 0) DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, CODE_DATA_FIELDS) @@ -70,6 +91,12 @@ class CodeDataContainer : public HeapObject { class BodyDescriptor; + private: + DECL_ACCESSORS(raw_code, Object) + inline void set_code_entry_point(Isolate* isolate, Address value); + + friend Factory; + OBJECT_CONSTRUCTORS(CodeDataContainer, HeapObject); }; @@ -562,6 +589,9 @@ class Code : public HeapObject { private: friend class RelocIterator; + friend class EvacuateVisitorBase; + + inline CodeDataContainer GCSafeCodeDataContainer(AcquireLoadTag) const; bool is_promise_rejection() const; bool is_exception_caught() const; diff --git a/src/objects/objects-body-descriptors-inl.h b/src/objects/objects-body-descriptors-inl.h index 2b25011071..9102016ebb 100644 --- a/src/objects/objects-body-descriptors-inl.h +++ b/src/objects/objects-body-descriptors-inl.h @@ -873,7 +873,7 @@ class CodeDataContainer::BodyDescriptor final : public BodyDescriptorBase { public: static bool IsValidSlot(Map map, HeapObject obj, int offset) { return offset >= CodeDataContainer::kHeaderSize && - offset < CodeDataContainer::kSize; + offset <= CodeDataContainer::kPointerFieldsWeakEndOffset; } template @@ -884,6 +884,12 @@ class CodeDataContainer::BodyDescriptor final : public BodyDescriptorBase { IterateCustomWeakPointers( obj, CodeDataContainer::kPointerFieldsStrongEndOffset, CodeDataContainer::kPointerFieldsWeakEndOffset, v); + + if (V8_EXTERNAL_CODE_SPACE_BOOL) { + // TODO(v8:11880): Currently, the |code| field is still compressed and + // the |code_entry_point| field doesn't require custom visitation, so + // nothing to do here yet. + } } static inline int SizeOf(Map map, HeapObject object) { diff --git a/src/roots/roots.h b/src/roots/roots.h index d4306b3115..e7ec614c63 100644 --- a/src/roots/roots.h +++ b/src/roots/roots.h @@ -190,9 +190,9 @@ class Symbol; /* Canonical off-heap trampoline data */ \ V(ByteArray, off_heap_trampoline_relocation_info, \ OffHeapTrampolineRelocationInfo) \ - V(CodeDataContainer, trampoline_trivial_code_data_container, \ + V(HeapObject, trampoline_trivial_code_data_container, \ TrampolineTrivialCodeDataContainer) \ - V(CodeDataContainer, trampoline_promise_rejection_code_data_container, \ + V(HeapObject, trampoline_promise_rejection_code_data_container, \ TrampolinePromiseRejectionCodeDataContainer) \ /* Canonical scope infos */ \ V(ScopeInfo, global_this_binding_scope_info, GlobalThisBindingScopeInfo) \ diff --git a/src/snapshot/deserializer.cc b/src/snapshot/deserializer.cc index d4f2052655..6be06c2dc8 100644 --- a/src/snapshot/deserializer.cc +++ b/src/snapshot/deserializer.cc @@ -386,6 +386,12 @@ void Deserializer::PostProcessNewObject(Handle map, Handle obj, if (deserializing_user_code()) { new_code_objects_.push_back(Handle::cast(obj)); } + } else if (V8_EXTERNAL_CODE_SPACE_BOOL && + InstanceTypeChecker::IsCodeDataContainer(instance_type)) { + auto code_data_container = Handle::cast(obj); + code_data_container->AllocateExternalPointerEntries(isolate()); + code_data_container->UpdateCodeEntryPoint(isolate(), + code_data_container->code()); } else if (InstanceTypeChecker::IsMap(instance_type)) { if (FLAG_log_maps) { // Keep track of all seen Maps to log them later since they might be only diff --git a/src/snapshot/read-only-serializer.cc b/src/snapshot/read-only-serializer.cc index 3dc5af0b0d..deb5edbe9a 100644 --- a/src/snapshot/read-only-serializer.cc +++ b/src/snapshot/read-only-serializer.cc @@ -42,9 +42,7 @@ void ReadOnlySerializer::SerializeObjectImpl(Handle obj) { // serialize twice. if (*obj != ReadOnlyRoots(isolate()).not_mapped_symbol()) { if (SerializeHotObject(obj)) return; - if (IsRootAndHasBeenSerialized(*obj) && SerializeRoot(obj)) { - return; - } + if (IsRootAndHasBeenSerialized(*obj) && SerializeRoot(obj)) return; if (SerializeBackReference(obj)) return; } diff --git a/src/snapshot/serializer.cc b/src/snapshot/serializer.cc index 14ceb9c7d6..450e1197d1 100644 --- a/src/snapshot/serializer.cc +++ b/src/snapshot/serializer.cc @@ -1079,13 +1079,19 @@ void Serializer::ObjectSerializer::OutputRawData(Address up_to) { } else if (object_->IsDescriptorArray()) { // The number of marked descriptors field can be changed by GC // concurrently. - byte field_value[2]; - field_value[0] = 0; - field_value[1] = 0; + static byte field_value[2] = {0}; OutputRawWithCustomField( sink_, object_start, base, bytes_to_output, DescriptorArray::kRawNumberOfMarkedDescriptorsOffset, sizeof(field_value), field_value); + } else if (V8_EXTERNAL_CODE_SPACE_BOOL && object_->IsCodeDataContainer()) { + // The CodeEntryPoint field is just a cached value which will be + // recomputed after deserialization, so write zeros to keep the snapshot + // deterministic. + static byte field_value[kExternalPointerSize] = {0}; + OutputRawWithCustomField(sink_, object_start, base, bytes_to_output, + CodeDataContainer::kCodeEntryPointOffset, + sizeof(field_value), field_value); } else { sink_->PutRaw(reinterpret_cast(object_start + base), bytes_to_output, "Bytes"); diff --git a/src/torque/torque-parser.cc b/src/torque/torque-parser.cc index c74ef02497..5d0695f2ad 100644 --- a/src/torque/torque-parser.cc +++ b/src/torque/torque-parser.cc @@ -46,6 +46,7 @@ class BuildFlags : public ContextualClass { public: BuildFlags() { build_flags_["V8_SFI_HAS_UNIQUE_ID"] = V8_SFI_HAS_UNIQUE_ID; + build_flags_["V8_EXTERNAL_CODE_SPACE"] = V8_EXTERNAL_CODE_SPACE_BOOL; build_flags_["TAGGED_SIZE_8_BYTES"] = TAGGED_SIZE_8_BYTES; build_flags_["TRUE_FOR_TESTING"] = true; build_flags_["FALSE_FOR_TESTING"] = false;