• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
14 namespace v8 {
15 
16 class Context;
17 class Isolate;
18 
19 template <typename T>
20 class Local;
21 
22 namespace internal {
23 
24 class Context;
25 class Map;
26 class Object;
27 class String;
28 
29 struct 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;
~WebSnapshotDataWebSnapshotData35   ~WebSnapshotData() { free(buffer); }
36 };
37 
38 class WebSnapshotSerializerDeserializer {
39  public:
has_error()40   inline bool has_error() const { return error_message_ != nullptr; }
error_message()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:
WebSnapshotSerializerDeserializer(Isolate * isolate)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 
factory()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 
115 class 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.
string_count()130   uint32_t string_count() const {
131     return static_cast<uint32_t>(string_ids_.size());
132   }
133 
map_count()134   uint32_t map_count() const { return static_cast<uint32_t>(map_ids_.size()); }
135 
context_count()136   uint32_t context_count() const {
137     return static_cast<uint32_t>(context_ids_.size());
138   }
139 
function_count()140   uint32_t function_count() const {
141     return static_cast<uint32_t>(function_ids_.size());
142   }
143 
class_count()144   uint32_t class_count() const {
145     return static_cast<uint32_t>(class_ids_.size());
146   }
147 
array_count()148   uint32_t array_count() const {
149     return static_cast<uint32_t>(array_ids_.size());
150   }
151 
object_count()152   uint32_t object_count() const {
153     return static_cast<uint32_t>(object_ids_.size());
154   }
155 
external_objects_count()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 
274 class 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.
string_count()285   uint32_t string_count() const { return string_count_; }
map_count()286   uint32_t map_count() const { return map_count_; }
context_count()287   uint32_t context_count() const { return context_count_; }
function_count()288   uint32_t function_count() const { return function_count_; }
class_count()289   uint32_t class_count() const { return class_count_; }
array_count()290   uint32_t array_count() const { return array_count_; }
object_count()291   uint32_t object_count() const { return object_count_; }
292 
UpdatePointersCallback(v8::Isolate * isolate,v8::GCType type,v8::GCCallbackFlags flags,void * deserializer)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 
value()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