diff --git a/src/env.h b/src/env.h index 4410ccb3e101..8069fa26ecb7 100644 --- a/src/env.h +++ b/src/env.h @@ -583,6 +583,7 @@ struct SnapshotData { // The result of v8::SnapshotCreator::CreateBlob() during the snapshot // building process. v8::StartupData v8_snapshot_blob_data{nullptr, 0}; + DataOwnership v8_snapshot_blob_data_ownership = DataOwnership::kOwned; IsolateDataSerializeInfo isolate_data_info; // TODO(joyeecheung): there should be a vector of env_info once we snapshot @@ -602,7 +603,11 @@ struct SnapshotData { bool Check() const; static bool FromFile(SnapshotData* out, FILE* in); static bool FromBlob(SnapshotData* out, const std::vector& in); - static bool FromBlob(SnapshotData* out, std::string_view in); + // If the V8 data is not owned, `in` must outlive `out`. + static bool FromBlob(SnapshotData* out, + std::string_view in, + DataOwnership v8_snapshot_blob_data_ownership = + DataOwnership::kOwned); static const SnapshotData* FromEmbedderWrapper( const EmbedderSnapshotData* data); EmbedderSnapshotData::Pointer AsEmbedderWrapper() const; diff --git a/src/node.cc b/src/node.cc index a43eb28b779d..a4ac41d9c7fa 100644 --- a/src/node.cc +++ b/src/node.cc @@ -1522,7 +1522,11 @@ bool LoadSnapshotData(const SnapshotData** snapshot_data_ptr) { std::unique_ptr read_data = std::make_unique(); std::string_view snapshot = sea.main_code_or_snapshot; - if (SnapshotData::FromBlob(read_data.get(), snapshot)) { + // The SEA resource remains mapped for the process lifetime, so V8 can + // consume the startup data directly from the executable image. + if (SnapshotData::FromBlob(read_data.get(), + snapshot, + SnapshotData::DataOwnership::kNotOwned)) { *snapshot_data_ptr = read_data.release(); return true; } else { diff --git a/src/node_snapshotable.cc b/src/node_snapshotable.cc index e861e499534c..b1817eb1604d 100644 --- a/src/node_snapshotable.cc +++ b/src/node_snapshotable.cc @@ -158,6 +158,27 @@ class SnapshotDeserializer : public BlobDeserializer { template requires(!std::is_arithmetic_v && !std::same_as) T Read(); + + v8::StartupData ReadV8StartupData( + SnapshotData::DataOwnership ownership) { + Debug("Read()\n"); + + int raw_size = ReadArithmetic(); + Debug("size=%d\n", raw_size); + + CHECK_GT(raw_size, 0); // There should be no startup data of size 0. + if (ownership == SnapshotData::DataOwnership::kOwned) { + // The data pointer of v8::StartupData would be deleted so it must be + // new'ed. + std::unique_ptr buf = std::unique_ptr(new char[raw_size]); + ReadArithmetic(buf.get(), raw_size); + return v8::StartupData{buf.release(), raw_size}; + } + + const char* data = sink.data() + read_total; + read_total += raw_size; + return v8::StartupData{data, raw_size}; + } }; class SnapshotSerializer : public BlobSerializer { @@ -181,17 +202,7 @@ class SnapshotSerializer : public BlobSerializer { // [ |raw_size| bytes ] contents template <> v8::StartupData SnapshotDeserializer::Read() { - Debug("Read()\n"); - - int raw_size = ReadArithmetic(); - Debug("size=%d\n", raw_size); - - CHECK_GT(raw_size, 0); // There should be no startup data of size 0. - // The data pointer of v8::StartupData would be deleted so it must be new'ed. - std::unique_ptr buf = std::unique_ptr(new char[raw_size]); - ReadArithmetic(buf.get(), raw_size); - - return v8::StartupData{buf.release(), raw_size}; + return ReadV8StartupData(SnapshotData::DataOwnership::kOwned); } template <> @@ -640,7 +651,9 @@ bool SnapshotData::FromBlob(SnapshotData* out, const std::vector& in) { return FromBlob(out, std::string_view(in.data(), in.size())); } -bool SnapshotData::FromBlob(SnapshotData* out, std::string_view in) { +bool SnapshotData::FromBlob(SnapshotData* out, + std::string_view in, + DataOwnership v8_snapshot_blob_data_ownership) { SnapshotDeserializer r(in); r.Debug("SnapshotData::FromBlob()\n"); @@ -656,7 +669,9 @@ bool SnapshotData::FromBlob(SnapshotData* out, std::string_view in) { return false; } - out->v8_snapshot_blob_data = r.Read(); + out->v8_snapshot_blob_data = + r.ReadV8StartupData(v8_snapshot_blob_data_ownership); + out->v8_snapshot_blob_data_ownership = v8_snapshot_blob_data_ownership; r.Debug("Read isolate_data_info\n"); out->isolate_data_info = r.Read(); out->env_info = r.Read(); @@ -701,6 +716,7 @@ bool SnapshotData::Check() const { SnapshotData::~SnapshotData() { if (data_ownership == DataOwnership::kOwned && + v8_snapshot_blob_data_ownership == DataOwnership::kOwned && v8_snapshot_blob_data.data != nullptr) { delete[] v8_snapshot_blob_data.data; } @@ -822,6 +838,9 @@ namespace node { // -- v8_snapshot_blob_data begins -- { v8_snapshot_blob_data, v8_snapshot_blob_size }, // -- v8_snapshot_blob_data ends -- + // -- v8_snapshot_blob_data_ownership begins -- + SnapshotData::DataOwnership::kNotOwned, + // -- v8_snapshot_blob_data_ownership ends -- // -- isolate_data_info begins -- )" << data->isolate_data_info << R"(