Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit e60b6de

Browse filesBrowse files
joyeecheungRafaelGSS
authored andcommitted
bootstrap: unify snapshot builder and embedder entry points
- Run the embedder entry point directly through runEmbedderEntryPoint(), instead of going through another JS -> C++ trip through the function returned by getEmbedderEntryFunction() - For --build-snapshot, read the snapshot script code directly in C++ and pass it to SnapshotBuilder::Generate(), this makes the entry point more explicit instead of hiding it in JS land, and also makes it possible to invoke SnapshotBuilder::Generate() internally to create a custom snapshot. - Previously we used process.execPath for the embedder to create __filename and __dirname in the snapshot builder script while using process.argv[1] for --build-snapshot (where it's always set) which results in inconsistencies. We now require the embedder to also set args[1] when creating the Environment if they intend to run snapshot scripts with a context that contains __filename and __dirname, which would be derived from args[1]. If they prefer not to include build-time paths in the snapshot, we now provide node::GetAnonymousMainPath() as an alternative. PR-URL: #48242 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 77cb1ee commit e60b6de
Copy full SHA for e60b6de

File tree

Expand file treeCollapse file tree

9 files changed

+198
-138
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

9 files changed

+198
-138
lines changed
Open diff view settings
Collapse file

‎lib/internal/main/embedding.js‎

Copy file name to clipboardExpand all lines: lib/internal/main/embedding.js
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const {
66
const { isExperimentalSeaWarningNeeded } = internalBinding('sea');
77
const { emitExperimentalWarning } = require('internal/util');
88
const { embedderRequire, embedderRunCjs } = require('internal/util/embedding');
9-
const { getEmbedderEntryFunction } = internalBinding('mksnapshot');
9+
const { runEmbedderEntryPoint } = internalBinding('mksnapshot');
1010

1111
prepareMainThreadExecution(false, true);
1212
markBootstrapComplete();
@@ -15,4 +15,4 @@ if (isExperimentalSeaWarningNeeded()) {
1515
emitExperimentalWarning('Single executable application');
1616
}
1717

18-
return getEmbedderEntryFunction()(embedderRequire, embedderRunCjs);
18+
return runEmbedderEntryPoint(process, embedderRequire, embedderRunCjs);
Collapse file

‎lib/internal/main/mksnapshot.js‎

Copy file name to clipboardExpand all lines: lib/internal/main/mksnapshot.js
+41-49Lines changed: 41 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,30 @@ const {
99
SafeSet,
1010
} = primordials;
1111

12-
const binding = internalBinding('mksnapshot');
1312
const { BuiltinModule: { normalizeRequirableId } } = require('internal/bootstrap/realm');
1413
const {
15-
getEmbedderEntryFunction,
14+
runEmbedderEntryPoint,
1615
compileSerializeMain,
17-
} = binding;
16+
anonymousMainPath,
17+
} = internalBinding('mksnapshot');
1818

1919
const {
2020
getOptionValue,
2121
} = require('internal/options');
2222

2323
const {
24-
readFileSync,
25-
} = require('fs');
24+
initializeCallbacks,
25+
namespace: {
26+
addSerializeCallback,
27+
addDeserializeCallback,
28+
},
29+
} = require('internal/v8/startup_snapshot');
30+
31+
const {
32+
prepareMainThreadExecution,
33+
} = require('internal/process/pre_execution');
34+
35+
const path = require('path');
2636

