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/heap/heap-inl.h"  // For Space::identity().
9 #include "src/heap/read-only-heap.h"
10 #include "src/interpreter/interpreter.h"
11 #include "src/objects/code.h"
12 #include "src/objects/js-array-buffer-inl.h"
13 #include "src/objects/js-array-inl.h"
14 #include "src/objects/map.h"
15 #include "src/objects/slots-inl.h"
16 #include "src/objects/smi.h"
17 #include "src/snapshot/snapshot.h"
18 
19 namespace v8 {
20 namespace internal {
21 
Serializer(Isolate * isolate)22 Serializer::Serializer(Isolate* isolate)
23     : isolate_(isolate),
24       external_reference_encoder_(isolate),
25       root_index_map_(isolate),
26       allocator_(this) {
27 #ifdef OBJECT_PRINT
28   if (FLAG_serialization_statistics) {
29     for (int space = 0; space < kNumberOfSpaces; ++space) {
30       instance_type_count_[space] = NewArray<int>(kInstanceTypes);
31       instance_type_size_[space] = NewArray<size_t>(kInstanceTypes);
32       for (int i = 0; i < kInstanceTypes; i++) {
33         instance_type_count_[space][i] = 0;
34         instance_type_size_[space][i] = 0;
35       }
36     }
37   } else {
38     for (int space = 0; space < kNumberOfSpaces; ++space) {
39       instance_type_count_[space] = nullptr;
40       instance_type_size_[space] = nullptr;
41     }
42   }
43 #endif  // OBJECT_PRINT
44 }
45 
~Serializer()46 Serializer::~Serializer() {
47   if (code_address_map_ != nullptr) delete code_address_map_;
48 #ifdef OBJECT_PRINT
49   for (int space = 0; space < kNumberOfSpaces; ++space) {
50     if (instance_type_count_[space] != nullptr) {
51       DeleteArray(instance_type_count_[space]);
52       DeleteArray(instance_type_size_[space]);
53     }
54   }
55 #endif  // OBJECT_PRINT
56 }
57 
58 #ifdef OBJECT_PRINT
CountInstanceType(Map map,int size,SnapshotSpace space)59 void Serializer::CountInstanceType(Map map, int size, SnapshotSpace space) {
60   const int space_number = static_cast<int>(space);
61   int instance_type = map.instance_type();
62   instance_type_count_[space_number][instance_type]++;
63   instance_type_size_[space_number][instance_type] += size;
64 }
65 #endif  // OBJECT_PRINT
66 
OutputStatistics(const char * name)67 void Serializer::OutputStatistics(const char* name) {
68   if (!FLAG_serialization_statistics) return;
69 
70   PrintF("%s:\n", name);
71   allocator()->OutputStatistics();
72 
73 #ifdef OBJECT_PRINT
74   PrintF("  Instance types (count and bytes):\n");
75 #define PRINT_INSTANCE_TYPE(Name)                                             \
76   for (int space = 0; space < kNumberOfSpaces; ++space) {                     \
77     if (instance_type_count_[space][Name]) {                                  \
78       PrintF("%10d %10zu  %-10s %s\n", instance_type_count_[space][Name],     \
79              instance_type_size_[space][Name],                                \
80              Heap::GetSpaceName(static_cast<AllocationSpace>(space)), #Name); \
81     }                                                                         \
82   }
83   INSTANCE_TYPE_LIST(PRINT_INSTANCE_TYPE)
84 #undef PRINT_INSTANCE_TYPE
85 
86   PrintF("\n");
87 #endif  // OBJECT_PRINT
88 }
89 
SerializeDeferredObjects()90 void Serializer::SerializeDeferredObjects() {
91   while (!deferred_objects_.empty()) {
92     HeapObject obj = deferred_objects_.back();
93     deferred_objects_.pop_back();
94     ObjectSerializer obj_serializer(this, obj, &sink_);
95     obj_serializer.SerializeDeferred();
96   }
97   sink_.Put(kSynchronize, "Finished with deferred objects");
98 }
99 
MustBeDeferred(HeapObject object)100 bool Serializer::MustBeDeferred(HeapObject object) { return false; }
101 
VisitRootPointers(Root root,const char * description,FullObjectSlot start,FullObjectSlot end)102 void Serializer::VisitRootPointers(Root root, const char* description,
103                                    FullObjectSlot start, FullObjectSlot end) {
104   for (FullObjectSlot current = start; current < end; ++current) {
105     SerializeRootObject(*current);
106   }
107 }
108 
SerializeRootObject(Object object)109 void Serializer::SerializeRootObject(Object object) {
110   if (object.IsSmi()) {
111     PutSmi(Smi::cast(object));
112   } else {
113     SerializeObject(HeapObject::cast(object));
114   }
115 }
116 
117 #ifdef DEBUG
PrintStack()118 void Serializer::PrintStack() { PrintStack(std::cout); }
119 
PrintStack(std::ostream & out)120 void Serializer::PrintStack(std::ostream& out) {
121   for (const auto o : stack_) {
122     o.Print(out);
123     out << "\n";
124   }
125 }
126 #endif  // DEBUG
127 
SerializeRoot(HeapObject obj)128 bool Serializer::SerializeRoot(HeapObject obj) {
129   RootIndex root_index;
130   // Derived serializers are responsible for determining if the root has
131   // actually been serialized before calling this.
132   if (root_index_map()->Lookup(obj, &root_index)) {
133     PutRoot(root_index, obj);
134     return true;
135   }
136   return false;
137 }
138 
SerializeHotObject(HeapObject obj)139 bool Serializer::SerializeHotObject(HeapObject obj) {
140   // Encode a reference to a hot object by its index in the working set.
141   int index = hot_objects_.Find(obj);
142   if (index == HotObjectsList::kNotFound) return false;
143   DCHECK(index >= 0 && index < kNumberOfHotObjects);
144   if (FLAG_trace_serializer) {
145     PrintF(" Encoding hot object %d:", index);
146     obj.ShortPrint();
147     PrintF("\n");
148   }
149   sink_.Put(kHotObject + index, "HotObject");
150   return true;
151 }
152 
SerializeBackReference(HeapObject obj)153 bool Serializer::SerializeBackReference(HeapObject obj) {
154   SerializerReference reference =
155       reference_map_.LookupReference(reinterpret_cast<void*>(obj.ptr()));
156   if (!reference.is_valid()) return false;
157   // Encode the location of an already deserialized object in order to write
158   // its location into a later object.  We can encode the location as an
159   // offset fromthe start of the deserialized objects or as an offset
160   // backwards from thecurrent allocation pointer.
161   if (reference.is_attached_reference()) {
162     if (FLAG_trace_serializer) {
163       PrintF(" Encoding attached reference %d\n",
164              reference.attached_reference_index());
165     }
166     PutAttachedReference(reference);
167   } else {
168     DCHECK(reference.is_back_reference());
169     if (FLAG_trace_serializer) {
170       PrintF(" Encoding back reference to: ");
171       obj.ShortPrint();
172       PrintF("\n");
173     }
174 
175     PutAlignmentPrefix(obj);
176     SnapshotSpace space = reference.space();
177     sink_.Put(kBackref + static_cast<int>(space), "BackRef");
178     PutBackReference(obj, reference);
179   }
180   return true;
181 }
182 
ObjectIsBytecodeHandler(HeapObject obj) const183 bool Serializer::ObjectIsBytecodeHandler(HeapObject obj) const {
184   if (!obj.IsCode()) return false;
185   return (Code::cast(obj).kind() == Code::BYTECODE_HANDLER);
186 }
187 
PutRoot(RootIndex root,HeapObject object)188 void Serializer::PutRoot(RootIndex root, HeapObject object) {
189   int root_index = static_cast<int>(root);
190   if (FLAG_trace_serializer) {
191     PrintF(" Encoding root %d:", root_index);
192     object.ShortPrint();
193     PrintF("\n");
194   }
195 
196   // Assert that the first 32 root array items are a conscious choice. They are
197   // chosen so that the most common ones can be encoded more efficiently.
198   STATIC_ASSERT(static_cast<int>(RootIndex::kArgumentsMarker) ==
199                 kNumberOfRootArrayConstants - 1);
200 
201   // TODO(ulan): Check that it works with young large objects.
202   if (root_index < kNumberOfRootArrayConstants &&
203       !Heap::InYoungGeneration(object)) {
204     sink_.Put(kRootArrayConstants + root_index, "RootConstant");
205   } else {
206     sink_.Put(kRootArray, "RootSerialization");
207     sink_.PutInt(root_index, "root_index");
208     hot_objects_.Add(object);
209   }
210 }
211 
PutSmi(Smi smi)212 void Serializer::PutSmi(Smi smi) {
213   sink_.Put(kOnePointerRawData, "Smi");
214   Tagged_t raw_value = static_cast<Tagged_t>(smi.ptr());
215   byte bytes[kTaggedSize];
216   memcpy(bytes, &raw_value, kTaggedSize);
217   for (int i = 0; i < kTaggedSize; i++) sink_.Put(bytes[i], "Byte");
218 }
219 
PutBackReference(HeapObject object,SerializerReference reference)220 void Serializer::PutBackReference(HeapObject object,
221                                   SerializerReference reference) {
222   DCHECK(allocator()->BackReferenceIsAlreadyAllocated(reference));
223   switch (reference.space()) {
224     case SnapshotSpace::kMap:
225       sink_.PutInt(reference.map_index(), "BackRefMapIndex");
226       break;
227 
228     case SnapshotSpace::kLargeObject:
229       sink_.PutInt(reference.large_object_index(), "BackRefLargeObjectIndex");
230       break;
231 
232     default:
233       sink_.PutInt(reference.chunk_index(), "BackRefChunkIndex");
234       sink_.PutInt(reference.chunk_offset(), "BackRefChunkOffset");
235       break;
236   }
237 
238   hot_objects_.Add(object);
239 }
240 
PutAttachedReference(SerializerReference reference)241 void Serializer::PutAttachedReference(SerializerReference reference) {
242   DCHECK(reference.is_attached_reference());
243   sink_.Put(kAttachedReference, "AttachedRef");
244   sink_.PutInt(reference.attached_reference_index(), "AttachedRefIndex");
245 }
246 
PutAlignmentPrefix(HeapObject object)247 int Serializer::PutAlignmentPrefix(HeapObject object) {
248   AllocationAlignment alignment = HeapObject::RequiredAlignment(object.map());
249   if (alignment != kWordAligned) {
250     DCHECK(1 <= alignment && alignment <= 3);
251     byte prefix = (kAlignmentPrefix - 1) + alignment;
252     sink_.Put(prefix, "Alignment");
253     return Heap::GetMaximumFillToAlign(alignment);
254   }
255   return 0;
256 }
257 
PutNextChunk(SnapshotSpace space)258 void Serializer::PutNextChunk(SnapshotSpace space) {
259   sink_.Put(kNextChunk, "NextChunk");
260   sink_.Put(static_cast<int>(space), "NextChunkSpace");
261 }
262 
PutRepeat(int repeat_count)263 void Serializer::PutRepeat(int repeat_count) {
264   if (repeat_count <= kLastEncodableFixedRepeatCount) {
265     sink_.Put(EncodeFixedRepeat(repeat_count), "FixedRepeat");
266   } else {
267     sink_.Put(kVariableRepeat, "VariableRepeat");
268     sink_.PutInt(EncodeVariableRepeatCount(repeat_count), "repeat count");
269   }
270 }
271 
Pad(int padding_offset)272 void Serializer::Pad(int padding_offset) {
273   // The non-branching GetInt will read up to 3 bytes too far, so we need
274   // to pad the snapshot to make sure we don't read over the end.
275   for (unsigned i = 0; i < sizeof(int32_t) - 1; i++) {
276     sink_.Put(kNop, "Padding");
277   }
278   // Pad up to pointer size for checksum.
279   while (!IsAligned(sink_.Position() + padding_offset, kPointerAlignment)) {
280     sink_.Put(kNop, "Padding");
281   }
282 }
283 
InitializeCodeAddressMap()284 void Serializer::InitializeCodeAddressMap() {
285   isolate_->InitializeLoggingAndCounters();
286   code_address_map_ = new CodeAddressMap(isolate_);
287 }
288 
CopyCode(Code code)289 Code Serializer::CopyCode(Code code) {
290   code_buffer_.clear();  // Clear buffer without deleting backing store.
291   int size = code.CodeSize();
292   code_buffer_.insert(code_buffer_.end(),
293                       reinterpret_cast<byte*>(code.address()),
294                       reinterpret_cast<byte*>(code.address() + size));
295   // When pointer compression is enabled the checked cast will try to
296   // decompress map field of off-heap Code object.
297   return Code::unchecked_cast(HeapObject::FromAddress(
298       reinterpret_cast<Address>(&code_buffer_.front())));
299 }
300 
SerializePrologue(SnapshotSpace space,int size,Map map)301 void Serializer::ObjectSerializer::SerializePrologue(SnapshotSpace space,
302                                                      int size, Map map) {
303   if (serializer_->code_address_map_) {
304     const char* code_name =
305         serializer_->code_address_map_->Lookup(object_.address());
306     LOG(serializer_->isolate_,
307         CodeNameEvent(object_.address(), sink_->Position(), code_name));
308   }
309 
310   const int space_number = static_cast<int>(space);
311   SerializerReference back_reference;
312   if (space == SnapshotSpace::kLargeObject) {
313     sink_->Put(kNewObject + space_number, "NewLargeObject");
314     sink_->PutInt(size >> kObjectAlignmentBits, "ObjectSizeInWords");
315     CHECK(!object_.IsCode());
316     back_reference = serializer_->allocator()->AllocateLargeObject(size);
317   } else if (space == SnapshotSpace::kMap) {
318     DCHECK_EQ(Map::kSize, size);
319     back_reference = serializer_->allocator()->AllocateMap();
320     sink_->Put(kNewObject + space_number, "NewMap");
321     // This is redundant, but we include it anyways.
322     sink_->PutInt(size >> kObjectAlignmentBits, "ObjectSizeInWords");
323   } else {
324     int fill = serializer_->PutAlignmentPrefix(object_);
325     back_reference = serializer_->allocator()->Allocate(space, size + fill);
326     sink_->Put(kNewObject + space_number, "NewObject");
327     sink_->PutInt(size >> kObjectAlignmentBits, "ObjectSizeInWords");
328   }
329 
330 #ifdef OBJECT_PRINT
331   if (FLAG_serialization_statistics) {
332     serializer_->CountInstanceType(map, size, space);
333   }
334 #endif  // OBJECT_PRINT
335 
336   // Mark this object as already serialized.
337   serializer_->reference_map()->Add(reinterpret_cast<void*>(object_.ptr()),
338                                     back_reference);
339 
340   // Serialize the map (first word of the object).
341   serializer_->SerializeObject(map);
342 }
343 
SerializeBackingStore(void * backing_store,int32_t byte_length)344 uint32_t Serializer::ObjectSerializer::SerializeBackingStore(
345     void* backing_store, int32_t byte_length) {
346   SerializerReference reference =
347       serializer_->reference_map()->LookupReference(backing_store);
348 
349   // Serialize the off-heap backing store.
350   if (!reference.is_valid()) {
351     sink_->Put(kOffHeapBackingStore, "Off-heap backing store");
352     sink_->PutInt(byte_length, "length");
353     sink_->PutRaw(static_cast<byte*>(backing_store), byte_length,
354                   "BackingStore");
355     reference = serializer_->allocator()->AllocateOffHeapBackingStore();
356     // Mark this backing store as already serialized.
357     serializer_->reference_map()->Add(backing_store, reference);
358   }
359 
360   return reference.off_heap_backing_store_index();
361 }
362 
SerializeJSTypedArray()363 void Serializer::ObjectSerializer::SerializeJSTypedArray() {
364   JSTypedArray typed_array = JSTypedArray::cast(object_);
365   if (typed_array.is_on_heap()) {
366     typed_array.RemoveExternalPointerCompensationForSerialization();
367   } else {
368     if (!typed_array.WasDetached()) {
369       // Explicitly serialize the backing store now.
370       JSArrayBuffer buffer = JSArrayBuffer::cast(typed_array.buffer());
371       CHECK_LE(buffer.byte_length(), Smi::kMaxValue);
372       CHECK_LE(typed_array.byte_offset(), Smi::kMaxValue);
373       int32_t byte_length = static_cast<int32_t>(buffer.byte_length());
374       int32_t byte_offset = static_cast<int32_t>(typed_array.byte_offset());
375 
376       // We need to calculate the backing store from the data pointer
377       // because the ArrayBuffer may already have been serialized.
378       void* backing_store = reinterpret_cast<void*>(
379           reinterpret_cast<Address>(typed_array.DataPtr()) - byte_offset);
380 
381       uint32_t ref = SerializeBackingStore(backing_store, byte_length);
382       // To properly share the buffer, we set the backing store ref as an
383       // off-heap offset from nullptr. On deserialization we re-set data
384       // pointer to proper value.
385       typed_array.SetOffHeapDataPtr(nullptr, ref);
386       DCHECK_EQ(ref, reinterpret_cast<Address>(typed_array.DataPtr()));
387     } else {
388       typed_array.SetOffHeapDataPtr(nullptr, 0);
389     }
390   }
391   SerializeObject();
392 }
393 
SerializeJSArrayBuffer()394 void Serializer::ObjectSerializer::SerializeJSArrayBuffer() {
395   JSArrayBuffer buffer = JSArrayBuffer::cast(object_);
396   void* backing_store = buffer.backing_store();
397   // We cannot store byte_length larger than Smi range in the snapshot.
398   CHECK_LE(buffer.byte_length(), Smi::kMaxValue);
399   int32_t byte_length = static_cast<int32_t>(buffer.byte_length());
400   ArrayBufferExtension* extension = buffer.extension();
401 
402   // The embedder-allocated backing store only exists for the off-heap case.
403   if (backing_store != nullptr) {
404     uint32_t ref = SerializeBackingStore(backing_store, byte_length);
405     // To properly share the buffer, we set the backing store ref as an
406     // a backing store address. On deserialization we re-set data pointer
407     // to proper value.
408     buffer.set_backing_store(reinterpret_cast<void*>(static_cast<size_t>(ref)));
409 
410     // Ensure deterministic output by setting extension to null during
411     // serialization.
412     buffer.set_extension(nullptr);
413   }
414 
415   SerializeObject();
416 
417   buffer.set_backing_store(backing_store);
418   buffer.set_extension(extension);
419 }
420 
SerializeExternalString()421 void Serializer::ObjectSerializer::SerializeExternalString() {
422   // For external strings with known resources, we replace the resource field
423   // with the encoded external reference, which we restore upon deserialize.
424   // For the rest we serialize them to look like ordinary sequential strings.
425   ExternalString string = ExternalString::cast(object_);
426   Address resource = string.resource_as_address();
427   ExternalReferenceEncoder::Value reference;
428   if (serializer_->external_reference_encoder_.TryEncode(resource).To(
429           &reference)) {
430     DCHECK(reference.is_from_api());
431     string.set_uint32_as_resource(reference.index());
432     SerializeObject();
433     string.set_address_as_resource(resource);
434   } else {
435     SerializeExternalStringAsSequentialString();
436   }
437 }
438 
SerializeExternalStringAsSequentialString()439 void Serializer::ObjectSerializer::SerializeExternalStringAsSequentialString() {
440   // Instead of serializing this as an external string, we serialize
441   // an imaginary sequential string with the same content.
442   ReadOnlyRoots roots(serializer_->isolate());
443   DCHECK(object_.IsExternalString());
444   ExternalString string = ExternalString::cast(object_);
445   int length = string.length();
446   Map map;
447   int content_size;
448   int allocation_size;
449   const byte* resource;
450   // Find the map and size for the imaginary sequential string.
451   bool internalized = object_.IsInternalizedString();
452   if (object_.IsExternalOneByteString()) {
453     map = internalized ? roots.one_byte_internalized_string_map()
454                        : roots.one_byte_string_map();
455     allocation_size = SeqOneByteString::SizeFor(length);
456     content_size = length * kCharSize;
457     resource = reinterpret_cast<const byte*>(
458         ExternalOneByteString::cast(string).resource()->data());
459   } else {
460     map = internalized ? roots.internalized_string_map() : roots.string_map();
461     allocation_size = SeqTwoByteString::SizeFor(length);
462     content_size = length * kShortSize;
463     resource = reinterpret_cast<const byte*>(
464         ExternalTwoByteString::cast(string).resource()->data());
465   }
466 
467   SnapshotSpace space = (allocation_size > kMaxRegularHeapObjectSize)
468                             ? SnapshotSpace::kLargeObject
469                             : SnapshotSpace::kOld;
470   SerializePrologue(space, allocation_size, map);
471 
472   // Output the rest of the imaginary string.
473   int bytes_to_output = allocation_size - HeapObject::kHeaderSize;
474   DCHECK(IsAligned(bytes_to_output, kTaggedSize));
475 
476   // Output raw data header. Do not bother with common raw length cases here.
477   sink_->Put(kVariableRawData, "RawDataForString");
478   sink_->PutInt(bytes_to_output, "length");
479 
480   // Serialize string header (except for map).
481   uint8_t* string_start = reinterpret_cast<uint8_t*>(string.address());
482   for (int i = HeapObject::kHeaderSize; i < SeqString::kHeaderSize; i++) {
483     sink_->PutSection(string_start[i], "StringHeader");
484   }
485 
486   // Serialize string content.
487   sink_->PutRaw(resource, content_size, "StringContent");
488 
489   // Since the allocation size is rounded up to object alignment, there
490   // maybe left-over bytes that need to be padded.
491   int padding_size = allocation_size - SeqString::kHeaderSize - content_size;
492   DCHECK(0 <= padding_size && padding_size < kObjectAlignment);
493   for (int i = 0; i < padding_size; i++) sink_->PutSection(0, "StringPadding");
494 }
495 
496 // Clear and later restore the next link in the weak cell or allocation site.
497 // TODO(all): replace this with proper iteration of weak slots in serializer.
498 class UnlinkWeakNextScope {
499  public:
UnlinkWeakNextScope(Heap * heap,HeapObject object)500   explicit UnlinkWeakNextScope(Heap* heap, HeapObject object) {
501     if (object.IsAllocationSite() &&
502         AllocationSite::cast(object).HasWeakNext()) {
503       object_ = object;
504       next_ = AllocationSite::cast(object).weak_next();
505       AllocationSite::cast(object).set_weak_next(
506           ReadOnlyRoots(heap).undefined_value());
507     }
508   }
509 
~UnlinkWeakNextScope()510   ~UnlinkWeakNextScope() {
511     if (!object_.is_null()) {
512       AllocationSite::cast(object_).set_weak_next(next_,
513                                                   UPDATE_WEAK_WRITE_BARRIER);
514     }
515   }
516 
517  private:
518   HeapObject object_;
519   Object next_;
520   DISALLOW_HEAP_ALLOCATION(no_gc_)
521 };
522 
Serialize()523 void Serializer::ObjectSerializer::Serialize() {
524   if (FLAG_trace_serializer) {
525     PrintF(" Encoding heap object: ");
526     object_.ShortPrint();
527     PrintF("\n");
528   }
529 
530   if (object_.IsExternalString()) {
531     SerializeExternalString();
532     return;
533   } else if (!ReadOnlyHeap::Contains(object_)) {
534     // Only clear padding for strings outside the read-only heap. Read-only heap
535     // should have been cleared elsewhere.
536     if (object_.IsSeqOneByteString()) {
537       // Clear padding bytes at the end. Done here to avoid having to do this
538       // at allocation sites in generated code.
539       SeqOneByteString::cast(object_).clear_padding();
540     } else if (object_.IsSeqTwoByteString()) {
541       SeqTwoByteString::cast(object_).clear_padding();
542     }
543   }
544   if (object_.IsJSTypedArray()) {
545     SerializeJSTypedArray();
546     return;
547   }
548   if (object_.IsJSArrayBuffer()) {
549     SerializeJSArrayBuffer();
550     return;
551   }
552 
553   // We don't expect fillers.
554   DCHECK(!object_.IsFreeSpaceOrFiller());
555 
556   if (object_.IsScript()) {
557     // Clear cached line ends.
558     Object undefined = ReadOnlyRoots(serializer_->isolate()).undefined_value();
559     Script::cast(object_).set_line_ends(undefined);
560   }
561 
562   SerializeObject();
563 }
564 
565 namespace {
GetSnapshotSpace(HeapObject object)566 SnapshotSpace GetSnapshotSpace(HeapObject object) {
567 #if V8_ENABLE_THIRD_PARTY_HEAP_BOOL
568     if (third_party_heap::Heap::InCodeSpace(object.address())) {
569       return SnapshotSpace::kCode;
570     } else if (ReadOnlyHeap::Contains(object)) {
571       return SnapshotSpace::kReadOnlyHeap;
572     } else if (object.Size() > kMaxRegularHeapObjectSize) {
573       return SnapshotSpace::kLargeObject;
574     } else if (object.IsMap()) {
575       return SnapshotSpace::kMap;
576     } else {
577       return SnapshotSpace::kNew;  // avoid new/young distinction in TPH
578     }
579 #else
580   if (ReadOnlyHeap::Contains(object)) {
581     return SnapshotSpace::kReadOnlyHeap;
582   } else {
583     AllocationSpace heap_space =
584         MemoryChunk::FromHeapObject(object)->owner_identity();
585     // Large code objects are not supported and cannot be expressed by
586     // SnapshotSpace.
587     DCHECK_NE(heap_space, CODE_LO_SPACE);
588     // Young generation large objects are tenured.
589     if (heap_space == NEW_LO_SPACE) {
590       return SnapshotSpace::kLargeObject;
591     } else {
592       return static_cast<SnapshotSpace>(heap_space);
593     }
594   }
595 #endif
596 }
597 }  // namespace
598 
SerializeObject()599 void Serializer::ObjectSerializer::SerializeObject() {
600   int size = object_.Size();
601   Map map = object_.map();
602   SnapshotSpace space = GetSnapshotSpace(object_);
603   SerializePrologue(space, size, map);
604 
605   // Serialize the rest of the object.
606   CHECK_EQ(0, bytes_processed_so_far_);
607   bytes_processed_so_far_ = kTaggedSize;
608 
609   RecursionScope recursion(serializer_);
610   // Objects that are immediately post processed during deserialization
611   // cannot be deferred, since post processing requires the object content.
612   if ((recursion.ExceedsMaximum() && CanBeDeferred(object_)) ||
613       serializer_->MustBeDeferred(object_)) {
614     serializer_->QueueDeferredObject(object_);
615     sink_->Put(kDeferred, "Deferring object content");
616     return;
617   }
618 
619   SerializeContent(map, size);
620 }
621 
SerializeDeferred()622 void Serializer::ObjectSerializer::SerializeDeferred() {
623   if (FLAG_trace_serializer) {
624     PrintF(" Encoding deferred heap object: ");
625     object_.ShortPrint();
626     PrintF("\n");
627   }
628 
629   int size = object_.Size();
630   Map map = object_.map();
631   SerializerReference back_reference =
632       serializer_->reference_map()->LookupReference(
633           reinterpret_cast<void*>(object_.ptr()));
634   DCHECK(back_reference.is_back_reference());
635 
636   // Serialize the rest of the object.
637   CHECK_EQ(0, bytes_processed_so_far_);
638   bytes_processed_so_far_ = kTaggedSize;
639 
640   serializer_->PutAlignmentPrefix(object_);
641   sink_->Put(kNewObject + static_cast<int>(back_reference.space()),
642              "deferred object");
643   serializer_->PutBackReference(object_, back_reference);
644   sink_->PutInt(size >> kTaggedSizeLog2, "deferred object size");
645 
646   SerializeContent(map, size);
647 }
648 
SerializeContent(Map map,int size)649 void Serializer::ObjectSerializer::SerializeContent(Map map, int size) {
650   UnlinkWeakNextScope unlink_weak_next(serializer_->isolate()->heap(), object_);
651   if (object_.IsCode()) {
652     // For code objects, output raw bytes first.
653     OutputCode(size);
654     // Then iterate references via reloc info.
655     object_.IterateBody(map, size, this);
656   } else {
657     // For other objects, iterate references first.
658     object_.IterateBody(map, size, this);
659     // Then output data payload, if any.
660     OutputRawData(object_.address() + size);
661   }
662 }
663 
VisitPointers(HeapObject host,ObjectSlot start,ObjectSlot end)664 void Serializer::ObjectSerializer::VisitPointers(HeapObject host,
665                                                  ObjectSlot start,
666                                                  ObjectSlot end) {
667   VisitPointers(host, MaybeObjectSlot(start), MaybeObjectSlot(end));
668 }
669 
VisitPointers(HeapObject host,MaybeObjectSlot start,MaybeObjectSlot end)670 void Serializer::ObjectSerializer::VisitPointers(HeapObject host,
671                                                  MaybeObjectSlot start,
672                                                  MaybeObjectSlot end) {
673   DisallowHeapAllocation no_gc;
674 
675   MaybeObjectSlot current = start;
676   while (current < end) {
677     while (current < end && (*current)->IsSmi()) {
678       ++current;
679     }
680     if (current < end) {
681       OutputRawData(current.address());
682     }
683     // TODO(ishell): Revisit this change once we stick to 32-bit compressed
684     // tagged values.
685     while (current < end && (*current)->IsCleared()) {
686       sink_->Put(kClearedWeakReference, "ClearedWeakReference");
687       bytes_processed_so_far_ += kTaggedSize;
688       ++current;
689     }
690     HeapObject current_contents;
691     HeapObjectReferenceType reference_type;
692     while (current < end &&
693            (*current)->GetHeapObject(&current_contents, &reference_type)) {
694       RootIndex root_index;
695       // Compute repeat count and write repeat prefix if applicable.
696       // Repeats are not subject to the write barrier so we can only use
697       // immortal immovable root members. They are never in new space.
698       MaybeObjectSlot repeat_end = current + 1;
699       if (repeat_end < end &&
700           serializer_->root_index_map()->Lookup(current_contents,
701                                                 &root_index) &&
702           RootsTable::IsImmortalImmovable(root_index) &&
703           *current == *repeat_end) {
704         DCHECK_EQ(reference_type, HeapObjectReferenceType::STRONG);
705         DCHECK(!Heap::InYoungGeneration(current_contents));
706         while (repeat_end < end && *repeat_end == *current) {
707           repeat_end++;
708         }
709         int repeat_count = static_cast<int>(repeat_end - current);
710         current = repeat_end;
711         bytes_processed_so_far_ += repeat_count * kTaggedSize;
712         serializer_->PutRepeat(repeat_count);
713       } else {
714         bytes_processed_so_far_ += kTaggedSize;
715         ++current;
716       }
717       // Now write the object itself.
718       if (reference_type == HeapObjectReferenceType::WEAK) {
719         sink_->Put(kWeakPrefix, "WeakReference");
720       }
721       serializer_->SerializeObject(current_contents);
722     }
723   }
724 }
725 
VisitEmbeddedPointer(Code host,RelocInfo * rinfo)726 void Serializer::ObjectSerializer::VisitEmbeddedPointer(Code host,
727                                                         RelocInfo* rinfo) {
728   Object object = rinfo->target_object();
729   serializer_->SerializeObject(HeapObject::cast(object));
730   bytes_processed_so_far_ += rinfo->target_address_size();
731 }
732 
VisitExternalReference(Foreign host,Address * p)733 void Serializer::ObjectSerializer::VisitExternalReference(Foreign host,
734                                                           Address* p) {
735   auto encoded_reference =
736       serializer_->EncodeExternalReference(host.foreign_address());
737   if (encoded_reference.is_from_api()) {
738     sink_->Put(kApiReference, "ApiRef");
739   } else {
740     sink_->Put(kExternalReference, "ExternalRef");
741   }
742   sink_->PutInt(encoded_reference.index(), "reference index");
743   bytes_processed_so_far_ += kSystemPointerSize;
744 }
745 
VisitExternalReference(Code host,RelocInfo * rinfo)746 void Serializer::ObjectSerializer::VisitExternalReference(Code host,
747                                                           RelocInfo* rinfo) {
748   Address target = rinfo->target_external_reference();
749   auto encoded_reference = serializer_->EncodeExternalReference(target);
750   if (encoded_reference.is_from_api()) {
751     DCHECK(!rinfo->IsCodedSpecially());
752     sink_->Put(kApiReference, "ApiRef");
753   } else {
754     sink_->Put(kExternalReference, "ExternalRef");
755   }
756   DCHECK_NE(target, kNullAddress);  // Code does not reference null.
757   sink_->PutInt(encoded_reference.index(), "reference index");
758   bytes_processed_so_far_ += rinfo->target_address_size();
759 }
760 
VisitInternalReference(Code host,RelocInfo * rinfo)761 void Serializer::ObjectSerializer::VisitInternalReference(Code host,
762                                                           RelocInfo* rinfo) {
763   Address entry = Code::cast(object_).entry();
764   DCHECK_GE(rinfo->target_internal_reference(), entry);
765   uintptr_t target_offset = rinfo->target_internal_reference() - entry;
766   DCHECK_LE(target_offset, Code::cast(object_).raw_instruction_size());
767   sink_->Put(kInternalReference, "InternalRef");
768   sink_->PutInt(target_offset, "internal ref value");
769 }
770 
VisitRuntimeEntry(Code host,RelocInfo * rinfo)771 void Serializer::ObjectSerializer::VisitRuntimeEntry(Code host,
772                                                      RelocInfo* rinfo) {
773   // We no longer serialize code that contains runtime entries.
774   UNREACHABLE();
775 }
776 
VisitOffHeapTarget(Code host,RelocInfo * rinfo)777 void Serializer::ObjectSerializer::VisitOffHeapTarget(Code host,
778                                                       RelocInfo* rinfo) {
779   STATIC_ASSERT(EmbeddedData::kTableSize == Builtins::builtin_count);
780 
781   Address addr = rinfo->target_off_heap_target();
782   CHECK_NE(kNullAddress, addr);
783 
784   Code target = InstructionStream::TryLookupCode(serializer_->isolate(), addr);
785   CHECK(Builtins::IsIsolateIndependentBuiltin(target));
786 
787   sink_->Put(kOffHeapTarget, "OffHeapTarget");
788   sink_->PutInt(target.builtin_index(), "builtin index");
789   bytes_processed_so_far_ += rinfo->target_address_size();
790 }
791 
VisitCodeTarget(Code host,RelocInfo * rinfo)792 void Serializer::ObjectSerializer::VisitCodeTarget(Code host,
793                                                    RelocInfo* rinfo) {
794 #ifdef V8_TARGET_ARCH_ARM
795   DCHECK(!RelocInfo::IsRelativeCodeTarget(rinfo->rmode()));
796 #endif
797   Code object = Code::GetCodeFromTargetAddress(rinfo->target_address());
798   serializer_->SerializeObject(object);
799   bytes_processed_so_far_ += rinfo->target_address_size();
800 }
801 
802 namespace {
803 
804 // Similar to OutputRawData, but substitutes the given field with the given
805 // 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)806 void OutputRawWithCustomField(SnapshotByteSink* sink, Address object_start,
807                               int written_so_far, int bytes_to_write,
808                               int field_offset, int field_size,
809                               const byte* field_value) {
810   int offset = field_offset - written_so_far;
811   if (0 <= offset && offset < bytes_to_write) {
812     DCHECK_GE(bytes_to_write, offset + field_size);
813     sink->PutRaw(reinterpret_cast<byte*>(object_start + written_so_far), offset,
814                  "Bytes");
815     sink->PutRaw(field_value, field_size, "Bytes");
816     written_so_far += offset + field_size;
817     bytes_to_write -= offset + field_size;
818     sink->PutRaw(reinterpret_cast<byte*>(object_start + written_so_far),
819                  bytes_to_write, "Bytes");
820   } else {
821     sink->PutRaw(reinterpret_cast<byte*>(object_start + written_so_far),
822                  bytes_to_write, "Bytes");
823   }
824 }
825 }  // anonymous namespace
826 
OutputRawData(Address up_to)827 void Serializer::ObjectSerializer::OutputRawData(Address up_to) {
828   Address object_start = object_.address();
829   int base = bytes_processed_so_far_;
830   int up_to_offset = static_cast<int>(up_to - object_start);
831   int to_skip = up_to_offset - bytes_processed_so_far_;
832   int bytes_to_output = to_skip;
833   bytes_processed_so_far_ += to_skip;
834   DCHECK_GE(to_skip, 0);
835   if (bytes_to_output != 0) {
836     DCHECK(to_skip == bytes_to_output);
837     if (IsAligned(bytes_to_output, kObjectAlignment) &&
838         bytes_to_output <= kNumberOfFixedRawData * kTaggedSize) {
839       int size_in_words = bytes_to_output >> kTaggedSizeLog2;
840       sink_->PutSection(kFixedRawDataStart + size_in_words, "FixedRawData");
841     } else {
842       sink_->Put(kVariableRawData, "VariableRawData");
843       sink_->PutInt(bytes_to_output, "length");
844     }
845 #ifdef MEMORY_SANITIZER
846     // Check that we do not serialize uninitialized memory.
847     __msan_check_mem_is_initialized(
848         reinterpret_cast<void*>(object_start + base), bytes_to_output);
849 #endif  // MEMORY_SANITIZER
850     if (object_.IsBytecodeArray()) {
851       // The bytecode age field can be changed by GC concurrently.
852       byte field_value = BytecodeArray::kNoAgeBytecodeAge;
853       OutputRawWithCustomField(sink_, object_start, base, bytes_to_output,
854                                BytecodeArray::kBytecodeAgeOffset,
855                                sizeof(field_value), &field_value);
856     } else if (object_.IsDescriptorArray()) {
857       // The number of marked descriptors field can be changed by GC
858       // concurrently.
859       byte field_value[2];
860       field_value[0] = 0;
861       field_value[1] = 0;
862       OutputRawWithCustomField(
863           sink_, object_start, base, bytes_to_output,
864           DescriptorArray::kRawNumberOfMarkedDescriptorsOffset,
865           sizeof(field_value), field_value);
866     } else {
867       sink_->PutRaw(reinterpret_cast<byte*>(object_start + base),
868                     bytes_to_output, "Bytes");
869     }
870   }
871 }
872 
OutputCode(int size)873 void Serializer::ObjectSerializer::OutputCode(int size) {
874   DCHECK_EQ(kTaggedSize, bytes_processed_so_far_);
875   Code on_heap_code = Code::cast(object_);
876   // To make snapshots reproducible, we make a copy of the code object
877   // and wipe all pointers in the copy, which we then serialize.
878   Code off_heap_code = serializer_->CopyCode(on_heap_code);
879   int mode_mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
880                   RelocInfo::ModeMask(RelocInfo::FULL_EMBEDDED_OBJECT) |
881                   RelocInfo::ModeMask(RelocInfo::COMPRESSED_EMBEDDED_OBJECT) |
882                   RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
883                   RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) |
884                   RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED) |
885                   RelocInfo::ModeMask(RelocInfo::OFF_HEAP_TARGET) |
886                   RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
887   // With enabled pointer compression normal accessors no longer work for
888   // off-heap objects, so we have to get the relocation info data via the
889   // on-heap code object.
890   ByteArray relocation_info = on_heap_code.unchecked_relocation_info();
891   for (RelocIterator it(off_heap_code, relocation_info, mode_mask); !it.done();
892        it.next()) {
893     RelocInfo* rinfo = it.rinfo();
894     rinfo->WipeOut();
895   }
896   // We need to wipe out the header fields *after* wiping out the
897   // relocations, because some of these fields are needed for the latter.
898   off_heap_code.WipeOutHeader();
899 
900   Address start = off_heap_code.address() + Code::kDataStart;
901   int bytes_to_output = size - Code::kDataStart;
902   DCHECK(IsAligned(bytes_to_output, kTaggedSize));
903 
904   sink_->Put(kVariableRawCode, "VariableRawCode");
905   sink_->PutInt(bytes_to_output, "length");
906 
907 #ifdef MEMORY_SANITIZER
908   // Check that we do not serialize uninitialized memory.
909   __msan_check_mem_is_initialized(reinterpret_cast<void*>(start),
910                                   bytes_to_output);
911 #endif  // MEMORY_SANITIZER
912   sink_->PutRaw(reinterpret_cast<byte*>(start), bytes_to_output, "Code");
913 }
914 
915 }  // namespace internal
916 }  // namespace v8
917