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