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(¤t_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