Skip to content

Commit d1439f7

Browse files
committed
src: avoid copying SEA snapshot data
Signed-off-by: Colin McDonnell <3084745+colinhacks@users.noreply.github.com>
1 parent 5f77f95 commit d1439f7

3 files changed

Lines changed: 46 additions & 19 deletions

File tree

src/env.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,7 @@ struct SnapshotData {
640640
// The result of v8::SnapshotCreator::CreateBlob() during the snapshot
641641
// building process.
642642
v8::StartupData v8_snapshot_blob_data{nullptr, 0};
643+
DataOwnership v8_snapshot_blob_data_ownership = DataOwnership::kOwned;
643644

644645
IsolateDataSerializeInfo isolate_data_info;
645646
// TODO(joyeecheung): there should be a vector of env_info once we snapshot
@@ -659,7 +660,11 @@ struct SnapshotData {
659660
bool Check() const;
660661
static bool FromFile(SnapshotData* out, FILE* in);
661662
static bool FromBlob(SnapshotData* out, const std::vector<char>& in);
662-
static bool FromBlob(SnapshotData* out, std::string_view in);
663+
// If the V8 data is not owned, `in` must outlive `out`.
664+
static bool FromBlob(
665+
SnapshotData* out,
666+
std::string_view in,
667+
DataOwnership v8_snapshot_blob_data_ownership = DataOwnership::kOwned);
663668
static const SnapshotData* FromEmbedderWrapper(
664669
const EmbedderSnapshotData* data);
665670

src/node.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1567,7 +1567,11 @@ bool LoadSnapshotData(const SnapshotData** snapshot_data_ptr) {
15671567
std::unique_ptr<SnapshotData> read_data =
15681568
std::make_unique<SnapshotData>();
15691569
std::string_view snapshot = sea.main_code_or_snapshot;
1570-
if (SnapshotData::FromBlob(read_data.get(), snapshot)) {
1570+
// The SEA resource remains mapped for the process lifetime, so V8 can
1571+
// consume the startup data directly from the executable image.
1572+
if (SnapshotData::FromBlob(read_data.get(),
1573+
snapshot,
1574+
SnapshotData::DataOwnership::kNotOwned)) {
15711575
*snapshot_data_ptr = read_data.release();
15721576
return true;
15731577
} else {

src/node_snapshotable.cc

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,30 @@ class SnapshotDeserializer : public BlobDeserializer<SnapshotDeserializer> {
159159
template <typename T>
160160
requires(!std::is_arithmetic_v<T> && !std::same_as<T, std::string>)
161161
T Read();
162+
163+
v8::StartupData ReadV8StartupData(SnapshotData::DataOwnership ownership) {
164+
Debug("Read<v8::StartupData>()\n");
165+
166+
int raw_size = ReadArithmetic<int>();
167+
Debug("size=%d\n", raw_size);
168+
169+
if (raw_size <= 0 ||
170+
static_cast<size_t>(raw_size) > sink.size() - read_total) {
171+
ok = false;
172+
return v8::StartupData{nullptr, 0};
173+
}
174+
if (ownership == SnapshotData::DataOwnership::kOwned) {
175+
// The data pointer of v8::StartupData would be deleted so it must be
176+
// new'ed.
177+
char* buf = new char[raw_size];
178+
ReadArithmetic<char>(buf, raw_size);
179+
return v8::StartupData{buf, raw_size};
180+
}
181+
182+
const char* data = sink.data() + read_total;
183+
read_total += raw_size;
184+
return v8::StartupData{data, raw_size};
185+
}
162186
};
163187

164188
class SnapshotSerializer : public BlobSerializer<SnapshotSerializer> {
@@ -182,21 +206,7 @@ class SnapshotSerializer : public BlobSerializer<SnapshotSerializer> {
182206
// [ |raw_size| bytes ] contents
183207
template <>
184208
v8::StartupData SnapshotDeserializer::Read() {
185-
Debug("Read<v8::StartupData>()\n");
186-
187-
int raw_size = ReadArithmetic<int>();
188-
Debug("size=%d\n", raw_size);
189-
190-
if (raw_size <= 0 ||
191-
static_cast<size_t>(raw_size) > sink.size() - read_total) {
192-
ok = false;
193-
return v8::StartupData{nullptr, 0};
194-
}
195-
// The data pointer of v8::StartupData would be deleted so it must be new'ed.
196-
char* buf = new char[raw_size];
197-
ReadArithmetic<char>(buf, raw_size);
198-
199-
return v8::StartupData{buf, raw_size};
209+
return ReadV8StartupData(SnapshotData::DataOwnership::kOwned);
200210
}
201211

202212
template <>
@@ -641,7 +651,9 @@ bool SnapshotData::FromBlob(SnapshotData* out, const std::vector<char>& in) {
641651
return FromBlob(out, std::string_view(in.data(), in.size()));
642652
}
643653

644-
bool SnapshotData::FromBlob(SnapshotData* out, std::string_view in) {
654+
bool SnapshotData::FromBlob(SnapshotData* out,
655+
std::string_view in,
656+
DataOwnership v8_snapshot_blob_data_ownership) {
645657
SnapshotDeserializer r(in);
646658
r.Debug("SnapshotData::FromBlob()\n");
647659

@@ -661,7 +673,9 @@ bool SnapshotData::FromBlob(SnapshotData* out, std::string_view in) {
661673
return false;
662674
}
663675

664-
out->v8_snapshot_blob_data = r.Read<v8::StartupData>();
676+
out->v8_snapshot_blob_data =
677+
r.ReadV8StartupData(v8_snapshot_blob_data_ownership);
678+
out->v8_snapshot_blob_data_ownership = v8_snapshot_blob_data_ownership;
665679
r.Debug("Read isolate_data_info\n");
666680
out->isolate_data_info = r.Read<IsolateDataSerializeInfo>();
667681
out->env_info = r.Read<EnvSerializeInfo>();
@@ -710,6 +724,7 @@ bool SnapshotData::Check() const {
710724

711725
SnapshotData::~SnapshotData() {
712726
if (data_ownership == DataOwnership::kOwned &&
727+
v8_snapshot_blob_data_ownership == DataOwnership::kOwned &&
713728
v8_snapshot_blob_data.data != nullptr &&
714729
!IsFirstSnapshotBlob(v8_snapshot_blob_data.data)) {
715730
delete[] v8_snapshot_blob_data.data;
@@ -832,6 +847,9 @@ namespace node {
832847
// -- v8_snapshot_blob_data begins --
833848
{ v8_snapshot_blob_data, v8_snapshot_blob_size },
834849
// -- v8_snapshot_blob_data ends --
850+
// -- v8_snapshot_blob_data_ownership begins --
851+
SnapshotData::DataOwnership::kNotOwned,
852+
// -- v8_snapshot_blob_data_ownership ends --
835853
// -- isolate_data_info begins --
836854
)" << data->isolate_data_info
837855
<< R"(

0 commit comments

Comments
 (0)