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