1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/snapshot/serializer.h"
6 
7 #include "src/codegen/assembler-inl.h"
8 #include "src/common/globals.h"
9 #include "src/handles/global-handles-inl.h"
10 #include "src/heap/heap-inl.h"  // For Space::identity().
11 #include "src/heap/memory-chunk-inl.h"
12 #include "src/heap/read-only-heap.h"
13 #include "src/interpreter/interpreter.h"
14 #include "src/objects/code.h"
15 #include "src/objects/js-array-buffer-inl.h"
16 #include "src/objects/js-array-inl.h"
17 #include "src/objects/map.h"
18 #include "src/objects/objects-body-descriptors-inl.h"
19 #include "src/objects/slots-inl.h"
20 #include "src/objects/smi.h"
21 #include "src/snapshot/serializer-deserializer.h"
22 
23 namespace v8 {
24 namespace internal {
25 
Serializer(Isolate * isolate,Snapshot::SerializerFlags flags)26 Serializer::Serializer(Isolate* isolate, Snapshot::SerializerFlags flags)
27     : isolate_(isolate),
28       hot_objects_(isolate->heap()),
29       reference_map_(isolate),
30       external_reference_encoder_(isolate),
31       root_index_map_(isolate),
32       deferred_objects_(isolate->heap()),
33       forward_refs_per_pending_object_(isolate->heap()),
34       flags_(flags)
35 #ifdef DEBUG
36       ,
37       back_refs_(isolate->heap()),
38       stack_(isolate->heap())
39 #endif
40 {
41 #ifdef OBJECT_PRINT
42   if (FLAG_serialization_statistics) {
43     for (int space = 0; space < kNumberOfSnapshotSpaces; ++space) {
44       // Value-initialized to 0.
45       instance_type_count_[space] = std::make_unique<int[]>(kInstanceTypes);
46       instance_type_size_[space] = std::make_unique<size_t[]>(kInstanceTypes);
47     }
48   }
49 #endif  // OBJECT_PRINT
50 }
51 
52 #ifdef DEBUG
PopStack()53 void Serializer::PopStack() { stack_.Pop(); }
54 #endif
55 
CountAllocation(Map map,int size,SnapshotSpace space)56 void Serializer::CountAllocation(Map map, int size, SnapshotSpace space) {
57   DCHECK(FLAG_serialization_statistics);
58 
59   const int space_number = static_cast<int>(space);
60   allocation_size_[space_number] += size;
61 #ifdef OBJECT_PRINT
62   int instance_type = map.instance_type();
63   instance_type_count_[space_number][instance_type]++;
64   instance_type_size_[space_number][instance_type] += size;
65 #endif  // OBJECT_PRINT
66 }
67 
TotalAllocationSize() const68 int Serializer::TotalAllocationSize() const {
69   int sum = 0;
70   for (int space = 0; space < kNumberOfSnapshotSpaces; space++) {
71     sum += allocation_size_[space];
72   }
73   return sum;
74 }
75 
OutputStatistics(const char * name)76 void Serializer::OutputStatistics(const char* name) {
77   if (!FLAG_serialization_statistics) return;
78 
79   PrintF("%s:\n", name);
80 
81   PrintF("  Spaces (bytes):\n");
82 
83   for (int space = 0; space < kNumberOfSnapshotSpaces; space++) {
84     PrintF("%16s",
85            BaseSpace::GetSpaceName(static_cast<AllocationSpace>(space)));
86   }
87   PrintF("\n");
88 
89   for (int space = 0; space < kNumberOfSnapshotSpaces; space++) {
90     PrintF("%16zu", allocation_size_[space]);
91   }
92 
93 #ifdef OBJECT_PRINT
94   PrintF("  Instance types (count and bytes):\n");
95 #define PRINT_INSTANCE_TYPE(Name)                                          \
96   for (int space = 0; space < kNumberOfSnapshotSpaces; ++space) {          \
97     if (instance_type_count_[space][Name]) {                               \
98       PrintF("%10d %10zu  %-10s %s\n", instance_type_count_[space][Name],  \
99              instance_type_size_[space][Name],                             \
100              BaseSpace::GetSpaceName(static_cast<AllocationSpace>(space)), \
101              #Name);                                                       \
102     }                                                                      \
103   }
104   INSTANCE_TYPE_LIST(PRINT_INSTANCE_TYPE)
105 #undef PRINT_INSTANCE_TYPE
106 #endif  // OBJECT_PRINT
107 
108   PrintF("\n");
109 }
110 
SerializeDeferredObjects()111 void Serializer::SerializeDeferredObjects() {
112   if (FLAG_trace_serializer) {
113     PrintF("Serializing deferred objects\n");
114   }
115   WHILE_WITH_HANDLE_SCOPE(isolate(), !deferred_objects_.empty(), {
116     Handle<HeapObject> obj = handle(deferred_objects_.Pop(), isolate());
117 
118     ObjectSerializer obj_serializer(this, obj, &sink_);
119     obj_serializer.SerializeDeferred();
120   });
121   sink_.Put(kSynchronize, "Finished with deferred objects");
122 }
123 
SerializeObject(Handle<HeapObject> obj)124 void Serializer::SerializeObject(Handle<HeapObject> obj) {
125   // ThinStrings are just an indirection to an internalized string, so elide the
126   // indirection and serialize the actual string directly.
127   if (obj->IsThinString(isolate())) {
128     obj = handle(ThinString::cast(*obj).actual(isolate()), isolate());
129   } else if (obj->IsCodeT()) {
130     Code code = FromCodeT(CodeT::cast(*obj));
131     if (code.kind() == CodeKind::BASELINE) {
132       // For now just serialize the BytecodeArray instead of baseline code.
133       // TODO(v8:11429,pthier): Handle Baseline code in cases we want to
134       // serialize it.
135       obj = handle(code.bytecode_or_interpreter_data(isolate()), isolate());
136     }
137   }
138   SerializeObjectImpl(obj);
139 }
140 
MustBeDeferred(HeapObject object)141 bool Serializer::MustBeDeferred(HeapObject object) { return false; }
142 
VisitRootPointers(Root root,const char * description,FullObjectSlot start,FullObjectSlot end)143 void Serializer::VisitRootPointers(Root root, const char* description,
144                                    FullObjectSlot start, FullObjectSlot end) {
145   for (FullObjectSlot current = start; current < end; ++current) {
146     SerializeRootObject(current);
147   }
148 }
149 
SerializeRootObject(FullObjectSlot slot)150 void Serializer::SerializeRootObject(FullObjectSlot slot) {
151   Object o = *slot;
152   if (o.IsSmi()) {
153     PutSmiRoot(slot);
154   } else {
155     SerializeObject(Handle<HeapObject>(slot.location()));
156   }
157 }
158 
159 #ifdef DEBUG
PrintStack()160 void Serializer::PrintStack() { PrintStack(std::cout); }
161 
PrintStack(std::ostream & out)162 void Serializer::PrintStack(std::ostream& out) {
163   for (const auto o : stack_) {
164     o->Print(out);
165     out << "\n";
166   }
167 }
168 #endif  // DEBUG
169 
SerializeRoot(Handle<HeapObject> obj)170 bool Serializer::SerializeRoot(Handle<HeapObject> obj) {
171   RootIndex root_index;
172   // Derived serializers are responsible for determining if the root has
173   // actually been serialized before calling this.
174   if (root_index_map()->Lookup(*obj, &root_index)) {
175     PutRoot(root_index);
176     return true;
177   }
178   return false;
179 }
180 
SerializeHotObject(Handle<HeapObject> obj)181 bool Serializer::SerializeHotObject(Handle<HeapObject> obj) {
182   // Encode a reference to a hot object by its index in the working set.
183   int index = hot_objects_.Find(*obj);
184   if (index == HotObjectsList::kNotFound) return false;
185   DCHECK(index >= 0 && index < kHotObjectCount);
186   if (FLAG_trace_serializer) {
187     PrintF(" Encoding hot object %d:", index);
188     obj->ShortPrint();
189     PrintF("\n");
190   }
191   sink_.Put(HotObject::Encode(index), "HotObject");
192   return true;
193 }
194 
SerializeBackReference(Handle<HeapObject> obj)195 bool Serializer::SerializeBackReference(Handle<HeapObject> obj) {
196   const SerializerReference* reference = reference_map_.LookupReference(obj);
197   if (reference == nullptr) return false;
198   // Encode the location of an already deserialized object in order to write
199   // its location into a later object.  We can encode the location as an
200   // offset fromthe start of the deserialized objects or as an offset
201   // backwards from thecurrent allocation pointer.
202   if (reference->is_attached_reference()) {
203     if (FLAG_trace_serializer) {
204       PrintF(" Encoding attached reference %d\n",
205              reference->attached_reference_index());
206     }
207     PutAttachedReference(*reference);
208   } else {
209     DCHECK(reference->is_back_reference());
210     if (FLAG_trace_serializer) {
211       PrintF(" Encoding back reference to: ");
212       obj->ShortPrint();
213       PrintF("\n");
214     }
215 
216     sink_.Put(kBackref, "Backref");
217     PutBackReference(obj, *reference);
218   }
219   return true;
220 }
221 
SerializePendingObject(Handle<HeapObject> obj)222 bool Serializer::SerializePendingObject(Handle<HeapObject> obj) {
223   PendingObjectReferences* refs_to_object =
224       forward_refs_per_pending_object_.Find(obj);
225   if (refs_to_object == nullptr) {
226     return false;
227   }
228 
229   PutPendingForwardReference(*refs_to_object);
230   return true;
231 }
232 
ObjectIsBytecodeHandler(Handle<HeapObject> obj) const233 bool Serializer::ObjectIsBytecodeHandler(Handle<HeapObject> obj) const {
234   if (!obj->IsCode()) return false;
235   return (Code::cast(*obj).kind() == CodeKind::BYTECODE_HANDLER);
236 }
237 
PutRoot(RootIndex root)238 void Serializer::PutRoot(RootIndex root) {
239   int root_index = static_cast<int>(root);
240   Handle<HeapObject> object =
241       Handle<HeapObject>::cast(isolate()->root_handle(root));
242   if (FLAG_trace_serializer) {
243     PrintF(" Encoding root %d:", root_index);
244     object->ShortPrint();
245     PrintF("\n");
246   }
247 
248   // Assert that the first 32 root array items are a conscious choice. They are
249   // chosen so that the most common ones can be encoded more efficiently.
250   STATIC_ASSERT(static_cast<int>(RootIndex::kArgumentsMarker) ==
251                 kRootArrayConstantsCount - 1);
252 
253   // TODO(ulan): Check that it works with young large objects.
254   if (root_index < kRootArrayConstantsCount &&
255       !Heap::InYoungGeneration(*object)) {
256     sink_.Put(RootArrayConstant::Encode(root), "RootConstant");
257   } else {
258     sink_.Put(kRootArray, "RootSerialization");
259     sink_.PutInt(root_index, "root_index");
260     hot_objects_.Add(*object);
261   }
262 }
263 
PutSmiRoot(FullObjectSlot slot)264 void Serializer::PutSmiRoot(FullObjectSlot slot) {
265   // Serializing a smi root in compressed pointer builds will serialize the
266   // full object slot (of kSystemPointerSize) to avoid complications during
267   // deserialization (endianness or smi sequences).
268   STATIC_ASSERT(decltype(slot)::kSlotDataSize == sizeof(Address));
269   STATIC_ASSERT(decltype(slot)::kSlotDataSize == kSystemPointerSize);
270   static constexpr int bytes_to_output = decltype(slot)::kSlotDataSize;
271   static constexpr int size_in_tagged = bytes_to_output >> kTaggedSizeLog2;
272   sink_.Put(FixedRawDataWithSize::Encode(size_in_tagged), "Smi");
273 
274   Address raw_value = Smi::cast(*slot).ptr();
275   const byte* raw_value_as_bytes = reinterpret_cast<const byte*>(&raw_value);
276   sink_.PutRaw(raw_value_as_bytes, bytes_to_output, "Bytes");
277 }
278 
PutBackReference(Handle<HeapObject> object,SerializerReference reference)279 void Serializer::PutBackReference(Handle<HeapObject> object,
280                                   SerializerReference reference) {
281   DCHECK_EQ(*object, *back_refs_[reference.back_ref_index()]);
282   sink_.PutInt(reference.back_ref_index(), "BackRefIndex");
283   hot_objects_.Add(*object);
284 }
285 
PutAttachedReference(SerializerReference reference)286 void Serializer::PutAttachedReference(SerializerReference reference) {
287   DCHECK(reference.is_attached_reference());
288   sink_.Put(kAttachedReference, "AttachedRef");
289   sink_.PutInt(reference.attached_reference_index(), "AttachedRefIndex");
290 }
291 
PutRepeat(int repeat_count)292 void Serializer::PutRepeat(int repeat_count) {
293   if (repeat_count <= kLastEncodableFixedRepeatCount) {
294     sink_.Put(FixedRepeatWithCount::Encode(repeat_count), "FixedRepeat");
295   } else {
296     sink_.Put(kVariableRepeat, "VariableRepeat");
297     sink_.PutInt(VariableRepeatCount::Encode(repeat_count), "repeat count");
298   }
299 }
300 
PutPendingForwardReference(PendingObjectReferences & refs)301 void Serializer::PutPendingForwardReference(PendingObjectReferences& refs) {
302   sink_.Put(kRegisterPendingForwardRef, "RegisterPendingForwardRef");
303   unresolved_forward_refs_++;
304   // Register the current slot with the pending object.
305   int forward_ref_id = next_forward_ref_id_++;
306   if (refs == nullptr) {
307     // The IdentityMap holding the pending object reference vectors does not
308     // support non-trivial types; in particular it doesn't support destructors
309     // on values. So, we manually allocate a vector with new, and delete it when
310     // resolving the pending object.
311     refs = new std::vector<int>();
312   }
313   refs->push_back(forward_ref_id);
314 }
315 
ResolvePendingForwardReference(int forward_reference_id)316 void Serializer::ResolvePendingForwardReference(int forward_reference_id) {
317   sink_.Put(kResolvePendingForwardRef, "ResolvePendingForwardRef");
318   sink_.PutInt(forward_reference_id, "with this index");
319   unresolved_forward_refs_--;
320 
321   // If there are no more unresolved forward refs, reset the forward ref id to
322   // zero so that future forward refs compress better.
323   if (unresolved_forward_refs_ == 0) {
324     next_forward_ref_id_ = 0;
325   }
326 }
327 
EncodeExternalReference(Address addr)328 ExternalReferenceEncoder::Value Serializer::EncodeExternalReference(
329     Address addr) {
330   Maybe<ExternalReferenceEncoder::Value> result =
331       external_reference_encoder_.TryEncode(addr);
332   if (result.IsNothing()) {
333 #ifdef DEBUG
334     PrintStack(std::cerr);
335 #endif
336     void* addr_ptr = reinterpret_cast<void*>(addr);
337     v8::base::OS::PrintError("Unknown external reference %p.\n", addr_ptr);
338     v8::base::OS::PrintError("%s\n",
339                              ExternalReferenceTable::ResolveSymbol(addr_ptr));
340     v8::base::OS::Abort();
341   }
342   return result.FromJust();
343 }
344 
RegisterObjectIsPending(Handle<HeapObject> obj)345 void Serializer::RegisterObjectIsPending(Handle<HeapObject> obj) {
346   if (*obj == ReadOnlyRoots(isolate()).not_mapped_symbol()) return;
347 
348   // Add the given object to the pending objects -> forward refs map.
349   auto find_result = forward_refs_per_pending_object_.FindOrInsert(obj);
350   USE(find_result);
351 
352   // If the above emplace didn't actually add the object, then the object must
353   // already have been registered pending by deferring. It might not be in the
354   // deferred objects queue though, since it may be the very object we just
355   // popped off that queue, so just check that it can be deferred.
356   DCHECK_IMPLIES(find_result.already_exists, *find_result.entry != nullptr);
357   DCHECK_IMPLIES(find_result.already_exists, CanBeDeferred(*obj));
358 }
359 
ResolvePendingObject(Handle<HeapObject> obj)360 void Serializer::ResolvePendingObject(Handle<HeapObject> obj) {
361   if (*obj == ReadOnlyRoots(isolate()).not_mapped_symbol()) return;
362 
363   std::vector<int>* refs;
364   CHECK(forward_refs_per_pending_object_.Delete(obj, &refs));
365   if (refs) {
366     for (int index : *refs) {
367       ResolvePendingForwardReference(index);
368     }
369     // See PutPendingForwardReference -- we have to manually manage the memory
370     // of non-trivial IdentityMap values.
371     delete refs;
372   }
373 }
374 
Pad(int padding_offset)375 void Serializer::Pad(int padding_offset) {
376   // The non-branching GetInt will read up to 3 bytes too far, so we need
377   // to pad the snapshot to make sure we don't read over the end.
378   for (unsigned i = 0; i < sizeof(int32_t) - 1; i++) {
379     sink_.Put(kNop, "Padding");
380   }
381   // Pad up to pointer size for checksum.
382   while (!IsAligned(sink_.Position() + padding_offset, kPointerAlignment)) {
383     sink_.Put(kNop, "Padding");
384   }
385 }
386 
InitializeCodeAddressMap()387 void Serializer::InitializeCodeAddressMap() {
388   isolate_->InitializeLoggingAndCounters();
389   code_address_map_ = std::make_unique<CodeAddressMap>(isolate_);
390 }
391 
CopyCode(Code code)392 Code Serializer::CopyCode(Code code) {
393   code_buffer_.clear();  // Clear buffer without deleting backing store.
394   int size = code.CodeSize();
395   code_buffer_.insert(code_buffer_.end(),
396                       reinterpret_cast<byte*>(code.address()),
397                       reinterpret_cast<byte*>(code.address() + size));
398   // When pointer compression is enabled the checked cast will try to
399   // decompress map field of off-heap Code object.
400   return Code::unchecked_cast(HeapObject::FromAddress(
401       reinterpret_cast<Address>(&code_buffer_.front())));
402 }
403 
SerializePrologue(SnapshotSpace space,int size,Map map)404 void Serializer::ObjectSerializer::SerializePrologue(SnapshotSpace space,
405                                                      int size, Map map) {
406   if (serializer_->code_address_map_) {
407     const char* code_name =
408         serializer_->code_address_map_->Lookup(object_->address());
409     LOG(serializer_->isolate_,
410         CodeNameEvent(object_->address(), sink_->Position(), code_name));
411   }
412 
413   if (map == *object_) {
414     DCHECK_EQ(*object_, ReadOnlyRoots(isolate()).meta_map());
415     DCHECK_EQ(space, SnapshotSpace::kReadOnlyHeap);
416     sink_->Put(kNewMetaMap, "NewMetaMap");
417 
418     DCHECK_EQ(size, Map::kSize);
419   } else {
420     sink_->Put(NewObject::Encode(space), "NewObject");
421 
422     // TODO(leszeks): Skip this when the map has a fixed size.
423     sink_->PutInt(size >> kObjectAlignmentBits, "ObjectSizeInWords");
424 
425     // Until the space for the object is allocated, it is considered "pending".
426     serializer_->RegisterObjectIsPending(object_);
427 
428     // Serialize map (first word of the object) before anything else, so that
429     // the deserializer can access it when allocating. Make sure that the map
430     // isn't a pending object.
431     DCHECK_NULL(serializer_->forward_refs_per_pending_object_.Find(map));
432     DCHECK(map.IsMap());
433     serializer_->SerializeObject(handle(map, isolate()));
434 
435     // Make sure the map serialization didn't accidentally recursively serialize
436     // this object.
437     DCHECK_IMPLIES(
438         *object_ != ReadOnlyRoots(isolate()).not_mapped_symbol(),
439         serializer_->reference_map()->LookupReference(object_) == nullptr);
440 
441     // Now that the object is allocated, we can resolve pending references to
442     // it.
443     serializer_->ResolvePendingObject(object_);
444   }
445 
446   if (FLAG_serialization_statistics) {
447     serializer_->CountAllocation(object_->map(), size, space);
448   }
449 
450   // Mark this object as already serialized, and add it to the reference map so
451   // that it can be accessed by backreference by future objects.
452   serializer_->num_back_refs_++;
453 #ifdef DEBUG
454   serializer_->back_refs_.Push(*object_);
455   DCHECK_EQ(serializer_->back_refs_.size(), serializer_->num_back_refs_);
456 #endif
457   if (*object_ != ReadOnlyRoots(isolate()).not_mapped_symbol()) {
458     // Only add the object to the map if it's not not_mapped_symbol, else
459     // the reference IdentityMap has issues. We don't expect to have back
460     // references to the not_mapped_symbol anyway, so it's fine.
461     SerializerReference back_reference =
462         SerializerReference::BackReference(serializer_->num_back_refs_ - 1);
463     serializer_->reference_map()->Add(*object_, back_reference);
464     DCHECK_EQ(*object_,
465               *serializer_->back_refs_[back_reference.back_ref_index()]);
466     DCHECK_EQ(back_reference.back_ref_index(), serializer_->reference_map()
467                                                    ->LookupReference(object_)
468                                                    ->back_ref_index());
469   }
470 }
471 
SerializeBackingStore(void * backing_store,int32_t byte_length)472 uint32_t Serializer::ObjectSerializer::SerializeBackingStore(
473     void* backing_store, int32_t byte_length) {
474   const SerializerReference* reference_ptr =
475       serializer_->reference_map()->LookupBackingStore(backing_store);
476 
477   // Serialize the off-heap backing store.
478   if (!reference_ptr) {
479     sink_->Put(kOffHeapBackingStore, "Off-heap backing store");
480     sink_->PutInt(byte_length, "length");
481     sink_->PutRaw(static_cast<byte*>(backing_store), byte_length,
482                   "BackingStore");
483     DCHECK_NE(0, serializer_->seen_backing_stores_index_);
484     SerializerReference reference =
485         SerializerReference::OffHeapBackingStoreReference(
486             serializer_->seen_backing_stores_index_++);
487     // Mark this backing store as already serialized.
488     serializer_->reference_map()->AddBackingStore(backing_store, reference);
489     return reference.off_heap_backing_store_index();
490   } else {
491     return reference_ptr->off_heap_backing_store_index();
492   }
493 }
494 
SerializeJSTypedArray()495 void Serializer::ObjectSerializer::SerializeJSTypedArray() {
496   Handle<JSTypedArray> typed_array = Handle<JSTypedArray>::cast(object_);
497   if (typed_array->is_on_heap()) {
498     typed_array->RemoveExternalPointerCompensationForSerialization(isolate());
499   } else {
500     if (!typed_array->WasDetached()) {
501       // Explicitly serialize the backing store now.
502       JSArrayBuffer buffer = JSArrayBuffer::cast(typed_array->buffer());
503       // We cannot store byte_length larger than int32 range in the snapshot.
504       CHECK_LE(buffer.byte_length(), std::numeric_limits<int32_t>::max());
505       int32_t byte_length = static_cast<int32_t>(buffer.byte_length());
506       size_t byte_offset = typed_array->byte_offset();
507 
508       // We need to calculate the backing store from the data pointer
509       // because the ArrayBuffer may already have been serialized.
510       void* backing_store = reinterpret_cast<void*>(
511           reinterpret_cast<Address>(typed_array->DataPtr()) - byte_offset);
512 
513       uint32_t ref = SerializeBackingStore(backing_store, byte_length);
514       typed_array->SetExternalBackingStoreRefForSerialization(ref);
515     } else {
516       typed_array->SetExternalBackingStoreRefForSerialization(0);
517     }
518   }
519   SerializeObject();
520 }
521 
SerializeJSArrayBuffer()522 void Serializer::ObjectSerializer::SerializeJSArrayBuffer() {
523   Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(object_);
524   void* backing_store = buffer->backing_store();
525   // We cannot store byte_length larger than int32 range in the snapshot.
526   CHECK_LE(buffer->byte_length(), std::numeric_limits<int32_t>::max());
527   int32_t byte_length = static_cast<int32_t>(buffer->byte_length());
528   ArrayBufferExtension* extension = buffer->extension();
529 
530   // The embedder-allocated backing store only exists for the off-heap case.
531   if (backing_store != nullptr) {
532     uint32_t ref = SerializeBackingStore(backing_store, byte_length);
533     buffer->SetBackingStoreRefForSerialization(ref);
534 
535     // Ensure deterministic output by setting extension to null during
536     // serialization.
537     buffer->set_extension(nullptr);
538   } else {
539     buffer->SetBackingStoreRefForSerialization(kNullRefSentinel);
540   }
541 
542   SerializeObject();
543 
544   buffer->set_backing_store(backing_store);
545   buffer->set_extension(extension);
546 }
547 
SerializeExternalString()548 void Serializer::ObjectSerializer::SerializeExternalString() {
549   // For external strings with known resources, we replace the resource field
550   // with the encoded external reference, which we restore upon deserialize.
551   // For the rest we serialize them to look like ordinary sequential strings.
552   Handle<ExternalString> string = Handle<ExternalString>::cast(object_);
553   Address resource = string->resource_as_address();
554   ExternalReferenceEncoder::Value reference;
555   if (serializer_->external_reference_encoder_.TryEncode(resource).To(
556           &reference)) {
557     DCHECK(reference.is_from_api());
558 #ifdef V8_HEAP_SANDBOX
559     uint32_t external_pointer_entry =
560         string->GetResourceRefForDeserialization();
561 #endif
562     string->SetResourceRefForSerialization(reference.index());
563     SerializeObject();
564 #ifdef V8_HEAP_SANDBOX
565     string->SetResourceRefForSerialization(external_pointer_entry);
566 #else
567     string->set_address_as_resource(isolate(), resource);
568 #endif
569   } else {
570     SerializeExternalStringAsSequentialString();
571   }
572 }
573 
SerializeExternalStringAsSequentialString()574 void Serializer::ObjectSerializer::SerializeExternalStringAsSequentialString() {
575   // Instead of serializing this as an external string, we serialize
576   // an imaginary sequential string with the same content.
577   ReadOnlyRoots roots(isolate());
578   DCHECK(object_->IsExternalString());
579   Handle<ExternalString> string = Handle<ExternalString>::cast(object_);
580   int length = string->length();
581   Map map;
582   int content_size;
583   int allocation_size;
584   const byte* resource;
585   // Find the map and size for the imaginary sequential string.
586   bool internalized = object_->IsInternalizedString();
587   if (object_->IsExternalOneByteString()) {
588     map = internalized ? roots.one_byte_internalized_string_map()
589                        : roots.one_byte_string_map();
590     allocation_size = SeqOneByteString::SizeFor(length);
591     content_size = length * kCharSize;
592     resource = reinterpret_cast<const byte*>(
593         Handle<ExternalOneByteString>::cast(string)->resource()->data());
594   } else {
595     map = internalized ? roots.internalized_string_map() : roots.string_map();
596     allocation_size = SeqTwoByteString::SizeFor(length);
597     content_size = length * kShortSize;
598     resource = reinterpret_cast<const byte*>(
599         Handle<ExternalTwoByteString>::cast(string)->resource()->data());
600   }
601 
602   SnapshotSpace space = SnapshotSpace::kOld;
603   SerializePrologue(space, allocation_size, map);
604 
605   // Output the rest of the imaginary string.
606   int bytes_to_output = allocation_size - HeapObject::kHeaderSize;
607   DCHECK(IsAligned(bytes_to_output, kTaggedSize));
608   int slots_to_output = bytes_to_output >> kTaggedSizeLog2;
609 
610   // Output raw data header. Do not bother with common raw length cases here.
611   sink_->Put(kVariableRawData, "RawDataForString");
612   sink_->PutInt(slots_to_output, "length");
613 
614   // Serialize string header (except for map).
615   byte* string_start = reinterpret_cast<byte*>(string->address());
616   for (int i = HeapObject::kHeaderSize; i < SeqString::kHeaderSize; i++) {
617     sink_->Put(string_start[i], "StringHeader");
618   }
619 
620   // Serialize string content.
621   sink_->PutRaw(resource, content_size, "StringContent");
622 
623   // Since the allocation size is rounded up to object alignment, there
624   // maybe left-over bytes that need to be padded.
625   int padding_size = allocation_size - SeqString::kHeaderSize - content_size;
626   DCHECK(0 <= padding_size && padding_size < kObjectAlignment);
627   for (int i = 0; i < padding_size; i++)
628     sink_->Put(static_cast<byte>(0), "StringPadding");
629 }
630 
631 // Clear and later restore the next link in the weak cell or allocation site.
632 // TODO(all): replace this with proper iteration of weak slots in serializer.
633 class V8_NODISCARD UnlinkWeakNextScope {
634  public:
UnlinkWeakNextScope(Heap * heap,Handle<HeapObject> object)635   explicit UnlinkWeakNextScope(Heap* heap, Handle<HeapObject> object) {
636     if (object->IsAllocationSite() &&
637         Handle<AllocationSite>::cast(object)->HasWeakNext()) {
638       object_ = object;
639       next_ =
640           handle(AllocationSite::cast(*object).weak_next(), heap->isolate());
641       Handle<AllocationSite>::cast(object)->set_weak_next(
642           ReadOnlyRoots(heap).undefined_value());
643     }
644   }
645 
~UnlinkWeakNextScope()646   ~UnlinkWeakNextScope() {
647     if (!object_.is_null()) {
648       Handle<AllocationSite>::cast(object_)->set_weak_next(
649           *next_, UPDATE_WEAK_WRITE_BARRIER);
650     }
651   }
652 
653  private:
654   Handle<HeapObject> object_;
655   Handle<Object> next_;
656   DISALLOW_GARBAGE_COLLECTION(no_gc_)
657 };
658 
Serialize()659 void Serializer::ObjectSerializer::Serialize() {
660   RecursionScope recursion(serializer_);
661 
662   // Defer objects as "pending" if they cannot be serialized now, or if we
663   // exceed a certain recursion depth. Some objects cannot be deferred.
664   if ((recursion.ExceedsMaximum() && CanBeDeferred(*object_)) ||
665       serializer_->MustBeDeferred(*object_)) {
666     DCHECK(CanBeDeferred(*object_));
667     if (FLAG_trace_serializer) {
668       PrintF(" Deferring heap object: ");
669       object_->ShortPrint();
670       PrintF("\n");
671     }
672     // Deferred objects are considered "pending".
673     serializer_->RegisterObjectIsPending(object_);
674     serializer_->PutPendingForwardReference(
675         *serializer_->forward_refs_per_pending_object_.Find(object_));
676     serializer_->QueueDeferredObject(object_);
677     return;
678   }
679 
680   if (FLAG_trace_serializer) {
681     PrintF(" Encoding heap object: ");
682     object_->ShortPrint();
683     PrintF("\n");
684   }
685 
686   if (object_->IsExternalString()) {
687     SerializeExternalString();
688     return;
689   } else if (!ReadOnlyHeap::Contains(*object_)) {
690     // Only clear padding for strings outside the read-only heap. Read-only heap
691     // should have been cleared elsewhere.
692     if (object_->IsSeqOneByteString()) {
693       // Clear padding bytes at the end. Done here to avoid having to do this
694       // at allocation sites in generated code.
695       Handle<SeqOneByteString>::cast(object_)->clear_padding();
696     } else if (object_->IsSeqTwoByteString()) {
697       Handle<SeqTwoByteString>::cast(object_)->clear_padding();
698     }
699   }
700   if (object_->IsJSTypedArray()) {
701     SerializeJSTypedArray();
702     return;
703   } else if (object_->IsJSArrayBuffer()) {
704     SerializeJSArrayBuffer();
705     return;
706   }
707 
708   // We don't expect fillers.
709   DCHECK(!object_->IsFreeSpaceOrFiller());
710 
711   if (object_->IsScript()) {
712     // Clear cached line ends.
713     Oddball undefined = ReadOnlyRoots(isolate()).undefined_value();
714     Handle<Script>::cast(object_)->set_line_ends(undefined);
715   }
716 
717   SerializeObject();
718 }
719 
720 namespace {
GetSnapshotSpace(Handle<HeapObject> object)721 SnapshotSpace GetSnapshotSpace(Handle<HeapObject> object) {
722   if (V8_ENABLE_THIRD_PARTY_HEAP_BOOL) {
723     if (object->IsCode()) {
724       return SnapshotSpace::kCode;
725     } else if (ReadOnlyHeap::Contains(*object)) {
726       return SnapshotSpace::kReadOnlyHeap;
727     } else if (object->IsMap()) {
728       return SnapshotSpace::kMap;
729     } else {
730       return SnapshotSpace::kOld;
731     }
732   } else if (ReadOnlyHeap::Contains(*object)) {
733     return SnapshotSpace::kReadOnlyHeap;
734   } else {
735     AllocationSpace heap_space =
736         MemoryChunk::FromHeapObject(*object)->owner_identity();
737     // Large code objects are not supported and cannot be expressed by
738     // SnapshotSpace.
739     DCHECK_NE(heap_space, CODE_LO_SPACE);
740     switch (heap_space) {
741       case OLD_SPACE:
742       // Young generation objects are tenured, as objects that have survived
743       // until snapshot building probably deserve to be considered 'old'.
744       case NEW_SPACE:
745       // Large objects (young and old) are encoded as simply 'old' snapshot
746       // obects, as "normal" objects vs large objects is a heap implementation
747       // detail and isn't relevant to the snapshot.
748       case NEW_LO_SPACE:
749       case LO_SPACE:
750         return SnapshotSpace::kOld;
751       case CODE_SPACE:
752         return SnapshotSpace::kCode;
753       case MAP_SPACE:
754         return SnapshotSpace::kMap;
755       case CODE_LO_SPACE:
756       case RO_SPACE:
757         UNREACHABLE();
758     }
759   }
760 }
761 }  // namespace
762 
SerializeObject()763 void Serializer::ObjectSerializer::SerializeObject() {
764   int size = object_->Size();
765   Map map = object_->map();
766 
767   // Descriptor arrays have complex element weakness, that is dependent on the
768   // maps pointing to them. During deserialization, this can cause them to get
769   // prematurely trimmed one of their owners isn't deserialized yet. We work
770   // around this by forcing all descriptor arrays to be serialized as "strong",
771   // i.e. no custom weakness, and "re-weaken" them in the deserializer once
772   // deserialization completes.
773   //
774   // See also `Deserializer::WeakenDescriptorArrays`.
775   if (map == ReadOnlyRoots(isolate()).descriptor_array_map()) {
776     map = ReadOnlyRoots(isolate()).strong_descriptor_array_map();
777   }
778   SnapshotSpace space = GetSnapshotSpace(object_);
779   SerializePrologue(space, size, map);
780 
781   // Serialize the rest of the object.
782   CHECK_EQ(0, bytes_processed_so_far_);
783   bytes_processed_so_far_ = kTaggedSize;
784 
785   SerializeContent(map, size);
786 }
787 
SerializeDeferred()788 void Serializer::ObjectSerializer::SerializeDeferred() {
789   const SerializerReference* back_reference =
790       serializer_->reference_map()->LookupReference(object_);
791 
792   if (back_reference != nullptr) {
793     if (FLAG_trace_serializer) {
794       PrintF(" Deferred heap object ");
795       object_->ShortPrint();
796       PrintF(" was already serialized\n");
797     }
798     return;
799   }
800 
801   if (FLAG_trace_serializer) {
802     PrintF(" Encoding deferred heap object\n");
803   }
804   Serialize();
805 }
806 
SerializeContent(Map map,int size)807 void Serializer::ObjectSerializer::SerializeContent(Map map, int size) {
808   UnlinkWeakNextScope unlink_weak_next(isolate()->heap(), object_);
809   if (object_->IsCode()) {
810     // For code objects, perform a custom serialization.
811     SerializeCode(map, size);
812   } else {
813     // For other objects, iterate references first.
814     object_->IterateBody(map, size, this);
815     // Then output data payload, if any.
816     OutputRawData(object_->address() + size);
817   }
818 }
819 
VisitPointers(HeapObject host,ObjectSlot start,ObjectSlot end)820 void Serializer::ObjectSerializer::VisitPointers(HeapObject host,
821                                                  ObjectSlot start,
822                                                  ObjectSlot end) {
823   VisitPointers(host, MaybeObjectSlot(start), MaybeObjectSlot(end));
824 }
825 
VisitPointers(HeapObject host,MaybeObjectSlot start,MaybeObjectSlot end)826 void Serializer::ObjectSerializer::VisitPointers(HeapObject host,
827                                                  MaybeObjectSlot start,
828                                                  MaybeObjectSlot end) {
829   HandleScope scope(isolate());
830   DisallowGarbageCollection no_gc;
831 
832   MaybeObjectSlot current = start;
833   while (current < end) {
834     while (current < end && (*current)->IsSmi()) {
835       ++current;
836     }
837     if (current < end) {
838       OutputRawData(current.address());
839     }
840     // TODO(ishell): Revisit this change once we stick to 32-bit compressed
841     // tagged values.
842     while (current < end && (*current)->IsCleared()) {
843       sink_->Put(kClearedWeakReference, "ClearedWeakReference");
844       bytes_processed_so_far_ += kTaggedSize;
845       ++current;
846     }
847     HeapObject current_contents;
848     HeapObjectReferenceType reference_type;
849     while (current < end &&
850            (*current)->GetHeapObject(&current_contents, &reference_type)) {
851       // Write a weak prefix if we need it. This has to be done before the
852       // potential pending object serialization.
853       if (reference_type == HeapObjectReferenceType::WEAK) {
854         sink_->Put(kWeakPrefix, "WeakReference");
855       }
856 
857       Handle<HeapObject> obj = handle(current_contents, isolate());
858       if (serializer_->SerializePendingObject(obj)) {
859         bytes_processed_so_far_ += kTaggedSize;
860         ++current;
861         continue;
862       }
863 
864       RootIndex root_index;
865       // Compute repeat count and write repeat prefix if applicable.
866       // Repeats are not subject to the write barrier so we can only use
867       // immortal immovable root members.
868       MaybeObjectSlot repeat_end = current + 1;
869       if (repeat_end < end &&
870           serializer_->root_index_map()->Lookup(*obj, &root_index) &&
871           RootsTable::IsImmortalImmovable(root_index) &&
872           *current == *repeat_end) {
873         DCHECK_EQ(reference_type, HeapObjectReferenceType::STRONG);
874         DCHECK(!Heap::InYoungGeneration(*obj));
875         while (repeat_end < end && *repeat_end == *current) {
876           repeat_end++;
877         }
878         int repeat_count = static_cast<int>(repeat_end - current);
879         current = repeat_end;
880         bytes_processed_so_far_ += repeat_count * kTaggedSize;
881         serializer_->PutRepeat(repeat_count);
882       } else {
883         bytes_processed_so_far_ += kTaggedSize;
884         ++current;
885       }
886       // Now write the object itself.
887       serializer_->SerializeObject(obj);
888     }
889   }
890 }
891 
VisitCodePointer(HeapObject host,CodeObjectSlot slot)892 void Serializer::ObjectSerializer::VisitCodePointer(HeapObject host,
893                                                     CodeObjectSlot slot) {
894   CHECK(V8_EXTERNAL_CODE_SPACE_BOOL);
895   // A version of VisitPointers() customized for CodeObjectSlot.
896   HandleScope scope(isolate());
897   DisallowGarbageCollection no_gc;
898 
899   // TODO(v8:11880): support external code space.
900   PtrComprCageBase code_cage_base = GetPtrComprCageBase(host);
901   Object contents = slot.load(code_cage_base);
902   DCHECK(HAS_STRONG_HEAP_OBJECT_TAG(contents.ptr()));
903   DCHECK(contents.IsCode());
904 
905   Handle<HeapObject> obj = handle(HeapObject::cast(contents), isolate());
906   if (!serializer_->SerializePendingObject(obj)) {
907     serializer_->SerializeObject(obj);
908   }
909   bytes_processed_so_far_ += kTaggedSize;
910 }
911 
OutputExternalReference(Address target,int target_size,bool sandboxify)912 void Serializer::ObjectSerializer::OutputExternalReference(Address target,
913                                                            int target_size,
914                                                            bool sandboxify) {
915   DCHECK_LE(target_size, sizeof(target));  // Must fit in Address.
916   ExternalReferenceEncoder::Value encoded_reference;
917   bool encoded_successfully;
918 
919   if (serializer_->allow_unknown_external_references_for_testing()) {
920     encoded_successfully =
921         serializer_->TryEncodeExternalReference(target).To(&encoded_reference);
922   } else {
923     encoded_reference = serializer_->EncodeExternalReference(target);
924     encoded_successfully = true;
925   }
926 
927   if (!encoded_successfully) {
928     // In this case the serialized snapshot will not be used in a different
929     // Isolate and thus the target address will not change between
930     // serialization and deserialization. We can serialize seen external
931     // references verbatim.
932     CHECK(serializer_->allow_unknown_external_references_for_testing());
933     CHECK(IsAligned(target_size, kTaggedSize));
934     CHECK_LE(target_size, kFixedRawDataCount * kTaggedSize);
935     int size_in_tagged = target_size >> kTaggedSizeLog2;
936     sink_->Put(FixedRawDataWithSize::Encode(size_in_tagged), "FixedRawData");
937     sink_->PutRaw(reinterpret_cast<byte*>(&target), target_size, "Bytes");
938   } else if (encoded_reference.is_from_api()) {
939     if (V8_HEAP_SANDBOX_BOOL && sandboxify) {
940       sink_->Put(kSandboxedApiReference, "SandboxedApiRef");
941     } else {
942       sink_->Put(kApiReference, "ApiRef");
943     }
944     sink_->PutInt(encoded_reference.index(), "reference index");
945   } else {
946     if (V8_HEAP_SANDBOX_BOOL && sandboxify) {
947       sink_->Put(kSandboxedExternalReference, "SandboxedExternalRef");
948     } else {
949       sink_->Put(kExternalReference, "ExternalRef");
950     }
951     sink_->PutInt(encoded_reference.index(), "reference index");
952   }
953 }
954 
VisitExternalReference(Foreign host,Address * p)955 void Serializer::ObjectSerializer::VisitExternalReference(Foreign host,
956                                                           Address* p) {
957   // "Sandboxify" external reference.
958   OutputExternalReference(host.foreign_address(), kExternalPointerSize, true);
959   bytes_processed_so_far_ += kExternalPointerSize;
960 }
961 
962 class Serializer::ObjectSerializer::RelocInfoObjectPreSerializer {
963  public:
RelocInfoObjectPreSerializer(Serializer * serializer)964   explicit RelocInfoObjectPreSerializer(Serializer* serializer)
965       : serializer_(serializer) {}
966 
VisitEmbeddedPointer(Code host,RelocInfo * target)967   void VisitEmbeddedPointer(Code host, RelocInfo* target) {
968     Object object = target->target_object();
969     serializer_->SerializeObject(handle(HeapObject::cast(object), isolate()));
970     num_serialized_objects_++;
971   }
VisitCodeTarget(Code host,RelocInfo * target)972   void VisitCodeTarget(Code host, RelocInfo* target) {
973 #ifdef V8_TARGET_ARCH_ARM
974     DCHECK(!RelocInfo::IsRelativeCodeTarget(target->rmode()));
975 #endif
976     Code object = Code::GetCodeFromTargetAddress(target->target_address());
977     serializer_->SerializeObject(handle(object, isolate()));
978     num_serialized_objects_++;
979   }
980 
VisitExternalReference(Code host,RelocInfo * rinfo)981   void VisitExternalReference(Code host, RelocInfo* rinfo) {}
VisitInternalReference(Code host,RelocInfo * rinfo)982   void VisitInternalReference(Code host, RelocInfo* rinfo) {}
VisitRuntimeEntry(Code host,RelocInfo * reloc)983   void VisitRuntimeEntry(Code host, RelocInfo* reloc) { UNREACHABLE(); }
VisitOffHeapTarget(Code host,RelocInfo * target)984   void VisitOffHeapTarget(Code host, RelocInfo* target) {}
985 
num_serialized_objects() const986   int num_serialized_objects() const { return num_serialized_objects_; }
987 
isolate()988   Isolate* isolate() { return serializer_->isolate(); }
989 
990  private:
991   Serializer* serializer_;
992   int num_serialized_objects_ = 0;
993 };
994 
VisitEmbeddedPointer(Code host,RelocInfo * rinfo)995 void Serializer::ObjectSerializer::VisitEmbeddedPointer(Code host,
996                                                         RelocInfo* rinfo) {
997   // Target object should be pre-serialized by RelocInfoObjectPreSerializer, so
998   // just track the pointer's existence as kTaggedSize in
999   // bytes_processed_so_far_.
1000   // TODO(leszeks): DCHECK that RelocInfoObjectPreSerializer serialized this
1001   // specific object already.
1002   bytes_processed_so_far_ += kTaggedSize;
1003 }
1004 
VisitExternalReference(Code host,RelocInfo * rinfo)1005 void Serializer::ObjectSerializer::VisitExternalReference(Code host,
1006                                                           RelocInfo* rinfo) {
1007   Address target = rinfo->target_external_reference();
1008   DCHECK_NE(target, kNullAddress);  // Code does not reference null.
1009   DCHECK_IMPLIES(serializer_->EncodeExternalReference(target).is_from_api(),
1010                  !rinfo->IsCodedSpecially());
1011   // Don't "sandboxify" external references embedded in the code.
1012   OutputExternalReference(target, rinfo->target_address_size(), false);
1013 }
1014 
VisitInternalReference(Code host,RelocInfo * rinfo)1015 void Serializer::ObjectSerializer::VisitInternalReference(Code host,
1016                                                           RelocInfo* rinfo) {
1017   Address entry = Handle<Code>::cast(object_)->entry();
1018   DCHECK_GE(rinfo->target_internal_reference(), entry);
1019   uintptr_t target_offset = rinfo->target_internal_reference() - entry;
1020   // TODO(jgruber,v8:11036): We are being permissive for this DCHECK, but
1021   // consider using raw_instruction_size() instead of raw_body_size() in the
1022   // future.
1023   STATIC_ASSERT(Code::kOnHeapBodyIsContiguous);
1024   DCHECK_LE(target_offset, Handle<Code>::cast(object_)->raw_body_size());
1025   sink_->Put(kInternalReference, "InternalRef");
1026   sink_->PutInt(target_offset, "internal ref value");
1027 }
1028 
VisitRuntimeEntry(Code host,RelocInfo * rinfo)1029 void Serializer::ObjectSerializer::VisitRuntimeEntry(Code host,
1030                                                      RelocInfo* rinfo) {
1031   // We no longer serialize code that contains runtime entries.
1032   UNREACHABLE();
1033 }
1034 
VisitOffHeapTarget(Code host,RelocInfo * rinfo)1035 void Serializer::ObjectSerializer::VisitOffHeapTarget(Code host,
1036                                                       RelocInfo* rinfo) {
1037   STATIC_ASSERT(EmbeddedData::kTableSize == Builtins::kBuiltinCount);
1038 
1039   Address addr = rinfo->target_off_heap_target();
1040   CHECK_NE(kNullAddress, addr);
1041 
1042   Builtin builtin = InstructionStream::TryLookupCode(isolate(), addr);
1043   CHECK(Builtins::IsBuiltinId(builtin));
1044   CHECK(Builtins::IsIsolateIndependent(builtin));
1045 
1046   sink_->Put(kOffHeapTarget, "OffHeapTarget");
1047   sink_->PutInt(static_cast<int>(builtin), "builtin index");
1048 }
1049 
VisitCodeTarget(Code host,RelocInfo * rinfo)1050 void Serializer::ObjectSerializer::VisitCodeTarget(Code host,
1051                                                    RelocInfo* rinfo) {
1052   // Target object should be pre-serialized by RelocInfoObjectPreSerializer, so
1053   // just track the pointer's existence as kTaggedSize in
1054   // bytes_processed_so_far_.
1055   // TODO(leszeks): DCHECK that RelocInfoObjectPreSerializer serialized this
1056   // specific object already.
1057   bytes_processed_so_far_ += kTaggedSize;
1058 }
1059 
1060 namespace {
1061 
1062 // Similar to OutputRawData, but substitutes the given field with the given
1063 // value instead of reading it from the object.
OutputRawWithCustomField(SnapshotByteSink * sink,Address object_start,int written_so_far,int bytes_to_write,int field_offset,int field_size,const byte * field_value)1064 void OutputRawWithCustomField(SnapshotByteSink* sink, Address object_start,
1065                               int written_so_far, int bytes_to_write,
1066                               int field_offset, int field_size,
1067                               const byte* field_value) {
1068   int offset = field_offset - written_so_far;
1069   if (0 <= offset && offset < bytes_to_write) {
1070     DCHECK_GE(bytes_to_write, offset + field_size);
1071     sink->PutRaw(reinterpret_cast<byte*>(object_start + written_so_far), offset,
1072                  "Bytes");
1073     sink->PutRaw(field_value, field_size, "Bytes");
1074     written_so_far += offset + field_size;
1075     bytes_to_write -= offset + field_size;
1076     sink->PutRaw(reinterpret_cast<byte*>(object_start + written_so_far),
1077                  bytes_to_write, "Bytes");
1078   } else {
1079     sink->PutRaw(reinterpret_cast<byte*>(object_start + written_so_far),
1080                  bytes_to_write, "Bytes");
1081   }
1082 }
1083 }  // anonymous namespace
1084 
OutputRawData(Address up_to)1085 void Serializer::ObjectSerializer::OutputRawData(Address up_to) {
1086   Address object_start = object_->address();
1087   int base = bytes_processed_so_far_;
1088   int up_to_offset = static_cast<int>(up_to - object_start);
1089   int to_skip = up_to_offset - bytes_processed_so_far_;
1090   int bytes_to_output = to_skip;
1091   DCHECK(IsAligned(bytes_to_output, kTaggedSize));
1092   int tagged_to_output = bytes_to_output / kTaggedSize;
1093   bytes_processed_so_far_ += to_skip;
1094   DCHECK_GE(to_skip, 0);
1095   if (bytes_to_output != 0) {
1096     DCHECK(to_skip == bytes_to_output);
1097     if (tagged_to_output <= kFixedRawDataCount) {
1098       sink_->Put(FixedRawDataWithSize::Encode(tagged_to_output),
1099                  "FixedRawData");
1100     } else {
1101       sink_->Put(kVariableRawData, "VariableRawData");
1102       sink_->PutInt(tagged_to_output, "length");
1103     }
1104 #ifdef MEMORY_SANITIZER
1105     // Check that we do not serialize uninitialized memory.
1106     __msan_check_mem_is_initialized(
1107         reinterpret_cast<void*>(object_start + base), bytes_to_output);
1108 #endif  // MEMORY_SANITIZER
1109     if (object_->IsBytecodeArray()) {
1110       // The bytecode age field can be changed by GC concurrently.
1111       byte field_value = BytecodeArray::kNoAgeBytecodeAge;
1112       OutputRawWithCustomField(sink_, object_start, base, bytes_to_output,
1113                                BytecodeArray::kBytecodeAgeOffset,
1114                                sizeof(field_value), &field_value);
1115     } else if (object_->IsDescriptorArray()) {
1116       // The number of marked descriptors field can be changed by GC
1117       // concurrently.
1118       static byte field_value[2] = {0};
1119       OutputRawWithCustomField(
1120           sink_, object_start, base, bytes_to_output,
1121           DescriptorArray::kRawNumberOfMarkedDescriptorsOffset,
1122           sizeof(field_value), field_value);
1123     } else if (V8_EXTERNAL_CODE_SPACE_BOOL && object_->IsCodeDataContainer()) {
1124       // The CodeEntryPoint field is just a cached value which will be
1125       // recomputed after deserialization, so write zeros to keep the snapshot
1126       // deterministic.
1127       static byte field_value[kExternalPointerSize] = {0};
1128       OutputRawWithCustomField(sink_, object_start, base, bytes_to_output,
1129                                CodeDataContainer::kCodeEntryPointOffset,
1130                                sizeof(field_value), field_value);
1131     } else {
1132       sink_->PutRaw(reinterpret_cast<byte*>(object_start + base),
1133                     bytes_to_output, "Bytes");
1134     }
1135   }
1136 }
1137 
SerializeCode(Map map,int size)1138 void Serializer::ObjectSerializer::SerializeCode(Map map, int size) {
1139   static const int kWipeOutModeMask =
1140       RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
1141       RelocInfo::ModeMask(RelocInfo::FULL_EMBEDDED_OBJECT) |
1142       RelocInfo::ModeMask(RelocInfo::COMPRESSED_EMBEDDED_OBJECT) |
1143       RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
1144       RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) |
1145       RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED) |
1146       RelocInfo::ModeMask(RelocInfo::OFF_HEAP_TARGET) |
1147       RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
1148 
1149   DCHECK_EQ(HeapObject::kHeaderSize, bytes_processed_so_far_);
1150   Handle<Code> on_heap_code = Handle<Code>::cast(object_);
1151 
1152   // With enabled pointer compression normal accessors no longer work for
1153   // off-heap objects, so we have to get the relocation info data via the
1154   // on-heap code object.
1155   ByteArray relocation_info = on_heap_code->unchecked_relocation_info();
1156 
1157   // To make snapshots reproducible, we make a copy of the code object
1158   // and wipe all pointers in the copy, which we then serialize.
1159   Code off_heap_code = serializer_->CopyCode(*on_heap_code);
1160   for (RelocIterator it(off_heap_code, relocation_info, kWipeOutModeMask);
1161        !it.done(); it.next()) {
1162     RelocInfo* rinfo = it.rinfo();
1163     rinfo->WipeOut();
1164   }
1165   // We need to wipe out the header fields *after* wiping out the
1166   // relocations, because some of these fields are needed for the latter.
1167   off_heap_code.WipeOutHeader();
1168 
1169   // Initially skip serializing the code header. We'll serialize it after the
1170   // Code body, so that the various fields the Code needs for iteration are
1171   // already valid.
1172   sink_->Put(kCodeBody, "kCodeBody");
1173 
1174   // Now serialize the wiped off-heap Code, as length + data.
1175   Address start = off_heap_code.address() + Code::kDataStart;
1176   int bytes_to_output = size - Code::kDataStart;
1177   DCHECK(IsAligned(bytes_to_output, kTaggedSize));
1178   int tagged_to_output = bytes_to_output / kTaggedSize;
1179 
1180   sink_->PutInt(tagged_to_output, "length");
1181 
1182 #ifdef MEMORY_SANITIZER
1183   // Check that we do not serialize uninitialized memory.
1184   __msan_check_mem_is_initialized(reinterpret_cast<void*>(start),
1185                                   bytes_to_output);
1186 #endif  // MEMORY_SANITIZER
1187   sink_->PutRaw(reinterpret_cast<byte*>(start), bytes_to_output, "Code");
1188 
1189   // Manually serialize the code header. We don't use Code::BodyDescriptor
1190   // here as we don't yet want to walk the RelocInfos.
1191   DCHECK_EQ(HeapObject::kHeaderSize, bytes_processed_so_far_);
1192   VisitPointers(*on_heap_code, on_heap_code->RawField(HeapObject::kHeaderSize),
1193                 on_heap_code->RawField(Code::kDataStart));
1194   DCHECK_EQ(bytes_processed_so_far_, Code::kDataStart);
1195 
1196   // Now serialize RelocInfos. We can't allocate during a RelocInfo walk during
1197   // deserualization, so we have two passes for RelocInfo serialization:
1198   //   1. A pre-serializer which serializes all allocatable objects in the
1199   //      RelocInfo, followed by a kSynchronize bytecode, and
1200   //   2. A walk the RelocInfo with this serializer, serializing any objects
1201   //      implicitly as offsets into the pre-serializer's object array.
1202   // This way, the deserializer can deserialize the allocatable objects first,
1203   // without walking RelocInfo, re-build the pre-serializer's object array, and
1204   // only then walk the RelocInfo itself.
1205   // TODO(leszeks): We only really need to pre-serialize objects which need
1206   // serialization, i.e. no backrefs or roots.
1207   RelocInfoObjectPreSerializer pre_serializer(serializer_);
1208   for (RelocIterator it(*on_heap_code, relocation_info,
1209                         Code::BodyDescriptor::kRelocModeMask);
1210        !it.done(); it.next()) {
1211     it.rinfo()->Visit(&pre_serializer);
1212   }
1213   // Mark that the pre-serialization finished with a kSynchronize bytecode.
1214   sink_->Put(kSynchronize, "PreSerializationFinished");
1215 
1216   // Finally serialize all RelocInfo objects in the on-heap Code, knowing that
1217   // we will not do a recursive serialization.
1218   // TODO(leszeks): Add a scope that DCHECKs this.
1219   for (RelocIterator it(*on_heap_code, relocation_info,
1220                         Code::BodyDescriptor::kRelocModeMask);
1221        !it.done(); it.next()) {
1222     it.rinfo()->Visit(this);
1223   }
1224 
1225   // We record a kTaggedSize for every object encountered during the
1226   // serialization, so DCHECK that bytes_processed_so_far_ matches the expected
1227   // number of bytes (i.e. the code header + a tagged size per pre-serialized
1228   // object).
1229   DCHECK_EQ(
1230       bytes_processed_so_far_,
1231       Code::kDataStart + kTaggedSize * pre_serializer.num_serialized_objects());
1232 }
1233 
HotObjectsList(Heap * heap)1234 Serializer::HotObjectsList::HotObjectsList(Heap* heap) : heap_(heap) {
1235   strong_roots_entry_ = heap->RegisterStrongRoots(
1236       "Serializer::HotObjectsList", FullObjectSlot(&circular_queue_[0]),
1237       FullObjectSlot(&circular_queue_[kSize]));
1238 }
~HotObjectsList()1239 Serializer::HotObjectsList::~HotObjectsList() {
1240   heap_->UnregisterStrongRoots(strong_roots_entry_);
1241 }
1242 
1243 }  // namespace internal
1244 }  // namespace v8
1245