Coverage Report

Created: 2025-09-05 10:05

/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_