2737
const supportedModules = new SafeSet(new SafeArrayIterator([
2838
// '_http_agent',
@@ -117,42 +127,7 @@ function requireForUserSnapshot(id) {
117127
}
118128

119129
function main() {
120-
const {
121-
prepareMainThreadExecution,
122-
} = require('internal/process/pre_execution');
123-
const path = require('path');
124-
125-
let serializeMainFunction = getEmbedderEntryFunction();
126-
const serializeMainArgs = [requireForUserSnapshot];
127-
128-
if (serializeMainFunction) { // embedded case
129-
prepareMainThreadExecution(false, false);
130-
// TODO(addaleax): Make this `embedderRunCjs` once require('module')
131-
// is supported in snapshots.
132-
const filename = process.execPath;
133-
const dirname = path.dirname(filename);
134-
function minimalRunCjs(source) {
135-
const fn = compileSerializeMain(filename, source);
136-
return fn(requireForUserSnapshot, filename, dirname);
137-
}
138-
serializeMainArgs.push(minimalRunCjs);
139-
} else {
140-
prepareMainThreadExecution(true, false);
141-
const file = process.argv[1];
142-
const filename = path.resolve(file);
143-
const dirname = path.dirname(filename);
144-
const source = readFileSync(file, 'utf-8');
145-
serializeMainFunction = compileSerializeMain(filename, source);
146-
serializeMainArgs.push(filename, dirname);
147-
}
148-
149-
const {
150-
initializeCallbacks,
151-
namespace: {
152-
addSerializeCallback,
153-
addDeserializeCallback,
154-
},
155-
} = require('internal/v8/startup_snapshot');
130+
prepareMainThreadExecution(true, false);
156131
initializeCallbacks();
157132

158133
let stackTraceLimitDesc;
@@ -161,14 +136,6 @@ function main() {
161136
ObjectDefineProperty(Error, 'stackTraceLimit', stackTraceLimitDesc);
162137
}
163138
});
164-
165-
if (getOptionValue('--inspect-brk')) {
166-
internalBinding('inspector').callAndPauseOnStart(
167-
serializeMainFunction, undefined, ...serializeMainArgs);
168-
} else {
169-
serializeMainFunction(...serializeMainArgs);
170-
}
171-
172139
addSerializeCallback(() => {
173140
stackTraceLimitDesc = ObjectGetOwnPropertyDescriptor(Error, 'stackTraceLimit');
174141

@@ -181,6 +148,31 @@ function main() {
181148
delete Error.stackTraceLimit;
182149
}
183150
});
151+
152+
// TODO(addaleax): Make this `embedderRunCjs` once require('module')
153+
// is supported in snapshots.
154+
function minimalRunCjs(source) {
155+
let filename;
156+
let dirname;
157+
if (process.argv[1] === anonymousMainPath) {
158+
filename = dirname = process.argv[1];
159+
} else {
160+
filename = path.resolve(process.argv[1]);
161+
dirname = path.dirname(filename);
162+
}
163+
164+
const fn = compileSerializeMain(filename, source);
165+
return fn(requireForUserSnapshot, filename, dirname);
166+
}
167+
168+
const serializeMainArgs = [process, requireForUserSnapshot, minimalRunCjs];
169+
170+
if (getOptionValue('--inspect-brk')) {
171+
internalBinding('inspector').callAndPauseOnStart(
172+
runEmbedderEntryPoint, undefined, ...serializeMainArgs);
173+
} else {
174+
runEmbedderEntryPoint(...serializeMainArgs);
175+
}
184176
}
185177

186178
main();
Collapse file

‎src/node.cc‎

Copy file name to clipboardExpand all lines: src/node.cc
+19-8Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,8 @@ MaybeLocal<Value> StartExecution(Environment* env, StartExecutionCallback cb) {
290290
return scope.EscapeMaybe(StartExecution(env, entry));
291291
}
292292

293+
CHECK(!env->isolate_data()->is_building_snapshot());
294+
293295
// TODO(joyeecheung): move these conditions into JS land and let the
294296
// deserialize main function take precedence. For workers, we need to
295297
// move the pre-execution part into a different file that can be
@@ -311,15 +313,10 @@ MaybeLocal<Value> StartExecution(Environment* env, StartExecutionCallback cb) {
311313
return StartExecution(env, "internal/main/inspect");
312314
}
313315

314-
if (env->isolate_data()->is_building_snapshot()) {
315-
return StartExecution(env, "internal/main/mksnapshot");
316-
}
317-
318316
if (per_process::cli_options->print_help) {
319317
return StartExecution(env, "internal/main/print_help");
320318
}
321319

322-
323320
if (env->options()->prof_process) {
324321
return StartExecution(env, "internal/main/prof_process");
325322
}
@@ -1119,7 +1116,8 @@ ExitCode GenerateAndWriteSnapshotData(const SnapshotData** snapshot_data_ptr,
11191116

11201117
// node:embedded_snapshot_main indicates that we are using the
11211118
// embedded snapshot and we are not supposed to clean it up.
1122-
if (result->args()[1] == "node:embedded_snapshot_main") {
1119+
const std::string& main_script = result->args()[1];
1120+
if (main_script == "node:embedded_snapshot_main") {
11231121
*snapshot_data_ptr = SnapshotBuilder::GetEmbeddedSnapshotData();
11241122
if (*snapshot_data_ptr == nullptr) {
11251123
// The Node.js binary is built without embedded snapshot
@@ -1134,8 +1132,21 @@ ExitCode GenerateAndWriteSnapshotData(const SnapshotData** snapshot_data_ptr,
11341132
// Otherwise, load and run the specified main script.
11351133
std::unique_ptr<SnapshotData> generated_data =
11361134
std::make_unique<SnapshotData>();
1137-
exit_code = node::SnapshotBuilder::Generate(
1138-
generated_data.get(), result->args(), result->exec_args());
1135+
std::string main_script_content;
1136+
int r = ReadFileSync(&main_script_content, main_script.c_str());
1137+
if (r != 0) {
1138+
FPrintF(stderr,
1139+
"Cannot read main script %s for building snapshot. %s: %s",
1140+
main_script,
1141+
uv_err_name(r),
1142+
uv_strerror(r));
1143+
return ExitCode::kGenericUserError;
1144+
}
1145+
1146+
exit_code = node::SnapshotBuilder::Generate(generated_data.get(),
1147+
result->args(),
1148+
result->exec_args(),
1149+
main_script_content);
11391150
if (exit_code == ExitCode::kNoFailure) {
11401151
*snapshot_data_ptr = generated_data.release();
11411152
} else {
Collapse file

‎src/node.h‎

Copy file name to clipboardExpand all lines: src/node.h
+10Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -816,6 +816,8 @@ NODE_EXTERN struct uv_loop_s* GetCurrentEventLoop(v8::Isolate* isolate);
816816
// This function only works if `env` has an associated `MultiIsolatePlatform`.
817817
NODE_EXTERN v8::Maybe<int> SpinEventLoop(Environment* env);
818818

819+
NODE_EXTERN std::string GetAnonymousMainPath();
820+
819821
class NODE_EXTERN CommonEnvironmentSetup {
820822
public:
821823
~CommonEnvironmentSetup();
@@ -848,6 +850,13 @@ class NODE_EXTERN CommonEnvironmentSetup {
848850
// no support for native/host objects other than Node.js builtins
849851
// in the snapshot.
850852
//
853+
// If the embedder wants to use LoadEnvironment() later to run a snapshot
854+
// builder script they should make sure args[1] contains the path of the
855+
// snapshot script, which will be used to create __filename and __dirname
856+
// in the context where the builder script is run. If they do not want to
857+
// include the build-time paths into the snapshot, use the string returned
858+
// by GetAnonymousMainPath() as args[1] to anonymize the script.
859+
//
851860
// Snapshots are an *experimental* feature. In particular, the embedder API
852861
// exposed through this class is subject to change or removal between Node.js
853862
// versions, including possible API and ABI breakage.
@@ -909,6 +918,7 @@ std::unique_ptr<CommonEnvironmentSetup> CommonEnvironmentSetup::Create(
909918
if (!errors->empty()) ret.reset();
910919
return ret;
911920
}
921+
912922
// Implementation for ::CreateFromSnapshot -- the ::Create() method
913923
// could call this with a nullptr snapshot_data in a major version.
914924
template <typename... EnvironmentArgs>
Collapse file

‎src/node_snapshot_builder.h‎

Copy file name to clipboardExpand all lines: src/node_snapshot_builder.h
+8-4Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
66

77
#include <cstdint>
8+
#include <optional>
9+
#include <string_view>
810
#include "node_exit_code.h"
911
#include "node_mutex.h"
1012
#include "v8.h"
@@ -17,13 +19,15 @@ struct SnapshotData;
1719
class NODE_EXTERN_PRIVATE SnapshotBuilder {
1820
public:
1921
static ExitCode Generate(std::ostream& out,
20-
const std::vector<std::string> args,
21-
const std::vector<std::string> exec_args);
22+
const std::vector<std::string>& args,
23+
const std::vector<std::string>& exec_args,
24+
std::optional<std::string_view> main_script);
2225

2326
// Generate the snapshot into out.
2427
static ExitCode Generate(SnapshotData* out,
25-
const std::vector<std::string> args,
26-
const std::vector<std::string> exec_args);
28+
const std::vector<std::string>& args,
29+
const std::vector<std::string>& exec_args,
30+
std::optional<std::string_view> main_script);
2731

2832
// If nullptr is returned, the binary is not built with embedded
2933
// snapshot.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.