• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef SRC_BLOB_SERIALIZER_DESERIALIZER_INL_H_
2 #define SRC_BLOB_SERIALIZER_DESERIALIZER_INL_H_
3 
4 #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
5 
6 #include "blob_serializer_deserializer.h"
7 
8 #include <ostream>
9 #include <sstream>
10 #include <string>
11 #include <type_traits>
12 #include <utility>
13 
14 #include "debug_utils-inl.h"
15 
16 // This is related to the blob that is used in snapshots and has nothing to do
17 // with `node_blob.h`.
18 
19 namespace node {
20 
21 struct EnvSerializeInfo;
22 struct PropInfo;
23 struct RealmSerializeInfo;
24 
25 namespace builtins {
26 struct CodeCacheInfo;
27 }  // namespace builtins
28 
29 // These operator<< overload declarations are needed because
30 // BlobSerializerDeserializer::ToStr() uses these.
31 
32 std::ostream& operator<<(std::ostream& output,
33                          const builtins::CodeCacheInfo& info);
34 
35 std::ostream& operator<<(std::ostream& output,
36                          const std::vector<builtins::CodeCacheInfo>& vec);
37 
38 std::ostream& operator<<(std::ostream& output, const std::vector<uint8_t>& vec);
39 
40 std::ostream& operator<<(std::ostream& output,
41                          const std::vector<PropInfo>& vec);
42 
43 std::ostream& operator<<(std::ostream& output, const PropInfo& info);
44 
45 std::ostream& operator<<(std::ostream& output,
46                          const std::vector<std::string>& vec);
47 
48 std::ostream& operator<<(std::ostream& output, const RealmSerializeInfo& i);
49 
50 std::ostream& operator<<(std::ostream& output, const EnvSerializeInfo& i);
51 
52 template <typename... Args>
Debug(const char * format,Args &&...args)53 void BlobSerializerDeserializer::Debug(const char* format,
54                                        Args&&... args) const {
55   if (is_debug) {
56     FPrintF(stderr, format, std::forward<Args>(args)...);
57   }
58 }
59 
60 template <typename T>
ToStr(const T & arg)61 std::string BlobSerializerDeserializer::ToStr(const T& arg) const {
62   std::stringstream ss;
63   ss << arg;
64   return ss.str();
65 }
66 
67 template <typename T>
GetName()68 std::string BlobSerializerDeserializer::GetName() const {
69 #define TYPE_LIST(V)                                                           \
70   V(builtins::CodeCacheInfo)                                                   \
71   V(PropInfo)                                                                  \
72   V(std::string)
73 
74 #define V(TypeName)                                                            \
75   if constexpr (std::is_same_v<T, TypeName>) {                                 \
76     return #TypeName;                                                          \
77   } else  // NOLINT(readability/braces)
78   TYPE_LIST(V)
79 #undef V
80 
81   if constexpr (std::is_arithmetic_v<T>) {
82     return (std::is_unsigned_v<T>   ? "uint"
83             : std::is_integral_v<T> ? "int"
84                                     : "float") +
85            std::to_string(sizeof(T) * 8) + "_t";
86   }
87   return "";
88 }
89 
90 // Helper for reading numeric types.
91 template <typename Impl>
92 template <typename T>
ReadArithmetic()93 T BlobDeserializer<Impl>::ReadArithmetic() {
94   static_assert(std::is_arithmetic_v<T>, "Not an arithmetic type");
95   T result;
96   ReadArithmetic(&result, 1);
97   return result;
98 }
99 
100 // Layout of vectors:
101 // [ 4/8 bytes ] count
102 // [   ...     ] contents (count * size of individual elements)
103 template <typename Impl>
104 template <typename T>
ReadVector()105 std::vector<T> BlobDeserializer<Impl>::ReadVector() {
106   if (is_debug) {
107     std::string name = GetName<T>();
108     Debug("\nReadVector<%s>()(%d-byte)\n", name.c_str(), sizeof(T));
109   }
110   size_t count = static_cast<size_t>(ReadArithmetic<size_t>());
111   if (count == 0) {
112     return std::vector<T>();
113   }
114   if (is_debug) {
115     Debug("Reading %d vector elements...\n", count);
116   }
117   std::vector<T> result;
118   if constexpr (std::is_arithmetic_v<T>) {
119     result = ReadArithmeticVector<T>(count);
120   } else {
121     result = ReadNonArithmeticVector<T>(count);
122   }
123   if (is_debug) {
124     std::string str = std::is_arithmetic_v<T> ? "" : ToStr(result);
125     std::string name = GetName<T>();
126     Debug("ReadVector<%s>() read %s\n", name.c_str(), str.c_str());
127   }
128   return result;
129 }
130 
131 template <typename Impl>
ReadString()132 std::string BlobDeserializer<Impl>::ReadString() {
133   size_t length = ReadArithmetic<size_t>();
134 
135   if (is_debug) {
136     Debug("ReadString(), length=%d: ", length);
137   }
138 
139   CHECK_GT(length, 0);  // There should be no empty strings.
140   MallocedBuffer<char> buf(length + 1);
141   memcpy(buf.data, sink.data() + read_total, length + 1);
142   std::string result(buf.data, length);  // This creates a copy of buf.data.
143 
144   if (is_debug) {
145     Debug("\"%s\", read %zu bytes\n", result.c_str(), length + 1);
146   }
147 
148   read_total += length + 1;
149   return result;
150 }
151 
152 // Helper for reading an array of numeric types.
153 template <typename Impl>
154 template <typename T>
ReadArithmetic(T * out,size_t count)155 void BlobDeserializer<Impl>::ReadArithmetic(T* out, size_t count) {
156   static_assert(std::is_arithmetic_v<T>, "Not an arithmetic type");
157   DCHECK_GT(count, 0);  // Should not read contents for vectors of size 0.
158   if (is_debug) {
159     std::string name = GetName<T>();
160     Debug("Read<%s>()(%d-byte), count=%d: ", name.c_str(), sizeof(T), count);
161   }
162 
163   size_t size = sizeof(T) * count;
164   memcpy(out, sink.data() + read_total, size);
165 
166   if (is_debug) {
167     std::string str =
168         "{ " + std::to_string(out[0]) + (count > 1 ? ", ... }" : " }");
169     Debug("%s, read %zu bytes\n", str.c_str(), size);
170   }
171   read_total += size;
172 }
173 
174 // Helper for reading numeric vectors.
175 template <typename Impl>
176 template <typename Number>
ReadArithmeticVector(size_t count)177 std::vector<Number> BlobDeserializer<Impl>::ReadArithmeticVector(size_t count) {
178   static_assert(std::is_arithmetic_v<Number>, "Not an arithmetic type");
179   DCHECK_GT(count, 0);  // Should not read contents for vectors of size 0.
180   std::vector<Number> result(count);
181   ReadArithmetic(result.data(), count);
182   return result;
183 }
184 
185 // Helper for reading non-numeric vectors.
186 template <typename Impl>
187 template <typename T>
ReadNonArithmeticVector(size_t count)188 std::vector<T> BlobDeserializer<Impl>::ReadNonArithmeticVector(size_t count) {
189   static_assert(!std::is_arithmetic_v<T>, "Arithmetic type");
190   DCHECK_GT(count, 0);  // Should not read contents for vectors of size 0.
191   std::vector<T> result;
192   result.reserve(count);
193   bool original_is_debug = is_debug;
194   is_debug = original_is_debug && !std::is_same_v<T, std::string>;
195   for (size_t i = 0; i < count; ++i) {
196     if (is_debug) {
197       Debug("\n[%d] ", i);
198     }
199     result.push_back(ReadElement<T>());
200   }
201   is_debug = original_is_debug;
202 
203   return result;
204 }
205 
206 template <typename Impl>
207 template <typename T>
ReadElement()208 T BlobDeserializer<Impl>::ReadElement() {
209   if constexpr (std::is_arithmetic_v<T>) {
210     return ReadArithmetic<T>();
211   } else if constexpr (std::is_same_v<T, std::string>) {
212     return ReadString();
213   } else {
214     return impl()->template Read<T>();
215   }
216 }
217 
218 // Helper for writing numeric types.
219 template <typename Impl>
220 template <typename T>
WriteArithmetic(const T & data)221 size_t BlobSerializer<Impl>::WriteArithmetic(const T& data) {
222   static_assert(std::is_arithmetic_v<T>, "Not an arithmetic type");
223   return WriteArithmetic(&data, 1);
224 }
225 
226 // Layout of vectors:
227 // [ 4/8 bytes ] count
228 // [   ...     ] contents (count * size of individual elements)
229 template <typename Impl>
230 template <typename T>
WriteVector(const std::vector<T> & data)231 size_t BlobSerializer<Impl>::WriteVector(const std::vector<T>& data) {
232   if (is_debug) {
233     std::string str = std::is_arithmetic_v<T> ? "" : ToStr(data);
234     std::string name = GetName<T>();
235     Debug("\nWriteVector<%s>() (%d-byte), count=%d: %s\n",
236           name.c_str(),
237           sizeof(T),
238           data.size(),
239           str.c_str());
240   }
241 
242   size_t written_total = WriteArithmetic<size_t>(data.size());
243   if (data.size() == 0) {
244     return written_total;
245   }
246 
247   if constexpr (std::is_arithmetic_v<T>) {
248     written_total += WriteArithmeticVector<T>(data);
249   } else {
250     written_total += WriteNonArithmeticVector<T>(data);
251   }
252 
253   if (is_debug) {
254     std::string name = GetName<T>();
255     Debug("WriteVector<%s>() wrote %d bytes\n", name.c_str(), written_total);
256   }
257 
258   return written_total;
259 }
260 
261 // The layout of a written string:
262 // [  4/8 bytes     ] length
263 // [ |length| bytes ] contents
264 template <typename Impl>
WriteString(const std::string & data)265 size_t BlobSerializer<Impl>::WriteString(const std::string& data) {
266   CHECK_GT(data.size(), 0);  // No empty strings should be written.
267   size_t written_total = WriteArithmetic<size_t>(data.size());
268   if (is_debug) {
269     std::string str = ToStr(data);
270     Debug("WriteString(), length=%zu: \"%s\"\n", data.size(), data.c_str());
271   }
272 
273   // Write the null-terminated string.
274   size_t length = data.size() + 1;
275   sink.insert(sink.end(), data.c_str(), data.c_str() + length);
276   written_total += length;
277 
278   if (is_debug) {
279     Debug("WriteString() wrote %zu bytes\n", written_total);
280   }
281 
282   return written_total;
283 }
284 
285 // Helper for writing an array of numeric types.
286 template <typename Impl>
287 template <typename T>
WriteArithmetic(const T * data,size_t count)288 size_t BlobSerializer<Impl>::WriteArithmetic(const T* data, size_t count) {
289   static_assert(std::is_arithmetic_v<T>, "Arithmetic type");
290   DCHECK_GT(count, 0);  // Should not write contents for vectors of size 0.
291   if (is_debug) {
292     std::string str =
293         "{ " + std::to_string(data[0]) + (count > 1 ? ", ... }" : " }");
294     std::string name = GetName<T>();
295     Debug("Write<%s>() (%zu-byte), count=%zu: %s",
296           name.c_str(),
297           sizeof(T),
298           count,
299           str.c_str());
300   }
301 
302   size_t size = sizeof(T) * count;
303   const char* pos = reinterpret_cast<const char*>(data);
304   sink.insert(sink.end(), pos, pos + size);
305 
306   if (is_debug) {
307     Debug(", wrote %zu bytes\n", size);
308   }
309   return size;
310 }
311 
312 // Helper for writing numeric vectors.
313 template <typename Impl>
314 template <typename Number>
WriteArithmeticVector(const std::vector<Number> & data)315 size_t BlobSerializer<Impl>::WriteArithmeticVector(
316     const std::vector<Number>& data) {
317   static_assert(std::is_arithmetic_v<Number>, "Arithmetic type");
318   return WriteArithmetic(data.data(), data.size());
319 }
320 
321 // Helper for writing non-numeric vectors.
322 template <typename Impl>
323 template <typename T>
WriteNonArithmeticVector(const std::vector<T> & data)324 size_t BlobSerializer<Impl>::WriteNonArithmeticVector(
325     const std::vector<T>& data) {
326   static_assert(!std::is_arithmetic_v<T>, "Arithmetic type");
327   DCHECK_GT(data.size(),
328             0);  // Should not write contents for vectors of size 0.
329   size_t written_total = 0;
330   bool original_is_debug = is_debug;
331   is_debug = original_is_debug && !std::is_same_v<T, std::string>;
332   for (size_t i = 0; i < data.size(); ++i) {
333     if (is_debug) {
334       Debug("\n[%d] ", i);
335     }
336     written_total += WriteElement<T>(data[i]);
337   }
338   is_debug = original_is_debug;
339 
340   return written_total;
341 }
342 
343 template <typename Impl>
344 template <typename T>
WriteElement(const T & data)345 size_t BlobSerializer<Impl>::WriteElement(const T& data) {
346   if constexpr (std::is_arithmetic_v<T>) {
347     return WriteArithmetic<T>(data);
348   } else if constexpr (std::is_same_v<T, std::string>) {
349     return WriteString(data);
350   } else {
351     return impl()->template Write<T>(data);
352   }
353 }
354 
355 }  // namespace node
356 
357 #endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
358 
359 #endif  // SRC_BLOB_SERIALIZER_DESERIALIZER_INL_H_
360