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