diff options
Diffstat (limited to 'deps/v8/src/snapshot/deserializer.cc')
-rw-r--r-- | deps/v8/src/snapshot/deserializer.cc | 879 |
1 files changed, 492 insertions, 387 deletions
diff --git a/deps/v8/src/snapshot/deserializer.cc b/deps/v8/src/snapshot/deserializer.cc index 0fb3655949..e71af5266d 100644 --- a/deps/v8/src/snapshot/deserializer.cc +++ b/deps/v8/src/snapshot/deserializer.cc @@ -9,6 +9,7 @@ #include "src/common/assert-scope.h" #include "src/common/globals.h" #include "src/execution/isolate.h" +#include "src/handles/global-handles-inl.h" #include "src/heap/heap-inl.h" #include "src/heap/heap-write-barrier-inl.h" #include "src/heap/heap-write-barrier.h" @@ -195,6 +196,7 @@ Deserializer<IsolateT>::Deserializer(IsolateT* isolate, : isolate_(isolate), source_(payload), magic_number_(magic_number), + new_descriptor_arrays_(isolate->heap()), deserializing_user_code_(deserializing_user_code), should_rehash_((v8_flags.rehash_snapshot && can_rehash) || deserializing_user_code) { @@ -272,21 +274,13 @@ void Deserializer<IsolateT>::LogNewMapEvents() { template <typename IsolateT> void Deserializer<IsolateT>::WeakenDescriptorArrays() { - DisallowGarbageCollection no_gc; - Map descriptor_array_map = ReadOnlyRoots(isolate()).descriptor_array_map(); - for (Handle<DescriptorArray> descriptor_array : new_descriptor_arrays_) { - DescriptorArray raw = *descriptor_array; - DCHECK(raw.IsStrongDescriptorArray()); - raw.set_map_safe_transition(descriptor_array_map); - WriteBarrier::Marking(raw, raw.number_of_descriptors()); - } + isolate()->heap()->WeakenDescriptorArrays(std::move(new_descriptor_arrays_)); } template <typename IsolateT> void Deserializer<IsolateT>::LogScriptEvents(Script script) { DisallowGarbageCollection no_gc; - LOG(isolate(), - ScriptEvent(V8FileLogger::ScriptEventType::kDeserialize, script.id())); + LOG(isolate(), ScriptEvent(ScriptEventType::kDeserialize, script.id())); LOG(isolate(), ScriptDetails(script)); } @@ -362,8 +356,9 @@ void Deserializer<Isolate>::PostProcessNewJSReceiver(Map map, SnapshotSpace space) { DCHECK_EQ(map.instance_type(), instance_type); - if (InstanceTypeChecker::IsJSDataView(instance_type)) { - auto data_view = JSDataView::cast(*obj); + if (InstanceTypeChecker::IsJSDataView(instance_type) || + InstanceTypeChecker::IsJSRabGsabDataView(instance_type)) { + auto data_view = JSDataViewOrRabGsabDataView::cast(*obj); auto buffer = JSArrayBuffer::cast(data_view.buffer()); if (buffer.was_detached()) { // Directly set the data pointer to point to the EmptyBackingStoreBuffer. @@ -441,10 +436,10 @@ void Deserializer<IsolateT>::PostProcessNewObject(Handle<Map> map, // Rehash strings before read-only space is sealed. Strings outside // read-only space are rehashed lazily. (e.g. when rehashing dictionaries) if (space == SnapshotSpace::kReadOnlyHeap) { - to_rehash_.push_back(obj); + PushObjectToRehash(obj); } } else if (raw_obj.NeedsRehashing(instance_type)) { - to_rehash_.push_back(obj); + PushObjectToRehash(obj); } if (deserializing_user_code()) { @@ -490,30 +485,23 @@ void Deserializer<IsolateT>::PostProcessNewObject(Handle<Map> map, } } - if (InstanceTypeChecker::IsCode(instance_type)) { + if (InstanceTypeChecker::IsInstructionStream(instance_type)) { // We flush all code pages after deserializing the startup snapshot. // Hence we only remember each individual code object when deserializing // user code. if (deserializing_user_code()) { - new_code_objects_.push_back(Handle<Code>::cast(obj)); + new_code_objects_.push_back(Handle<InstructionStream>::cast(obj)); } - } else if (V8_EXTERNAL_CODE_SPACE_BOOL && - InstanceTypeChecker::IsCodeDataContainer(instance_type)) { - auto code_data_container = CodeDataContainer::cast(raw_obj); - code_data_container.init_code_entry_point(main_thread_isolate(), - kNullAddress); -#ifdef V8_EXTERNAL_CODE_SPACE - if (V8_EXTERNAL_CODE_SPACE_BOOL && - code_data_container.is_off_heap_trampoline()) { - Address entry = OffHeapInstructionStart(code_data_container, - code_data_container.builtin_id()); - code_data_container.SetEntryPointForOffHeapBuiltin(main_thread_isolate(), - entry); + } else if (InstanceTypeChecker::IsCode(instance_type)) { + Code code = Code::cast(raw_obj); + code.init_code_entry_point(main_thread_isolate(), kNullAddress); + if (!code.has_instruction_stream()) { + code.SetEntryPointForOffHeapBuiltin(main_thread_isolate(), + code.OffHeapInstructionStart()); } else { - code_data_container.UpdateCodeEntryPoint(main_thread_isolate(), - code_data_container.code()); + code.UpdateCodeEntryPoint(main_thread_isolate(), + code.instruction_stream()); } -#endif } else if (InstanceTypeChecker::IsMap(instance_type)) { if (v8_flags.log_maps) { // Keep track of all seen Maps to log them later since they might be only @@ -539,7 +527,7 @@ void Deserializer<IsolateT>::PostProcessNewObject(Handle<Map> map, } else if (InstanceTypeChecker::IsDescriptorArray(instance_type)) { DCHECK(InstanceTypeChecker::IsStrongDescriptorArray(instance_type)); Handle<DescriptorArray> descriptors = Handle<DescriptorArray>::cast(obj); - new_descriptor_arrays_.push_back(descriptors); + new_descriptor_arrays_.Push(*descriptors); } else if (InstanceTypeChecker::IsNativeContext(instance_type)) { NativeContext::cast(raw_obj).init_microtask_queue(main_thread_isolate(), nullptr); @@ -691,7 +679,7 @@ Handle<HeapObject> Deserializer<IsolateT>::ReadObject(SnapshotSpace space) { PostProcessNewObject(map, obj, space); #ifdef DEBUG - if (obj->IsCode(cage_base)) { + if (obj->IsInstructionStream(cage_base)) { DCHECK(space == SnapshotSpace::kCode || space == SnapshotSpace::kReadOnlyHeap); } else { @@ -742,11 +730,11 @@ class DeserializerRelocInfoVisitor { DCHECK_EQ(current_object_, objects_->size()); } - void VisitCodeTarget(Code host, RelocInfo* rinfo); - void VisitEmbeddedPointer(Code host, RelocInfo* rinfo); - void VisitExternalReference(Code host, RelocInfo* rinfo); - void VisitInternalReference(Code host, RelocInfo* rinfo); - void VisitOffHeapTarget(Code host, RelocInfo* rinfo); + void VisitCodeTarget(RelocInfo* rinfo); + void VisitEmbeddedPointer(RelocInfo* rinfo); + void VisitExternalReference(RelocInfo* rinfo); + void VisitInternalReference(RelocInfo* rinfo); + void VisitOffHeapTarget(RelocInfo* rinfo); private: Isolate* isolate() { return deserializer_->isolate(); } @@ -757,21 +745,19 @@ class DeserializerRelocInfoVisitor { int current_object_; }; -void DeserializerRelocInfoVisitor::VisitCodeTarget(Code host, - RelocInfo* rinfo) { +void DeserializerRelocInfoVisitor::VisitCodeTarget(RelocInfo* rinfo) { HeapObject object = *objects_->at(current_object_++); - rinfo->set_target_address(Code::cast(object).raw_instruction_start()); + rinfo->set_target_address( + InstructionStream::cast(object).instruction_start()); } -void DeserializerRelocInfoVisitor::VisitEmbeddedPointer(Code host, - RelocInfo* rinfo) { +void DeserializerRelocInfoVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) { HeapObject object = *objects_->at(current_object_++); // Embedded object reference must be a strong one. rinfo->set_target_object(isolate()->heap(), object); } -void DeserializerRelocInfoVisitor::VisitExternalReference(Code host, - RelocInfo* rinfo) { +void DeserializerRelocInfoVisitor::VisitExternalReference(RelocInfo* rinfo) { byte data = source().Get(); CHECK_EQ(data, Deserializer<Isolate>::kExternalReference); @@ -780,32 +766,27 @@ void DeserializerRelocInfoVisitor::VisitExternalReference(Code host, if (rinfo->IsCodedSpecially()) { Address location_of_branch_data = rinfo->pc(); Assembler::deserialization_set_special_target_at(location_of_branch_data, - host, address); + rinfo->code(), address); } else { WriteUnalignedValue(rinfo->target_address_address(), address); } } -void DeserializerRelocInfoVisitor::VisitInternalReference(Code host, - RelocInfo* rinfo) { +void DeserializerRelocInfoVisitor::VisitInternalReference(RelocInfo* rinfo) { byte data = source().Get(); CHECK_EQ(data, Deserializer<Isolate>::kInternalReference); - // Internal reference target is encoded as an offset from code entry. + // An internal reference target is encoded as an offset from code entry. int target_offset = source().GetInt(); - // TODO(jgruber,v8:11036): We are being permissive for this DCHECK, but - // consider using raw_instruction_size() instead of raw_body_size() in the - // future. - static_assert(Code::kOnHeapBodyIsContiguous); + static_assert(InstructionStream::kOnHeapBodyIsContiguous); DCHECK_LT(static_cast<unsigned>(target_offset), - static_cast<unsigned>(host.raw_body_size())); - Address target = host.entry() + target_offset; + static_cast<unsigned>(rinfo->code().instruction_size())); + Address target = rinfo->code().InstructionStart() + target_offset; Assembler::deserialization_set_target_internal_reference_at( rinfo->pc(), target, rinfo->rmode()); } -void DeserializerRelocInfoVisitor::VisitOffHeapTarget(Code host, - RelocInfo* rinfo) { +void DeserializerRelocInfoVisitor::VisitOffHeapTarget(RelocInfo* rinfo) { // Currently we don't serialize code that contains near builtin entries. DCHECK_NE(rinfo->rmode(), RelocInfo::NEAR_BUILTIN_ENTRY); @@ -823,7 +804,7 @@ void DeserializerRelocInfoVisitor::VisitOffHeapTarget(Code host, if (RelocInfo::OffHeapTargetIsCodedSpecially()) { Address location_of_branch_data = rinfo->pc(); Assembler::deserialization_set_special_target_at(location_of_branch_data, - host, address); + rinfo->code(), address); } else { WriteUnalignedValue(rinfo->target_address_address(), address); } @@ -905,366 +886,490 @@ template <typename IsolateT> template <typename SlotAccessor> int Deserializer<IsolateT>::ReadSingleBytecodeData(byte data, SlotAccessor slot_accessor) { - using TSlot = decltype(slot_accessor.slot()); - switch (data) { - // Deserialize a new object and write a pointer to it to the current - // object. - case CASE_RANGE_ALL_SPACES(kNewObject): { - SnapshotSpace space = NewObject::Decode(data); - // Save the reference type before recursing down into reading the object. - HeapObjectReferenceType ref_type = GetAndResetNextReferenceType(); - Handle<HeapObject> heap_object = ReadObject(space); - return slot_accessor.Write(heap_object, ref_type); - } - - // Find a recently deserialized object using its offset from the current - // allocation point and write a pointer to it to the current object. - case kBackref: { - Handle<HeapObject> heap_object = GetBackReferencedObject(); - return slot_accessor.Write(heap_object, GetAndResetNextReferenceType()); - } - - // Reference an object in the read-only heap. This should be used when an - // object is read-only, but is not a root. - case kReadOnlyHeapRef: { - DCHECK(isolate()->heap()->deserialization_complete()); - uint32_t chunk_index = source_.GetInt(); - uint32_t chunk_offset = source_.GetInt(); - - ReadOnlySpace* read_only_space = isolate()->heap()->read_only_space(); - ReadOnlyPage* page = read_only_space->pages()[chunk_index]; - Address address = page->OffsetToAddress(chunk_offset); - HeapObject heap_object = HeapObject::FromAddress(address); + case CASE_RANGE_ALL_SPACES(kNewObject): + return ReadNewObject(data, slot_accessor); + case kBackref: + return ReadBackref(data, slot_accessor); + case kReadOnlyHeapRef: + return ReadReadOnlyHeapRef(data, slot_accessor); + case kRootArray: + return ReadRootArray(data, slot_accessor); + case kStartupObjectCache: + return ReadStartupObjectCache(data, slot_accessor); + case kReadOnlyObjectCache: + return ReadReadOnlyObjectCache(data, slot_accessor); + case kSharedHeapObjectCache: + return ReadSharedHeapObjectCache(data, slot_accessor); + case kNewMetaMap: + return ReadNewMetaMap(data, slot_accessor); + case kSandboxedExternalReference: + case kExternalReference: + return ReadExternalReference(data, slot_accessor); + case kSandboxedRawExternalReference: + case kRawExternalReference: + return ReadRawExternalReference(data, slot_accessor); + case kInternalReference: + case kOffHeapTarget: + // These bytecodes are expected only during RelocInfo iteration. + UNREACHABLE(); + case kAttachedReference: + return ReadAttachedReference(data, slot_accessor); + case kNop: + return 0; + case kRegisterPendingForwardRef: + return ReadRegisterPendingForwardRef(data, slot_accessor); + case kResolvePendingForwardRef: + return ReadResolvePendingForwardRef(data, slot_accessor); + case kSynchronize: + // If we get here then that indicates that you have a mismatch between + // the number of GC roots when serializing and deserializing. + UNREACHABLE(); + case kVariableRawData: + return ReadVariableRawData(data, slot_accessor); + case kCodeBody: + return ReadCodeBody(data, slot_accessor); + case kVariableRepeat: + return ReadVariableRepeat(data, slot_accessor); + case kOffHeapBackingStore: + case kOffHeapResizableBackingStore: + return ReadOffHeapBackingStore(data, slot_accessor); + case kSandboxedApiReference: + case kApiReference: + return ReadApiReference(data, slot_accessor); + case kClearedWeakReference: + return ReadClearedWeakReference(data, slot_accessor); + case kWeakPrefix: + return ReadWeakPrefix(data, slot_accessor); + case CASE_RANGE(kRootArrayConstants, 32): + return ReadRootArrayConstants(data, slot_accessor); + case CASE_RANGE(kHotObject, 8): + return ReadHotObject(data, slot_accessor); + case CASE_RANGE(kFixedRawData, 32): + return ReadFixedRawData(data, slot_accessor); + case CASE_RANGE(kFixedRepeat, 16): + return ReadFixedRepeat(data, slot_accessor); - return slot_accessor.Write(heap_object, GetAndResetNextReferenceType()); - } +#ifdef DEBUG +#define UNUSED_CASE(byte_code) \ + case byte_code: \ + UNREACHABLE(); + UNUSED_SERIALIZER_BYTE_CODES(UNUSED_CASE) +#endif +#undef UNUSED_CASE + } - // Find an object in the roots array and write a pointer to it to the - // current object. - case kRootArray: { - int id = source_.GetInt(); - RootIndex root_index = static_cast<RootIndex>(id); - Handle<HeapObject> heap_object = - Handle<HeapObject>::cast(isolate()->root_handle(root_index)); - hot_objects_.Add(heap_object); - return slot_accessor.Write(heap_object, GetAndResetNextReferenceType()); - } + // The above switch, including UNUSED_SERIALIZER_BYTE_CODES, covers all + // possible bytecodes; but, clang doesn't realize this, so we have an explicit + // UNREACHABLE here too. + UNREACHABLE(); +} - // Find an object in the startup object cache and write a pointer to it to - // the current object. - case kStartupObjectCache: { - int cache_index = source_.GetInt(); - // TODO(leszeks): Could we use the address of the startup_object_cache - // entry as a Handle backing? - HeapObject heap_object = HeapObject::cast( - main_thread_isolate()->startup_object_cache()->at(cache_index)); - return slot_accessor.Write(heap_object, GetAndResetNextReferenceType()); - } +// Deserialize a new object and write a pointer to it to the current +// object. +template <typename IsolateT> +template <typename SlotAccessor> +int Deserializer<IsolateT>::ReadNewObject(byte data, + SlotAccessor slot_accessor) { + SnapshotSpace space = NewObject::Decode(data); + DCHECK_IMPLIES(V8_STATIC_ROOTS_BOOL, space != SnapshotSpace::kReadOnlyHeap); + // Save the reference type before recursing down into reading the object. + HeapObjectReferenceType ref_type = GetAndResetNextReferenceType(); + Handle<HeapObject> heap_object = ReadObject(space); + return slot_accessor.Write(heap_object, ref_type); +} - // Find an object in the read-only object cache and write a pointer to it - // to the current object. - case kReadOnlyObjectCache: { - int cache_index = source_.GetInt(); - // TODO(leszeks): Could we use the address of the cached_read_only_object - // entry as a Handle backing? - HeapObject heap_object = HeapObject::cast( - isolate()->read_only_heap()->cached_read_only_object(cache_index)); - return slot_accessor.Write(heap_object, GetAndResetNextReferenceType()); - } +// Find a recently deserialized object using its offset from the current +// allocation point and write a pointer to it to the current object. +template <typename IsolateT> +template <typename SlotAccessor> +int Deserializer<IsolateT>::ReadBackref(byte data, SlotAccessor slot_accessor) { + Handle<HeapObject> heap_object = GetBackReferencedObject(); + return slot_accessor.Write(heap_object, GetAndResetNextReferenceType()); +} - // Find an object in the shared heap object cache and write a pointer to it - // to the current object. - case kSharedHeapObjectCache: { - int cache_index = source_.GetInt(); - // TODO(leszeks): Could we use the address of the - // shared_heap_object_cache entry as a Handle backing? - HeapObject heap_object = HeapObject::cast( - main_thread_isolate()->shared_heap_object_cache()->at(cache_index)); - DCHECK( - SharedHeapSerializer::ShouldBeInSharedHeapObjectCache(heap_object)); - return slot_accessor.Write(heap_object, GetAndResetNextReferenceType()); - } +// Reference an object in the read-only heap. This should be used when an +// object is read-only, but is not a root. Except with static roots we +// always use this reference to refer to read only objects since they are +// created by loading a memory dump of r/o space. +template <typename IsolateT> +template <typename SlotAccessor> +int Deserializer<IsolateT>::ReadReadOnlyHeapRef(byte data, + SlotAccessor slot_accessor) { + DCHECK(isolate()->heap()->deserialization_complete() || V8_STATIC_ROOTS_BOOL); + uint32_t chunk_index = source_.GetInt(); + uint32_t chunk_offset = source_.GetInt(); + + ReadOnlySpace* read_only_space = isolate()->heap()->read_only_space(); + ReadOnlyPage* page = read_only_space->pages()[chunk_index]; + Address address = page->OffsetToAddress(chunk_offset); + HeapObject heap_object = HeapObject::FromAddress(address); + + return slot_accessor.Write(heap_object, GetAndResetNextReferenceType()); +} - // Deserialize a new meta-map and write a pointer to it to the current - // object. - case kNewMetaMap: { - Handle<HeapObject> heap_object = ReadMetaMap(); - return slot_accessor.Write(heap_object, HeapObjectReferenceType::STRONG); - } +// Find an object in the roots array and write a pointer to it to the +// current object. +template <typename IsolateT> +template <typename SlotAccessor> +int Deserializer<IsolateT>::ReadRootArray(byte data, + SlotAccessor slot_accessor) { + int id = source_.GetInt(); + RootIndex root_index = static_cast<RootIndex>(id); + Handle<HeapObject> heap_object = + Handle<HeapObject>::cast(isolate()->root_handle(root_index)); + hot_objects_.Add(heap_object); + return slot_accessor.Write(heap_object, GetAndResetNextReferenceType()); +} - // Find an external reference and write a pointer to it to the current - // object. - case kSandboxedExternalReference: - case kExternalReference: { - DCHECK_IMPLIES(data == kSandboxedExternalReference, - V8_ENABLE_SANDBOX_BOOL); - Address address = ReadExternalReferenceCase(); - ExternalPointerTag tag = kExternalPointerNullTag; - if (data == kSandboxedExternalReference) { - tag = ReadExternalPointerTag(); - } - return WriteExternalPointer(slot_accessor.external_pointer_slot(), - address, tag); - } +// Find an object in the startup object cache and write a pointer to it to +// the current object. +template <typename IsolateT> +template <typename SlotAccessor> +int Deserializer<IsolateT>::ReadStartupObjectCache(byte data, + SlotAccessor slot_accessor) { + int cache_index = source_.GetInt(); + // TODO(leszeks): Could we use the address of the startup_object_cache + // entry as a Handle backing? + HeapObject heap_object = HeapObject::cast( + main_thread_isolate()->startup_object_cache()->at(cache_index)); + return slot_accessor.Write(heap_object, GetAndResetNextReferenceType()); +} - case kSandboxedRawExternalReference: - case kRawExternalReference: { - DCHECK_IMPLIES(data == kSandboxedExternalReference, - V8_ENABLE_SANDBOX_BOOL); - Address address; - source_.CopyRaw(&address, kSystemPointerSize); - ExternalPointerTag tag = kExternalPointerNullTag; - if (data == kSandboxedRawExternalReference) { - tag = ReadExternalPointerTag(); - } - return WriteExternalPointer(slot_accessor.external_pointer_slot(), - address, tag); - } +// Find an object in the read-only object cache and write a pointer to it +// to the current object. +template <typename IsolateT> +template <typename SlotAccessor> +int Deserializer<IsolateT>::ReadReadOnlyObjectCache( + byte data, SlotAccessor slot_accessor) { + DCHECK(!V8_STATIC_ROOTS_BOOL); + int cache_index = source_.GetInt(); + // TODO(leszeks): Could we use the address of the cached_read_only_object + // entry as a Handle backing? + HeapObject heap_object = HeapObject::cast( + isolate()->read_only_heap()->cached_read_only_object(cache_index)); + return slot_accessor.Write(heap_object, GetAndResetNextReferenceType()); +} - case kInternalReference: - case kOffHeapTarget: - // These bytecodes are expected only during RelocInfo iteration. - UNREACHABLE(); +// Find an object in the shared heap object cache and write a pointer to it +// to the current object. +template <typename IsolateT> +template <typename SlotAccessor> +int Deserializer<IsolateT>::ReadSharedHeapObjectCache( + byte data, SlotAccessor slot_accessor) { + int cache_index = source_.GetInt(); + // TODO(leszeks): Could we use the address of the + // shared_heap_object_cache entry as a Handle backing? + HeapObject heap_object = HeapObject::cast( + main_thread_isolate()->shared_heap_object_cache()->at(cache_index)); + DCHECK(SharedHeapSerializer::ShouldBeInSharedHeapObjectCache(heap_object)); + return slot_accessor.Write(heap_object, GetAndResetNextReferenceType()); +} - // Find an object in the attached references and write a pointer to it to - // the current object. - case kAttachedReference: { - int index = source_.GetInt(); - Handle<HeapObject> heap_object = attached_objects_[index]; - return slot_accessor.Write(heap_object, GetAndResetNextReferenceType()); - } +// Deserialize a new meta-map and write a pointer to it to the current +// object. +template <typename IsolateT> +template <typename SlotAccessor> +int Deserializer<IsolateT>::ReadNewMetaMap(byte data, + SlotAccessor slot_accessor) { + Handle<HeapObject> heap_object = ReadMetaMap(); + return slot_accessor.Write(heap_object, HeapObjectReferenceType::STRONG); +} - case kNop: - return 0; +// Find an external reference and write a pointer to it to the current +// object. +template <typename IsolateT> +template <typename SlotAccessor> +int Deserializer<IsolateT>::ReadExternalReference(byte data, + SlotAccessor slot_accessor) { + DCHECK_IMPLIES(data == kSandboxedExternalReference, V8_ENABLE_SANDBOX_BOOL); + Address address = ReadExternalReferenceCase(); + ExternalPointerTag tag = kExternalPointerNullTag; + if (data == kSandboxedExternalReference) { + tag = ReadExternalPointerTag(); + } + return WriteExternalPointer(slot_accessor.external_pointer_slot(), address, + tag); +} - case kRegisterPendingForwardRef: { - HeapObjectReferenceType ref_type = GetAndResetNextReferenceType(); - unresolved_forward_refs_.emplace_back(slot_accessor.object(), - slot_accessor.offset(), ref_type); - num_unresolved_forward_refs_++; - return 1; - } +template <typename IsolateT> +template <typename SlotAccessor> +int Deserializer<IsolateT>::ReadRawExternalReference( + byte data, SlotAccessor slot_accessor) { + DCHECK_IMPLIES(data == kSandboxedExternalReference, V8_ENABLE_SANDBOX_BOOL); + Address address; + source_.CopyRaw(&address, kSystemPointerSize); + ExternalPointerTag tag = kExternalPointerNullTag; + if (data == kSandboxedRawExternalReference) { + tag = ReadExternalPointerTag(); + } + return WriteExternalPointer(slot_accessor.external_pointer_slot(), address, + tag); +} - case kResolvePendingForwardRef: { - // Pending forward refs can only be resolved after the heap object's map - // field is deserialized; currently they only appear immediately after - // the map field. - DCHECK_EQ(slot_accessor.offset(), HeapObject::kHeaderSize); - Handle<HeapObject> obj = slot_accessor.object(); - int index = source_.GetInt(); - auto& forward_ref = unresolved_forward_refs_[index]; - SlotAccessorForHeapObject::ForSlotOffset(forward_ref.object, - forward_ref.offset) - .Write(*obj, forward_ref.ref_type); - num_unresolved_forward_refs_--; - if (num_unresolved_forward_refs_ == 0) { - // If there's no more pending fields, clear the entire pending field - // vector. - unresolved_forward_refs_.clear(); - } else { - // Otherwise, at least clear the pending field. - forward_ref.object = Handle<HeapObject>(); - } - return 0; - } +// Find an object in the attached references and write a pointer to it to +// the current object. +template <typename IsolateT> +template <typename SlotAccessor> +int Deserializer<IsolateT>::ReadAttachedReference(byte data, + SlotAccessor slot_accessor) { + int index = source_.GetInt(); + Handle<HeapObject> heap_object = attached_objects_[index]; + return slot_accessor.Write(heap_object, GetAndResetNextReferenceType()); +} - case kSynchronize: - // If we get here then that indicates that you have a mismatch between - // the number of GC roots when serializing and deserializing. - UNREACHABLE(); +template <typename IsolateT> +template <typename SlotAccessor> +int Deserializer<IsolateT>::ReadRegisterPendingForwardRef( + byte data, SlotAccessor slot_accessor) { + HeapObjectReferenceType ref_type = GetAndResetNextReferenceType(); + unresolved_forward_refs_.emplace_back(slot_accessor.object(), + slot_accessor.offset(), ref_type); + num_unresolved_forward_refs_++; + return 1; +} - // Deserialize raw data of variable length. - case kVariableRawData: { - // This operation is only supported for tagged-size slots, else we might - // become misaligned. - DCHECK_EQ(TSlot::kSlotDataSize, kTaggedSize); - int size_in_tagged = source_.GetInt(); - // TODO(leszeks): Only copy slots when there are Smis in the serialized - // data. - source_.CopySlots(slot_accessor.slot().location(), size_in_tagged); - return size_in_tagged; - } +template <typename IsolateT> +template <typename SlotAccessor> +int Deserializer<IsolateT>::ReadResolvePendingForwardRef( + byte data, SlotAccessor slot_accessor) { + // Pending forward refs can only be resolved after the heap object's map + // field is deserialized; currently they only appear immediately after + // the map field. + DCHECK_EQ(slot_accessor.offset(), HeapObject::kHeaderSize); + Handle<HeapObject> obj = slot_accessor.object(); + int index = source_.GetInt(); + auto& forward_ref = unresolved_forward_refs_[index]; + SlotAccessorForHeapObject::ForSlotOffset(forward_ref.object, + forward_ref.offset) + .Write(*obj, forward_ref.ref_type); + num_unresolved_forward_refs_--; + if (num_unresolved_forward_refs_ == 0) { + // If there's no more pending fields, clear the entire pending field + // vector. + unresolved_forward_refs_.clear(); + } else { + // Otherwise, at least clear the pending field. + forward_ref.object = Handle<HeapObject>(); + } + return 0; +} - // Deserialize raw code directly into the body of the code object. - case kCodeBody: { - // This operation is only supported for tagged-size slots, else we might - // become misaligned. - DCHECK_EQ(TSlot::kSlotDataSize, kTaggedSize); - // CodeBody can only occur right after the heap object header. - DCHECK_EQ(slot_accessor.offset(), HeapObject::kHeaderSize); - - int size_in_tagged = source_.GetInt(); - int size_in_bytes = size_in_tagged * kTaggedSize; - - { - DisallowGarbageCollection no_gc; - Code code = Code::cast(*slot_accessor.object()); - - // First deserialize the code itself. - source_.CopyRaw( - reinterpret_cast<void*>(code.address() + Code::kDataStart), - size_in_bytes); - } +// Deserialize raw data of variable length. +template <typename IsolateT> +template <typename SlotAccessor> +int Deserializer<IsolateT>::ReadVariableRawData(byte data, + SlotAccessor slot_accessor) { + // This operation is only supported for tagged-size slots, else we might + // become misaligned. + DCHECK_EQ(decltype(slot_accessor.slot())::kSlotDataSize, kTaggedSize); + int size_in_tagged = source_.GetInt(); + // TODO(leszeks): Only copy slots when there are Smis in the serialized + // data. + source_.CopySlots(slot_accessor.slot().location(), size_in_tagged); + return size_in_tagged; +} - // Then deserialize the code header - ReadData(slot_accessor.object(), HeapObject::kHeaderSize / kTaggedSize, - Code::kDataStart / kTaggedSize); +// Custom deserialization for a Code object and its associated InstructionStream +// object. +template <typename IsolateT> +template <typename SlotAccessor> +int Deserializer<IsolateT>::ReadCodeBody(byte data, + SlotAccessor slot_accessor) { + // This operation is only supported for tagged-size slots, else we might + // become misaligned. + DCHECK_EQ(decltype(slot_accessor.slot())::kSlotDataSize, kTaggedSize); + // CodeBody can only occur right after the heap object header. + DCHECK_EQ(slot_accessor.offset(), HeapObject::kHeaderSize); + + int size_in_tagged = source_.GetInt(); + int size_in_bytes = size_in_tagged * kTaggedSize; + + { + DisallowGarbageCollection no_gc; + InstructionStream istream = + InstructionStream::cast(*slot_accessor.object()); + + // First deserialize the untagged region of the InstructionStream object. + source_.CopyRaw(reinterpret_cast<void*>(istream.address() + + InstructionStream::kDataStart), + size_in_bytes); + } - // Then deserialize the pre-serialized RelocInfo objects. - std::vector<Handle<HeapObject>> preserialized_objects; - while (source_.Peek() != kSynchronize) { - Handle<HeapObject> obj = ReadObject(); - preserialized_objects.push_back(obj); - } - // Skip the synchronize bytecode. - source_.Advance(1); - - // Finally iterate RelocInfos (the same way it was done by the serializer) - // and deserialize respective data into RelocInfos. The RelocIterator - // holds a raw pointer to the code, so we have to disable garbage - // collection here. It's ok though, any objects it would have needed are - // in the preserialized_objects vector. - { - DisallowGarbageCollection no_gc; - - Code code = Code::cast(*slot_accessor.object()); - if (V8_EXTERNAL_CODE_SPACE_BOOL) { - code.set_main_cage_base(isolate()->cage_base(), kRelaxedStore); - } - DeserializerRelocInfoVisitor visitor(this, &preserialized_objects); - for (RelocIterator it(code, Code::BodyDescriptor::kRelocModeMask); - !it.done(); it.next()) { - it.rinfo()->Visit(&visitor); - } - } + // Then deserialize the InstructionStream header + ReadData(slot_accessor.object(), HeapObject::kHeaderSize / kTaggedSize, + InstructionStream::kDataStart / kTaggedSize); - // Advance to the end of the code object. - return (int{Code::kDataStart} - HeapObject::kHeaderSize) / kTaggedSize + - size_in_tagged; + // Then deserialize the pre-serialized RelocInfo objects. + std::vector<Handle<HeapObject>> preserialized_objects; + while (source_.Peek() != kSynchronize) { + Handle<HeapObject> obj = ReadObject(); + preserialized_objects.push_back(obj); + } + // Skip the synchronize bytecode. + source_.Advance(1); + + // Finally iterate RelocInfos (the same way it was done by the serializer) + // and deserialize respective data into RelocInfos. The RelocIterator + // holds a raw pointer to the code, so we have to disable garbage + // collection here. It's ok though, any objects it would have needed are + // in the preserialized_objects vector. + { + DisallowGarbageCollection no_gc; + + InstructionStream istream = + InstructionStream::cast(*slot_accessor.object()); + if (V8_EXTERNAL_CODE_SPACE_BOOL) { + istream.set_main_cage_base(isolate()->cage_base(), kRelaxedStore); } - - case kVariableRepeat: { - int repeats = VariableRepeatCount::Decode(source_.GetInt()); - return ReadRepeatedObject(slot_accessor, repeats); + Code code = istream.code(kAcquireLoad); + DeserializerRelocInfoVisitor visitor(this, &preserialized_objects); + for (RelocIterator it(code, istream, code.relocation_info(), + code.constant_pool(), + InstructionStream::BodyDescriptor::kRelocModeMask); + !it.done(); it.next()) { + it.rinfo()->Visit(&visitor); } + } - case kOffHeapBackingStore: - case kOffHeapResizableBackingStore: { - int byte_length = source_.GetInt(); - std::unique_ptr<BackingStore> backing_store; - if (data == kOffHeapBackingStore) { - backing_store = BackingStore::Allocate( - main_thread_isolate(), byte_length, SharedFlag::kNotShared, - InitializedFlag::kUninitialized); - } else { - int max_byte_length = source_.GetInt(); - size_t page_size, initial_pages, max_pages; - Maybe<bool> result = - JSArrayBuffer::GetResizableBackingStorePageConfiguration( - nullptr, byte_length, max_byte_length, kDontThrow, &page_size, - &initial_pages, &max_pages); - DCHECK(result.FromJust()); - USE(result); - backing_store = BackingStore::TryAllocateAndPartiallyCommitMemory( - main_thread_isolate(), byte_length, max_byte_length, page_size, - initial_pages, max_pages, WasmMemoryFlag::kNotWasm, - SharedFlag::kNotShared); - } - CHECK_NOT_NULL(backing_store); - source_.CopyRaw(backing_store->buffer_start(), byte_length); - backing_stores_.push_back(std::move(backing_store)); - return 0; - } + // Advance to the end of the code object. + return (int{InstructionStream::kDataStart} - HeapObject::kHeaderSize) / + kTaggedSize + + size_in_tagged; +} - case kSandboxedApiReference: - case kApiReference: { - DCHECK_IMPLIES(data == kSandboxedExternalReference, - V8_ENABLE_SANDBOX_BOOL); - uint32_t reference_id = static_cast<uint32_t>(source_.GetInt()); - Address address; - if (main_thread_isolate()->api_external_references()) { - DCHECK_WITH_MSG(reference_id < num_api_references_, - "too few external references provided through the API"); - address = static_cast<Address>( - main_thread_isolate()->api_external_references()[reference_id]); - } else { - address = reinterpret_cast<Address>(NoExternalReferencesCallback); - } - ExternalPointerTag tag = kExternalPointerNullTag; - if (data == kSandboxedApiReference) { - tag = ReadExternalPointerTag(); - } - return WriteExternalPointer(slot_accessor.external_pointer_slot(), - address, tag); - } +template <typename IsolateT> +template <typename SlotAccessor> +int Deserializer<IsolateT>::ReadVariableRepeat(byte data, + SlotAccessor slot_accessor) { + int repeats = VariableRepeatCount::Decode(source_.GetInt()); + return ReadRepeatedObject(slot_accessor, repeats); +} - case kClearedWeakReference: - return slot_accessor.Write(HeapObjectReference::ClearedValue(isolate())); - - case kWeakPrefix: { - // We shouldn't have two weak prefixes in a row. - DCHECK(!next_reference_is_weak_); - // We shouldn't have weak refs without a current object. - DCHECK_NE(slot_accessor.object()->address(), kNullAddress); - next_reference_is_weak_ = true; - return 0; - } +template <typename IsolateT> +template <typename SlotAccessor> +int Deserializer<IsolateT>::ReadOffHeapBackingStore( + byte data, SlotAccessor slot_accessor) { + int byte_length = source_.GetInt(); + std::unique_ptr<BackingStore> backing_store; + if (data == kOffHeapBackingStore) { + backing_store = BackingStore::Allocate(main_thread_isolate(), byte_length, + SharedFlag::kNotShared, + InitializedFlag::kUninitialized); + } else { + int max_byte_length = source_.GetInt(); + size_t page_size, initial_pages, max_pages; + Maybe<bool> result = + JSArrayBuffer::GetResizableBackingStorePageConfiguration( + nullptr, byte_length, max_byte_length, kDontThrow, &page_size, + &initial_pages, &max_pages); + DCHECK(result.FromJust()); + USE(result); + backing_store = BackingStore::TryAllocateAndPartiallyCommitMemory( + main_thread_isolate(), byte_length, max_byte_length, page_size, + initial_pages, max_pages, WasmMemoryFlag::kNotWasm, + SharedFlag::kNotShared); + } + CHECK_NOT_NULL(backing_store); + source_.CopyRaw(backing_store->buffer_start(), byte_length); + backing_stores_.push_back(std::move(backing_store)); + return 0; +} - case CASE_RANGE(kRootArrayConstants, 32): { - // First kRootArrayConstantsCount roots are guaranteed to be in - // the old space. - static_assert(static_cast<int>(RootIndex::kFirstImmortalImmovableRoot) == - 0); - static_assert(kRootArrayConstantsCount <= - static_cast<int>(RootIndex::kLastImmortalImmovableRoot)); - - RootIndex root_index = RootArrayConstant::Decode(data); - Handle<HeapObject> heap_object = - Handle<HeapObject>::cast(isolate()->root_handle(root_index)); - return slot_accessor.Write(heap_object, HeapObjectReferenceType::STRONG); - } +template <typename IsolateT> +template <typename SlotAccessor> +int Deserializer<IsolateT>::ReadApiReference(byte data, + SlotAccessor slot_accessor) { + DCHECK_IMPLIES(data == kSandboxedExternalReference, V8_ENABLE_SANDBOX_BOOL); + uint32_t reference_id = static_cast<uint32_t>(source_.GetInt()); + Address address; + if (main_thread_isolate()->api_external_references()) { + DCHECK_WITH_MSG(reference_id < num_api_references_, + "too few external references provided through the API"); + address = static_cast<Address>( + main_thread_isolate()->api_external_references()[reference_id]); + } else { + address = reinterpret_cast<Address>(NoExternalReferencesCallback); + } + ExternalPointerTag tag = kExternalPointerNullTag; + if (data == kSandboxedApiReference) { + tag = ReadExternalPointerTag(); + } + return WriteExternalPointer(slot_accessor.external_pointer_slot(), address, + tag); +} - case CASE_RANGE(kHotObject, 8): { - int index = HotObject::Decode(data); - Handle<HeapObject> hot_object = hot_objects_.Get(index); - return slot_accessor.Write(hot_object, GetAndResetNextReferenceType()); - } +template <typename IsolateT> +template <typename SlotAccessor> +int Deserializer<IsolateT>::ReadClearedWeakReference( + byte data, SlotAccessor slot_accessor) { + return slot_accessor.Write(HeapObjectReference::ClearedValue(isolate())); +} - case CASE_RANGE(kFixedRawData, 32): { - // Deserialize raw data of fixed length from 1 to 32 times kTaggedSize. - int size_in_tagged = FixedRawDataWithSize::Decode(data); - static_assert(TSlot::kSlotDataSize == kTaggedSize || - TSlot::kSlotDataSize == 2 * kTaggedSize); - int size_in_slots = size_in_tagged / (TSlot::kSlotDataSize / kTaggedSize); - // kFixedRawData can have kTaggedSize != TSlot::kSlotDataSize when - // serializing Smi roots in pointer-compressed builds. In this case, the - // size in bytes is unconditionally the (full) slot size. - DCHECK_IMPLIES(kTaggedSize != TSlot::kSlotDataSize, size_in_slots == 1); - // TODO(leszeks): Only copy slots when there are Smis in the serialized - // data. - source_.CopySlots(slot_accessor.slot().location(), size_in_slots); - return size_in_slots; - } +template <typename IsolateT> +template <typename SlotAccessor> +int Deserializer<IsolateT>::ReadWeakPrefix(byte data, + SlotAccessor slot_accessor) { + // We shouldn't have two weak prefixes in a row. + DCHECK(!next_reference_is_weak_); + // We shouldn't have weak refs without a current object. + DCHECK_NE(slot_accessor.object()->address(), kNullAddress); + next_reference_is_weak_ = true; + return 0; +} - case CASE_RANGE(kFixedRepeat, 16): { - int repeats = FixedRepeatWithCount::Decode(data); - return ReadRepeatedObject(slot_accessor, repeats); - } +template <typename IsolateT> +template <typename SlotAccessor> +int Deserializer<IsolateT>::ReadRootArrayConstants(byte data, + SlotAccessor slot_accessor) { + // First kRootArrayConstantsCount roots are guaranteed to be in + // the old space. + static_assert(static_cast<int>(RootIndex::kFirstImmortalImmovableRoot) == 0); + static_assert(kRootArrayConstantsCount <= + static_cast<int>(RootIndex::kLastImmortalImmovableRoot)); + + RootIndex root_index = RootArrayConstant::Decode(data); + Handle<HeapObject> heap_object = + Handle<HeapObject>::cast(isolate()->root_handle(root_index)); + return slot_accessor.Write(heap_object, HeapObjectReferenceType::STRONG); +} -#ifdef DEBUG -#define UNUSED_CASE(byte_code) \ - case byte_code: \ - UNREACHABLE(); - UNUSED_SERIALIZER_BYTE_CODES(UNUSED_CASE) -#endif -#undef UNUSED_CASE - } +template <typename IsolateT> +template <typename SlotAccessor> +int Deserializer<IsolateT>::ReadHotObject(byte data, + SlotAccessor slot_accessor) { + int index = HotObject::Decode(data); + Handle<HeapObject> hot_object = hot_objects_.Get(index); + return slot_accessor.Write(hot_object, GetAndResetNextReferenceType()); +} - // The above switch, including UNUSED_SERIALIZER_BYTE_CODES, covers all - // possible bytecodes; but, clang doesn't realize this, so we have an explicit - // UNREACHABLE here too. - UNREACHABLE(); +template <typename IsolateT> +template <typename SlotAccessor> +int Deserializer<IsolateT>::ReadFixedRawData(byte data, + SlotAccessor slot_accessor) { + using TSlot = decltype(slot_accessor.slot()); + + // Deserialize raw data of fixed length from 1 to 32 times kTaggedSize. + int size_in_tagged = FixedRawDataWithSize::Decode(data); + static_assert(TSlot::kSlotDataSize == kTaggedSize || + TSlot::kSlotDataSize == 2 * kTaggedSize); + int size_in_slots = size_in_tagged / (TSlot::kSlotDataSize / kTaggedSize); + // kFixedRawData can have kTaggedSize != TSlot::kSlotDataSize when + // serializing Smi roots in pointer-compressed builds. In this case, the + // size in bytes is unconditionally the (full) slot size. + DCHECK_IMPLIES(kTaggedSize != TSlot::kSlotDataSize, size_in_slots == 1); + // TODO(leszeks): Only copy slots when there are Smis in the serialized + // data. + source_.CopySlots(slot_accessor.slot().location(), size_in_slots); + return size_in_slots; +} + +template <typename IsolateT> +template <typename SlotAccessor> +int Deserializer<IsolateT>::ReadFixedRepeat(byte data, + SlotAccessor slot_accessor) { + int repeats = FixedRepeatWithCount::Decode(data); + return ReadRepeatedObject(slot_accessor, repeats); } #undef CASE_RANGE_ALL_SPACES |