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#ifndef V8_SNAPSHOT_DESERIALIZER_H_
6#define V8_SNAPSHOT_DESERIALIZER_H_
7
8#include <utility>
9#include <vector>
10
11#include "src/base/macros.h"
12#include "src/base/optional.h"
13#include "src/common/globals.h"
14#include "src/execution/local-isolate.h"
15#include "src/objects/allocation-site.h"
16#include "src/objects/api-callbacks.h"
17#include "src/objects/backing-store.h"
18#include "src/objects/code.h"
19#include "src/objects/js-array.h"
20#include "src/objects/map.h"
21#include "src/objects/smi.h"
22#include "src/objects/string-table.h"
23#include "src/objects/string.h"
24#include "src/snapshot/serializer-deserializer.h"
25#include "src/snapshot/snapshot-source-sink.h"
26
27namespace v8 {
28namespace internal {
29
30class HeapObject;
31class Object;
32
33// Used for platforms with embedded constant pools to trigger deserialization
34// of objects found in code.
35#if defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64) ||   \
36    defined(V8_TARGET_ARCH_PPC) || defined(V8_TARGET_ARCH_S390) ||      \
37    defined(V8_TARGET_ARCH_PPC64) || defined(V8_TARGET_ARCH_RISCV64) || \
38    V8_EMBEDDED_CONSTANT_POOL
39#define V8_CODE_EMBEDS_OBJECT_POINTER 1
40#else
41#define V8_CODE_EMBEDS_OBJECT_POINTER 0
42#endif
43
44// A Deserializer reads a snapshot and reconstructs the Object graph it defines.
45template <typename IsolateT>
46class Deserializer : public SerializerDeserializer {
47 public:
48  ~Deserializer() override;
49  Deserializer(const Deserializer&) = delete;
50  Deserializer& operator=(const Deserializer&) = delete;
51
52 protected:
53  // Create a deserializer from a snapshot byte source.
54  Deserializer(IsolateT* isolate, base::Vector<const byte> payload,
55               uint32_t magic_number, bool deserializing_user_code,
56               bool can_rehash);
57
58  void DeserializeDeferredObjects();
59
60  // Create Log events for newly deserialized objects.
61  void LogNewObjectEvents();
62  void LogScriptEvents(Script script);
63  void LogNewMapEvents();
64
65  // Descriptor arrays are deserialized as "strong", so that there is no risk of
66  // them getting trimmed during a partial deserialization. This method makes
67  // them "weak" again after deserialization completes.
68  void WeakenDescriptorArrays();
69
70  // This returns the address of an object that has been described in the
71  // snapshot by object vector index.
72  Handle<HeapObject> GetBackReferencedObject();
73
74  // Add an object to back an attached reference. The order to add objects must
75  // mirror the order they are added in the serializer.
76  void AddAttachedObject(Handle<HeapObject> attached_object) {
77    attached_objects_.push_back(attached_object);
78  }
79
80  void CheckNoArrayBufferBackingStores() {
81    CHECK_EQ(new_off_heap_array_buffers().size(), 0);
82  }
83
84  IsolateT* isolate() const { return isolate_; }
85
86  Isolate* main_thread_isolate() const { return isolate_->AsIsolate(); }
87
88  SnapshotByteSource* source() { return &source_; }
89  const std::vector<Handle<AllocationSite>>& new_allocation_sites() const {
90    return new_allocation_sites_;
91  }
92  const std::vector<Handle<Code>>& new_code_objects() const {
93    return new_code_objects_;
94  }
95  const std::vector<Handle<Map>>& new_maps() const { return new_maps_; }
96  const std::vector<Handle<AccessorInfo>>& accessor_infos() const {
97    return accessor_infos_;
98  }
99  const std::vector<Handle<CallHandlerInfo>>& call_handler_infos() const {
100    return call_handler_infos_;
101  }
102  const std::vector<Handle<Script>>& new_scripts() const {
103    return new_scripts_;
104  }
105
106  const std::vector<Handle<JSArrayBuffer>>& new_off_heap_array_buffers() const {
107    return new_off_heap_array_buffers_;
108  }
109
110  const std::vector<Handle<DescriptorArray>>& new_descriptor_arrays() const {
111    return new_descriptor_arrays_;
112  }
113
114  std::shared_ptr<BackingStore> backing_store(size_t i) {
115    DCHECK_LT(i, backing_stores_.size());
116    return backing_stores_[i];
117  }
118
119  bool deserializing_user_code() const { return deserializing_user_code_; }
120  bool should_rehash() const { return should_rehash_; }
121
122  void Rehash();
123
124  Handle<HeapObject> ReadObject();
125
126 private:
127  friend class DeserializerRelocInfoVisitor;
128  // A circular queue of hot objects. This is added to in the same order as in
129  // Serializer::HotObjectsList, but this stores the objects as a vector of
130  // existing handles. This allows us to add Handles to the queue without having
131  // to create new handles. Note that this depends on those Handles staying
132  // valid as long as the HotObjectsList is alive.
133  class HotObjectsList {
134   public:
135    HotObjectsList() = default;
136    HotObjectsList(const HotObjectsList&) = delete;
137    HotObjectsList& operator=(const HotObjectsList&) = delete;
138
139    void Add(Handle<HeapObject> object) {
140      circular_queue_[index_] = object;
141      index_ = (index_ + 1) & kSizeMask;
142    }
143
144    Handle<HeapObject> Get(int index) {
145      DCHECK(!circular_queue_[index].is_null());
146      return circular_queue_[index];
147    }
148
149   private:
150    static const int kSize = kHotObjectCount;
151    static const int kSizeMask = kSize - 1;
152    STATIC_ASSERT(base::bits::IsPowerOfTwo(kSize));
153    Handle<HeapObject> circular_queue_[kSize];
154    int index_ = 0;
155  };
156
157  void VisitRootPointers(Root root, const char* description,
158                         FullObjectSlot start, FullObjectSlot end) override;
159
160  void Synchronize(VisitorSynchronization::SyncTag tag) override;
161
162  template <typename TSlot>
163  inline int WriteAddress(TSlot dest, Address value);
164
165  template <typename TSlot>
166  inline int WriteExternalPointer(TSlot dest, Address value,
167                                  ExternalPointerTag tag);
168
169  // Fills in a heap object's data from start to end (exclusive). Start and end
170  // are slot indices within the object.
171  void ReadData(Handle<HeapObject> object, int start_slot_index,
172                int end_slot_index);
173
174  // Fills in a contiguous range of full object slots (e.g. root pointers) from
175  // start to end (exclusive).
176  void ReadData(FullMaybeObjectSlot start, FullMaybeObjectSlot end);
177
178  // Helper for ReadData which reads the given bytecode and fills in some heap
179  // data into the given slot. May fill in zero or multiple slots, so it returns
180  // the number of slots filled.
181  template <typename SlotAccessor>
182  int ReadSingleBytecodeData(byte data, SlotAccessor slot_accessor);
183
184  // A helper function for ReadData for reading external references.
185  inline Address ReadExternalReferenceCase();
186
187  // A helper function for reading external pointer tags.
188  ExternalPointerTag ReadExternalPointerTag();
189
190  Handle<HeapObject> ReadObject(SnapshotSpace space_number);
191  Handle<HeapObject> ReadMetaMap();
192
193  HeapObjectReferenceType GetAndResetNextReferenceType();
194
195  template <typename SlotGetter>
196  int ReadRepeatedObject(SlotGetter slot_getter, int repeat_count);
197
198  // Special handling for serialized code like hooking up internalized strings.
199  void PostProcessNewObject(Handle<Map> map, Handle<HeapObject> obj,
200                            SnapshotSpace space);
201  void PostProcessNewJSReceiver(Map map, Handle<JSReceiver> obj,
202                                JSReceiver raw_obj, InstanceType instance_type,
203                                SnapshotSpace space);
204
205  HeapObject Allocate(AllocationType allocation, int size,
206                      AllocationAlignment alignment);
207
208  // Cached current isolate.
209  IsolateT* isolate_;
210
211  // Objects from the attached object descriptions in the serialized user code.
212  std::vector<Handle<HeapObject>> attached_objects_;
213
214  SnapshotByteSource source_;
215  uint32_t magic_number_;
216
217  HotObjectsList hot_objects_;
218  std::vector<Handle<Map>> new_maps_;
219  std::vector<Handle<AllocationSite>> new_allocation_sites_;
220  std::vector<Handle<Code>> new_code_objects_;
221  std::vector<Handle<AccessorInfo>> accessor_infos_;
222  std::vector<Handle<CallHandlerInfo>> call_handler_infos_;
223  std::vector<Handle<Script>> new_scripts_;
224  std::vector<Handle<JSArrayBuffer>> new_off_heap_array_buffers_;
225  std::vector<Handle<DescriptorArray>> new_descriptor_arrays_;
226  std::vector<std::shared_ptr<BackingStore>> backing_stores_;
227
228  // Vector of allocated objects that can be accessed by a backref, by index.
229  std::vector<Handle<HeapObject>> back_refs_;
230
231  // Unresolved forward references (registered with kRegisterPendingForwardRef)
232  // are collected in order as (object, field offset) pairs. The subsequent
233  // forward ref resolution (with kResolvePendingForwardRef) accesses this
234  // vector by index.
235  //
236  // The vector is cleared when there are no more unresolved forward refs.
237  struct UnresolvedForwardRef {
238    UnresolvedForwardRef(Handle<HeapObject> object, int offset,
239                         HeapObjectReferenceType ref_type)
240        : object(object), offset(offset), ref_type(ref_type) {}
241
242    Handle<HeapObject> object;
243    int offset;
244    HeapObjectReferenceType ref_type;
245  };
246  std::vector<UnresolvedForwardRef> unresolved_forward_refs_;
247  int num_unresolved_forward_refs_ = 0;
248
249  const bool deserializing_user_code_;
250
251  bool next_reference_is_weak_ = false;
252
253  // TODO(6593): generalize rehashing, and remove this flag.
254  const bool should_rehash_;
255  std::vector<Handle<HeapObject>> to_rehash_;
256
257#ifdef DEBUG
258  uint32_t num_api_references_;
259
260  // Record the previous object allocated for DCHECKs.
261  Handle<HeapObject> previous_allocation_obj_;
262  int previous_allocation_size_ = 0;
263#endif  // DEBUG
264};
265
266extern template class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
267    Deserializer<Isolate>;
268extern template class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
269    Deserializer<LocalIsolate>;
270
271enum class DeserializingUserCodeOption {
272  kNotDeserializingUserCode,
273  kIsDeserializingUserCode
274};
275
276// Used to insert a deserialized internalized string into the string table.
277class StringTableInsertionKey final : public StringTableKey {
278 public:
279  explicit StringTableInsertionKey(
280      Isolate* isolate, Handle<String> string,
281      DeserializingUserCodeOption deserializing_user_code);
282  explicit StringTableInsertionKey(
283      LocalIsolate* isolate, Handle<String> string,
284      DeserializingUserCodeOption deserializing_user_code);
285
286  template <typename IsolateT>
287  bool IsMatch(IsolateT* isolate, String string);
288
289  void PrepareForInsertion(Isolate* isolate) {
290    // When sharing the string table, all string table lookups during snapshot
291    // deserialization are hits.
292    DCHECK(isolate->OwnsStringTable() ||
293           deserializing_user_code_ ==
294               DeserializingUserCodeOption::kIsDeserializingUserCode);
295  }
296  void PrepareForInsertion(LocalIsolate* isolate) {}
297  V8_WARN_UNUSED_RESULT Handle<String> GetHandleForInsertion() {
298    return string_;
299  }
300
301 private:
302  Handle<String> string_;
303#ifdef DEBUG
304  DeserializingUserCodeOption deserializing_user_code_;
305#endif
306  DISALLOW_GARBAGE_COLLECTION(no_gc)
307};
308
309}  // namespace internal
310}  // namespace v8
311
312#endif  // V8_SNAPSHOT_DESERIALIZER_H_
313