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/deserializer.h"
6
7#include "src/base/logging.h"
8#include "src/base/platform/wrappers.h"
9#include "src/codegen/assembler-inl.h"
10#include "src/common/assert-scope.h"
11#include "src/common/globals.h"
12#include "src/execution/isolate.h"
13#include "src/heap/heap-inl.h"
14#include "src/heap/heap-write-barrier-inl.h"
15#include "src/heap/heap-write-barrier.h"
16#include "src/heap/heap.h"
17#include "src/heap/local-heap-inl.h"
18#include "src/heap/read-only-heap.h"
19#include "src/interpreter/interpreter.h"
20#include "src/logging/local-logger.h"
21#include "src/logging/log.h"
22#include "src/objects/api-callbacks.h"
23#include "src/objects/backing-store.h"
24#include "src/objects/cell-inl.h"
25#include "src/objects/embedder-data-array-inl.h"
26#include "src/objects/hash-table.h"
27#include "src/objects/js-array-buffer-inl.h"
28#include "src/objects/js-array-inl.h"
29#include "src/objects/maybe-object.h"
30#include "src/objects/objects-body-descriptors-inl.h"
31#include "src/objects/objects.h"
32#include "src/objects/slots.h"
33#include "src/objects/string.h"
34#include "src/roots/roots.h"
35#include "src/sandbox/external-pointer.h"
36#include "src/snapshot/embedded/embedded-data-inl.h"
37#include "src/snapshot/references.h"
38#include "src/snapshot/serializer-deserializer.h"
39#include "src/snapshot/shared-heap-serializer.h"
40#include "src/snapshot/snapshot-data.h"
41#include "src/snapshot/snapshot.h"
42#include "src/tracing/trace-event.h"
43#include "src/tracing/traced-value.h"
44#include "src/utils/memcopy.h"
45
46namespace v8 {
47namespace internal {
48
49// A SlotAccessor for a slot in a HeapObject, which abstracts the slot
50// operations done by the deserializer in a way which is GC-safe. In particular,
51// rather than an absolute slot address, this accessor holds a Handle to the
52// HeapObject, which is updated if the HeapObject moves.
53class SlotAccessorForHeapObject {
54 public:
55  static SlotAccessorForHeapObject ForSlotIndex(Handle<HeapObject> object,
56                                                int index) {
57    return SlotAccessorForHeapObject(object, index * kTaggedSize);
58  }
59  static SlotAccessorForHeapObject ForSlotOffset(Handle<HeapObject> object,
60                                                 int offset) {
61    return SlotAccessorForHeapObject(object, offset);
62  }
63
64  MaybeObjectSlot slot() const { return object_->RawMaybeWeakField(offset_); }
65  Handle<HeapObject> object() const { return object_; }
66  int offset() const { return offset_; }
67
68  // Writes the given value to this slot, optionally with an offset (e.g. for
69  // repeat writes). Returns the number of slots written (which is one).
70  int Write(MaybeObject value, int slot_offset = 0) {
71    MaybeObjectSlot current_slot = slot() + slot_offset;
72    current_slot.Relaxed_Store(value);
73    WriteBarrier::Marking(*object_, current_slot, value);
74    // No need for a generational write barrier.
75    DCHECK(!Heap::InYoungGeneration(value));
76    return 1;
77  }
78  int Write(HeapObject value, HeapObjectReferenceType ref_type,
79            int slot_offset = 0) {
80    return Write(HeapObjectReference::From(value, ref_type), slot_offset);
81  }
82  int Write(Handle<HeapObject> value, HeapObjectReferenceType ref_type,
83            int slot_offset = 0) {
84    return Write(*value, ref_type, slot_offset);
85  }
86
87  // Same as Write, but additionally with a generational barrier.
88  int WriteWithGenerationalBarrier(MaybeObject value) {
89    MaybeObjectSlot current_slot = slot();
90    current_slot.Relaxed_Store(value);
91    WriteBarrier::Marking(*object_, current_slot, value);
92    if (Heap::InYoungGeneration(value)) {
93      GenerationalBarrier(*object_, current_slot, value);
94    }
95    return 1;
96  }
97  int WriteWithGenerationalBarrier(HeapObject value,
98                                   HeapObjectReferenceType ref_type) {
99    return WriteWithGenerationalBarrier(
100        HeapObjectReference::From(value, ref_type));
101  }
102  int WriteWithGenerationalBarrier(Handle<HeapObject> value,
103                                   HeapObjectReferenceType ref_type) {
104    return WriteWithGenerationalBarrier(*value, ref_type);
105  }
106
107 private:
108  SlotAccessorForHeapObject(Handle<HeapObject> object, int offset)
109      : object_(object), offset_(offset) {}
110
111  const Handle<HeapObject> object_;
112  const int offset_;
113};
114
115// A SlotAccessor for absolute full slot addresses.
116class SlotAccessorForRootSlots {
117 public:
118  explicit SlotAccessorForRootSlots(FullMaybeObjectSlot slot) : slot_(slot) {}
119
120  FullMaybeObjectSlot slot() const { return slot_; }
121  Handle<HeapObject> object() const { UNREACHABLE(); }
122  int offset() const { UNREACHABLE(); }
123
124  // Writes the given value to this slot, optionally with an offset (e.g. for
125  // repeat writes). Returns the number of slots written (which is one).
126  int Write(MaybeObject value, int slot_offset = 0) {
127    FullMaybeObjectSlot current_slot = slot() + slot_offset;
128    current_slot.Relaxed_Store(value);
129    return 1;
130  }
131  int Write(HeapObject value, HeapObjectReferenceType ref_type,
132            int slot_offset = 0) {
133    return Write(HeapObjectReference::From(value, ref_type), slot_offset);
134  }
135  int Write(Handle<HeapObject> value, HeapObjectReferenceType ref_type,
136            int slot_offset = 0) {
137    return Write(*value, ref_type, slot_offset);
138  }
139
140  int WriteWithGenerationalBarrier(MaybeObject value) { return Write(value); }
141  int WriteWithGenerationalBarrier(HeapObject value,
142                                   HeapObjectReferenceType ref_type) {
143    return WriteWithGenerationalBarrier(
144        HeapObjectReference::From(value, ref_type));
145  }
146  int WriteWithGenerationalBarrier(Handle<HeapObject> value,
147                                   HeapObjectReferenceType ref_type) {
148    return WriteWithGenerationalBarrier(*value, ref_type);
149  }
150
151 private:
152  const FullMaybeObjectSlot slot_;
153};
154
155// A SlotAccessor for creating a Handle, which saves a Handle allocation when
156// a Handle already exists.
157template <typename IsolateT>
158class SlotAccessorForHandle {
159 public:
160  SlotAccessorForHandle(Handle<HeapObject>* handle, IsolateT* isolate)
161      : handle_(handle), isolate_(isolate) {}
162
163  MaybeObjectSlot slot() const { UNREACHABLE(); }
164  Handle<HeapObject> object() const { UNREACHABLE(); }
165  int offset() const { UNREACHABLE(); }
166
167  int Write(MaybeObject value, int slot_offset = 0) { UNREACHABLE(); }
168  int Write(HeapObject value, HeapObjectReferenceType ref_type,
169            int slot_offset = 0) {
170    DCHECK_EQ(slot_offset, 0);
171    DCHECK_EQ(ref_type, HeapObjectReferenceType::STRONG);
172    *handle_ = handle(value, isolate_);
173    return 1;
174  }
175  int Write(Handle<HeapObject> value, HeapObjectReferenceType ref_type,
176            int slot_offset = 0) {
177    DCHECK_EQ(slot_offset, 0);
178    DCHECK_EQ(ref_type, HeapObjectReferenceType::STRONG);
179    *handle_ = value;
180    return 1;
181  }
182
183  int WriteWithGenerationalBarrier(HeapObject value,
184                                   HeapObjectReferenceType ref_type) {
185    return Write(value, ref_type);
186  }
187  int WriteWithGenerationalBarrier(Handle<HeapObject> value,
188                                   HeapObjectReferenceType ref_type) {
189    return Write(value, ref_type);
190  }
191
192 private:
193  Handle<HeapObject>* handle_;
194  IsolateT* isolate_;
195};
196
197template <typename IsolateT>
198template <typename TSlot>
199int Deserializer<IsolateT>::WriteAddress(TSlot dest, Address value) {
200  DCHECK(!next_reference_is_weak_);
201  memcpy(dest.ToVoidPtr(), &value, kSystemPointerSize);
202  STATIC_ASSERT(IsAligned(kSystemPointerSize, TSlot::kSlotDataSize));
203  return (kSystemPointerSize / TSlot::kSlotDataSize);
204}
205
206template <typename IsolateT>
207template <typename TSlot>
208int Deserializer<IsolateT>::WriteExternalPointer(TSlot dest, Address value,
209                                                 ExternalPointerTag tag) {
210  DCHECK(!next_reference_is_weak_);
211  DCHECK(IsAligned(kExternalPointerSize, TSlot::kSlotDataSize));
212  InitExternalPointerField(dest.address(), main_thread_isolate(), value, tag);
213  return (kExternalPointerSize / TSlot::kSlotDataSize);
214}
215
216namespace {
217#ifdef DEBUG
218int GetNumApiReferences(Isolate* isolate) {
219  int num_api_references = 0;
220  // The read-only deserializer is run by read-only heap set-up before the
221  // heap is fully set up. External reference table relies on a few parts of
222  // this set-up (like old-space), so it may be uninitialized at this point.
223  if (isolate->isolate_data()->external_reference_table()->is_initialized()) {
224    // Count the number of external references registered through the API.
225    if (isolate->api_external_references() != nullptr) {
226      while (isolate->api_external_references()[num_api_references] != 0) {
227        num_api_references++;
228      }
229    }
230  }
231  return num_api_references;
232}
233int GetNumApiReferences(LocalIsolate* isolate) { return 0; }
234#endif
235}  // namespace
236
237template <typename IsolateT>
238Deserializer<IsolateT>::Deserializer(IsolateT* isolate,
239                                     base::Vector<const byte> payload,
240                                     uint32_t magic_number,
241                                     bool deserializing_user_code,
242                                     bool can_rehash)
243    : isolate_(isolate),
244      source_(payload),
245      magic_number_(magic_number),
246      deserializing_user_code_(deserializing_user_code),
247      should_rehash_((FLAG_rehash_snapshot && can_rehash) ||
248                     deserializing_user_code) {
249  DCHECK_NOT_NULL(isolate);
250  isolate->RegisterDeserializerStarted();
251
252  // We start the indices here at 1, so that we can distinguish between an
253  // actual index and an empty backing store (serialized as
254  // kEmptyBackingStoreRefSentinel) in a deserialized object requiring fix-up.
255  STATIC_ASSERT(kEmptyBackingStoreRefSentinel == 0);
256  backing_stores_.push_back({});
257
258#ifdef DEBUG
259  num_api_references_ = GetNumApiReferences(isolate);
260#endif  // DEBUG
261  CHECK_EQ(magic_number_, SerializedData::kMagicNumber);
262}
263
264template <typename IsolateT>
265void Deserializer<IsolateT>::Rehash() {
266  DCHECK(should_rehash());
267  for (Handle<HeapObject> item : to_rehash_) {
268    item->RehashBasedOnMap(isolate());
269  }
270}
271
272template <typename IsolateT>
273Deserializer<IsolateT>::~Deserializer() {
274#ifdef DEBUG
275  // Do not perform checks if we aborted deserialization.
276  if (source_.position() == 0) return;
277  // Check that we only have padding bytes remaining.
278  while (source_.HasMore()) DCHECK_EQ(kNop, source_.Get());
279  // Check that there are no remaining forward refs.
280  DCHECK_EQ(num_unresolved_forward_refs_, 0);
281  DCHECK(unresolved_forward_refs_.empty());
282#endif  // DEBUG
283  isolate_->RegisterDeserializerFinished();
284}
285
286// This is called on the roots.  It is the driver of the deserialization
287// process.  It is also called on the body of each function.
288template <typename IsolateT>
289void Deserializer<IsolateT>::VisitRootPointers(Root root,
290                                               const char* description,
291                                               FullObjectSlot start,
292                                               FullObjectSlot end) {
293  ReadData(FullMaybeObjectSlot(start), FullMaybeObjectSlot(end));
294}
295
296template <typename IsolateT>
297void Deserializer<IsolateT>::Synchronize(VisitorSynchronization::SyncTag tag) {
298  static const byte expected = kSynchronize;
299  CHECK_EQ(expected, source_.Get());
300}
301
302template <typename IsolateT>
303void Deserializer<IsolateT>::DeserializeDeferredObjects() {
304  for (int code = source_.Get(); code != kSynchronize; code = source_.Get()) {
305    SnapshotSpace space = NewObject::Decode(code);
306    ReadObject(space);
307  }
308}
309
310template <typename IsolateT>
311void Deserializer<IsolateT>::LogNewMapEvents() {
312  if (V8_LIKELY(!FLAG_log_maps)) return;
313  DisallowGarbageCollection no_gc;
314  for (Handle<Map> map : new_maps_) {
315    DCHECK(FLAG_log_maps);
316    LOG(isolate(), MapCreate(*map));
317    LOG(isolate(), MapDetails(*map));
318  }
319}
320
321template <typename IsolateT>
322void Deserializer<IsolateT>::WeakenDescriptorArrays() {
323  DisallowGarbageCollection no_gc;
324  Map descriptor_array_map = ReadOnlyRoots(isolate()).descriptor_array_map();
325  for (Handle<DescriptorArray> descriptor_array : new_descriptor_arrays_) {
326    DescriptorArray raw = *descriptor_array;
327    DCHECK(raw.IsStrongDescriptorArray());
328    raw.set_map_safe_transition(descriptor_array_map);
329    WriteBarrier::Marking(raw, raw.number_of_descriptors());
330  }
331}
332
333template <typename IsolateT>
334void Deserializer<IsolateT>::LogScriptEvents(Script script) {
335  DisallowGarbageCollection no_gc;
336  LOG(isolate(),
337      ScriptEvent(Logger::ScriptEventType::kDeserialize, script.id()));
338  LOG(isolate(), ScriptDetails(script));
339}
340
341namespace {
342template <typename IsolateT>
343uint32_t ComputeRawHashField(IsolateT* isolate, String string) {
344  // Make sure raw_hash_field() is computed.
345  string.EnsureHash(SharedStringAccessGuardIfNeeded(isolate));
346  return string.raw_hash_field();
347}
348}  // namespace
349
350StringTableInsertionKey::StringTableInsertionKey(
351    Isolate* isolate, Handle<String> string,
352    DeserializingUserCodeOption deserializing_user_code)
353    : StringTableKey(ComputeRawHashField(isolate, *string), string->length()),
354      string_(string) {
355#ifdef DEBUG
356  deserializing_user_code_ = deserializing_user_code;
357#endif
358  DCHECK(string->IsInternalizedString());
359}
360
361StringTableInsertionKey::StringTableInsertionKey(
362    LocalIsolate* isolate, Handle<String> string,
363    DeserializingUserCodeOption deserializing_user_code)
364    : StringTableKey(ComputeRawHashField(isolate, *string), string->length()),
365      string_(string) {
366#ifdef DEBUG
367  deserializing_user_code_ = deserializing_user_code;
368#endif
369  DCHECK(string->IsInternalizedString());
370}
371
372template <typename IsolateT>
373bool StringTableInsertionKey::IsMatch(IsolateT* isolate, String string) {
374  // We want to compare the content of two strings here.
375  return string_->SlowEquals(string, SharedStringAccessGuardIfNeeded(isolate));
376}
377template bool StringTableInsertionKey::IsMatch(Isolate* isolate, String string);
378template bool StringTableInsertionKey::IsMatch(LocalIsolate* isolate,
379                                               String string);
380
381namespace {
382
383void NoExternalReferencesCallback() {
384  // The following check will trigger if a function or object template
385  // with references to native functions have been deserialized from
386  // snapshot, but no actual external references were provided when the
387  // isolate was created.
388  FATAL("No external references provided via API");
389}
390
391void PostProcessExternalString(ExternalString string, Isolate* isolate) {
392  DisallowGarbageCollection no_gc;
393  uint32_t index = string.GetResourceRefForDeserialization();
394  Address address =
395      static_cast<Address>(isolate->api_external_references()[index]);
396  string.AllocateExternalPointerEntries(isolate);
397  string.set_address_as_resource(isolate, address);
398  isolate->heap()->UpdateExternalString(string, 0,
399                                        string.ExternalPayloadSize());
400  isolate->heap()->RegisterExternalString(string);
401}
402
403}  // namespace
404
405template <typename IsolateT>
406void Deserializer<IsolateT>::PostProcessNewJSReceiver(
407    Map map, Handle<JSReceiver> obj, JSReceiver raw_obj,
408    InstanceType instance_type, SnapshotSpace space) {
409  DisallowGarbageCollection no_gc;
410  DCHECK_EQ(*obj, raw_obj);
411  DCHECK_EQ(raw_obj.map(), map);
412  DCHECK_EQ(map.instance_type(), instance_type);
413
414  if (InstanceTypeChecker::IsJSDataView(instance_type)) {
415    auto data_view = JSDataView::cast(raw_obj);
416    auto buffer = JSArrayBuffer::cast(data_view.buffer());
417    void* backing_store = EmptyBackingStoreBuffer();
418    uint32_t store_index = buffer.GetBackingStoreRefForDeserialization();
419    if (store_index != kEmptyBackingStoreRefSentinel) {
420      // The backing store of the JSArrayBuffer has not been correctly restored
421      // yet, as that may trigger GC. The backing_store field currently contains
422      // a numbered reference to an already deserialized backing store.
423      backing_store = backing_stores_[store_index]->buffer_start();
424    }
425    data_view.set_data_pointer(
426        main_thread_isolate(),
427        reinterpret_cast<uint8_t*>(backing_store) + data_view.byte_offset());
428  } else if (InstanceTypeChecker::IsJSTypedArray(instance_type)) {
429    auto typed_array = JSTypedArray::cast(raw_obj);
430    // Note: ByteArray objects must not be deferred s.t. they are
431    // available here for is_on_heap(). See also: CanBeDeferred.
432    // Fixup typed array pointers.
433    if (typed_array.is_on_heap()) {
434      typed_array.AddExternalPointerCompensationForDeserialization(
435          main_thread_isolate());
436    } else {
437      // Serializer writes backing store ref as a DataPtr() value.
438      uint32_t store_index =
439          typed_array.GetExternalBackingStoreRefForDeserialization();
440      auto backing_store = backing_stores_[store_index];
441      void* start = backing_store ? backing_store->buffer_start()
442                                  : EmptyBackingStoreBuffer();
443      typed_array.SetOffHeapDataPtr(main_thread_isolate(), start,
444                                    typed_array.byte_offset());
445    }
446  } else if (InstanceTypeChecker::IsJSArrayBuffer(instance_type)) {
447    auto buffer = JSArrayBuffer::cast(raw_obj);
448    // Postpone allocation of backing store to avoid triggering the GC.
449    if (buffer.GetBackingStoreRefForDeserialization() !=
450        kEmptyBackingStoreRefSentinel) {
451      new_off_heap_array_buffers_.push_back(Handle<JSArrayBuffer>::cast(obj));
452    } else {
453      buffer.set_backing_store(main_thread_isolate(),
454                               EmptyBackingStoreBuffer());
455    }
456  }
457
458  // Check alignment.
459  DCHECK_EQ(0, Heap::GetFillToAlign(obj->address(),
460                                    HeapObject::RequiredAlignment(map)));
461}
462
463template <typename IsolateT>
464void Deserializer<IsolateT>::PostProcessNewObject(Handle<Map> map,
465                                                  Handle<HeapObject> obj,
466                                                  SnapshotSpace space) {
467  DisallowGarbageCollection no_gc;
468  Map raw_map = *map;
469  DCHECK_EQ(raw_map, obj->map(isolate_));
470  InstanceType instance_type = raw_map.instance_type();
471
472  // Check alignment.
473  DCHECK_EQ(0, Heap::GetFillToAlign(obj->address(),
474                                    HeapObject::RequiredAlignment(raw_map)));
475  HeapObject raw_obj = *obj;
476  DCHECK_IMPLIES(deserializing_user_code(), should_rehash());
477  if (should_rehash()) {
478    if (InstanceTypeChecker::IsString(instance_type)) {
479      // Uninitialize hash field as we need to recompute the hash.
480      String string = String::cast(raw_obj);
481      string.set_raw_hash_field(String::kEmptyHashField);
482      // Rehash strings before read-only space is sealed. Strings outside
483      // read-only space are rehashed lazily. (e.g. when rehashing dictionaries)
484      if (space == SnapshotSpace::kReadOnlyHeap) {
485        to_rehash_.push_back(obj);
486      }
487    } else if (raw_obj.NeedsRehashing(instance_type)) {
488      to_rehash_.push_back(obj);
489    }
490
491    if (deserializing_user_code()) {
492      if (InstanceTypeChecker::IsInternalizedString(instance_type)) {
493        // Canonicalize the internalized string. If it already exists in the
494        // string table, set the string to point to the existing one and patch
495        // the deserialized string handle to point to the existing one.
496        // TODO(leszeks): This handle patching is ugly, consider adding an
497        // explicit internalized string bytecode. Also, the new thin string
498        // should be dead, try immediately freeing it.
499        Handle<String> string = Handle<String>::cast(obj);
500
501        StringTableInsertionKey key(
502            isolate(), string,
503            DeserializingUserCodeOption::kIsDeserializingUserCode);
504        String result = *isolate()->string_table()->LookupKey(isolate(), &key);
505
506        if (result != raw_obj) {
507          String::cast(raw_obj).MakeThin(isolate(), result);
508          // Mutate the given object handle so that the backreference entry is
509          // also updated.
510          obj.PatchValue(result);
511        }
512        return;
513      } else if (InstanceTypeChecker::IsScript(instance_type)) {
514        new_scripts_.push_back(Handle<Script>::cast(obj));
515      } else if (InstanceTypeChecker::IsAllocationSite(instance_type)) {
516        // We should link new allocation sites, but we can't do this immediately
517        // because |AllocationSite::HasWeakNext()| internally accesses
518        // |Heap::roots_| that may not have been initialized yet. So defer this
519        // to |ObjectDeserializer::CommitPostProcessedObjects()|.
520        new_allocation_sites_.push_back(Handle<AllocationSite>::cast(obj));
521      } else {
522        // We dont defer ByteArray because JSTypedArray needs the base_pointer
523        // ByteArray immediately if it's on heap.
524        DCHECK(CanBeDeferred(*obj) ||
525               InstanceTypeChecker::IsByteArray(instance_type));
526      }
527    }
528  }
529
530  if (InstanceTypeChecker::IsCode(instance_type)) {
531    // We flush all code pages after deserializing the startup snapshot.
532    // Hence we only remember each individual code object when deserializing
533    // user code.
534    if (deserializing_user_code()) {
535      new_code_objects_.push_back(Handle<Code>::cast(obj));
536    }
537  } else if (V8_EXTERNAL_CODE_SPACE_BOOL &&
538             InstanceTypeChecker::IsCodeDataContainer(instance_type)) {
539    auto code_data_container = CodeDataContainer::cast(raw_obj);
540    code_data_container.set_code_cage_base(isolate()->code_cage_base());
541    code_data_container.AllocateExternalPointerEntries(main_thread_isolate());
542    code_data_container.UpdateCodeEntryPoint(main_thread_isolate(),
543                                             code_data_container.code());
544  } else if (InstanceTypeChecker::IsMap(instance_type)) {
545    if (FLAG_log_maps) {
546      // Keep track of all seen Maps to log them later since they might be only
547      // partially initialized at this point.
548      new_maps_.push_back(Handle<Map>::cast(obj));
549    }
550  } else if (InstanceTypeChecker::IsAccessorInfo(instance_type)) {
551#ifdef USE_SIMULATOR
552    accessor_infos_.push_back(Handle<AccessorInfo>::cast(obj));
553#endif
554  } else if (InstanceTypeChecker::IsCallHandlerInfo(instance_type)) {
555#ifdef USE_SIMULATOR
556    call_handler_infos_.push_back(Handle<CallHandlerInfo>::cast(obj));
557#endif
558  } else if (InstanceTypeChecker::IsExternalString(instance_type)) {
559    PostProcessExternalString(ExternalString::cast(raw_obj),
560                              main_thread_isolate());
561  } else if (InstanceTypeChecker::IsJSReceiver(instance_type)) {
562    return PostProcessNewJSReceiver(raw_map, Handle<JSReceiver>::cast(obj),
563                                    JSReceiver::cast(raw_obj), instance_type,
564                                    space);
565  } else if (InstanceTypeChecker::IsBytecodeArray(instance_type)) {
566    // TODO(mythria): Remove these once we store the default values for these
567    // fields in the serializer.
568    BytecodeArray::cast(raw_obj).reset_osr_urgency();
569  } else if (InstanceTypeChecker::IsDescriptorArray(instance_type)) {
570    DCHECK(InstanceTypeChecker::IsStrongDescriptorArray(instance_type));
571    Handle<DescriptorArray> descriptors = Handle<DescriptorArray>::cast(obj);
572    new_descriptor_arrays_.push_back(descriptors);
573  } else if (InstanceTypeChecker::IsNativeContext(instance_type)) {
574    NativeContext::cast(raw_obj).AllocateExternalPointerEntries(
575        main_thread_isolate());
576  } else if (InstanceTypeChecker::IsScript(instance_type)) {
577    LogScriptEvents(Script::cast(*obj));
578  }
579}
580
581template <typename IsolateT>
582HeapObjectReferenceType Deserializer<IsolateT>::GetAndResetNextReferenceType() {
583  HeapObjectReferenceType type = next_reference_is_weak_
584                                     ? HeapObjectReferenceType::WEAK
585                                     : HeapObjectReferenceType::STRONG;
586  next_reference_is_weak_ = false;
587  return type;
588}
589
590template <typename IsolateT>
591Handle<HeapObject> Deserializer<IsolateT>::GetBackReferencedObject() {
592  Handle<HeapObject> obj = back_refs_[source_.GetInt()];
593
594  // We don't allow ThinStrings in backreferences -- if internalization produces
595  // a thin string, then it should also update the backref handle.
596  DCHECK(!obj->IsThinString(isolate()));
597
598  hot_objects_.Add(obj);
599  DCHECK(!HasWeakHeapObjectTag(*obj));
600  return obj;
601}
602
603template <typename IsolateT>
604Handle<HeapObject> Deserializer<IsolateT>::ReadObject() {
605  Handle<HeapObject> ret;
606  CHECK_EQ(ReadSingleBytecodeData(
607               source_.Get(), SlotAccessorForHandle<IsolateT>(&ret, isolate())),
608           1);
609  return ret;
610}
611
612namespace {
613AllocationType SpaceToAllocation(SnapshotSpace space) {
614  switch (space) {
615    case SnapshotSpace::kCode:
616      return AllocationType::kCode;
617    case SnapshotSpace::kMap:
618      return AllocationType::kMap;
619    case SnapshotSpace::kOld:
620      return AllocationType::kOld;
621    case SnapshotSpace::kReadOnlyHeap:
622      return AllocationType::kReadOnly;
623  }
624}
625}  // namespace
626
627template <typename IsolateT>
628Handle<HeapObject> Deserializer<IsolateT>::ReadObject(SnapshotSpace space) {
629  const int size_in_tagged = source_.GetInt();
630  const int size_in_bytes = size_in_tagged * kTaggedSize;
631
632  // The map can't be a forward ref. If you want the map to be a forward ref,
633  // then you're probably serializing the meta-map, in which case you want to
634  // use the kNewMetaMap bytecode.
635  DCHECK_NE(source()->Peek(), kRegisterPendingForwardRef);
636  Handle<Map> map = Handle<Map>::cast(ReadObject());
637
638  AllocationType allocation = SpaceToAllocation(space);
639
640  // When sharing a string table, all in-place internalizable and internalized
641  // strings internalized strings are allocated in the shared heap.
642  //
643  // TODO(12007): When shipping, add a new SharedOld SnapshotSpace.
644  if (FLAG_shared_string_table) {
645    InstanceType instance_type = map->instance_type();
646    if (InstanceTypeChecker::IsInternalizedString(instance_type) ||
647        String::IsInPlaceInternalizable(instance_type)) {
648      allocation = isolate()
649                       ->factory()
650                       ->RefineAllocationTypeForInPlaceInternalizableString(
651                           allocation, *map);
652    }
653  }
654
655  // Filling an object's fields can cause GCs and heap walks, so this object has
656  // to be in a 'sufficiently initialised' state by the time the next allocation
657  // can happen. For this to be the case, the object is carefully deserialized
658  // as follows:
659  //   * The space for the object is allocated.
660  //   * The map is set on the object so that the GC knows what type the object
661  //     has.
662  //   * The rest of the object is filled with a fixed Smi value
663  //     - This is a Smi so that tagged fields become initialized to a valid
664  //       tagged value.
665  //     - It's a fixed value, "Smi::uninitialized_deserialization_value()", so
666  //       that we can DCHECK for it when reading objects that are assumed to be
667  //       partially initialized objects.
668  //   * The fields of the object are deserialized in order, under the
669  //     assumption that objects are laid out in such a way that any fields
670  //     required for object iteration (e.g. length fields) are deserialized
671  //     before fields with objects.
672  //     - We ensure this is the case by DCHECKing on object allocation that the
673  //       previously allocated object has a valid size (see `Allocate`).
674  HeapObject raw_obj =
675      Allocate(allocation, size_in_bytes, HeapObject::RequiredAlignment(*map));
676  raw_obj.set_map_after_allocation(*map);
677  MemsetTagged(raw_obj.RawField(kTaggedSize),
678               Smi::uninitialized_deserialization_value(), size_in_tagged - 1);
679
680  // Make sure BytecodeArrays have a valid age, so that the marker doesn't
681  // break when making them older.
682  if (raw_obj.IsBytecodeArray(isolate())) {
683    BytecodeArray::cast(raw_obj).set_bytecode_age(
684        BytecodeArray::kFirstBytecodeAge);
685  }
686
687#ifdef DEBUG
688  PtrComprCageBase cage_base(isolate());
689  // We want to make sure that all embedder pointers are initialized to null.
690  if (raw_obj.IsJSObject(cage_base) &&
691      JSObject::cast(raw_obj).MayHaveEmbedderFields()) {
692    JSObject js_obj = JSObject::cast(raw_obj);
693    for (int i = 0; i < js_obj.GetEmbedderFieldCount(); ++i) {
694      void* pointer;
695      CHECK(EmbedderDataSlot(js_obj, i).ToAlignedPointer(main_thread_isolate(),
696                                                         &pointer));
697      CHECK_NULL(pointer);
698    }
699  } else if (raw_obj.IsEmbedderDataArray(cage_base)) {
700    EmbedderDataArray array = EmbedderDataArray::cast(raw_obj);
701    EmbedderDataSlot start(array, 0);
702    EmbedderDataSlot end(array, array.length());
703    for (EmbedderDataSlot slot = start; slot < end; ++slot) {
704      void* pointer;
705      CHECK(slot.ToAlignedPointer(main_thread_isolate(), &pointer));
706      CHECK_NULL(pointer);
707    }
708  }
709#endif
710
711  Handle<HeapObject> obj = handle(raw_obj, isolate());
712  back_refs_.push_back(obj);
713
714  ReadData(obj, 1, size_in_tagged);
715  PostProcessNewObject(map, obj, space);
716
717#ifdef DEBUG
718  if (obj->IsCode(cage_base)) {
719    DCHECK(space == SnapshotSpace::kCode ||
720           space == SnapshotSpace::kReadOnlyHeap);
721  } else {
722    DCHECK_NE(space, SnapshotSpace::kCode);
723  }
724#endif  // DEBUG
725
726  return obj;
727}
728
729template <typename IsolateT>
730Handle<HeapObject> Deserializer<IsolateT>::ReadMetaMap() {
731  const SnapshotSpace space = SnapshotSpace::kReadOnlyHeap;
732  const int size_in_bytes = Map::kSize;
733  const int size_in_tagged = size_in_bytes / kTaggedSize;
734
735  HeapObject raw_obj =
736      Allocate(SpaceToAllocation(space), size_in_bytes, kTaggedAligned);
737  raw_obj.set_map_after_allocation(Map::unchecked_cast(raw_obj));
738  MemsetTagged(raw_obj.RawField(kTaggedSize),
739               Smi::uninitialized_deserialization_value(), size_in_tagged - 1);
740
741  Handle<HeapObject> obj = handle(raw_obj, isolate());
742  back_refs_.push_back(obj);
743
744  // Set the instance-type manually, to allow backrefs to read it.
745  Map::unchecked_cast(*obj).set_instance_type(MAP_TYPE);
746
747  ReadData(obj, 1, size_in_tagged);
748  PostProcessNewObject(Handle<Map>::cast(obj), obj, space);
749
750  return obj;
751}
752
753class DeserializerRelocInfoVisitor {
754 public:
755  DeserializerRelocInfoVisitor(Deserializer<Isolate>* deserializer,
756                               const std::vector<Handle<HeapObject>>* objects)
757      : deserializer_(deserializer), objects_(objects), current_object_(0) {}
758
759  DeserializerRelocInfoVisitor(Deserializer<LocalIsolate>* deserializer,
760                               const std::vector<Handle<HeapObject>>* objects) {
761    UNREACHABLE();
762  }
763
764  ~DeserializerRelocInfoVisitor() {
765    DCHECK_EQ(current_object_, objects_->size());
766  }
767
768  void VisitCodeTarget(Code host, RelocInfo* rinfo);
769  void VisitEmbeddedPointer(Code host, RelocInfo* rinfo);
770  void VisitRuntimeEntry(Code host, RelocInfo* rinfo);
771  void VisitExternalReference(Code host, RelocInfo* rinfo);
772  void VisitInternalReference(Code host, RelocInfo* rinfo);
773  void VisitOffHeapTarget(Code host, RelocInfo* rinfo);
774
775 private:
776  Isolate* isolate() { return deserializer_->isolate(); }
777  SnapshotByteSource& source() { return deserializer_->source_; }
778
779  Deserializer<Isolate>* deserializer_;
780  const std::vector<Handle<HeapObject>>* objects_;
781  int current_object_;
782};
783
784void DeserializerRelocInfoVisitor::VisitCodeTarget(Code host,
785                                                   RelocInfo* rinfo) {
786  HeapObject object = *objects_->at(current_object_++);
787  rinfo->set_target_address(Code::cast(object).raw_instruction_start());
788}
789
790void DeserializerRelocInfoVisitor::VisitEmbeddedPointer(Code host,
791                                                        RelocInfo* rinfo) {
792  HeapObject object = *objects_->at(current_object_++);
793  // Embedded object reference must be a strong one.
794  rinfo->set_target_object(isolate()->heap(), object);
795}
796
797void DeserializerRelocInfoVisitor::VisitRuntimeEntry(Code host,
798                                                     RelocInfo* rinfo) {
799  // We no longer serialize code that contains runtime entries.
800  UNREACHABLE();
801}
802
803void DeserializerRelocInfoVisitor::VisitExternalReference(Code host,
804                                                          RelocInfo* rinfo) {
805  byte data = source().Get();
806  CHECK_EQ(data, Deserializer<Isolate>::kExternalReference);
807
808  Address address = deserializer_->ReadExternalReferenceCase();
809
810  if (rinfo->IsCodedSpecially()) {
811    Address location_of_branch_data = rinfo->pc();
812    Assembler::deserialization_set_special_target_at(location_of_branch_data,
813                                                     host, address);
814  } else {
815    WriteUnalignedValue(rinfo->target_address_address(), address);
816  }
817}
818
819void DeserializerRelocInfoVisitor::VisitInternalReference(Code host,
820                                                          RelocInfo* rinfo) {
821  byte data = source().Get();
822  CHECK_EQ(data, Deserializer<Isolate>::kInternalReference);
823
824  // Internal reference target is encoded as an offset from code entry.
825  int target_offset = source().GetInt();
826  // TODO(jgruber,v8:11036): We are being permissive for this DCHECK, but
827  // consider using raw_instruction_size() instead of raw_body_size() in the
828  // future.
829  STATIC_ASSERT(Code::kOnHeapBodyIsContiguous);
830  DCHECK_LT(static_cast<unsigned>(target_offset),
831            static_cast<unsigned>(host.raw_body_size()));
832  Address target = host.entry() + target_offset;
833  Assembler::deserialization_set_target_internal_reference_at(
834      rinfo->pc(), target, rinfo->rmode());
835}
836
837void DeserializerRelocInfoVisitor::VisitOffHeapTarget(Code host,
838                                                      RelocInfo* rinfo) {
839  byte data = source().Get();
840  CHECK_EQ(data, Deserializer<Isolate>::kOffHeapTarget);
841
842  Builtin builtin = Builtins::FromInt(source().GetInt());
843
844  CHECK_NOT_NULL(isolate()->embedded_blob_code());
845  EmbeddedData d = EmbeddedData::FromBlob(isolate());
846  Address address = d.InstructionStartOfBuiltin(builtin);
847  CHECK_NE(kNullAddress, address);
848
849  // TODO(ishell): implement RelocInfo::set_target_off_heap_target()
850  if (RelocInfo::OffHeapTargetIsCodedSpecially()) {
851    Address location_of_branch_data = rinfo->pc();
852    Assembler::deserialization_set_special_target_at(location_of_branch_data,
853                                                     host, address);
854  } else {
855    WriteUnalignedValue(rinfo->target_address_address(), address);
856  }
857}
858
859template <typename IsolateT>
860template <typename SlotAccessor>
861int Deserializer<IsolateT>::ReadRepeatedObject(SlotAccessor slot_accessor,
862                                               int repeat_count) {
863  CHECK_LE(2, repeat_count);
864
865  Handle<HeapObject> heap_object = ReadObject();
866  DCHECK(!Heap::InYoungGeneration(*heap_object));
867  for (int i = 0; i < repeat_count; i++) {
868    // TODO(leszeks): Use a ranged barrier here.
869    slot_accessor.Write(heap_object, HeapObjectReferenceType::STRONG, i);
870  }
871  return repeat_count;
872}
873
874namespace {
875
876// Template used by the below CASE_RANGE macro to statically verify that the
877// given number of cases matches the number of expected cases for that bytecode.
878template <int byte_code_count, int expected>
879constexpr byte VerifyBytecodeCount(byte bytecode) {
880  STATIC_ASSERT(byte_code_count == expected);
881  return bytecode;
882}
883
884}  // namespace
885
886// Helper macro (and its implementation detail) for specifying a range of cases.
887// Use as "case CASE_RANGE(byte_code, num_bytecodes):"
888#define CASE_RANGE(byte_code, num_bytecodes) \
889  CASE_R##num_bytecodes(                     \
890      (VerifyBytecodeCount<byte_code##Count, num_bytecodes>(byte_code)))
891#define CASE_R1(byte_code) byte_code
892#define CASE_R2(byte_code) CASE_R1(byte_code) : case CASE_R1(byte_code + 1)
893#define CASE_R3(byte_code) CASE_R2(byte_code) : case CASE_R1(byte_code + 2)
894#define CASE_R4(byte_code) CASE_R2(byte_code) : case CASE_R2(byte_code + 2)
895#define CASE_R8(byte_code) CASE_R4(byte_code) : case CASE_R4(byte_code + 4)
896#define CASE_R16(byte_code) CASE_R8(byte_code) : case CASE_R8(byte_code + 8)
897#define CASE_R32(byte_code) CASE_R16(byte_code) : case CASE_R16(byte_code + 16)
898
899// This generates a case range for all the spaces.
900#define CASE_RANGE_ALL_SPACES(bytecode)                           \
901  SpaceEncoder<bytecode>::Encode(SnapshotSpace::kOld)             \
902      : case SpaceEncoder<bytecode>::Encode(SnapshotSpace::kCode) \
903      : case SpaceEncoder<bytecode>::Encode(SnapshotSpace::kMap)  \
904      : case SpaceEncoder<bytecode>::Encode(SnapshotSpace::kReadOnlyHeap)
905
906template <typename IsolateT>
907void Deserializer<IsolateT>::ReadData(Handle<HeapObject> object,
908                                      int start_slot_index,
909                                      int end_slot_index) {
910  int current = start_slot_index;
911  while (current < end_slot_index) {
912    byte data = source_.Get();
913    current += ReadSingleBytecodeData(
914        data, SlotAccessorForHeapObject::ForSlotIndex(object, current));
915  }
916  CHECK_EQ(current, end_slot_index);
917}
918
919template <typename IsolateT>
920void Deserializer<IsolateT>::ReadData(FullMaybeObjectSlot start,
921                                      FullMaybeObjectSlot end) {
922  FullMaybeObjectSlot current = start;
923  while (current < end) {
924    byte data = source_.Get();
925    current += ReadSingleBytecodeData(data, SlotAccessorForRootSlots(current));
926  }
927  CHECK_EQ(current, end);
928}
929
930template <typename IsolateT>
931template <typename SlotAccessor>
932int Deserializer<IsolateT>::ReadSingleBytecodeData(byte data,
933                                                   SlotAccessor slot_accessor) {
934  using TSlot = decltype(slot_accessor.slot());
935
936  switch (data) {
937    // Deserialize a new object and write a pointer to it to the current
938    // object.
939    case CASE_RANGE_ALL_SPACES(kNewObject): {
940      SnapshotSpace space = NewObject::Decode(data);
941      // Save the reference type before recursing down into reading the object.
942      HeapObjectReferenceType ref_type = GetAndResetNextReferenceType();
943      Handle<HeapObject> heap_object = ReadObject(space);
944      return slot_accessor.Write(heap_object, ref_type);
945    }
946
947    // Find a recently deserialized object using its offset from the current
948    // allocation point and write a pointer to it to the current object.
949    case kBackref: {
950      Handle<HeapObject> heap_object = GetBackReferencedObject();
951      return slot_accessor.Write(heap_object, GetAndResetNextReferenceType());
952    }
953
954    // Reference an object in the read-only heap. This should be used when an
955    // object is read-only, but is not a root.
956    case kReadOnlyHeapRef: {
957      DCHECK(isolate()->heap()->deserialization_complete());
958      uint32_t chunk_index = source_.GetInt();
959      uint32_t chunk_offset = source_.GetInt();
960
961      ReadOnlySpace* read_only_space = isolate()->heap()->read_only_space();
962      ReadOnlyPage* page = read_only_space->pages()[chunk_index];
963      Address address = page->OffsetToAddress(chunk_offset);
964      HeapObject heap_object = HeapObject::FromAddress(address);
965
966      return slot_accessor.Write(heap_object, GetAndResetNextReferenceType());
967    }
968
969    // Find an object in the roots array and write a pointer to it to the
970    // current object.
971    case kRootArray: {
972      int id = source_.GetInt();
973      RootIndex root_index = static_cast<RootIndex>(id);
974      Handle<HeapObject> heap_object =
975          Handle<HeapObject>::cast(isolate()->root_handle(root_index));
976      hot_objects_.Add(heap_object);
977      return slot_accessor.Write(heap_object, GetAndResetNextReferenceType());
978    }
979
980    // Find an object in the startup object cache and write a pointer to it to
981    // the current object.
982    case kStartupObjectCache: {
983      int cache_index = source_.GetInt();
984      // TODO(leszeks): Could we use the address of the startup_object_cache
985      // entry as a Handle backing?
986      HeapObject heap_object = HeapObject::cast(
987          main_thread_isolate()->startup_object_cache()->at(cache_index));
988      return slot_accessor.Write(heap_object, GetAndResetNextReferenceType());
989    }
990
991    // Find an object in the read-only object cache and write a pointer to it
992    // to the current object.
993    case kReadOnlyObjectCache: {
994      int cache_index = source_.GetInt();
995      // TODO(leszeks): Could we use the address of the cached_read_only_object
996      // entry as a Handle backing?
997      HeapObject heap_object = HeapObject::cast(
998          isolate()->read_only_heap()->cached_read_only_object(cache_index));
999      return slot_accessor.Write(heap_object, GetAndResetNextReferenceType());
1000    }
1001
1002    // Find an object in the shared heap object cache and write a pointer to it
1003    // to the current object.
1004    case kSharedHeapObjectCache: {
1005      int cache_index = source_.GetInt();
1006      // TODO(leszeks): Could we use the address of the
1007      // shared_heap_object_cache entry as a Handle backing?
1008      HeapObject heap_object = HeapObject::cast(
1009          main_thread_isolate()->shared_heap_object_cache()->at(cache_index));
1010      DCHECK(
1011          SharedHeapSerializer::ShouldBeInSharedHeapObjectCache(heap_object));
1012      return slot_accessor.Write(heap_object, GetAndResetNextReferenceType());
1013    }
1014
1015    // Deserialize a new meta-map and write a pointer to it to the current
1016    // object.
1017    case kNewMetaMap: {
1018      Handle<HeapObject> heap_object = ReadMetaMap();
1019      return slot_accessor.Write(heap_object, HeapObjectReferenceType::STRONG);
1020    }
1021
1022    // Find an external reference and write a pointer to it to the current
1023    // object.
1024    case kSandboxedExternalReference:
1025    case kExternalReference: {
1026      Address address = ReadExternalReferenceCase();
1027      if (V8_SANDBOXED_EXTERNAL_POINTERS_BOOL &&
1028          data == kSandboxedExternalReference) {
1029        ExternalPointerTag tag = ReadExternalPointerTag();
1030        return WriteExternalPointer(slot_accessor.slot(), address, tag);
1031      } else {
1032        DCHECK(!V8_SANDBOXED_EXTERNAL_POINTERS_BOOL);
1033        return WriteAddress(slot_accessor.slot(), address);
1034      }
1035    }
1036
1037    case kInternalReference:
1038    case kOffHeapTarget:
1039      // These bytecodes are expected only during RelocInfo iteration.
1040      UNREACHABLE();
1041
1042    // Find an object in the attached references and write a pointer to it to
1043    // the current object.
1044    case kAttachedReference: {
1045      int index = source_.GetInt();
1046      Handle<HeapObject> heap_object = attached_objects_[index];
1047
1048      // This is the only case where we might encounter new space objects, so
1049      // maybe emit a generational write barrier.
1050      return slot_accessor.WriteWithGenerationalBarrier(
1051          heap_object, GetAndResetNextReferenceType());
1052    }
1053
1054    case kNop:
1055      return 0;
1056
1057    case kRegisterPendingForwardRef: {
1058      HeapObjectReferenceType ref_type = GetAndResetNextReferenceType();
1059      unresolved_forward_refs_.emplace_back(slot_accessor.object(),
1060                                            slot_accessor.offset(), ref_type);
1061      num_unresolved_forward_refs_++;
1062      return 1;
1063    }
1064
1065    case kResolvePendingForwardRef: {
1066      // Pending forward refs can only be resolved after the heap object's map
1067      // field is deserialized; currently they only appear immediately after
1068      // the map field.
1069      DCHECK_EQ(slot_accessor.offset(), HeapObject::kHeaderSize);
1070      Handle<HeapObject> obj = slot_accessor.object();
1071      int index = source_.GetInt();
1072      auto& forward_ref = unresolved_forward_refs_[index];
1073      SlotAccessorForHeapObject::ForSlotOffset(forward_ref.object,
1074                                               forward_ref.offset)
1075          .Write(*obj, forward_ref.ref_type);
1076      num_unresolved_forward_refs_--;
1077      if (num_unresolved_forward_refs_ == 0) {
1078        // If there's no more pending fields, clear the entire pending field
1079        // vector.
1080        unresolved_forward_refs_.clear();
1081      } else {
1082        // Otherwise, at least clear the pending field.
1083        forward_ref.object = Handle<HeapObject>();
1084      }
1085      return 0;
1086    }
1087
1088    case kSynchronize:
1089      // If we get here then that indicates that you have a mismatch between
1090      // the number of GC roots when serializing and deserializing.
1091      UNREACHABLE();
1092
1093    // Deserialize raw data of variable length.
1094    case kVariableRawData: {
1095      // This operation is only supported for tagged-size slots, else we might
1096      // become misaligned.
1097      DCHECK_EQ(TSlot::kSlotDataSize, kTaggedSize);
1098      int size_in_tagged = source_.GetInt();
1099      // TODO(leszeks): Only copy slots when there are Smis in the serialized
1100      // data.
1101      source_.CopySlots(slot_accessor.slot().location(), size_in_tagged);
1102      return size_in_tagged;
1103    }
1104
1105    // Deserialize raw code directly into the body of the code object.
1106    case kCodeBody: {
1107      // This operation is only supported for tagged-size slots, else we might
1108      // become misaligned.
1109      DCHECK_EQ(TSlot::kSlotDataSize, kTaggedSize);
1110      // CodeBody can only occur right after the heap object header.
1111      DCHECK_EQ(slot_accessor.offset(), HeapObject::kHeaderSize);
1112
1113      int size_in_tagged = source_.GetInt();
1114      int size_in_bytes = size_in_tagged * kTaggedSize;
1115
1116      {
1117        DisallowGarbageCollection no_gc;
1118        Code code = Code::cast(*slot_accessor.object());
1119
1120        // First deserialize the code itself.
1121        source_.CopyRaw(
1122            reinterpret_cast<void*>(code.address() + Code::kDataStart),
1123            size_in_bytes);
1124      }
1125
1126      // Then deserialize the code header
1127      ReadData(slot_accessor.object(), HeapObject::kHeaderSize / kTaggedSize,
1128               Code::kDataStart / kTaggedSize);
1129
1130      // Then deserialize the pre-serialized RelocInfo objects.
1131      std::vector<Handle<HeapObject>> preserialized_objects;
1132      while (source_.Peek() != kSynchronize) {
1133        Handle<HeapObject> obj = ReadObject();
1134        preserialized_objects.push_back(obj);
1135      }
1136      // Skip the synchronize bytecode.
1137      source_.Advance(1);
1138
1139      // Finally iterate RelocInfos (the same way it was done by the serializer)
1140      // and deserialize respective data into RelocInfos. The RelocIterator
1141      // holds a raw pointer to the code, so we have to disable garbage
1142      // collection here. It's ok though, any objects it would have needed are
1143      // in the preserialized_objects vector.
1144      {
1145        DisallowGarbageCollection no_gc;
1146
1147        Code code = Code::cast(*slot_accessor.object());
1148        if (V8_EXTERNAL_CODE_SPACE_BOOL) {
1149          code.set_main_cage_base(isolate()->cage_base(), kRelaxedStore);
1150        }
1151        DeserializerRelocInfoVisitor visitor(this, &preserialized_objects);
1152        for (RelocIterator it(code, Code::BodyDescriptor::kRelocModeMask);
1153             !it.done(); it.next()) {
1154          it.rinfo()->Visit(&visitor);
1155        }
1156      }
1157
1158      // Advance to the end of the code object.
1159      return (Code::kDataStart - HeapObject::kHeaderSize) / kTaggedSize +
1160             size_in_tagged;
1161    }
1162
1163    case kVariableRepeat: {
1164      int repeats = VariableRepeatCount::Decode(source_.GetInt());
1165      return ReadRepeatedObject(slot_accessor, repeats);
1166    }
1167
1168    case kOffHeapBackingStore:
1169    case kOffHeapResizableBackingStore: {
1170      int byte_length = source_.GetInt();
1171      std::unique_ptr<BackingStore> backing_store;
1172      if (data == kOffHeapBackingStore) {
1173        backing_store = BackingStore::Allocate(
1174            main_thread_isolate(), byte_length, SharedFlag::kNotShared,
1175            InitializedFlag::kUninitialized);
1176      } else {
1177        int max_byte_length = source_.GetInt();
1178        size_t page_size, initial_pages, max_pages;
1179        Maybe<bool> result =
1180            JSArrayBuffer::GetResizableBackingStorePageConfiguration(
1181                nullptr, byte_length, max_byte_length, kDontThrow, &page_size,
1182                &initial_pages, &max_pages);
1183        DCHECK(result.FromJust());
1184        USE(result);
1185        constexpr bool kIsWasmMemory = false;
1186        backing_store = BackingStore::TryAllocateAndPartiallyCommitMemory(
1187            main_thread_isolate(), byte_length, max_byte_length, page_size,
1188            initial_pages, max_pages, kIsWasmMemory, SharedFlag::kNotShared);
1189      }
1190      CHECK_NOT_NULL(backing_store);
1191      source_.CopyRaw(backing_store->buffer_start(), byte_length);
1192      backing_stores_.push_back(std::move(backing_store));
1193      return 0;
1194    }
1195
1196    case kSandboxedApiReference:
1197    case kApiReference: {
1198      uint32_t reference_id = static_cast<uint32_t>(source_.GetInt());
1199      Address address;
1200      if (main_thread_isolate()->api_external_references()) {
1201        DCHECK_WITH_MSG(reference_id < num_api_references_,
1202                        "too few external references provided through the API");
1203        address = static_cast<Address>(
1204            main_thread_isolate()->api_external_references()[reference_id]);
1205      } else {
1206        address = reinterpret_cast<Address>(NoExternalReferencesCallback);
1207      }
1208      if (V8_SANDBOXED_EXTERNAL_POINTERS_BOOL &&
1209          data == kSandboxedApiReference) {
1210        ExternalPointerTag tag = ReadExternalPointerTag();
1211        return WriteExternalPointer(slot_accessor.slot(), address, tag);
1212      } else {
1213        DCHECK(!V8_SANDBOXED_EXTERNAL_POINTERS_BOOL);
1214        return WriteAddress(slot_accessor.slot(), address);
1215      }
1216    }
1217
1218    case kClearedWeakReference:
1219      return slot_accessor.Write(HeapObjectReference::ClearedValue(isolate()));
1220
1221    case kWeakPrefix: {
1222      // We shouldn't have two weak prefixes in a row.
1223      DCHECK(!next_reference_is_weak_);
1224      // We shouldn't have weak refs without a current object.
1225      DCHECK_NE(slot_accessor.object()->address(), kNullAddress);
1226      next_reference_is_weak_ = true;
1227      return 0;
1228    }
1229
1230    case CASE_RANGE(kRootArrayConstants, 32): {
1231      // First kRootArrayConstantsCount roots are guaranteed to be in
1232      // the old space.
1233      STATIC_ASSERT(static_cast<int>(RootIndex::kFirstImmortalImmovableRoot) ==
1234                    0);
1235      STATIC_ASSERT(kRootArrayConstantsCount <=
1236                    static_cast<int>(RootIndex::kLastImmortalImmovableRoot));
1237
1238      RootIndex root_index = RootArrayConstant::Decode(data);
1239      Handle<HeapObject> heap_object =
1240          Handle<HeapObject>::cast(isolate()->root_handle(root_index));
1241      return slot_accessor.Write(heap_object, HeapObjectReferenceType::STRONG);
1242    }
1243
1244    case CASE_RANGE(kHotObject, 8): {
1245      int index = HotObject::Decode(data);
1246      Handle<HeapObject> hot_object = hot_objects_.Get(index);
1247      return slot_accessor.Write(hot_object, GetAndResetNextReferenceType());
1248    }
1249
1250    case CASE_RANGE(kFixedRawData, 32): {
1251      // Deserialize raw data of fixed length from 1 to 32 times kTaggedSize.
1252      int size_in_tagged = FixedRawDataWithSize::Decode(data);
1253      STATIC_ASSERT(TSlot::kSlotDataSize == kTaggedSize ||
1254                    TSlot::kSlotDataSize == 2 * kTaggedSize);
1255      int size_in_slots = size_in_tagged / (TSlot::kSlotDataSize / kTaggedSize);
1256      // kFixedRawData can have kTaggedSize != TSlot::kSlotDataSize when
1257      // serializing Smi roots in pointer-compressed builds. In this case, the
1258      // size in bytes is unconditionally the (full) slot size.
1259      DCHECK_IMPLIES(kTaggedSize != TSlot::kSlotDataSize, size_in_slots == 1);
1260      // TODO(leszeks): Only copy slots when there are Smis in the serialized
1261      // data.
1262      source_.CopySlots(slot_accessor.slot().location(), size_in_slots);
1263      return size_in_slots;
1264    }
1265
1266    case CASE_RANGE(kFixedRepeat, 16): {
1267      int repeats = FixedRepeatWithCount::Decode(data);
1268      return ReadRepeatedObject(slot_accessor, repeats);
1269    }
1270
1271#ifdef DEBUG
1272#define UNUSED_CASE(byte_code) \
1273  case byte_code:              \
1274    UNREACHABLE();
1275      UNUSED_SERIALIZER_BYTE_CODES(UNUSED_CASE)
1276#endif
1277#undef UNUSED_CASE
1278  }
1279
1280  // The above switch, including UNUSED_SERIALIZER_BYTE_CODES, covers all
1281  // possible bytecodes; but, clang doesn't realize this, so we have an explicit
1282  // UNREACHABLE here too.
1283  UNREACHABLE();
1284}
1285
1286#undef CASE_RANGE_ALL_SPACES
1287#undef CASE_RANGE
1288#undef CASE_R32
1289#undef CASE_R16
1290#undef CASE_R8
1291#undef CASE_R4
1292#undef CASE_R3
1293#undef CASE_R2
1294#undef CASE_R1
1295
1296template <typename IsolateT>
1297Address Deserializer<IsolateT>::ReadExternalReferenceCase() {
1298  uint32_t reference_id = static_cast<uint32_t>(source_.GetInt());
1299  return main_thread_isolate()->external_reference_table()->address(
1300      reference_id);
1301}
1302
1303template <typename IsolateT>
1304ExternalPointerTag Deserializer<IsolateT>::ReadExternalPointerTag() {
1305  uint64_t shifted_tag = static_cast<uint64_t>(source_.GetInt());
1306  return static_cast<ExternalPointerTag>(shifted_tag
1307                                         << kExternalPointerTagShift);
1308}
1309
1310template <typename IsolateT>
1311HeapObject Deserializer<IsolateT>::Allocate(AllocationType allocation, int size,
1312                                            AllocationAlignment alignment) {
1313#ifdef DEBUG
1314  if (!previous_allocation_obj_.is_null()) {
1315    // Make sure that the previous object is initialized sufficiently to
1316    // be iterated over by the GC.
1317    int object_size = previous_allocation_obj_->Size(isolate_);
1318    DCHECK_LE(object_size, previous_allocation_size_);
1319  }
1320#endif
1321
1322  HeapObject obj = HeapObject::FromAddress(isolate()->heap()->AllocateRawOrFail(
1323      size, allocation, AllocationOrigin::kRuntime, alignment));
1324
1325#ifdef DEBUG
1326  previous_allocation_obj_ = handle(obj, isolate());
1327  previous_allocation_size_ = size;
1328#endif
1329
1330  return obj;
1331}
1332
1333template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) Deserializer<Isolate>;
1334template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
1335    Deserializer<LocalIsolate>;
1336
1337}  // namespace internal
1338}  // namespace v8
1339