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/assembler-inl.h"
8 #include "src/interpreter/interpreter.h"
9 #include "src/objects/code.h"
10 #include "src/objects/map.h"
11 #include "src/snapshot/builtin-serializer-allocator.h"
12 #include "src/snapshot/natives.h"
13 #include "src/snapshot/snapshot.h"
14 
15 namespace v8 {
16 namespace internal {
17 
18 template <class AllocatorT>
Serializer(Isolate * isolate)19 Serializer<AllocatorT>::Serializer(Isolate* isolate)
20     : isolate_(isolate),
21       external_reference_encoder_(isolate),
22       root_index_map_(isolate),
23       allocator_(this) {
24 #ifdef OBJECT_PRINT
25   if (FLAG_serialization_statistics) {
26     instance_type_count_ = NewArray<int>(kInstanceTypes);
27     instance_type_size_ = NewArray<size_t>(kInstanceTypes);
28     read_only_instance_type_count_ = NewArray<int>(kInstanceTypes);
29     read_only_instance_type_size_ = NewArray<size_t>(kInstanceTypes);
30     for (int i = 0; i < kInstanceTypes; i++) {
31       instance_type_count_[i] = 0;
32       instance_type_size_[i] = 0;
33       read_only_instance_type_count_[i] = 0;
34       read_only_instance_type_size_[i] = 0;
35     }
36   } else {
37     instance_type_count_ = nullptr;
38     instance_type_size_ = nullptr;
39     read_only_instance_type_count_ = nullptr;
40     read_only_instance_type_size_ = nullptr;
41   }
42 #endif  // OBJECT_PRINT
43 }
44 
45 template <class AllocatorT>
~Serializer()46 Serializer<AllocatorT>::~Serializer() {
47   if (code_address_map_ != nullptr) delete code_address_map_;
48 #ifdef OBJECT_PRINT
49   if (instance_type_count_ != nullptr) {
50     DeleteArray(instance_type_count_);
51     DeleteArray(instance_type_size_);
52     DeleteArray(read_only_instance_type_count_);
53     DeleteArray(read_only_instance_type_size_);
54   }
55 #endif  // OBJECT_PRINT
56 }
57 
58 #ifdef OBJECT_PRINT
59 template <class AllocatorT>
CountInstanceType(Map * map,int size,AllocationSpace space)60 void Serializer<AllocatorT>::CountInstanceType(Map* map, int size,
61                                                AllocationSpace space) {
62   int instance_type = map->instance_type();
63   if (space != RO_SPACE) {
64     instance_type_count_[instance_type]++;
65     instance_type_size_[instance_type] += size;
66   } else {
67     read_only_instance_type_count_[instance_type]++;
68     read_only_instance_type_size_[instance_type] += size;
69   }
70 }
71 #endif  // OBJECT_PRINT
72 
73 template <class AllocatorT>
OutputStatistics(const char * name)74 void Serializer<AllocatorT>::OutputStatistics(const char* name) {
75   if (!FLAG_serialization_statistics) return;
76 
77   PrintF("%s:\n", name);
78   allocator()->OutputStatistics();
79 
80 #ifdef OBJECT_PRINT
81   PrintF("  Instance types (count and bytes):\n");
82 #define PRINT_INSTANCE_TYPE(Name)                                 \
83   if (instance_type_count_[Name]) {                               \
84     PrintF("%10d %10" PRIuS "  %s\n", instance_type_count_[Name], \
85            instance_type_size_[Name], #Name);                     \
86   }
87   INSTANCE_TYPE_LIST(PRINT_INSTANCE_TYPE)
88 #undef PRINT_INSTANCE_TYPE
89   size_t read_only_total = 0;
90 #define UPDATE_TOTAL(Name) \
91   read_only_total += read_only_instance_type_size_[Name];
92   INSTANCE_TYPE_LIST(UPDATE_TOTAL)
93 #undef UPDATE_TOTAL
94   if (read_only_total > 0) {
95     PrintF("\n  Read Only Instance types (count and bytes):\n");
96 #define PRINT_INSTANCE_TYPE(Name)                                           \
97   if (read_only_instance_type_count_[Name]) {                               \
98     PrintF("%10d %10" PRIuS "  %s\n", read_only_instance_type_count_[Name], \
99            read_only_instance_type_size_[Name], #Name);                     \
100   }
101     INSTANCE_TYPE_LIST(PRINT_INSTANCE_TYPE)
102 #undef PRINT_INSTANCE_TYPE
103   }
104   PrintF("\n");
105 #endif  // OBJECT_PRINT
106 }
107 
108 template <class AllocatorT>
SerializeDeferredObjects()109 void Serializer<AllocatorT>::SerializeDeferredObjects() {
110   while (!deferred_objects_.empty()) {
111     HeapObject* obj = deferred_objects_.back();
112     deferred_objects_.pop_back();
113     ObjectSerializer obj_serializer(this, obj, &sink_, kPlain, kStartOfObject);
114     obj_serializer.SerializeDeferred();
115   }
116   sink_.Put(kSynchronize, "Finished with deferred objects");
117 }
118 
119 template <class AllocatorT>
MustBeDeferred(HeapObject * object)120 bool Serializer<AllocatorT>::MustBeDeferred(HeapObject* object) {
121   return false;
122 }
123 
124 template <class AllocatorT>
VisitRootPointers(Root root,const char * description,Object ** start,Object ** end)125 void Serializer<AllocatorT>::VisitRootPointers(Root root,
126                                                const char* description,
127                                                Object** start, Object** end) {
128   // Builtins and bytecode handlers are serialized in a separate pass by the
129   // BuiltinSerializer.
130   if (root == Root::kBuiltins || root == Root::kDispatchTable) return;
131 
132   for (Object** current = start; current < end; current++) {
133     if ((*current)->IsSmi()) {
134       PutSmi(Smi::cast(*current));
135     } else {
136       SerializeObject(HeapObject::cast(*current), kPlain, kStartOfObject, 0);
137     }
138   }
139 }
140 
141 #ifdef DEBUG
142 template <class AllocatorT>
PrintStack()143 void Serializer<AllocatorT>::PrintStack() {
144   for (const auto o : stack_) {
145     o->Print();
146     PrintF("\n");
147   }
148 }
149 #endif  // DEBUG
150 
151 template <class AllocatorT>
SerializeHotObject(HeapObject * obj,HowToCode how_to_code,WhereToPoint where_to_point,int skip)152 bool Serializer<AllocatorT>::SerializeHotObject(HeapObject* obj,
153                                                 HowToCode how_to_code,
154                                                 WhereToPoint where_to_point,
155                                                 int skip) {
156   if (how_to_code != kPlain || where_to_point != kStartOfObject) return false;
157   // Encode a reference to a hot object by its index in the working set.
158   int index = hot_objects_.Find(obj);
159   if (index == HotObjectsList::kNotFound) return false;
160   DCHECK(index >= 0 && index < kNumberOfHotObjects);
161   if (FLAG_trace_serializer) {
162     PrintF(" Encoding hot object %d:", index);
163     obj->ShortPrint();
164     PrintF("\n");
165   }
166   if (skip != 0) {
167     sink_.Put(kHotObjectWithSkip + index, "HotObjectWithSkip");
168     sink_.PutInt(skip, "HotObjectSkipDistance");
169   } else {
170     sink_.Put(kHotObject + index, "HotObject");
171   }
172   return true;
173 }
174 
175 template <class AllocatorT>
SerializeBackReference(HeapObject * obj,HowToCode how_to_code,WhereToPoint where_to_point,int skip)176 bool Serializer<AllocatorT>::SerializeBackReference(HeapObject* obj,
177                                                     HowToCode how_to_code,
178                                                     WhereToPoint where_to_point,
179                                                     int skip) {
180   SerializerReference reference = reference_map_.Lookup(obj);
181   if (!reference.is_valid()) return false;
182   // Encode the location of an already deserialized object in order to write
183   // its location into a later object.  We can encode the location as an
184   // offset fromthe start of the deserialized objects or as an offset
185   // backwards from thecurrent allocation pointer.
186   if (reference.is_attached_reference()) {
187     FlushSkip(skip);
188     if (FLAG_trace_serializer) {
189       PrintF(" Encoding attached reference %d\n",
190              reference.attached_reference_index());
191     }
192     PutAttachedReference(reference, how_to_code, where_to_point);
193   } else {
194     DCHECK(reference.is_back_reference());
195     if (FLAG_trace_serializer) {
196       PrintF(" Encoding back reference to: ");
197       obj->ShortPrint();
198       PrintF("\n");
199     }
200 
201     PutAlignmentPrefix(obj);
202     AllocationSpace space = reference.space();
203     if (skip == 0) {
204       sink_.Put(kBackref + how_to_code + where_to_point + space, "BackRef");
205     } else {
206       sink_.Put(kBackrefWithSkip + how_to_code + where_to_point + space,
207                 "BackRefWithSkip");
208       sink_.PutInt(skip, "BackRefSkipDistance");
209     }
210     PutBackReference(obj, reference);
211   }
212   return true;
213 }
214 
215 template <class AllocatorT>
SerializeBuiltinReference(HeapObject * obj,HowToCode how_to_code,WhereToPoint where_to_point,int skip)216 bool Serializer<AllocatorT>::SerializeBuiltinReference(
217     HeapObject* obj, HowToCode how_to_code, WhereToPoint where_to_point,
218     int skip) {
219   if (!obj->IsCode()) return false;
220 
221   Code* code = Code::cast(obj);
222   int builtin_index = code->builtin_index();
223   if (builtin_index < 0) return false;
224 
225   DCHECK((how_to_code == kPlain && where_to_point == kStartOfObject) ||
226          (how_to_code == kFromCode));
227   DCHECK_LT(builtin_index, Builtins::builtin_count);
228   DCHECK_LE(0, builtin_index);
229 
230   if (FLAG_trace_serializer) {
231     PrintF(" Encoding builtin reference: %s\n",
232            isolate()->builtins()->name(builtin_index));
233   }
234 
235   FlushSkip(skip);
236   sink_.Put(kBuiltin + how_to_code + where_to_point, "Builtin");
237   sink_.PutInt(builtin_index, "builtin_index");
238 
239   return true;
240 }
241 
242 template <class AllocatorT>
ObjectIsBytecodeHandler(HeapObject * obj) const243 bool Serializer<AllocatorT>::ObjectIsBytecodeHandler(HeapObject* obj) const {
244   if (!obj->IsCode()) return false;
245   Code* code = Code::cast(obj);
246   if (isolate()->heap()->IsDeserializeLazyHandler(code)) return false;
247   return (code->kind() == Code::BYTECODE_HANDLER);
248 }
249 
250 template <class AllocatorT>
PutRoot(int root_index,HeapObject * object,SerializerDeserializer::HowToCode how_to_code,SerializerDeserializer::WhereToPoint where_to_point,int skip)251 void Serializer<AllocatorT>::PutRoot(
252     int root_index, HeapObject* object,
253     SerializerDeserializer::HowToCode how_to_code,
254     SerializerDeserializer::WhereToPoint where_to_point, int skip) {
255   if (FLAG_trace_serializer) {
256     PrintF(" Encoding root %d:", root_index);
257     object->ShortPrint();
258     PrintF("\n");
259   }
260 
261   // Assert that the first 32 root array items are a conscious choice. They are
262   // chosen so that the most common ones can be encoded more efficiently.
263   STATIC_ASSERT(Heap::kEmptyDescriptorArrayRootIndex ==
264                 kNumberOfRootArrayConstants - 1);
265 
266   if (how_to_code == kPlain && where_to_point == kStartOfObject &&
267       root_index < kNumberOfRootArrayConstants &&
268       !isolate()->heap()->InNewSpace(object)) {
269     if (skip == 0) {
270       sink_.Put(kRootArrayConstants + root_index, "RootConstant");
271     } else {
272       sink_.Put(kRootArrayConstantsWithSkip + root_index, "RootConstant");
273       sink_.PutInt(skip, "SkipInPutRoot");
274     }
275   } else {
276     FlushSkip(skip);
277     sink_.Put(kRootArray + how_to_code + where_to_point, "RootSerialization");
278     sink_.PutInt(root_index, "root_index");
279     hot_objects_.Add(object);
280   }
281 }
282 
283 template <class AllocatorT>
PutSmi(Smi * smi)284 void Serializer<AllocatorT>::PutSmi(Smi* smi) {
285   sink_.Put(kOnePointerRawData, "Smi");
286   byte* bytes = reinterpret_cast<byte*>(&smi);
287   for (int i = 0; i < kPointerSize; i++) sink_.Put(bytes[i], "Byte");
288 }
289 
290 template <class AllocatorT>
PutBackReference(HeapObject * object,SerializerReference reference)291 void Serializer<AllocatorT>::PutBackReference(HeapObject* object,
292                                               SerializerReference reference) {
293   DCHECK(allocator()->BackReferenceIsAlreadyAllocated(reference));
294   sink_.PutInt(reference.back_reference(), "BackRefValue");
295   hot_objects_.Add(object);
296 }
297 
298 template <class AllocatorT>
PutAttachedReference(SerializerReference reference,HowToCode how_to_code,WhereToPoint where_to_point)299 void Serializer<AllocatorT>::PutAttachedReference(SerializerReference reference,
300                                                   HowToCode how_to_code,
301                                                   WhereToPoint where_to_point) {
302   DCHECK(reference.is_attached_reference());
303   DCHECK((how_to_code == kPlain && where_to_point == kStartOfObject) ||
304          (how_to_code == kFromCode && where_to_point == kStartOfObject) ||
305          (how_to_code == kFromCode && where_to_point == kInnerPointer));
306   sink_.Put(kAttachedReference + how_to_code + where_to_point, "AttachedRef");
307   sink_.PutInt(reference.attached_reference_index(), "AttachedRefIndex");
308 }
309 
310 template <class AllocatorT>
PutAlignmentPrefix(HeapObject * object)311 int Serializer<AllocatorT>::PutAlignmentPrefix(HeapObject* object) {
312   AllocationAlignment alignment = HeapObject::RequiredAlignment(object->map());
313   if (alignment != kWordAligned) {
314     DCHECK(1 <= alignment && alignment <= 3);
315     byte prefix = (kAlignmentPrefix - 1) + alignment;
316     sink_.Put(prefix, "Alignment");
317     return Heap::GetMaximumFillToAlign(alignment);
318   }
319   return 0;
320 }
321 
322 template <class AllocatorT>
PutNextChunk(int space)323 void Serializer<AllocatorT>::PutNextChunk(int space) {
324   sink_.Put(kNextChunk, "NextChunk");
325   sink_.Put(space, "NextChunkSpace");
326 }
327 
328 template <class AllocatorT>
Pad()329 void Serializer<AllocatorT>::Pad() {
330   // The non-branching GetInt will read up to 3 bytes too far, so we need
331   // to pad the snapshot to make sure we don't read over the end.
332   for (unsigned i = 0; i < sizeof(int32_t) - 1; i++) {
333     sink_.Put(kNop, "Padding");
334   }
335   // Pad up to pointer size for checksum.
336   while (!IsAligned(sink_.Position(), kPointerAlignment)) {
337     sink_.Put(kNop, "Padding");
338   }
339 }
340 
341 template <class AllocatorT>
InitializeCodeAddressMap()342 void Serializer<AllocatorT>::InitializeCodeAddressMap() {
343   isolate_->InitializeLoggingAndCounters();
344   code_address_map_ = new CodeAddressMap(isolate_);
345 }
346 
347 template <class AllocatorT>
CopyCode(Code * code)348 Code* Serializer<AllocatorT>::CopyCode(Code* code) {
349   code_buffer_.clear();  // Clear buffer without deleting backing store.
350   int size = code->CodeSize();
351   code_buffer_.insert(code_buffer_.end(),
352                       reinterpret_cast<byte*>(code->address()),
353                       reinterpret_cast<byte*>(code->address() + size));
354   return Code::cast(HeapObject::FromAddress(
355       reinterpret_cast<Address>(&code_buffer_.front())));
356 }
357 
358 template <class AllocatorT>
SerializePrologue(AllocationSpace space,int size,Map * map)359 void Serializer<AllocatorT>::ObjectSerializer::SerializePrologue(
360     AllocationSpace space, int size, Map* map) {
361   if (serializer_->code_address_map_) {
362     const char* code_name =
363         serializer_->code_address_map_->Lookup(object_->address());
364     LOG(serializer_->isolate_,
365         CodeNameEvent(object_->address(), sink_->Position(), code_name));
366   }
367 
368   SerializerReference back_reference;
369   if (space == LO_SPACE) {
370     sink_->Put(kNewObject + reference_representation_ + space,
371                "NewLargeObject");
372     sink_->PutInt(size >> kObjectAlignmentBits, "ObjectSizeInWords");
373     if (object_->IsCode()) {
374       sink_->Put(EXECUTABLE, "executable large object");
375     } else {
376       sink_->Put(NOT_EXECUTABLE, "not executable large object");
377     }
378     back_reference = serializer_->allocator()->AllocateLargeObject(size);
379   } else if (space == MAP_SPACE) {
380     DCHECK_EQ(Map::kSize, size);
381     back_reference = serializer_->allocator()->AllocateMap();
382     sink_->Put(kNewObject + reference_representation_ + space, "NewMap");
383     // This is redundant, but we include it anyways.
384     sink_->PutInt(size >> kObjectAlignmentBits, "ObjectSizeInWords");
385   } else {
386     int fill = serializer_->PutAlignmentPrefix(object_);
387     back_reference = serializer_->allocator()->Allocate(space, size + fill);
388     sink_->Put(kNewObject + reference_representation_ + space, "NewObject");
389     sink_->PutInt(size >> kObjectAlignmentBits, "ObjectSizeInWords");
390   }
391 
392 #ifdef OBJECT_PRINT
393   if (FLAG_serialization_statistics) {
394     serializer_->CountInstanceType(map, size, space);
395   }
396 #endif  // OBJECT_PRINT
397 
398   // Mark this object as already serialized.
399   serializer_->reference_map()->Add(object_, back_reference);
400 
401   // Serialize the map (first word of the object).
402   serializer_->SerializeObject(map, kPlain, kStartOfObject, 0);
403 }
404 
405 template <class AllocatorT>
SerializeBackingStore(void * backing_store,int32_t byte_length)406 int32_t Serializer<AllocatorT>::ObjectSerializer::SerializeBackingStore(
407     void* backing_store, int32_t byte_length) {
408   SerializerReference reference =
409       serializer_->reference_map()->Lookup(backing_store);
410 
411   // Serialize the off-heap backing store.
412   if (!reference.is_valid()) {
413     sink_->Put(kOffHeapBackingStore, "Off-heap backing store");
414     sink_->PutInt(byte_length, "length");
415     sink_->PutRaw(static_cast<byte*>(backing_store), byte_length,
416                   "BackingStore");
417     reference = serializer_->allocator()->AllocateOffHeapBackingStore();
418     // Mark this backing store as already serialized.
419     serializer_->reference_map()->Add(backing_store, reference);
420   }
421 
422   return static_cast<int32_t>(reference.off_heap_backing_store_index());
423 }
424 
425 template <class AllocatorT>
SerializeJSTypedArray()426 void Serializer<AllocatorT>::ObjectSerializer::SerializeJSTypedArray() {
427   JSTypedArray* typed_array = JSTypedArray::cast(object_);
428   FixedTypedArrayBase* elements =
429       FixedTypedArrayBase::cast(typed_array->elements());
430 
431   if (!typed_array->WasNeutered()) {
432     if (!typed_array->is_on_heap()) {
433       // Explicitly serialize the backing store now.
434       JSArrayBuffer* buffer = JSArrayBuffer::cast(typed_array->buffer());
435       CHECK(buffer->byte_length()->IsSmi());
436       CHECK(typed_array->byte_offset()->IsSmi());
437       int32_t byte_length = NumberToInt32(buffer->byte_length());
438       int32_t byte_offset = NumberToInt32(typed_array->byte_offset());
439 
440       // We need to calculate the backing store from the external pointer
441       // because the ArrayBuffer may already have been serialized.
442       void* backing_store = reinterpret_cast<void*>(
443           reinterpret_cast<intptr_t>(elements->external_pointer()) -
444           byte_offset);
445       int32_t ref = SerializeBackingStore(backing_store, byte_length);
446 
447       // The external_pointer is the backing_store + typed_array->byte_offset.
448       // To properly share the buffer, we set the backing store ref here. On
449       // deserialization we re-add the byte_offset to external_pointer.
450       elements->set_external_pointer(Smi::FromInt(ref));
451     }
452   } else {
453     // When a JSArrayBuffer is neutered, the FixedTypedArray that points to the
454     // same backing store does not know anything about it. This fixup step finds
455     // neutered TypedArrays and clears the values in the FixedTypedArray so that
456     // we don't try to serialize the now invalid backing store.
457     elements->set_external_pointer(Smi::kZero);
458     elements->set_length(0);
459   }
460   SerializeObject();
461 }
462 
463 template <class AllocatorT>
SerializeJSArrayBuffer()464 void Serializer<AllocatorT>::ObjectSerializer::SerializeJSArrayBuffer() {
465   JSArrayBuffer* buffer = JSArrayBuffer::cast(object_);
466   void* backing_store = buffer->backing_store();
467   // We cannot store byte_length larger than Smi range in the snapshot.
468   // Attempt to make sure that NumberToInt32 produces something sensible.
469   CHECK(buffer->byte_length()->IsSmi());
470   int32_t byte_length = NumberToInt32(buffer->byte_length());
471 
472   // The embedder-allocated backing store only exists for the off-heap case.
473   if (backing_store != nullptr) {
474     int32_t ref = SerializeBackingStore(backing_store, byte_length);
475     buffer->set_backing_store(Smi::FromInt(ref));
476   }
477   SerializeObject();
478   buffer->set_backing_store(backing_store);
479 }
480 
481 template <class AllocatorT>
SerializeExternalString()482 void Serializer<AllocatorT>::ObjectSerializer::SerializeExternalString() {
483   Heap* heap = serializer_->isolate()->heap();
484   // For external strings with known resources, we replace the resource field
485   // with the encoded external reference, which we restore upon deserialize.
486   // for native native source code strings, we replace the resource field
487   // with the native source id.
488   // For the rest we serialize them to look like ordinary sequential strings.
489   if (object_->map() != heap->native_source_string_map()) {
490     ExternalString* string = ExternalString::cast(object_);
491     Address resource = string->resource_as_address();
492     ExternalReferenceEncoder::Value reference;
493     if (serializer_->external_reference_encoder_.TryEncode(resource).To(
494             &reference)) {
495       DCHECK(reference.is_from_api());
496       string->set_uint32_as_resource(reference.index());
497       SerializeObject();
498       string->set_address_as_resource(resource);
499     } else {
500       SerializeExternalStringAsSequentialString();
501     }
502   } else {
503     ExternalOneByteString* string = ExternalOneByteString::cast(object_);
504     DCHECK(string->is_short());
505     const NativesExternalStringResource* resource =
506         reinterpret_cast<const NativesExternalStringResource*>(
507             string->resource());
508     // Replace the resource field with the type and index of the native source.
509     string->set_resource(resource->EncodeForSerialization());
510     SerializeObject();
511     // Restore the resource field.
512     string->set_resource(resource);
513   }
514 }
515 
516 template <class AllocatorT>
517 void Serializer<
SerializeExternalStringAsSequentialString()518     AllocatorT>::ObjectSerializer::SerializeExternalStringAsSequentialString() {
519   // Instead of serializing this as an external string, we serialize
520   // an imaginary sequential string with the same content.
521   Isolate* isolate = serializer_->isolate();
522   DCHECK(object_->IsExternalString());
523   DCHECK(object_->map() != isolate->heap()->native_source_string_map());
524   ExternalString* string = ExternalString::cast(object_);
525   int length = string->length();
526   Map* map;
527   int content_size;
528   int allocation_size;
529   const byte* resource;
530   // Find the map and size for the imaginary sequential string.
531   bool internalized = object_->IsInternalizedString();
532   if (object_->IsExternalOneByteString()) {
533     map = internalized ? isolate->heap()->one_byte_internalized_string_map()
534                        : isolate->heap()->one_byte_string_map();
535     allocation_size = SeqOneByteString::SizeFor(length);
536     content_size = length * kCharSize;
537     resource = reinterpret_cast<const byte*>(
538         ExternalOneByteString::cast(string)->resource()->data());
539   } else {
540     map = internalized ? isolate->heap()->internalized_string_map()
541                        : isolate->heap()->string_map();
542     allocation_size = SeqTwoByteString::SizeFor(length);
543     content_size = length * kShortSize;
544     resource = reinterpret_cast<const byte*>(
545         ExternalTwoByteString::cast(string)->resource()->data());
546   }
547 
548   AllocationSpace space =
549       (allocation_size > kMaxRegularHeapObjectSize) ? LO_SPACE : OLD_SPACE;
550   SerializePrologue(space, allocation_size, map);
551 
552   // Output the rest of the imaginary string.
553   int bytes_to_output = allocation_size - HeapObject::kHeaderSize;
554 
555   // Output raw data header. Do not bother with common raw length cases here.
556   sink_->Put(kVariableRawData, "RawDataForString");
557   sink_->PutInt(bytes_to_output, "length");
558 
559   // Serialize string header (except for map).
560   uint8_t* string_start = reinterpret_cast<uint8_t*>(string->address());
561   for (int i = HeapObject::kHeaderSize; i < SeqString::kHeaderSize; i++) {
562     sink_->PutSection(string_start[i], "StringHeader");
563   }
564 
565   // Serialize string content.
566   sink_->PutRaw(resource, content_size, "StringContent");
567 
568   // Since the allocation size is rounded up to object alignment, there
569   // maybe left-over bytes that need to be padded.
570   int padding_size = allocation_size - SeqString::kHeaderSize - content_size;
571   DCHECK(0 <= padding_size && padding_size < kObjectAlignment);
572   for (int i = 0; i < padding_size; i++) sink_->PutSection(0, "StringPadding");
573 }
574 
575 // Clear and later restore the next link in the weak cell or allocation site.
576 // TODO(all): replace this with proper iteration of weak slots in serializer.
577 class UnlinkWeakNextScope {
578  public:
UnlinkWeakNextScope(HeapObject * object)579   explicit UnlinkWeakNextScope(HeapObject* object) : object_(nullptr) {
580     if (object->IsAllocationSite()) {
581       object_ = object;
582       next_ = AllocationSite::cast(object)->weak_next();
583       AllocationSite::cast(object)->set_weak_next(
584           object->GetHeap()->undefined_value());
585     }
586   }
587 
~UnlinkWeakNextScope()588   ~UnlinkWeakNextScope() {
589     if (object_ != nullptr) {
590       AllocationSite::cast(object_)->set_weak_next(next_,
591                                                    UPDATE_WEAK_WRITE_BARRIER);
592     }
593   }
594 
595  private:
596   HeapObject* object_;
597   Object* next_;
598   DisallowHeapAllocation no_gc_;
599 };
600 
601 template <class AllocatorT>
Serialize()602 void Serializer<AllocatorT>::ObjectSerializer::Serialize() {
603   if (FLAG_trace_serializer) {
604     PrintF(" Encoding heap object: ");
605     object_->ShortPrint();
606     PrintF("\n");
607   }
608 
609   if (object_->IsExternalString()) {
610     SerializeExternalString();
611     return;
612   } else if (!serializer_->isolate()->heap()->InReadOnlySpace(object_)) {
613     // Only clear padding for strings outside RO_SPACE. RO_SPACE should have
614     // been cleared elsewhere.
615     if (object_->IsSeqOneByteString()) {
616       // Clear padding bytes at the end. Done here to avoid having to do this
617       // at allocation sites in generated code.
618       SeqOneByteString::cast(object_)->clear_padding();
619     } else if (object_->IsSeqTwoByteString()) {
620       SeqTwoByteString::cast(object_)->clear_padding();
621     }
622   }
623   if (object_->IsJSTypedArray()) {
624     SerializeJSTypedArray();
625     return;
626   }
627   if (object_->IsJSArrayBuffer()) {
628     SerializeJSArrayBuffer();
629     return;
630   }
631 
632   // We don't expect fillers.
633   DCHECK(!object_->IsFiller());
634 
635   if (object_->IsScript()) {
636     // Clear cached line ends.
637     Object* undefined = serializer_->isolate()->heap()->undefined_value();
638     Script::cast(object_)->set_line_ends(undefined);
639   }
640 
641   SerializeObject();
642 }
643 
644 template <class AllocatorT>
SerializeObject()645 void Serializer<AllocatorT>::ObjectSerializer::SerializeObject() {
646   int size = object_->Size();
647   Map* map = object_->map();
648   AllocationSpace space =
649       MemoryChunk::FromAddress(object_->address())->owner()->identity();
650   SerializePrologue(space, size, map);
651 
652   // Serialize the rest of the object.
653   CHECK_EQ(0, bytes_processed_so_far_);
654   bytes_processed_so_far_ = kPointerSize;
655 
656   RecursionScope recursion(serializer_);
657   // Objects that are immediately post processed during deserialization
658   // cannot be deferred, since post processing requires the object content.
659   if ((recursion.ExceedsMaximum() && CanBeDeferred(object_)) ||
660       serializer_->MustBeDeferred(object_)) {
661     serializer_->QueueDeferredObject(object_);
662     sink_->Put(kDeferred, "Deferring object content");
663     return;
664   }
665 
666   SerializeContent(map, size);
667 }
668 
669 template <class AllocatorT>
SerializeDeferred()670 void Serializer<AllocatorT>::ObjectSerializer::SerializeDeferred() {
671   if (FLAG_trace_serializer) {
672     PrintF(" Encoding deferred heap object: ");
673     object_->ShortPrint();
674     PrintF("\n");
675   }
676 
677   int size = object_->Size();
678   Map* map = object_->map();
679   SerializerReference back_reference =
680       serializer_->reference_map()->Lookup(object_);
681   DCHECK(back_reference.is_back_reference());
682 
683   // Serialize the rest of the object.
684   CHECK_EQ(0, bytes_processed_so_far_);
685   bytes_processed_so_far_ = kPointerSize;
686 
687   serializer_->PutAlignmentPrefix(object_);
688   sink_->Put(kNewObject + back_reference.space(), "deferred object");
689   serializer_->PutBackReference(object_, back_reference);
690   sink_->PutInt(size >> kPointerSizeLog2, "deferred object size");
691 
692   SerializeContent(map, size);
693 }
694 
695 template <class AllocatorT>
SerializeContent(Map * map,int size)696 void Serializer<AllocatorT>::ObjectSerializer::SerializeContent(Map* map,
697                                                                 int size) {
698   UnlinkWeakNextScope unlink_weak_next(object_);
699   if (object_->IsCode()) {
700     // For code objects, output raw bytes first.
701     OutputCode(size);
702     // Then iterate references via reloc info.
703     object_->IterateBody(map, size, this);
704     // Finally skip to the end.
705     serializer_->FlushSkip(SkipTo(object_->address() + size));
706   } else {
707     // For other objects, iterate references first.
708     object_->IterateBody(map, size, this);
709     // Then output data payload, if any.
710     OutputRawData(object_->address() + size);
711   }
712 }
713 
714 template <class AllocatorT>
VisitPointers(HeapObject * host,Object ** start,Object ** end)715 void Serializer<AllocatorT>::ObjectSerializer::VisitPointers(HeapObject* host,
716                                                              Object** start,
717                                                              Object** end) {
718   VisitPointers(host, reinterpret_cast<MaybeObject**>(start),
719                 reinterpret_cast<MaybeObject**>(end));
720 }
721 
722 template <class AllocatorT>
VisitPointers(HeapObject * host,MaybeObject ** start,MaybeObject ** end)723 void Serializer<AllocatorT>::ObjectSerializer::VisitPointers(
724     HeapObject* host, MaybeObject** start, MaybeObject** end) {
725   MaybeObject** current = start;
726   while (current < end) {
727     while (current < end &&
728            ((*current)->IsSmi() || (*current)->IsClearedWeakHeapObject())) {
729       current++;
730     }
731     if (current < end) {
732       OutputRawData(reinterpret_cast<Address>(current));
733     }
734     HeapObject* current_contents;
735     HeapObjectReferenceType reference_type;
736     while (current < end && (*current)->ToStrongOrWeakHeapObject(
737                                 &current_contents, &reference_type)) {
738       int root_index = serializer_->root_index_map()->Lookup(current_contents);
739       // Repeats are not subject to the write barrier so we can only use
740       // immortal immovable root members. They are never in new space.
741       if (current != start && root_index != RootIndexMap::kInvalidRootIndex &&
742           Heap::RootIsImmortalImmovable(root_index) &&
743           *current == current[-1]) {
744         DCHECK_EQ(reference_type, HeapObjectReferenceType::STRONG);
745         DCHECK(!serializer_->isolate()->heap()->InNewSpace(current_contents));
746         int repeat_count = 1;
747         while (&current[repeat_count] < end - 1 &&
748                current[repeat_count] == *current) {
749           repeat_count++;
750         }
751         current += repeat_count;
752         bytes_processed_so_far_ += repeat_count * kPointerSize;
753         if (repeat_count > kNumberOfFixedRepeat) {
754           sink_->Put(kVariableRepeat, "VariableRepeat");
755           sink_->PutInt(repeat_count, "repeat count");
756         } else {
757           sink_->Put(kFixedRepeatStart + repeat_count, "FixedRepeat");
758         }
759       } else {
760         if (reference_type == HeapObjectReferenceType::WEAK) {
761           sink_->Put(kWeakPrefix, "WeakReference");
762         }
763         serializer_->SerializeObject(current_contents, kPlain, kStartOfObject,
764                                      0);
765         bytes_processed_so_far_ += kPointerSize;
766         current++;
767       }
768     }
769   }
770 }
771 
772 template <class AllocatorT>
VisitEmbeddedPointer(Code * host,RelocInfo * rinfo)773 void Serializer<AllocatorT>::ObjectSerializer::VisitEmbeddedPointer(
774     Code* host, RelocInfo* rinfo) {
775   int skip = SkipTo(rinfo->target_address_address());
776   HowToCode how_to_code = rinfo->IsCodedSpecially() ? kFromCode : kPlain;
777   Object* object = rinfo->target_object();
778   serializer_->SerializeObject(HeapObject::cast(object), how_to_code,
779                                kStartOfObject, skip);
780   bytes_processed_so_far_ += rinfo->target_address_size();
781 }
782 
783 template <class AllocatorT>
VisitExternalReference(Foreign * host,Address * p)784 void Serializer<AllocatorT>::ObjectSerializer::VisitExternalReference(
785     Foreign* host, Address* p) {
786   int skip = SkipTo(reinterpret_cast<Address>(p));
787   Address target = *p;
788   auto encoded_reference = serializer_->EncodeExternalReference(target);
789   if (encoded_reference.is_from_api()) {
790     sink_->Put(kApiReference, "ApiRef");
791   } else {
792     sink_->Put(kExternalReference + kPlain + kStartOfObject, "ExternalRef");
793   }
794   sink_->PutInt(skip, "SkipB4ExternalRef");
795   sink_->PutInt(encoded_reference.index(), "reference index");
796   bytes_processed_so_far_ += kPointerSize;
797 }
798 
799 template <class AllocatorT>
VisitExternalReference(Code * host,RelocInfo * rinfo)800 void Serializer<AllocatorT>::ObjectSerializer::VisitExternalReference(
801     Code* host, RelocInfo* rinfo) {
802   int skip = SkipTo(rinfo->target_address_address());
803   Address target = rinfo->target_external_reference();
804   auto encoded_reference = serializer_->EncodeExternalReference(target);
805   if (encoded_reference.is_from_api()) {
806     DCHECK(!rinfo->IsCodedSpecially());
807     sink_->Put(kApiReference, "ApiRef");
808   } else {
809     HowToCode how_to_code = rinfo->IsCodedSpecially() ? kFromCode : kPlain;
810     sink_->Put(kExternalReference + how_to_code + kStartOfObject,
811                "ExternalRef");
812   }
813   sink_->PutInt(skip, "SkipB4ExternalRef");
814   DCHECK_NE(target, kNullAddress);  // Code does not reference null.
815   sink_->PutInt(encoded_reference.index(), "reference index");
816   bytes_processed_so_far_ += rinfo->target_address_size();
817 }
818 
819 template <class AllocatorT>
VisitInternalReference(Code * host,RelocInfo * rinfo)820 void Serializer<AllocatorT>::ObjectSerializer::VisitInternalReference(
821     Code* host, RelocInfo* rinfo) {
822   // We do not use skip from last patched pc to find the pc to patch, since
823   // target_address_address may not return addresses in ascending order when
824   // used for internal references. External references may be stored at the
825   // end of the code in the constant pool, whereas internal references are
826   // inline. That would cause the skip to be negative. Instead, we store the
827   // offset from code entry.
828   Address entry = Code::cast(object_)->entry();
829   DCHECK_GE(rinfo->target_internal_reference_address(), entry);
830   uintptr_t pc_offset = rinfo->target_internal_reference_address() - entry;
831   DCHECK_LE(pc_offset, Code::cast(object_)->raw_instruction_size());
832   DCHECK_GE(rinfo->target_internal_reference(), entry);
833   uintptr_t target_offset = rinfo->target_internal_reference() - entry;
834   DCHECK_LE(target_offset, Code::cast(object_)->raw_instruction_size());
835   sink_->Put(rinfo->rmode() == RelocInfo::INTERNAL_REFERENCE
836                  ? kInternalReference
837                  : kInternalReferenceEncoded,
838              "InternalRef");
839   sink_->PutInt(pc_offset, "internal ref address");
840   sink_->PutInt(target_offset, "internal ref value");
841 }
842 
843 template <class AllocatorT>
VisitRuntimeEntry(Code * host,RelocInfo * rinfo)844 void Serializer<AllocatorT>::ObjectSerializer::VisitRuntimeEntry(
845     Code* host, RelocInfo* rinfo) {
846   int skip = SkipTo(rinfo->target_address_address());
847   HowToCode how_to_code = rinfo->IsCodedSpecially() ? kFromCode : kPlain;
848   Address target = rinfo->target_address();
849   auto encoded_reference = serializer_->EncodeExternalReference(target);
850   DCHECK(!encoded_reference.is_from_api());
851   sink_->Put(kExternalReference + how_to_code + kStartOfObject, "ExternalRef");
852   sink_->PutInt(skip, "SkipB4ExternalRef");
853   sink_->PutInt(encoded_reference.index(), "reference index");
854   bytes_processed_so_far_ += rinfo->target_address_size();
855 }
856 
857 template <class AllocatorT>
VisitOffHeapTarget(Code * host,RelocInfo * rinfo)858 void Serializer<AllocatorT>::ObjectSerializer::VisitOffHeapTarget(
859     Code* host, RelocInfo* rinfo) {
860 #ifdef V8_EMBEDDED_BUILTINS
861   {
862     STATIC_ASSERT(EmbeddedData::kTableSize == Builtins::builtin_count);
863     CHECK(Builtins::IsEmbeddedBuiltin(host));
864     Address addr = rinfo->target_off_heap_target();
865     CHECK_NE(kNullAddress, addr);
866     CHECK_NOT_NULL(
867         InstructionStream::TryLookupCode(serializer_->isolate(), addr));
868   }
869 
870   int skip = SkipTo(rinfo->target_address_address());
871   sink_->Put(kOffHeapTarget, "OffHeapTarget");
872   sink_->PutInt(skip, "SkipB4OffHeapTarget");
873   sink_->PutInt(host->builtin_index(), "builtin index");
874   bytes_processed_so_far_ += rinfo->target_address_size();
875 #else
876   UNREACHABLE();
877 #endif
878 }
879 
880 namespace {
881 class CompareRelocInfo {
882  public:
operator ()(RelocInfo x,RelocInfo y)883   bool operator()(RelocInfo x, RelocInfo y) {
884     // Everything that does not use target_address_address will compare equal.
885     Address x_num = 0;
886     Address y_num = 0;
887     if (HasTargetAddressAddress(x.rmode())) {
888       x_num = x.target_address_address();
889     }
890     if (HasTargetAddressAddress(y.rmode())) {
891       y_num = y.target_address_address();
892     }
893     return x_num > y_num;
894   }
895 
896  private:
HasTargetAddressAddress(RelocInfo::Mode mode)897   static bool HasTargetAddressAddress(RelocInfo::Mode mode) {
898     return RelocInfo::IsEmbeddedObject(mode) || RelocInfo::IsCodeTarget(mode) ||
899            RelocInfo::IsExternalReference(mode) ||
900            RelocInfo::IsRuntimeEntry(mode);
901   }
902 };
903 }  // namespace
904 
905 template <class AllocatorT>
VisitRelocInfo(RelocIterator * it)906 void Serializer<AllocatorT>::ObjectSerializer::VisitRelocInfo(
907     RelocIterator* it) {
908   std::priority_queue<RelocInfo, std::vector<RelocInfo>, CompareRelocInfo>
909       reloc_queue;
910   for (; !it->done(); it->next()) {
911     reloc_queue.push(*it->rinfo());
912   }
913   while (!reloc_queue.empty()) {
914     RelocInfo rinfo = reloc_queue.top();
915     reloc_queue.pop();
916     rinfo.Visit(this);
917   }
918 }
919 
920 template <class AllocatorT>
VisitCodeTarget(Code * host,RelocInfo * rinfo)921 void Serializer<AllocatorT>::ObjectSerializer::VisitCodeTarget(
922     Code* host, RelocInfo* rinfo) {
923   int skip = SkipTo(rinfo->target_address_address());
924   Code* object = Code::GetCodeFromTargetAddress(rinfo->target_address());
925   serializer_->SerializeObject(object, kFromCode, kInnerPointer, skip);
926   bytes_processed_so_far_ += rinfo->target_address_size();
927 }
928 
929 template <class AllocatorT>
OutputRawData(Address up_to)930 void Serializer<AllocatorT>::ObjectSerializer::OutputRawData(Address up_to) {
931   Address object_start = object_->address();
932   int base = bytes_processed_so_far_;
933   int up_to_offset = static_cast<int>(up_to - object_start);
934   int to_skip = up_to_offset - bytes_processed_so_far_;
935   int bytes_to_output = to_skip;
936   bytes_processed_so_far_ += to_skip;
937   DCHECK_GE(to_skip, 0);
938   if (bytes_to_output != 0) {
939     DCHECK(to_skip == bytes_to_output);
940     if (IsAligned(bytes_to_output, kPointerAlignment) &&
941         bytes_to_output <= kNumberOfFixedRawData * kPointerSize) {
942       int size_in_words = bytes_to_output >> kPointerSizeLog2;
943       sink_->PutSection(kFixedRawDataStart + size_in_words, "FixedRawData");
944     } else {
945       sink_->Put(kVariableRawData, "VariableRawData");
946       sink_->PutInt(bytes_to_output, "length");
947     }
948 #ifdef MEMORY_SANITIZER
949     // Check that we do not serialize uninitialized memory.
950     __msan_check_mem_is_initialized(
951         reinterpret_cast<void*>(object_start + base), bytes_to_output);
952 #endif  // MEMORY_SANITIZER
953     if (object_->IsBytecodeArray()) {
954       // The code age byte can be changed concurrently by GC.
955       const int bytes_to_age_byte = BytecodeArray::kBytecodeAgeOffset - base;
956       if (0 <= bytes_to_age_byte && bytes_to_age_byte < bytes_to_output) {
957         sink_->PutRaw(reinterpret_cast<byte*>(object_start + base),
958                       bytes_to_age_byte, "Bytes");
959         byte bytecode_age = BytecodeArray::kNoAgeBytecodeAge;
960         sink_->PutRaw(&bytecode_age, 1, "Bytes");
961         const int bytes_written = bytes_to_age_byte + 1;
962         sink_->PutRaw(
963             reinterpret_cast<byte*>(object_start + base + bytes_written),
964             bytes_to_output - bytes_written, "Bytes");
965       } else {
966         sink_->PutRaw(reinterpret_cast<byte*>(object_start + base),
967                       bytes_to_output, "Bytes");
968       }
969     } else {
970       sink_->PutRaw(reinterpret_cast<byte*>(object_start + base),
971                     bytes_to_output, "Bytes");
972     }
973   }
974 }
975 
976 template <class AllocatorT>
SkipTo(Address to)977 int Serializer<AllocatorT>::ObjectSerializer::SkipTo(Address to) {
978   Address object_start = object_->address();
979   int up_to_offset = static_cast<int>(to - object_start);
980   int to_skip = up_to_offset - bytes_processed_so_far_;
981   bytes_processed_so_far_ += to_skip;
982   // This assert will fail if the reloc info gives us the target_address_address
983   // locations in a non-ascending order. We make sure this doesn't happen by
984   // sorting the relocation info.
985   DCHECK_GE(to_skip, 0);
986   return to_skip;
987 }
988 
989 template <class AllocatorT>
OutputCode(int size)990 void Serializer<AllocatorT>::ObjectSerializer::OutputCode(int size) {
991   DCHECK_EQ(kPointerSize, bytes_processed_so_far_);
992   Code* code = Code::cast(object_);
993   // To make snapshots reproducible, we make a copy of the code object
994   // and wipe all pointers in the copy, which we then serialize.
995   code = serializer_->CopyCode(code);
996   int mode_mask = RelocInfo::kCodeTargetMask |
997                   RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
998                   RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
999                   RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) |
1000                   RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) |
1001                   RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED);
1002   for (RelocIterator it(code, mode_mask); !it.done(); it.next()) {
1003     RelocInfo* rinfo = it.rinfo();
1004     rinfo->WipeOut();
1005   }
1006   // We need to wipe out the header fields *after* wiping out the
1007   // relocations, because some of these fields are needed for the latter.
1008   code->WipeOutHeader();
1009 
1010   Address start = code->address() + Code::kDataStart;
1011   int bytes_to_output = size - Code::kDataStart;
1012 
1013   sink_->Put(kVariableRawCode, "VariableRawCode");
1014   sink_->PutInt(bytes_to_output, "length");
1015 
1016 #ifdef MEMORY_SANITIZER
1017   // Check that we do not serialize uninitialized memory.
1018   __msan_check_mem_is_initialized(reinterpret_cast<void*>(start),
1019                                   bytes_to_output);
1020 #endif  // MEMORY_SANITIZER
1021   sink_->PutRaw(reinterpret_cast<byte*>(start), bytes_to_output, "Code");
1022 }
1023 
1024 // Explicit instantiation.
1025 template class Serializer<BuiltinSerializerAllocator>;
1026 template class Serializer<DefaultSerializerAllocator>;
1027 
1028 }  // namespace internal
1029 }  // namespace v8
1030