// Copyright 2021 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_WEB_SNAPSHOT_WEB_SNAPSHOT_H_ #define V8_WEB_SNAPSHOT_WEB_SNAPSHOT_H_ #include #include #include "src/handles/handles.h" #include "src/objects/value-serializer.h" #include "src/snapshot/serializer.h" // For ObjectCacheIndexMap namespace v8 { class Context; class Isolate; template class Local; namespace internal { class Context; class Map; class Object; class String; struct WebSnapshotData : public std::enable_shared_from_this { uint8_t* buffer = nullptr; size_t buffer_size = 0; WebSnapshotData() = default; WebSnapshotData(const WebSnapshotData&) = delete; WebSnapshotData& operator=(const WebSnapshotData&) = delete; ~WebSnapshotData() { free(buffer); } }; class WebSnapshotSerializerDeserializer { public: inline bool has_error() const { return error_message_ != nullptr; } const char* error_message() const { return error_message_; } enum ValueType : uint8_t { FALSE_CONSTANT, TRUE_CONSTANT, NULL_CONSTANT, UNDEFINED_CONSTANT, INTEGER, DOUBLE, STRING_ID, ARRAY_ID, OBJECT_ID, FUNCTION_ID, CLASS_ID, REGEXP }; enum ContextType : uint8_t { FUNCTION, BLOCK }; enum PropertyAttributesType : uint8_t { DEFAULT, CUSTOM }; uint32_t FunctionKindToFunctionFlags(FunctionKind kind); FunctionKind FunctionFlagsToFunctionKind(uint32_t flags); bool IsFunctionOrMethod(uint32_t flags); bool IsConstructor(uint32_t flags); uint32_t GetDefaultAttributeFlags(); uint32_t AttributesToFlags(PropertyDetails details); PropertyAttributes FlagsToAttributes(uint32_t flags); // The maximum count of items for each value type (strings, objects etc.) static constexpr uint32_t kMaxItemCount = static_cast(FixedArray::kMaxLength - 1); // This ensures indices and lengths can be converted between uint32_t and int // without problems: STATIC_ASSERT(kMaxItemCount < std::numeric_limits::max()); protected: explicit WebSnapshotSerializerDeserializer(Isolate* isolate) : isolate_(isolate) {} // Not virtual, on purpose (because it doesn't need to be). void Throw(const char* message); Isolate* isolate_; const char* error_message_ = nullptr; private: WebSnapshotSerializerDeserializer(const WebSnapshotSerializerDeserializer&) = delete; WebSnapshotSerializerDeserializer& operator=( const WebSnapshotSerializerDeserializer&) = delete; // Keep most common function kinds in the 7 least significant bits to make the // flags fit in 1 byte. using AsyncFunctionBitField = base::BitField; using GeneratorFunctionBitField = AsyncFunctionBitField::Next; using ArrowFunctionBitField = GeneratorFunctionBitField::Next; using MethodBitField = ArrowFunctionBitField::Next; using StaticBitField = MethodBitField::Next; using ClassConstructorBitField = StaticBitField::Next; using DefaultConstructorBitField = ClassConstructorBitField::Next; using DerivedConstructorBitField = DefaultConstructorBitField::Next; using ReadOnlyBitField = base::BitField; using ConfigurableBitField = ReadOnlyBitField::Next; using EnumerableBitField = ConfigurableBitField::Next; }; class V8_EXPORT WebSnapshotSerializer : public WebSnapshotSerializerDeserializer { public: explicit WebSnapshotSerializer(v8::Isolate* isolate); ~WebSnapshotSerializer(); bool TakeSnapshot(v8::Local context, v8::Local exports, WebSnapshotData& data_out); // For inspecting the state after taking a snapshot. uint32_t string_count() const { return static_cast(string_ids_.size()); } uint32_t map_count() const { return static_cast(map_ids_.size()); } uint32_t context_count() const { return static_cast(context_ids_.size()); } uint32_t function_count() const { return static_cast(function_ids_.size()); } uint32_t class_count() const { return static_cast(class_ids_.size()); } uint32_t array_count() const { return static_cast(array_ids_.size()); } uint32_t object_count() const { return static_cast(object_ids_.size()); } private: WebSnapshotSerializer(const WebSnapshotSerializer&) = delete; WebSnapshotSerializer& operator=(const WebSnapshotSerializer&) = delete; void SerializePendingItems(); void WriteSnapshot(uint8_t*& buffer, size_t& buffer_size); // Returns true if the object was already in the map, false if it was added. bool InsertIntoIndexMap(ObjectCacheIndexMap& map, Handle object, uint32_t& id); void SerializeSource(ValueSerializer* serializer, Handle function); void SerializeFunctionInfo(ValueSerializer* serializer, Handle function); void SerializeString(Handle string, uint32_t& id); void SerializeMap(Handle map, uint32_t& id); void SerializeFunction(Handle function, uint32_t& id); void SerializeClass(Handle function, uint32_t& id); void SerializeContext(Handle context, uint32_t& id); void SerializeArray(Handle array, uint32_t& id); void SerializePendingArray(Handle array); void SerializeObject(Handle object, uint32_t& id); void SerializePendingObject(Handle object); void SerializeExport(Handle object, Handle export_name); void WriteValue(Handle object, ValueSerializer& serializer); ValueSerializer string_serializer_; ValueSerializer map_serializer_; ValueSerializer context_serializer_; ValueSerializer function_serializer_; ValueSerializer class_serializer_; ValueSerializer array_serializer_; ValueSerializer object_serializer_; ValueSerializer export_serializer_; ObjectCacheIndexMap string_ids_; ObjectCacheIndexMap map_ids_; ObjectCacheIndexMap context_ids_; ObjectCacheIndexMap function_ids_; ObjectCacheIndexMap class_ids_; ObjectCacheIndexMap array_ids_; ObjectCacheIndexMap object_ids_; uint32_t export_count_ = 0; std::queue> pending_objects_; std::queue> pending_arrays_; }; class V8_EXPORT WebSnapshotDeserializer : public WebSnapshotSerializerDeserializer { public: explicit WebSnapshotDeserializer(v8::Isolate* v8_isolate); ~WebSnapshotDeserializer(); bool UseWebSnapshot(const uint8_t* data, size_t buffer_size); // For inspecting the state after deserializing a snapshot. uint32_t string_count() const { return string_count_; } uint32_t map_count() const { return map_count_; } uint32_t context_count() const { return context_count_; } uint32_t function_count() const { return function_count_; } uint32_t class_count() const { return class_count_; } uint32_t array_count() const { return array_count_; } uint32_t object_count() const { return object_count_; } private: WebSnapshotDeserializer(const WebSnapshotDeserializer&) = delete; WebSnapshotDeserializer& operator=(const WebSnapshotDeserializer&) = delete; void DeserializeStrings(); Handle ReadString(bool internalize = false); void DeserializeMaps(); void DeserializeContexts(); Handle CreateScopeInfo(uint32_t variable_count, bool has_parent, ContextType context_type); Handle CreateJSFunction(int index, uint32_t start, uint32_t length, uint32_t flags, uint32_t context_id); void DeserializeFunctionData(uint32_t count, uint32_t current_count); void DeserializeFunctions(); void DeserializeClasses(); void DeserializeArrays(); void DeserializeObjects(); void DeserializeExports(); void ReadValue( Handle& value, Representation& representation, Handle object_for_deferred_reference = Handle(), uint32_t index_for_deferred_reference = 0); void AddDeferredReference(Handle container, uint32_t index, ValueType target_type, uint32_t target_object_index); void ProcessDeferredReferences(); // Not virtual, on purpose (because it doesn't need to be). void Throw(const char* message); Handle strings_; Handle maps_; Handle contexts_; Handle functions_; Handle classes_; Handle arrays_; Handle objects_; Handle deferred_references_; Handle shared_function_infos_; Handle shared_function_info_table_; Handle