/src/node/src/node_snapshotable.h
Line | Count | Source (jump to first uncovered line) |
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 "aliased_buffer.h" |
8 | | #include "base_object.h" |
9 | | #include "util.h" |
10 | | |
11 | | namespace node { |
12 | | |
13 | | class Environment; |
14 | | struct RealmSerializeInfo; |
15 | | struct SnapshotData; |
16 | | class ExternalReferenceRegistry; |
17 | | |
18 | | using SnapshotIndex = size_t; |
19 | | |
20 | | struct PropInfo { |
21 | | std::string name; // name for debugging |
22 | | uint32_t id; // In the list - in case there are any empty entries |
23 | | SnapshotIndex index; // In the snapshot |
24 | | }; |
25 | | |
26 | | typedef size_t SnapshotIndex; |
27 | | |
28 | | bool WithoutCodeCache(const SnapshotFlags& flags); |
29 | | bool WithoutCodeCache(const SnapshotConfig& config); |
30 | | |
31 | | // When serializing an embedder object, we'll serialize the native states |
32 | | // into a chunk that can be mapped into a subclass of InternalFieldInfoBase, |
33 | | // and pass it into the V8 callback as the payload of StartupData. |
34 | | // The memory chunk looks like this: |
35 | | // |
36 | | // [ type ] - EmbedderObjectType (a uint8_t) |
37 | | // [ length ] - a size_t |
38 | | // [ ... ] - custom bytes of size |length - header size| |
39 | | struct InternalFieldInfoBase { |
40 | | public: |
41 | | EmbedderObjectType type; |
42 | | size_t length; |
43 | | |
44 | | template <typename T> |
45 | 0 | static T* New(EmbedderObjectType type) { |
46 | 0 | static_assert(std::is_base_of_v<InternalFieldInfoBase, T> || |
47 | 0 | std::is_same_v<InternalFieldInfoBase, T>, |
48 | 0 | "Can only accept InternalFieldInfoBase subclasses"); |
49 | 0 | void* buf = ::operator new[](sizeof(T)); |
50 | 0 | T* result = new (buf) T; |
51 | 0 | result->type = type; |
52 | 0 | result->length = sizeof(T); |
53 | 0 | return result; |
54 | 0 | } Unexecuted instantiation: node::InternalFieldInfoBase* node::InternalFieldInfoBase::New<node::InternalFieldInfoBase>(node::EmbedderObjectType) Unexecuted instantiation: node::fs::BindingData::InternalFieldInfo* node::InternalFieldInfoBase::New<node::fs::BindingData::InternalFieldInfo>(node::EmbedderObjectType) Unexecuted instantiation: node::process::BindingData::InternalFieldInfo* node::InternalFieldInfoBase::New<node::process::BindingData::InternalFieldInfo>(node::EmbedderObjectType) Unexecuted instantiation: node::mksnapshot::BindingData::InternalFieldInfo* node::InternalFieldInfoBase::New<node::mksnapshot::BindingData::InternalFieldInfo>(node::EmbedderObjectType) Unexecuted instantiation: node::v8_utils::BindingData::InternalFieldInfo* node::InternalFieldInfoBase::New<node::v8_utils::BindingData::InternalFieldInfo>(node::EmbedderObjectType) Unexecuted instantiation: node::encoding_binding::BindingData::InternalFieldInfo* node::InternalFieldInfoBase::New<node::encoding_binding::BindingData::InternalFieldInfo>(node::EmbedderObjectType) |
55 | | |
56 | | template <typename T> |
57 | 0 | T* Copy() const { |
58 | 0 | static_assert(std::is_base_of_v<InternalFieldInfoBase, T> || |
59 | 0 | std::is_same_v<InternalFieldInfoBase, T>, |
60 | 0 | "Can only accept InternalFieldInfoBase subclasses"); |
61 | 0 | static_assert(std::is_trivially_copyable_v<T>, |
62 | 0 | "Can only memcpy trivially copyable class"); |
63 | 0 | void* buf = ::operator new[](sizeof(T)); |
64 | 0 | T* result = new (buf) T; |
65 | 0 | memcpy(result, this, sizeof(T)); |
66 | 0 | return result; |
67 | 0 | } Unexecuted instantiation: node::encoding_binding::BindingData::InternalFieldInfo* node::InternalFieldInfoBase::Copy<node::encoding_binding::BindingData::InternalFieldInfo>() const Unexecuted instantiation: node::fs::BindingData::InternalFieldInfo* node::InternalFieldInfoBase::Copy<node::fs::BindingData::InternalFieldInfo>() const Unexecuted instantiation: node::mksnapshot::BindingData::InternalFieldInfo* node::InternalFieldInfoBase::Copy<node::mksnapshot::BindingData::InternalFieldInfo>() const Unexecuted instantiation: node::v8_utils::BindingData::InternalFieldInfo* node::InternalFieldInfoBase::Copy<node::v8_utils::BindingData::InternalFieldInfo>() const Unexecuted instantiation: node::InternalFieldInfoBase* node::InternalFieldInfoBase::Copy<node::InternalFieldInfoBase>() const Unexecuted instantiation: node::process::BindingData::InternalFieldInfo* node::InternalFieldInfoBase::Copy<node::process::BindingData::InternalFieldInfo>() const |
68 | | |
69 | 0 | void Delete() { ::operator delete[](this); } |
70 | | |
71 | | InternalFieldInfoBase() = default; |
72 | | }; |
73 | | |
74 | | struct EmbedderTypeInfo { |
75 | | enum class MemoryMode : uint8_t { kBaseObject, kCppGC }; |
76 | 0 | EmbedderTypeInfo(EmbedderObjectType t, MemoryMode m) : type(t), mode(m) {} |
77 | | EmbedderTypeInfo() = default; |
78 | | EmbedderObjectType type; |
79 | | MemoryMode mode; |
80 | | }; |
81 | | |
82 | | // An interface for snapshotable native objects to inherit from. |
83 | | // Use the SERIALIZABLE_OBJECT_METHODS() macro in the class to define |
84 | | // the following methods to implement: |
85 | | // |
86 | | // - PrepareForSerialization(): This would be run prior to context |
87 | | // serialization. Use this method to e.g. release references that |
88 | | // can be re-initialized, or perform property store operations |
89 | | // that needs a V8 context. |
90 | | // - Serialize(): This would be called during context serialization, |
91 | | // once for each embedder field of the object. |
92 | | // Allocate and construct an InternalFieldInfoBase object that contains |
93 | | // data that can be used to deserialize native states. |
94 | | // - Deserialize(): This would be called after the context is |
95 | | // deserialized and the object graph is complete, once for each |
96 | | // embedder field of the object. Use this to restore native states |
97 | | // in the object. |
98 | | class SnapshotableObject : public BaseObject { |
99 | | public: |
100 | | SnapshotableObject(Realm* realm, |
101 | | v8::Local<v8::Object> wrap, |
102 | | EmbedderObjectType type); |
103 | | std::string GetTypeName() const; |
104 | | |
105 | | // If returns false, the object will not be serialized. |
106 | | virtual bool PrepareForSerialization(v8::Local<v8::Context> context, |
107 | | v8::SnapshotCreator* creator) = 0; |
108 | | virtual InternalFieldInfoBase* Serialize(int index) = 0; |
109 | 0 | bool is_snapshotable() const override { return true; } |
110 | | // We'll make sure that the type is set in the constructor |
111 | 0 | EmbedderObjectType type() { return type_; } |
112 | | |
113 | | private: |
114 | | EmbedderObjectType type_; |
115 | | }; |
116 | | |
117 | | #define SERIALIZABLE_OBJECT_METHODS() \ |
118 | | bool PrepareForSerialization(v8::Local<v8::Context> context, \ |
119 | | v8::SnapshotCreator* creator) override; \ |
120 | | InternalFieldInfoBase* Serialize(int index) override; \ |
121 | | static void Deserialize(v8::Local<v8::Context> context, \ |
122 | | v8::Local<v8::Object> holder, \ |
123 | | int index, \ |
124 | | InternalFieldInfoBase* info); |
125 | | |
126 | | v8::StartupData SerializeNodeContextInternalFields(v8::Local<v8::Object> holder, |
127 | | int index, |
128 | | void* env); |
129 | | void DeserializeNodeInternalFields(v8::Local<v8::Object> holder, |
130 | | int index, |
131 | | v8::StartupData payload, |
132 | | void* env); |
133 | | void SerializeSnapshotableObjects(Realm* realm, |
134 | | v8::SnapshotCreator* creator, |
135 | | RealmSerializeInfo* info); |
136 | | |
137 | | #define DCHECK_IS_SNAPSHOT_SLOT(index) DCHECK_EQ(index, BaseObject::kSlot) |
138 | | |
139 | | namespace mksnapshot { |
140 | | class BindingData : public SnapshotableObject { |
141 | | public: |
142 | | struct InternalFieldInfo : public node::InternalFieldInfoBase { |
143 | | AliasedBufferIndex is_building_snapshot_buffer; |
144 | | }; |
145 | | |
146 | | BindingData(Realm* realm, |
147 | | v8::Local<v8::Object> obj, |
148 | | InternalFieldInfo* info = nullptr); |
149 | | SET_BINDING_ID(mksnapshot_binding_data) |
150 | | SERIALIZABLE_OBJECT_METHODS() |
151 | | |
152 | | void MemoryInfo(MemoryTracker* tracker) const override; |
153 | | SET_SELF_SIZE(BindingData) |
154 | | SET_MEMORY_INFO_NAME(BindingData) |
155 | | |
156 | | private: |
157 | | AliasedUint8Array is_building_snapshot_buffer_; |
158 | | InternalFieldInfo* internal_field_info_ = nullptr; |
159 | | }; |
160 | | } // namespace mksnapshot |
161 | | |
162 | | } // namespace node |
163 | | |
164 | | #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS |
165 | | |
166 | | #endif // SRC_NODE_SNAPSHOTABLE_H_ |