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 19namespace node { 20 21struct EnvSerializeInfo; 22struct PropInfo; 23struct RealmSerializeInfo; 24 25namespace builtins { 26struct CodeCacheInfo; 27} // namespace builtins 28 29// These operator<< overload declarations are needed because 30// BlobSerializerDeserializer::ToStr() uses these. 31 32std::ostream& operator<<(std::ostream& output, 33 const builtins::CodeCacheInfo& info); 34 35std::ostream& operator<<(std::ostream& output, 36 const std::vector<builtins::CodeCacheInfo>& vec); 37 38std::ostream& operator<<(std::ostream& output, const std::vector<uint8_t>& vec); 39 40std::ostream& operator<<(std::ostream& output, 41 const std::vector<PropInfo>& vec); 42 43std::ostream& operator<<(std::ostream& output, const PropInfo& info); 44 45std::ostream& operator<<(std::ostream& output, 46 const std::vector<std::string>& vec); 47 48std::ostream& operator<<(std::ostream& output, const RealmSerializeInfo& i); 49 50std::ostream& operator<<(std::ostream& output, const EnvSerializeInfo& i); 51 52template <typename... Args> 53void BlobSerializerDeserializer::Debug(const char* format, 54 Args&&... args) const { 55 if (is_debug) { 56 FPrintF(stderr, format, std::forward<Args>(args)...); 57 } 58} 59 60template <typename T> 61std::string BlobSerializerDeserializer::ToStr(const T& arg) const { 62 std::stringstream ss; 63 ss << arg; 64 return ss.str(); 65} 66 67template <typename T> 68std::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. 91template <typename Impl> 92template <typename T> 93T 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) 103template <typename Impl> 104template <typename T> 105std::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 131template <typename Impl> 132std::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. 153template <typename Impl> 154template <typename T> 155void 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. 175template <typename Impl> 176template <typename Number> 177std::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. 186template <typename Impl> 187template <typename T> 188std::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 206template <typename Impl> 207template <typename T> 208T 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. 219template <typename Impl> 220template <typename T> 221size_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) 229template <typename Impl> 230template <typename T> 231size_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 264template <typename Impl> 265size_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. 286template <typename Impl> 287template <typename T> 288size_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. 313template <typename Impl> 314template <typename Number> 315size_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. 322template <typename Impl> 323template <typename T> 324size_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 343template <typename Impl> 344template <typename T> 345size_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