#include "node_snapshotable.h" #include "base_object-inl.h" #include "debug_utils-inl.h" #include "node_file.h" #include "node_v8.h" namespace node { using v8::Local; using v8::Object; using v8::SnapshotCreator; using v8::StartupData; SnapshotableObject::SnapshotableObject(Environment* env, Local wrap, EmbedderObjectType type) : BaseObject(env, wrap), type_(type) { set_is_snapshotable(true); } const char* SnapshotableObject::GetTypeNameChars() const { switch (type_) { #define V(PropertyName, NativeTypeName) \ case EmbedderObjectType::k_##PropertyName: { \ return NativeTypeName::type_name.c_str(); \ } SERIALIZABLE_OBJECT_TYPES(V) #undef V default: { UNREACHABLE(); } } } bool IsSnapshotableType(FastStringKey key) { #define V(PropertyName, NativeTypeName) \ if (key == NativeTypeName::type_name) { \ return true; \ } SERIALIZABLE_OBJECT_TYPES(V) #undef V return false; } void DeserializeNodeInternalFields(Local holder, int index, StartupData payload, void* env) { per_process::Debug(DebugCategory::MKSNAPSHOT, "Deserialize internal field %d of %p, size=%d\n", static_cast(index), (*holder), static_cast(payload.raw_size)); if (payload.raw_size == 0) { holder->SetAlignedPointerInInternalField(index, nullptr); return; } Environment* env_ptr = static_cast(env); const InternalFieldInfo* info = reinterpret_cast(payload.data); switch (info->type) { #define V(PropertyName, NativeTypeName) \ case EmbedderObjectType::k_##PropertyName: { \ per_process::Debug(DebugCategory::MKSNAPSHOT, \ "Object %p is %s\n", \ (*holder), \ NativeTypeName::type_name.c_str()); \ env_ptr->EnqueueDeserializeRequest( \ NativeTypeName::Deserialize, holder, index, info->Copy()); \ break; \ } SERIALIZABLE_OBJECT_TYPES(V) #undef V default: { UNREACHABLE(); } } } StartupData SerializeNodeContextInternalFields(Local holder, int index, void* env) { per_process::Debug(DebugCategory::MKSNAPSHOT, "Serialize internal field, index=%d, holder=%p\n", static_cast(index), *holder); void* ptr = holder->GetAlignedPointerFromInternalField(BaseObject::kSlot); if (ptr == nullptr) { return StartupData{nullptr, 0}; } DCHECK(static_cast(ptr)->is_snapshotable()); SnapshotableObject* obj = static_cast(ptr); per_process::Debug(DebugCategory::MKSNAPSHOT, "Object %p is %s, ", *holder, obj->GetTypeNameChars()); InternalFieldInfo* info = obj->Serialize(index); per_process::Debug(DebugCategory::MKSNAPSHOT, "payload size=%d\n", static_cast(info->length)); return StartupData{reinterpret_cast(info), static_cast(info->length)}; } void SerializeBindingData(Environment* env, SnapshotCreator* creator, EnvSerializeInfo* info) { size_t i = 0; env->ForEachBindingData([&](FastStringKey key, BaseObjectPtr binding) { per_process::Debug(DebugCategory::MKSNAPSHOT, "Serialize binding %i, %p, type=%s\n", static_cast(i), *(binding->object()), key.c_str()); if (IsSnapshotableType(key)) { size_t index = creator->AddData(env->context(), binding->object()); per_process::Debug(DebugCategory::MKSNAPSHOT, "Serialized with index=%d\n", static_cast(index)); info->bindings.push_back({key.c_str(), i, index}); SnapshotableObject* ptr = static_cast(binding.get()); ptr->PrepareForSerialization(env->context(), creator); } else { UNREACHABLE(); } i++; }); } } // namespace node