diff --git a/node.gyp b/node.gyp index 605bc811936a6f..6622b95f22a0a5 100644 --- a/node.gyp +++ b/node.gyp @@ -569,6 +569,7 @@ 'src/async_wrap-inl.h', 'src/base_object.h', 'src/base_object-inl.h', + 'src/base_object_types.h', 'src/base64.h', 'src/base64-inl.h', 'src/callback_queue.h', diff --git a/src/README.md b/src/README.md index f8b2dfd871cd78..8ea3ebb2ff36d9 100644 --- a/src/README.md +++ b/src/README.md @@ -486,19 +486,24 @@ that state is through the use of `Environment::AddBindingData`, which gives binding functions access to an object for storing such state. That object is always a [`BaseObject`][]. -If the binding should be supported in a snapshot, it needs to be in the -`SERIALIZABLE_OBJECT_TYPES` list in `node_snapshotable.h` and implement the -serialization and deserialization methods. See the comments of -`SnapshotableObject` on how to implement them. Otherwise, the `type_int` field -needs to be added to the `UNSERIALIZABLE_OBJECT_TYPES` list. +In the binding, call `SET_BINDING_ID()` with an identifier for the binding +type. For example, for `http_parser::BindingData`, the identifier can be +`http_parser_binding_data`. + +If the binding should be supported in a snapshot, the id and the +fully-specified class name should be added to the `SERIALIZABLE_BINDING_TYPES` +list in `base_object_types.h`, and the class should implement the serialization +and deserialization methods. See the comments of `SnapshotableObject` on how to +implement them. Otherwise, add the id and the class name to the +`UNSERIALIZABLE_BINDING_TYPES` list instead. ```cpp -// In node_snapshotable.h, add the binding to either UNSERIALIZABLE_OBJECT_TYPES -// or SERIALIZABLE_OBJECT_TYPES. The second parameter is a descriptive name -// of the class, which is usually the class name with the (actual or conceptual) -// namespace. +// In base_object_types.h, add the binding to either +// UNSERIALIZABLE_BINDING_TYPES or SERIALIZABLE_BINDING_TYPES. +// The second parameter is a descriptive name of the class, which is +// usually the fully-specified class name. -#define UNSERIALIZABLE_OBJECT_TYPES(V) \ +#define UNSERIALIZABLE_BINDING_TYPES(V) \ V(http_parser_binding_data, http_parser::BindingData) // In the HTTP parser source code file: @@ -506,8 +511,7 @@ class BindingData : public BaseObject { public: BindingData(Environment* env, Local obj) : BaseObject(env, obj) {} - static constexpr EmbedderObjectType type_int = - EmbedderObjectType::k_http_parser_binding_data; + SET_BINDING_ID(http_parser_binding_data) std::vector parser_buffer; bool parser_buffer_in_use = false; diff --git a/src/base_object.h b/src/base_object.h index 779573362268a6..719f1d38ddf739 100644 --- a/src/base_object.h +++ b/src/base_object.h @@ -25,6 +25,7 @@ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS #include // std::remove_reference +#include "base_object_types.h" #include "memory_tracker.h" #include "v8.h" diff --git a/src/base_object_types.h b/src/base_object_types.h new file mode 100644 index 00000000000000..f4c70a89177975 --- /dev/null +++ b/src/base_object_types.h @@ -0,0 +1,69 @@ +#ifndef SRC_BASE_OBJECT_TYPES_H_ +#define SRC_BASE_OBJECT_TYPES_H_ + +#include + +#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS + +namespace node { +// List of internalBinding() data wrappers. The first argument should match +// what the class passes to SET_BINDING_ID(), the second argument should match +// the C++ class name. +#define SERIALIZABLE_BINDING_TYPES(V) \ + V(fs_binding_data, fs::BindingData) \ + V(v8_binding_data, v8_utils::BindingData) \ + V(blob_binding_data, BlobBindingData) \ + V(process_binding_data, process::BindingData) + +#define UNSERIALIZABLE_BINDING_TYPES(V) \ + V(http2_binding_data, http2::BindingData) \ + V(http_parser_binding_data, http_parser::BindingData) + +// List of (non-binding) BaseObjects that are serializable in the snapshot. +// The first argument should match what the type passes to +// SET_OBJECT_ID(), the second argument should match the C++ class +// name. +#define SERIALIZABLE_NON_BINDING_TYPES(V) \ + V(util_weak_reference, util::WeakReference) + +// Helper list of all binding data wrapper types. +#define BINDING_TYPES(V) \ + SERIALIZABLE_BINDING_TYPES(V) \ + UNSERIALIZABLE_BINDING_TYPES(V) + +// Helper list of all BaseObjects that implement snapshot support. +#define SERIALIZABLE_OBJECT_TYPES(V) \ + SERIALIZABLE_BINDING_TYPES(V) \ + SERIALIZABLE_NON_BINDING_TYPES(V) + +#define V(TypeId, NativeType) k_##TypeId, +enum class BindingDataType : uint8_t { BINDING_TYPES(V) kBindingDataTypeCount }; +// Make sure that we put the bindings first so that we can also use the enums +// for the bindings as index to the binding data store. +enum class EmbedderObjectType : uint8_t { + BINDING_TYPES(V) SERIALIZABLE_NON_BINDING_TYPES(V) + // We do not need to know about all the unserializable non-binding types for + // now so we do not list them. + kEmbedderObjectTypeCount +}; +#undef V + +// For now, BaseObjects only need to call this when they implement snapshot +// support. +#define SET_OBJECT_ID(TypeId) \ + static constexpr EmbedderObjectType type_int = EmbedderObjectType::k_##TypeId; + +// Binding data should call this so that they can be looked up from the binding +// data store. +#define SET_BINDING_ID(TypeId) \ + static constexpr BindingDataType binding_type_int = \ + BindingDataType::k_##TypeId; \ + SET_OBJECT_ID(TypeId) \ + static_assert(static_cast(type_int) == \ + static_cast(binding_type_int)); + +} // namespace node + +#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS + +#endif // SRC_BASE_OBJECT_TYPES_H_ diff --git a/src/env-inl.h b/src/env-inl.h index ab0f1ed9b8c244..a0ecc1c22575ec 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -218,7 +218,7 @@ inline T* Environment::GetBindingData(v8::Local context) { context->GetAlignedPointerFromEmbedderData( ContextEmbedderIndex::kBindingListIndex)); DCHECK_NOT_NULL(map); - constexpr size_t binding_index = static_cast(T::type_int); + constexpr size_t binding_index = static_cast(T::binding_type_int); static_assert(binding_index < std::tuple_size_v); auto ptr = (*map)[binding_index]; if (UNLIKELY(!ptr)) return nullptr; @@ -239,7 +239,7 @@ inline T* Environment::AddBindingData( context->GetAlignedPointerFromEmbedderData( ContextEmbedderIndex::kBindingListIndex)); DCHECK_NOT_NULL(map); - constexpr size_t binding_index = static_cast(T::type_int); + constexpr size_t binding_index = static_cast(T::binding_type_int); static_assert(binding_index < std::tuple_size_v); CHECK(!(*map)[binding_index]); // Should not insert the binding twice. (*map)[binding_index] = item; diff --git a/src/env.h b/src/env.h index c4d4419ed82113..ba1a8a5b731ce6 100644 --- a/src/env.h +++ b/src/env.h @@ -603,7 +603,7 @@ class Environment : public MemoryRetainer { typedef std::array, static_cast( - EmbedderObjectType::kEmbedderObjectTypeCount)> + BindingDataType::kBindingDataTypeCount)> BindingDataStore; // Create an Environment without initializing a main Context. Use diff --git a/src/node_blob.h b/src/node_blob.h index 82a86eebac69f2..29d72c63b575cb 100644 --- a/src/node_blob.h +++ b/src/node_blob.h @@ -147,8 +147,7 @@ class BlobBindingData : public SnapshotableObject { SERIALIZABLE_OBJECT_METHODS() - static constexpr EmbedderObjectType type_int = - EmbedderObjectType::k_blob_binding_data; + SET_BINDING_ID(blob_binding_data) void MemoryInfo(MemoryTracker* tracker) const override; SET_SELF_SIZE(BlobBindingData) diff --git a/src/node_file.h b/src/node_file.h index 07224cb5512261..30f19867a7d9d4 100644 --- a/src/node_file.h +++ b/src/node_file.h @@ -69,8 +69,7 @@ class BindingData : public SnapshotableObject { using InternalFieldInfo = InternalFieldInfoBase; SERIALIZABLE_OBJECT_METHODS() - static constexpr EmbedderObjectType type_int = - EmbedderObjectType::k_fs_binding_data; + SET_BINDING_ID(fs_binding_data) void MemoryInfo(MemoryTracker* tracker) const override; SET_SELF_SIZE(BindingData) diff --git a/src/node_http2_state.h b/src/node_http2_state.h index 1fd5d34d05fae4..9deb58d2f79a3d 100644 --- a/src/node_http2_state.h +++ b/src/node_http2_state.h @@ -127,8 +127,7 @@ class Http2State : public BaseObject { SET_SELF_SIZE(Http2State) SET_MEMORY_INFO_NAME(Http2State) - static constexpr EmbedderObjectType type_int = - EmbedderObjectType::k_http2_binding_data; + SET_BINDING_ID(http2_binding_data) private: struct http2_state_internal { diff --git a/src/node_http_parser.cc b/src/node_http_parser.cc index dcd627c66db48f..ef048089944747 100644 --- a/src/node_http_parser.cc +++ b/src/node_http_parser.cc @@ -96,8 +96,7 @@ class BindingData : public BaseObject { BindingData(Environment* env, Local obj) : BaseObject(env, obj) {} - static constexpr EmbedderObjectType type_int = - EmbedderObjectType::k_http_parser_binding_data; + SET_BINDING_ID(http_parser_binding_data) std::vector parser_buffer; bool parser_buffer_in_use = false; diff --git a/src/node_process.h b/src/node_process.h index 00af553ed80e29..8b2068ec615d85 100644 --- a/src/node_process.h +++ b/src/node_process.h @@ -54,8 +54,7 @@ class BindingData : public SnapshotableObject { using InternalFieldInfo = InternalFieldInfoBase; SERIALIZABLE_OBJECT_METHODS() - static constexpr EmbedderObjectType type_int = - EmbedderObjectType::k_process_binding_data; + SET_BINDING_ID(process_binding_data) BindingData(Environment* env, v8::Local object); diff --git a/src/node_snapshotable.h b/src/node_snapshotable.h index 86bc9d96bdfad8..eecda20b282dae 100644 --- a/src/node_snapshotable.h +++ b/src/node_snapshotable.h @@ -22,24 +22,6 @@ struct PropInfo { SnapshotIndex index; // In the snapshot }; -#define UNSERIALIZABLE_OBJECT_TYPES(V) \ - V(http2_binding_data, http2::BindingData) \ - V(http_parser_binding_data, http_parser::BindingData) - -#define SERIALIZABLE_OBJECT_TYPES(V) \ - V(fs_binding_data, fs::BindingData) \ - V(v8_binding_data, v8_utils::BindingData) \ - V(blob_binding_data, BlobBindingData) \ - V(process_binding_data, process::BindingData) \ - V(util_weak_reference, util::WeakReference) - -enum class EmbedderObjectType : uint8_t { -#define V(PropertyName, NativeType) k_##PropertyName, - SERIALIZABLE_OBJECT_TYPES(V) UNSERIALIZABLE_OBJECT_TYPES(V) -#undef V - kEmbedderObjectTypeCount -}; - typedef size_t SnapshotIndex; // When serializing an embedder object, we'll serialize the native states diff --git a/src/node_util.h b/src/node_util.h index c36e4ea11a114f..0ac0ffc340fc78 100644 --- a/src/node_util.h +++ b/src/node_util.h @@ -14,8 +14,7 @@ class WeakReference : public SnapshotableObject { public: SERIALIZABLE_OBJECT_METHODS() - static constexpr EmbedderObjectType type_int = - EmbedderObjectType::k_util_weak_reference; + SET_OBJECT_ID(util_weak_reference) WeakReference(Environment* env, v8::Local object, diff --git a/src/node_v8.h b/src/node_v8.h index 38e68e0b6a0106..612bddf81bbcbc 100644 --- a/src/node_v8.h +++ b/src/node_v8.h @@ -23,8 +23,7 @@ class BindingData : public SnapshotableObject { using InternalFieldInfo = InternalFieldInfoBase; SERIALIZABLE_OBJECT_METHODS() - static constexpr EmbedderObjectType type_int = - EmbedderObjectType::k_v8_binding_data; + SET_BINDING_ID(v8_binding_data) AliasedFloat64Array heap_statistics_buffer; AliasedFloat64Array heap_space_statistics_buffer;