1// Copyright 2021 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_WEB_SNAPSHOT_WEB_SNAPSHOT_H_
6#define V8_WEB_SNAPSHOT_WEB_SNAPSHOT_H_
7
8#include <queue>
9
10#include "src/handles/handles.h"
11#include "src/objects/value-serializer.h"
12#include "src/snapshot/serializer.h"  // For ObjectCacheIndexMap
13
14namespace v8 {
15
16class Context;
17class Isolate;
18
19template <typename T>
20class Local;
21
22namespace internal {
23
24class Context;
25class Map;
26class Object;
27class String;
28
29struct WebSnapshotData : public std::enable_shared_from_this<WebSnapshotData> {
30  uint8_t* buffer = nullptr;
31  size_t buffer_size = 0;
32  WebSnapshotData() = default;
33  WebSnapshotData(const WebSnapshotData&) = delete;
34  WebSnapshotData& operator=(const WebSnapshotData&) = delete;
35  ~WebSnapshotData() { free(buffer); }
36};
37
38class WebSnapshotSerializerDeserializer {
39 public:
40  inline bool has_error() const { return error_message_ != nullptr; }
41  const char* error_message() const { return error_message_; }
42
43  enum ValueType : uint8_t {
44    FALSE_CONSTANT,
45    TRUE_CONSTANT,
46    NULL_CONSTANT,
47    UNDEFINED_CONSTANT,
48    INTEGER,
49    DOUBLE,
50    STRING_ID,
51    ARRAY_ID,
52    OBJECT_ID,
53    FUNCTION_ID,
54    CLASS_ID,
55    REGEXP,
56    EXTERNAL_ID,
57    IN_PLACE_STRING_ID
58  };
59
60  static constexpr uint8_t kMagicNumber[4] = {'+', '+', '+', ';'};
61
62  enum ContextType : uint8_t { FUNCTION, BLOCK };
63
64  enum PropertyAttributesType : uint8_t { DEFAULT, CUSTOM };
65
66  uint32_t FunctionKindToFunctionFlags(FunctionKind kind);
67  FunctionKind FunctionFlagsToFunctionKind(uint32_t flags);
68  bool IsFunctionOrMethod(uint32_t flags);
69  bool IsConstructor(uint32_t flags);
70
71  uint32_t GetDefaultAttributeFlags();
72  uint32_t AttributesToFlags(PropertyDetails details);
73  PropertyAttributes FlagsToAttributes(uint32_t flags);
74
75  // The maximum count of items for each value type (strings, objects etc.)
76  static constexpr uint32_t kMaxItemCount =
77      static_cast<uint32_t>(FixedArray::kMaxLength - 1);
78  // This ensures indices and lengths can be converted between uint32_t and int
79  // without problems:
80  STATIC_ASSERT(kMaxItemCount < std::numeric_limits<int32_t>::max());
81
82 protected:
83  explicit WebSnapshotSerializerDeserializer(Isolate* isolate)
84      : isolate_(isolate) {}
85  // Not virtual, on purpose (because it doesn't need to be).
86  void Throw(const char* message);
87
88  inline Factory* factory() const { return isolate_->factory(); }
89
90  Isolate* isolate_;
91  const char* error_message_ = nullptr;
92
93 private:
94  WebSnapshotSerializerDeserializer(const WebSnapshotSerializerDeserializer&) =
95      delete;
96  WebSnapshotSerializerDeserializer& operator=(
97      const WebSnapshotSerializerDeserializer&) = delete;
98
99  // Keep most common function kinds in the 7 least significant bits to make the
100  // flags fit in 1 byte.
101  using AsyncFunctionBitField = base::BitField<bool, 0, 1>;
102  using GeneratorFunctionBitField = AsyncFunctionBitField::Next<bool, 1>;
103  using ArrowFunctionBitField = GeneratorFunctionBitField::Next<bool, 1>;
104  using MethodBitField = ArrowFunctionBitField::Next<bool, 1>;
105  using StaticBitField = MethodBitField::Next<bool, 1>;
106  using ClassConstructorBitField = StaticBitField::Next<bool, 1>;
107  using DefaultConstructorBitField = ClassConstructorBitField::Next<bool, 1>;
108  using DerivedConstructorBitField = DefaultConstructorBitField::Next<bool, 1>;
109
110  using ReadOnlyBitField = base::BitField<bool, 0, 1>;
111  using ConfigurableBitField = ReadOnlyBitField::Next<bool, 1>;
112  using EnumerableBitField = ConfigurableBitField::Next<bool, 1>;
113};
114
115class V8_EXPORT WebSnapshotSerializer
116    : public WebSnapshotSerializerDeserializer {
117 public:
118  explicit WebSnapshotSerializer(v8::Isolate* isolate);
119  explicit WebSnapshotSerializer(Isolate* isolate);
120
121  ~WebSnapshotSerializer();
122
123  bool TakeSnapshot(v8::Local<v8::Context> context,
124                    v8::Local<v8::PrimitiveArray> exports,
125                    WebSnapshotData& data_out);
126  bool TakeSnapshot(Handle<Object> object, MaybeHandle<FixedArray> block_list,
127                    WebSnapshotData& data_out);
128
129  // For inspecting the state after taking a snapshot.
130  uint32_t string_count() const {
131    return static_cast<uint32_t>(string_ids_.size());
132  }
133
134  uint32_t map_count() const { return static_cast<uint32_t>(map_ids_.size()); }
135
136  uint32_t context_count() const {
137    return static_cast<uint32_t>(context_ids_.size());
138  }
139
140  uint32_t function_count() const {
141    return static_cast<uint32_t>(function_ids_.size());
142  }
143
144  uint32_t class_count() const {
145    return static_cast<uint32_t>(class_ids_.size());
146  }
147
148  uint32_t array_count() const {
149    return static_cast<uint32_t>(array_ids_.size());
150  }
151
152  uint32_t object_count() const {
153    return static_cast<uint32_t>(object_ids_.size());
154  }
155
156  uint32_t external_objects_count() const {
157    return static_cast<uint32_t>(external_objects_ids_.size());
158  }
159
160  Handle<FixedArray> GetExternals();
161
162 private:
163  WebSnapshotSerializer(const WebSnapshotSerializer&) = delete;
164  WebSnapshotSerializer& operator=(const WebSnapshotSerializer&) = delete;
165
166  enum class AllowInPlace {
167    No,   // This reference cannot be replace with an in-place item.
168    Yes,  // This reference can be replaced with an in-place item.
169  };
170
171  void SerializePendingItems();
172  void WriteSnapshot(uint8_t*& buffer, size_t& buffer_size);
173  void WriteObjects(ValueSerializer& destination, size_t count,
174                    ValueSerializer& source, const char* name);
175
176  // Returns true if the object was already in the map, false if it was added.
177  bool InsertIntoIndexMap(ObjectCacheIndexMap& map, HeapObject heap_object,
178                          uint32_t& id);
179
180  void ShallowDiscoverExternals(FixedArray externals);
181  void Discover(Handle<HeapObject> object);
182  void DiscoverString(Handle<String> string,
183                      AllowInPlace can_be_in_place = AllowInPlace::No);
184  void DiscoverMap(Handle<Map> map);
185  void DiscoverFunction(Handle<JSFunction> function);
186  void DiscoverClass(Handle<JSFunction> function);
187  void DiscoverContextAndPrototype(Handle<JSFunction> function);
188  void DiscoverContext(Handle<Context> context);
189  void DiscoverArray(Handle<JSArray> array);
190  void DiscoverObject(Handle<JSObject> object);
191  void DiscoverSource(Handle<JSFunction> function);
192  void ConstructSource();
193
194  void SerializeFunctionInfo(ValueSerializer* serializer,
195                             Handle<JSFunction> function);
196
197  void SerializeString(Handle<String> string, ValueSerializer& serializer);
198  void SerializeMap(Handle<Map> map);
199  void SerializeFunction(Handle<JSFunction> function);
200  void SerializeClass(Handle<JSFunction> function);
201  void SerializeContext(Handle<Context> context);
202  void SerializeArray(Handle<JSArray> array);
203  void SerializeObject(Handle<JSObject> object);
204
205  void SerializeExport(Handle<Object> object, Handle<String> export_name);
206  void WriteValue(Handle<Object> object, ValueSerializer& serializer);
207  void WriteStringMaybeInPlace(Handle<String> string,
208                               ValueSerializer& serializer);
209  void WriteStringId(Handle<String> string, ValueSerializer& serializer);
210
211  uint32_t GetStringId(Handle<String> string, bool& in_place);
212  uint32_t GetMapId(Map map);
213  uint32_t GetFunctionId(JSFunction function);
214  uint32_t GetClassId(JSFunction function);
215  uint32_t GetContextId(Context context);
216  uint32_t GetArrayId(JSArray array);
217  uint32_t GetObjectId(JSObject object);
218  uint32_t GetExternalId(HeapObject object);
219
220  ValueSerializer string_serializer_;
221  ValueSerializer map_serializer_;
222  ValueSerializer context_serializer_;
223  ValueSerializer function_serializer_;
224  ValueSerializer class_serializer_;
225  ValueSerializer array_serializer_;
226  ValueSerializer object_serializer_;
227  ValueSerializer export_serializer_;
228
229  // These are needed for being able to serialize items in order.
230  Handle<ArrayList> contexts_;
231  Handle<ArrayList> functions_;
232  Handle<ArrayList> classes_;
233  Handle<ArrayList> arrays_;
234  Handle<ArrayList> objects_;
235  Handle<ArrayList> strings_;
236  Handle<ArrayList> maps_;
237
238  // IndexMap to keep track of explicitly blocked external objects and
239  // non-serializable/not-supported objects (e.g. API Objects).
240  ObjectCacheIndexMap external_objects_ids_;
241
242  // ObjectCacheIndexMap implements fast lookup item -> id. Some items (context,
243  // function, class, array, object) can point to other items and we serialize
244  // them in the reverse order. This ensures that the items this item points to
245  // have a lower ID and will be deserialized first.
246  ObjectCacheIndexMap string_ids_;
247  ObjectCacheIndexMap map_ids_;
248  ObjectCacheIndexMap context_ids_;
249  ObjectCacheIndexMap function_ids_;
250  ObjectCacheIndexMap class_ids_;
251  ObjectCacheIndexMap array_ids_;
252  ObjectCacheIndexMap object_ids_;
253  uint32_t export_count_ = 0;
254
255  std::queue<Handle<HeapObject>> discovery_queue_;
256
257  // For keeping track of which strings have exactly one reference. Strings are
258  // inserted here when the first reference is discovered, and never removed.
259  // Strings which have more than one reference get an ID and are inserted to
260  // strings_.
261  IdentityMap<int, base::DefaultAllocationPolicy> all_strings_;
262
263  // For constructing the minimal, "compacted", source string to cover all
264  // function bodies.
265  Handle<String> full_source_;
266  uint32_t source_id_;
267  // Ordered set of (start, end) pairs of all functions we've discovered.
268  std::set<std::pair<int, int>> source_intervals_;
269  // Maps function positions in the real source code into the function positions
270  // in the constructed source code (which we'll include in the web snapshot).
271  std::unordered_map<int, int> source_offset_to_compacted_source_offset_;
272};
273
274class V8_EXPORT WebSnapshotDeserializer
275    : public WebSnapshotSerializerDeserializer {
276 public:
277  WebSnapshotDeserializer(v8::Isolate* v8_isolate, const uint8_t* data,
278                          size_t buffer_size);
279  WebSnapshotDeserializer(Isolate* isolate, Handle<Script> snapshot_as_script);
280  ~WebSnapshotDeserializer();
281  bool Deserialize(MaybeHandle<FixedArray> external_references = {},
282                   bool skip_exports = false);
283
284  // For inspecting the state after deserializing a snapshot.
285  uint32_t string_count() const { return string_count_; }
286  uint32_t map_count() const { return map_count_; }
287  uint32_t context_count() const { return context_count_; }
288  uint32_t function_count() const { return function_count_; }
289  uint32_t class_count() const { return class_count_; }
290  uint32_t array_count() const { return array_count_; }
291  uint32_t object_count() const { return object_count_; }
292
293  static void UpdatePointersCallback(v8::Isolate* isolate, v8::GCType type,
294                                     v8::GCCallbackFlags flags,
295                                     void* deserializer) {
296    reinterpret_cast<WebSnapshotDeserializer*>(deserializer)->UpdatePointers();
297  }
298
299  void UpdatePointers();
300
301  MaybeHandle<Object> value() const { return return_value_; }
302
303 private:
304  WebSnapshotDeserializer(Isolate* isolate, Handle<Object> script_name,
305                          base::Vector<const uint8_t> buffer);
306  base::Vector<const uint8_t> ExtractScriptBuffer(
307      Isolate* isolate, Handle<Script> snapshot_as_script);
308  bool DeserializeSnapshot(bool skip_exports);
309  bool DeserializeScript();
310
311  WebSnapshotDeserializer(const WebSnapshotDeserializer&) = delete;
312  WebSnapshotDeserializer& operator=(const WebSnapshotDeserializer&) = delete;
313
314  void DeserializeStrings();
315  void DeserializeMaps();
316  void DeserializeContexts();
317  Handle<ScopeInfo> CreateScopeInfo(uint32_t variable_count, bool has_parent,
318                                    ContextType context_type);
319  Handle<JSFunction> CreateJSFunction(int index, uint32_t start,
320                                      uint32_t length, uint32_t parameter_count,
321                                      uint32_t flags, uint32_t context_id);
322  void DeserializeFunctionData(uint32_t count, uint32_t current_count);
323  void DeserializeFunctions();
324  void DeserializeClasses();
325  void DeserializeArrays();
326  void DeserializeObjects();
327  void DeserializeExports(bool skip_exports);
328
329  Object ReadValue(
330      Handle<HeapObject> object_for_deferred_reference = Handle<HeapObject>(),
331      uint32_t index_for_deferred_reference = 0);
332
333  Object ReadInteger();
334  Object ReadNumber();
335  String ReadString(bool internalize = false);
336  String ReadInPlaceString(bool internalize = false);
337  Object ReadArray(Handle<HeapObject> container, uint32_t container_index);
338  Object ReadObject(Handle<HeapObject> container, uint32_t container_index);
339  Object ReadFunction(Handle<HeapObject> container, uint32_t container_index);
340  Object ReadClass(Handle<HeapObject> container, uint32_t container_index);
341  Object ReadRegexp();
342  Object ReadExternalReference();
343
344  void ReadFunctionPrototype(Handle<JSFunction> function);
345  bool SetFunctionPrototype(JSFunction function, JSReceiver prototype);
346
347  HeapObject AddDeferredReference(Handle<HeapObject> container, uint32_t index,
348                                  ValueType target_type,
349                                  uint32_t target_object_index);
350  void ProcessDeferredReferences();
351  // Not virtual, on purpose (because it doesn't need to be).
352  void Throw(const char* message);
353
354  Handle<FixedArray> strings_handle_;
355  FixedArray strings_;
356
357  Handle<FixedArray> maps_handle_;
358  FixedArray maps_;
359
360  Handle<FixedArray> contexts_handle_;
361  FixedArray contexts_;
362
363  Handle<FixedArray> functions_handle_;
364  FixedArray functions_;
365
366  Handle<FixedArray> classes_handle_;
367  FixedArray classes_;
368
369  Handle<FixedArray> arrays_handle_;
370  FixedArray arrays_;
371
372  Handle<FixedArray> objects_handle_;
373  FixedArray objects_;
374
375  Handle<FixedArray> external_references_handle_;
376  FixedArray external_references_;
377
378  Handle<ArrayList> deferred_references_;
379
380  Handle<WeakFixedArray> shared_function_infos_handle_;
381  WeakFixedArray shared_function_infos_;
382
383  Handle<ObjectHashTable> shared_function_info_table_;
384
385  Handle<Script> script_;
386  Handle<Object> script_name_;
387
388  Handle<Object> return_value_;
389
390  uint32_t string_count_ = 0;
391  uint32_t map_count_ = 0;
392  uint32_t context_count_ = 0;
393  uint32_t function_count_ = 0;
394  uint32_t current_function_count_ = 0;
395  uint32_t class_count_ = 0;
396  uint32_t current_class_count_ = 0;
397  uint32_t array_count_ = 0;
398  uint32_t current_array_count_ = 0;
399  uint32_t object_count_ = 0;
400  uint32_t current_object_count_ = 0;
401
402  ValueDeserializer deserializer_;
403  ReadOnlyRoots roots_;
404
405  bool deserialized_ = false;
406};
407
408}  // namespace internal
409}  // namespace v8
410
411#endif  // V8_WEB_SNAPSHOT_WEB_SNAPSHOT_H_
412