1 2 #ifndef SRC_NODE_SNAPSHOTABLE_H_ 3 #define SRC_NODE_SNAPSHOTABLE_H_ 4 5 #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS 6 7 #include "base_object.h" 8 #include "util.h" 9 10 namespace node { 11 12 class Environment; 13 struct RealmSerializeInfo; 14 struct SnapshotData; 15 class ExternalReferenceRegistry; 16 17 using SnapshotIndex = size_t; 18 19 struct PropInfo { 20 std::string name; // name for debugging 21 uint32_t id; // In the list - in case there are any empty entries 22 SnapshotIndex index; // In the snapshot 23 }; 24 25 #define SERIALIZABLE_OBJECT_TYPES(V) \ 26 V(fs_binding_data, fs::BindingData) \ 27 V(v8_binding_data, v8_utils::BindingData) \ 28 V(blob_binding_data, BlobBindingData) \ 29 V(process_binding_data, process::BindingData) \ 30 V(url_binding_data, url::BindingData) \ 31 V(util_weak_reference, util::WeakReference) 32 33 enum class EmbedderObjectType : uint8_t { 34 #define V(PropertyName, NativeType) k_##PropertyName, 35 SERIALIZABLE_OBJECT_TYPES(V) 36 #undef V 37 }; 38 39 typedef size_t SnapshotIndex; 40 41 // When serializing an embedder object, we'll serialize the native states 42 // into a chunk that can be mapped into a subclass of InternalFieldInfoBase, 43 // and pass it into the V8 callback as the payload of StartupData. 44 // The memory chunk looks like this: 45 // 46 // [ type ] - EmbedderObjectType (a uint8_t) 47 // [ length ] - a size_t 48 // [ ... ] - custom bytes of size |length - header size| 49 struct InternalFieldInfoBase { 50 public: 51 EmbedderObjectType type; 52 size_t length; 53 54 template <typename T> NewInternalFieldInfoBase55 static T* New(EmbedderObjectType type) { 56 static_assert(std::is_base_of_v<InternalFieldInfoBase, T> || 57 std::is_same_v<InternalFieldInfoBase, T>, 58 "Can only accept InternalFieldInfoBase subclasses"); 59 void* buf = ::operator new[](sizeof(T)); 60 T* result = new (buf) T; 61 result->type = type; 62 result->length = sizeof(T); 63 return result; 64 } 65 66 template <typename T> CopyInternalFieldInfoBase67 T* Copy() const { 68 static_assert(std::is_base_of_v<InternalFieldInfoBase, T> || 69 std::is_same_v<InternalFieldInfoBase, T>, 70 "Can only accept InternalFieldInfoBase subclasses"); 71 static_assert(std::is_trivially_copyable_v<T>, 72 "Can only memcpy trivially copyable class"); 73 void* buf = ::operator new[](sizeof(T)); 74 T* result = new (buf) T; 75 memcpy(result, this, sizeof(T)); 76 return result; 77 } 78 DeleteInternalFieldInfoBase79 void Delete() { ::operator delete[](this); } 80 81 InternalFieldInfoBase() = default; 82 }; 83 84 // An interface for snapshotable native objects to inherit from. 85 // Use the SERIALIZABLE_OBJECT_METHODS() macro in the class to define 86 // the following methods to implement: 87 // 88 // - PrepareForSerialization(): This would be run prior to context 89 // serialization. Use this method to e.g. release references that 90 // can be re-initialized, or perform property store operations 91 // that needs a V8 context. 92 // - Serialize(): This would be called during context serialization, 93 // once for each embedder field of the object. 94 // Allocate and construct an InternalFieldInfoBase object that contains 95 // data that can be used to deserialize native states. 96 // - Deserialize(): This would be called after the context is 97 // deserialized and the object graph is complete, once for each 98 // embedder field of the object. Use this to restore native states 99 // in the object. 100 class SnapshotableObject : public BaseObject { 101 public: 102 SnapshotableObject(Realm* realm, 103 v8::Local<v8::Object> wrap, 104 EmbedderObjectType type); 105 std::string_view GetTypeName() const; 106 107 // If returns false, the object will not be serialized. 108 virtual bool PrepareForSerialization(v8::Local<v8::Context> context, 109 v8::SnapshotCreator* creator) = 0; 110 virtual InternalFieldInfoBase* Serialize(int index) = 0; is_snapshotable()111 bool is_snapshotable() const override { return true; } 112 // We'll make sure that the type is set in the constructor type()113 EmbedderObjectType type() { return type_; } 114 115 private: 116 EmbedderObjectType type_; 117 }; 118 119 #define SERIALIZABLE_OBJECT_METHODS() \ 120 bool PrepareForSerialization(v8::Local<v8::Context> context, \ 121 v8::SnapshotCreator* creator) override; \ 122 InternalFieldInfoBase* Serialize(int index) override; \ 123 static void Deserialize(v8::Local<v8::Context> context, \ 124 v8::Local<v8::Object> holder, \ 125 int index, \ 126 InternalFieldInfoBase* info); 127 128 v8::StartupData SerializeNodeContextInternalFields(v8::Local<v8::Object> holder, 129 int index, 130 void* env); 131 void DeserializeNodeInternalFields(v8::Local<v8::Object> holder, 132 int index, 133 v8::StartupData payload, 134 void* env); 135 void SerializeSnapshotableObjects(Realm* realm, 136 v8::SnapshotCreator* creator, 137 RealmSerializeInfo* info); 138 } // namespace node 139 140 #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS 141 142 #endif // SRC_NODE_SNAPSHOTABLE_H_ 143