Skip to content

Commit c34bac2

Browse files
addaleaxMylesBorins
authored andcommitted
src: allow blobs in addition to FILE*s in embedder snapshot API
This is a shared follow-up to 06bb6b4 and a466fea now that both have been merged. PR-URL: #46491 Refs: #45888 Refs: #46463 Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Darshan Sen <raisinten@gmail.com> Reviewed-By: Tobias Nießen <tniessen@tnie.de>
1 parent a51fe3c commit c34bac2

9 files changed

+84
-29
lines changed

src/api/embed_helpers.cc

+11-2
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,8 @@ EmbedderSnapshotData::Pointer EmbedderSnapshotData::BuiltinSnapshotData() {
291291
SnapshotBuilder::GetEmbeddedSnapshotData(), false)};
292292
}
293293

294-
EmbedderSnapshotData::Pointer EmbedderSnapshotData::FromFile(FILE* in) {
294+
EmbedderSnapshotData::Pointer EmbedderSnapshotData::FromBlob(
295+
const std::vector<char>& in) {
295296
SnapshotData* snapshot_data = new SnapshotData();
296297
CHECK_EQ(snapshot_data->data_ownership, SnapshotData::DataOwnership::kOwned);
297298
EmbedderSnapshotData::Pointer result{
@@ -302,8 +303,16 @@ EmbedderSnapshotData::Pointer EmbedderSnapshotData::FromFile(FILE* in) {
302303
return result;
303304
}
304305

306+
EmbedderSnapshotData::Pointer EmbedderSnapshotData::FromFile(FILE* in) {
307+
return FromBlob(ReadFileSync(in));
308+
}
309+
310+
std::vector<char> EmbedderSnapshotData::ToBlob() const {
311+
return impl_->ToBlob();
312+
}
313+
305314
void EmbedderSnapshotData::ToFile(FILE* out) const {
306-
impl_->ToBlob(out);
315+
impl_->ToFile(out);
307316
}
308317

309318
EmbedderSnapshotData::EmbedderSnapshotData(const SnapshotData* impl,

src/env.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -517,11 +517,13 @@ struct SnapshotData {
517517
// v8::ScriptCompiler::CachedData is not copyable.
518518
std::vector<builtins::CodeCacheInfo> code_cache;
519519

520-
void ToBlob(FILE* out) const;
520+
void ToFile(FILE* out) const;
521+
std::vector<char> ToBlob() const;
521522
// If returns false, the metadata doesn't match the current Node.js binary,
522523
// and the caller should not consume the snapshot data.
523524
bool Check() const;
524-
static bool FromBlob(SnapshotData* out, FILE* in);
525+
static bool FromFile(SnapshotData* out, FILE* in);
526+
static bool FromBlob(SnapshotData* out, const std::vector<char>& in);
525527
static const SnapshotData* FromEmbedderWrapper(
526528
const EmbedderSnapshotData* data);
527529
EmbedderSnapshotData::Pointer AsEmbedderWrapper() const;

src/node.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -1140,7 +1140,7 @@ ExitCode GenerateAndWriteSnapshotData(const SnapshotData** snapshot_data_ptr,
11401140

11411141
FILE* fp = fopen(snapshot_blob_path.c_str(), "wb");
11421142
if (fp != nullptr) {
1143-
(*snapshot_data_ptr)->ToBlob(fp);
1143+
(*snapshot_data_ptr)->ToFile(fp);
11441144
fclose(fp);
11451145
} else {
11461146
fprintf(stderr,
@@ -1168,7 +1168,7 @@ ExitCode LoadSnapshotDataAndRun(const SnapshotData** snapshot_data_ptr,
11681168
return exit_code;
11691169
}
11701170
std::unique_ptr<SnapshotData> read_data = std::make_unique<SnapshotData>();
1171-
bool ok = SnapshotData::FromBlob(read_data.get(), fp);
1171+
bool ok = SnapshotData::FromFile(read_data.get(), fp);
11721172
fclose(fp);
11731173
if (!ok) {
11741174
// If we fail to read the customized snapshot, simply exit with 1.

src/node.h

+2
Original file line numberDiff line numberDiff line change
@@ -518,11 +518,13 @@ class EmbedderSnapshotData {
518518
// The FILE* handle can be closed immediately following this call.
519519
// If the snapshot is invalid, this returns an empty pointer.
520520
static Pointer FromFile(FILE* in);
521+
static Pointer FromBlob(const std::vector<char>& in);
521522

522523
// Write this EmbedderSnapshotData object to an output file.
523524
// Calling this method will not close the FILE* handle.
524525
// The FILE* handle can be closed immediately following this call.
525526
void ToFile(FILE* out) const;
527+
std::vector<char> ToBlob() const;
526528

527529
// Returns whether custom snapshots can be used. Currently, this means
528530
// that V8 was configured without the shared-readonly-heap feature.

src/node_snapshotable.cc

+13-16
Original file line numberDiff line numberDiff line change
@@ -840,7 +840,7 @@ size_t SnapshotSerializer::Write(const SnapshotMetadata& data) {
840840
// [ ... ] env_info
841841
// [ ... ] code_cache
842842

843-
void SnapshotData::ToBlob(FILE* out) const {
843+
std::vector<char> SnapshotData::ToBlob() const {
844844
SnapshotSerializer w;
845845
w.Debug("SnapshotData::ToBlob()\n");
846846

@@ -858,9 +858,14 @@ void SnapshotData::ToBlob(FILE* out) const {
858858
written_total += w.Write<EnvSerializeInfo>(env_info);
859859
w.Debug("Write code_cache\n");
860860
written_total += w.WriteVector<builtins::CodeCacheInfo>(code_cache);
861-
size_t num_written = fwrite(w.sink.data(), w.sink.size(), 1, out);
862-
CHECK_EQ(num_written, 1);
863861
w.Debug("SnapshotData::ToBlob() Wrote %d bytes\n", written_total);
862+
return w.sink;
863+
}
864+
865+
void SnapshotData::ToFile(FILE* out) const {
866+
const std::vector<char> sink = ToBlob();
867+
size_t num_written = fwrite(sink.data(), sink.size(), 1, out);
868+
CHECK_EQ(num_written, 1);
864869
}
865870

866871
const SnapshotData* SnapshotData::FromEmbedderWrapper(
@@ -872,20 +877,12 @@ EmbedderSnapshotData::Pointer SnapshotData::AsEmbedderWrapper() const {
872877
return EmbedderSnapshotData::Pointer{new EmbedderSnapshotData(this, false)};
873878
}
874879

875-
bool SnapshotData::FromBlob(SnapshotData* out, FILE* in) {
876-
CHECK_EQ(ftell(in), 0);
877-
int err = fseek(in, 0, SEEK_END);
878-
CHECK_EQ(err, 0);
879-
size_t size = ftell(in);
880-
CHECK_NE(size, static_cast<size_t>(-1L));
881-
err = fseek(in, 0, SEEK_SET);
882-
CHECK_EQ(err, 0);
883-
884-
std::vector<char> sink(size);
885-
size_t num_read = fread(sink.data(), size, 1, in);
886-
CHECK_EQ(num_read, 1);
880+
bool SnapshotData::FromFile(SnapshotData* out, FILE* in) {
881+
return FromBlob(out, ReadFileSync(in));
882+
}
887883

888-
SnapshotDeserializer r(sink);
884+
bool SnapshotData::FromBlob(SnapshotData* out, const std::vector<char>& in) {
885+
SnapshotDeserializer r(in);
889886
r.Debug("SnapshotData::FromBlob()\n");
890887

891888
DCHECK_EQ(out->data_ownership, SnapshotData::DataOwnership::kOwned);

src/util.cc

+15
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,21 @@ int ReadFileSync(std::string* result, const char* path) {
267267
return 0;
268268
}
269269

270+
std::vector<char> ReadFileSync(FILE* fp) {
271+
CHECK_EQ(ftell(fp), 0);
272+
int err = fseek(fp, 0, SEEK_END);
273+
CHECK_EQ(err, 0);
274+
size_t size = ftell(fp);
275+
CHECK_NE(size, static_cast<size_t>(-1L));
276+
err = fseek(fp, 0, SEEK_SET);
277+
CHECK_EQ(err, 0);
278+
279+
std::vector<char> contents(size);
280+
size_t num_read = fread(contents.data(), size, 1, fp);
281+
CHECK_EQ(num_read, 1);
282+
return contents;
283+
}
284+
270285
void DiagnosticFilename::LocalTime(TIME_TYPE* tm_struct) {
271286
#ifdef _WIN32
272287
GetLocalTime(tm_struct);

src/util.h

+2
Original file line numberDiff line numberDiff line change
@@ -867,6 +867,8 @@ std::unique_ptr<T> static_unique_pointer_cast(std::unique_ptr<U>&& ptr) {
867867
// Returns a non-zero code if it fails to open or read the file,
868868
// aborts if it fails to close the file.
869869
int ReadFileSync(std::string* result, const char* path);
870+
// Reads all contents of a FILE*, aborts if it fails.
871+
std::vector<char> ReadFileSync(FILE* fp);
870872

871873
v8::Local<v8::FunctionTemplate> NewFunctionTemplate(
872874
v8::Isolate* isolate,

test/embedding/embedtest.cc

+30-5
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,30 @@ int RunNodeInstance(MultiIsolatePlatform* platform,
6565
std::find(args.begin(), args.end(), "--embedder-snapshot-create");
6666
auto snapshot_arg_it =
6767
std::find(args.begin(), args.end(), "--embedder-snapshot-blob");
68+
auto snapshot_as_file_it =
69+
std::find(args.begin(), args.end(), "--embedder-snapshot-as-file");
6870
if (snapshot_arg_it < args.end() - 1 &&
6971
snapshot_build_mode_it == args.end()) {
70-
FILE* fp = fopen((snapshot_arg_it + 1)->c_str(), "r");
72+
const char* filename = (snapshot_arg_it + 1)->c_str();
73+
FILE* fp = fopen(filename, "r");
7174
assert(fp != nullptr);
72-
snapshot = node::EmbedderSnapshotData::FromFile(fp);
73-
fclose(fp);
75+
if (snapshot_as_file_it != args.end()) {
76+
snapshot = node::EmbedderSnapshotData::FromFile(fp);
77+
} else {
78+
uv_fs_t req;
79+
int statret = uv_fs_stat(nullptr, &req, filename, nullptr);
80+
assert(statret == 0);
81+
size_t filesize = req.statbuf.st_size;
82+
uv_fs_req_cleanup(&req);
83+
84+
std::vector<char> vec(filesize);
85+
size_t read = fread(vec.data(), filesize, 1, fp);
86+
assert(read == 1);
87+
snapshot = node::EmbedderSnapshotData::FromBlob(vec);
88+
}
89+
assert(snapshot);
90+
int ret = fclose(fp);
91+
assert(ret == 0);
7492
}
7593

7694
std::vector<std::string> errors;
@@ -125,8 +143,15 @@ int RunNodeInstance(MultiIsolatePlatform* platform,
125143

126144
FILE* fp = fopen((snapshot_arg_it + 1)->c_str(), "w");
127145
assert(fp != nullptr);
128-
snapshot->ToFile(fp);
129-
fclose(fp);
146+
if (snapshot_as_file_it != args.end()) {
147+
snapshot->ToFile(fp);
148+
} else {
149+
const std::vector<char> vec = snapshot->ToBlob();
150+
size_t written = fwrite(vec.data(), vec.size(), 1, fp);
151+
assert(written == 1);
152+
}
153+
int ret = fclose(fp);
154+
assert(ret == 0);
130155
}
131156

132157
node::Stop(env);

test/embedding/test-embedding.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,18 @@ function getReadFileCodeForPath(path) {
5555
}
5656

5757
// Basic snapshot support
58-
{
58+
for (const extraSnapshotArgs of [[], ['--embedder-snapshot-as-file']]) {
5959
// readSync + eval since snapshots don't support userland require() (yet)
6060
const snapshotFixture = fixtures.path('snapshot', 'echo-args.js');
6161
const blobPath = path.join(tmpdir.path, 'embedder-snapshot.blob');
6262
const buildSnapshotArgs = [
6363
`eval(${getReadFileCodeForPath(snapshotFixture)})`, 'arg1', 'arg2',
6464
'--embedder-snapshot-blob', blobPath, '--embedder-snapshot-create',
65+
...extraSnapshotArgs,
66+
];
67+
const runEmbeddedArgs = [
68+
'--embedder-snapshot-blob', blobPath, ...extraSnapshotArgs, 'arg3', 'arg4',
6569
];
66-
const runEmbeddedArgs = ['--embedder-snapshot-blob', blobPath, 'arg3', 'arg4'];
6770

6871
fs.rmSync(blobPath, { force: true });
6972
assert.strictEqual(child_process.spawnSync(binary, [

0 commit comments

Comments
 (0)