21class ObjectPreProcessor final {
23 explicit ObjectPreProcessor(Isolate* isolate)
26#define PRE_PROCESS_TYPE_LIST(V) \
30 V(FunctionTemplateInfo) \
36 if (InstanceTypeChecker::Is##TYPE(itype)) { \
37 return PreProcess##TYPE(Cast<TYPE>(o)); \
43#undef PRE_PROCESS_TYPE_LIST
46 void EncodeExternalPointerSlot(ExternalPointerSlot slot) {
47 Address value = slot.load(isolate_);
48 EncodeExternalPointerSlot(slot, value);
51 void EncodeExternalPointerSlot(ExternalPointerSlot slot,
Address value) {
54 ExternalReferenceEncoder::Value encoder_value =
58 ro::EncodedExternalReference encoded{encoder_value.is_from_api(),
59 encoder_value.index()};
65 slot.ReplaceContentWithIndexForSerialization(no_gc, encoded.ToUint32());
68 EncodeExternalPointerSlot(
69 o->RawExternalPointerField(AccessorInfo::kMaybeRedirectedGetterOffset,
72 EncodeExternalPointerSlot(o->RawExternalPointerField(
78#define PROCESS_FIELD(Name, name) \
79 EncodeExternalPointerSlot(o->RawExternalPointerField( \
80 InterceptorInfo::k##Name##Offset, \
81 is_named ? kApiNamedProperty##Name##CallbackTag \
82 : kApiIndexedProperty##Name##CallbackTag));
88 EncodeExternalPointerSlot(
89 o->RawExternalPointerField(JSExternalObject::kValueOffset,
91 reinterpret_cast<Address>(o->value(isolate_)));
94 EncodeExternalPointerSlot(
95 o->RawExternalPointerField(
96 FunctionTemplateInfo::kMaybeRedirectedCallbackOffset,
98 o->callback(isolate_));
101 o->ClearInstructionStartForSerialization(isolate_);
102 CHECK(!o->has_source_position_table_or_bytecode_offset_table());
103 CHECK(!o->has_deoptimization_data_or_interpreter_data());
104#ifdef V8_ENABLE_LEAPTIERING
113struct ReadOnlySegmentForSerialization {
114 ReadOnlySegmentForSerialization(Isolate* isolate,
115 const ReadOnlyPageMetadata* page,
117 ObjectPreProcessor* pre_processor)
127 CHECK_LT(isolate->read_only_heap()->read_only_space()->IndexOf(page),
132 PreProcessSegment(pre_processor);
136 void PreProcessSegment(ObjectPreProcessor* pre_processor) {
141 DCHECK_GE(segment_start, page->area_start());
143 ReadOnlyPageObjectIterator it(page, segment_start);
145 if (o.address() >= segment_end)
break;
148 pre_processor->PreProcessIfNeeded(
153 void EncodeTaggedSlots(Isolate* isolate);
155 const ReadOnlyPageMetadata*
const page;
164 friend class EncodeRelocationsVisitor;
168 Address o_address = o.address();
171 ReadOnlySpace* ro_space = isolate->read_only_heap()->read_only_space();
172 int index =
static_cast<int>(ro_space->IndexOf(chunk));
173 uint32_t
offset =
static_cast<int>(chunk->Offset(o_address));
183class EncodeRelocationsVisitor final :
public ObjectVisitor {
185 EncodeRelocationsVisitor(Isolate* isolate,
186 ReadOnlySegmentForSerialization* segment)
211 DCHECK(!host->has_instruction_stream());
229 ExternalPointerSlot slot)
override {
232 ExternalPointerSlot slot_in_segment{
234 SegmentOffsetOf(slot)),
242 slot_in_segment.GetContentAsIndexAfterDeserialization(no_gc));
243 if (encoded.is_api_reference) {
255 if (!o.IsStrongOrWeak())
return;
258 int slot_offset = SegmentOffsetOf(slot);
262 ro::EncodedTagged encoded = Encode(isolate_, o.GetHeapObject());
263 memcpy(
segment_->contents.get() + slot_offset, &encoded,
267 segment_->tagged_slots.set(AsSlot(slot_offset));
270 template <
class SlotT>
271 int SegmentOffsetOf(SlotT slot)
const {
275 return static_cast<int>(addr -
segment_->segment_start);
278 static constexpr int AsSlot(
int byte_offset) {
286void ReadOnlySegmentForSerialization::EncodeTaggedSlots(Isolate* isolate) {
288 EncodeRelocationsVisitor v(isolate,
this);
289 PtrComprCageBase cage_base(isolate);
294 SkipFreeSpaceOrFiller::kNo);
295 for (Tagged<HeapObject> o = it.Next(); !o.is_null(); o = it.Next()) {
296 if (o.address() >= segment_end)
break;
301class ReadOnlyHeapImageSerializer {
303 struct MemoryRegion {
308 static void Serialize(Isolate* isolate, SnapshotByteSink* sink,
309 const std::vector<MemoryRegion>& unmapped_regions) {
310 ReadOnlyHeapImageSerializer{
isolate, sink}.SerializeImpl(unmapped_regions);
314 using Bytecode = ro::Bytecode;
316 ReadOnlyHeapImageSerializer(Isolate* isolate, SnapshotByteSink* sink)
319 void SerializeImpl(
const std::vector<MemoryRegion>& unmapped_regions) {
322 ReadOnlySpace* ro_space =
isolate_->read_only_heap()->read_only_space();
326 for (
const ReadOnlyPageMetadata* page : ro_space->pages()) {
327 EmitAllocatePage(page, unmapped_regions);
331 for (
const ReadOnlyPageMetadata* page : ro_space->pages()) {
332 SerializePage(page, unmapped_regions);
335 EmitReadOnlyRootsTable();
336 sink_->Put(Bytecode::kFinalizeReadOnlySpace,
"space end");
339 uint32_t IndexOf(
const ReadOnlyPageMetadata* page) {
340 ReadOnlySpace* ro_space =
isolate_->read_only_heap()->read_only_space();
341 return static_cast<uint32_t
>(ro_space->IndexOf(page));
344 void EmitAllocatePage(
const ReadOnlyPageMetadata* page,
345 const std::vector<MemoryRegion>& unmapped_regions) {
347 sink_->Put(Bytecode::kAllocatePageAt,
"fixed page begin");
349 sink_->Put(Bytecode::kAllocatePage,
"page begin");
351 sink_->PutUint30(IndexOf(page),
"page index");
353 static_cast<uint32_t
>(page->HighWaterMark() - page->area_start()),
354 "area size in bytes");
356 auto page_addr = page->ChunkAddress();
357 sink_->PutUint32(V8HeapCompressionScheme::CompressAny(page_addr),
358 "page start offset");
362 void SerializePage(
const ReadOnlyPageMetadata* page,
363 const std::vector<MemoryRegion>& unmapped_regions) {
367 for (
auto r = unmapped_regions.begin();
r != unmapped_regions.end(); ++
r) {
369 if (
r + 1 != unmapped_regions.end()) {
370 CHECK(
r->start < (
r + 1)->start);
371 CHECK(
r->start +
r->size < (
r + 1)->start);
373 if (base::IsInRange(
r->start,
pos, page->HighWaterMark())) {
375 ReadOnlySegmentForSerialization segment(
isolate_, page,
pos,
377 EmitSegment(&segment);
387 EmitSegment(&segment);
390 void EmitSegment(
const ReadOnlySegmentForSerialization* segment) {
391 sink_->Put(Bytecode::kSegment,
"segment begin");
392 sink_->PutUint30(IndexOf(segment->page),
"page index");
393 sink_->PutUint30(
static_cast<uint32_t
>(segment->segment_offset),
394 "segment start offset");
395 sink_->PutUint30(
static_cast<uint32_t
>(segment->segment_size),
396 "segment byte size");
397 sink_->PutRaw(segment->contents.get(),
398 static_cast<int>(segment->segment_size),
"page");
400 sink_->Put(Bytecode::kRelocateSegment,
"relocate segment");
401 sink_->PutRaw(segment->tagged_slots.data(),
402 static_cast<int>(segment->tagged_slots.size_in_bytes()),
407 void EmitReadOnlyRootsTable() {
408 sink_->Put(Bytecode::kReadOnlyRootsTable,
"read only roots table");
411 for (
size_t i = 0;
i < ReadOnlyRoots::kEntriesCount;
i++) {
413 Tagged<HeapObject> rudolf = Cast<HeapObject>(roots.object_at(rudi));
414 ro::EncodedTagged encoded = Encode(
isolate_, rudolf);
415 sink_->PutUint32(encoded.ToUint32(),
"read only roots entry");
425std::vector<ReadOnlyHeapImageSerializer::MemoryRegion> GetUnmappedRegions(
427#ifdef V8_STATIC_ROOTS
432 ReadOnlyRoots ro_roots(isolate);
435 CHECK(IsFreeSpace(wasm_null_padding));
436 Address wasm_null_padding_start =
437 wasm_null_padding.address() + FreeSpace::kHeaderSize;
438 std::vector<ReadOnlyHeapImageSerializer::MemoryRegion> unmapped;
439 if (wasm_null.address() > wasm_null_padding_start) {
440 unmapped.push_back({wasm_null_padding_start,
441 wasm_null.address() - wasm_null_padding_start});
443 unmapped.push_back({wasm_null->payload(), WasmNull::kPayloadSize});
462 ReadOnlyHeapImageSerializer::Serialize(
isolate(), &
sink_,
463 GetUnmappedRegions(
isolate()));
468 if (
v8_flags.serialization_statistics) {
#define INTERCEPTOR_INFO_CALLBACK_LIST(V)
static constexpr int kSize
static constexpr int kMapOffset
ReadOnlySerializer(Isolate *isolate, Snapshot::SerializerFlags flags)
~ReadOnlySerializer() override
void CheckRehashability(Tagged< HeapObject > obj)
Isolate * isolate() const
void CountAllocation(Tagged< Map > map, int size, SnapshotSpace space)
void OutputStatistics(const char *name)
V8_INLINE constexpr bool is_null() const
constexpr int kTaggedSize
PerThreadAssertScopeDebugOnly< false, SAFEPOINTS_ASSERT, HEAP_ALLOCATION_ASSERT > DisallowGarbageCollection
SlotTraits::TObjectSlot ObjectSlot
Tagged(T object) -> Tagged< T >
kInterpreterTrampolineOffset Tagged< HeapObject >
SlotTraits::TInstructionStreamSlot InstructionStreamSlot
void VisitObject(Isolate *isolate, Tagged< HeapObject > object, ObjectVisitor *visitor)
constexpr JSDispatchHandle kNullJSDispatchHandle(0)
@ kExternalObjectValueTag
@ kFunctionTemplateInfoCallbackTag
V8_EXPORT_PRIVATE FlagValues v8_flags
SlotTraits::TMaybeObjectSlot MaybeObjectSlot
void MemCopy(void *dest, const void *src, size_t size)
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
#define PROCESS_FIELD(Name, name)
ReadOnlySegmentForSerialization *const segment_
const size_t segment_size
const Address segment_start
#define PRE_PROCESS_TYPE_LIST(V)
ObjectPreProcessor pre_processor_
ExternalReferenceEncoder extref_encoder_
const size_t segment_offset
SnapshotByteSink *const sink_
base::Vector< const char > contents
#define CHECK_LT(lhs, rhs)
#define DCHECK_GE(v1, v2)
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
#define DCHECK_LT(v1, v2)
#define DCHECK_EQ(v1, v2)
constexpr bool IsAligned(T value, U alignment)
static constexpr int kIndexBits
static EncodedExternalReference FromUint32(uint32_t v)
static constexpr int kPageIndexBits
static constexpr int kSize
#define V8_STATIC_ROOTS_BOOL