GeezerVison is showing github.com — bootstrap: unify snapshot builder and embedder entry points · nodejs/node@e60b6de
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: lib/internal/main/embedding.js +2-2Lines changed: 2 additions & 2 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 6 | 6 | const { isExperimentalSeaWarningNeeded } = internalBinding('sea'); | 7 | 7 | const { emitExperimentalWarning } = require('internal/util'); | 8 | 8 | const { embedderRequire, embedderRunCjs } = require('internal/util/embedding'); | 9 | | -const { getEmbedderEntryFunction } = internalBinding('mksnapshot'); | | 9 | +const { runEmbedderEntryPoint } = internalBinding('mksnapshot'); | 10 | 10 |
| 11 | 11 | prepareMainThreadExecution(false, true); | 12 | 12 | markBootstrapComplete(); | @@ -15,4 +15,4 @@ if (isExperimentalSeaWarningNeeded()) { | 15 | 15 | emitExperimentalWarning('Single executable application'); | 16 | 16 | } | 17 | 17 |
| 18 | | -return getEmbedderEntryFunction()(embedderRequire, embedderRunCjs); | | 18 | +return runEmbedderEntryPoint(process, embedderRequire, embedderRunCjs); |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/main/mksnapshot.js +41-49Lines changed: 41 additions & 49 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -9,20 +9,30 @@ const { | 9 | 9 | SafeSet, | 10 | 10 | } = primordials; | 11 | 11 |
| 12 | | -const binding = internalBinding('mksnapshot'); | 13 | 12 | const { BuiltinModule: { normalizeRequirableId } } = require('internal/bootstrap/realm'); | 14 | 13 | const { | 15 | | - getEmbedderEntryFunction, | | 14 | + runEmbedderEntryPoint, | 16 | 15 | compileSerializeMain, | 17 | | -} = binding; | | 16 | + anonymousMainPath, | | 17 | +} = internalBinding('mksnapshot'); | 18 | 18 |
| 19 | 19 | const { | 20 | 20 | getOptionValue, | 21 | 21 | } = require('internal/options'); | 22 | 22 |
| 23 | 23 | 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'); | 26 | 36 |
| 27 | 37 | const supportedModules = new SafeSet(new SafeArrayIterator([ | 28 | 38 | // '_http_agent', | @@ -117,42 +127,7 @@ function requireForUserSnapshot(id) { | 117 | 127 | } | 118 | 128 |
| 119 | 129 | 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); | 156 | 131 | initializeCallbacks(); | 157 | 132 |
| 158 | 133 | let stackTraceLimitDesc; | @@ -161,14 +136,6 @@ function main() { | 161 | 136 | ObjectDefineProperty(Error, 'stackTraceLimit', stackTraceLimitDesc); | 162 | 137 | } | 163 | 138 | }); | 164 | | - | 165 | | - if (getOptionValue('--inspect-brk')) { | 166 | | - internalBinding('inspector').callAndPauseOnStart( | 167 | | - serializeMainFunction, undefined, ...serializeMainArgs); | 168 | | - } else { | 169 | | - serializeMainFunction(...serializeMainArgs); | 170 | | - } | 171 | | - | 172 | 139 | addSerializeCallback(() => { | 173 | 140 | stackTraceLimitDesc = ObjectGetOwnPropertyDescriptor(Error, 'stackTraceLimit'); | 174 | 141 |
| @@ -181,6 +148,31 @@ function main() { | 181 | 148 | delete Error.stackTraceLimit; | 182 | 149 | } | 183 | 150 | }); | | 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 | + } | 184 | 176 | } | 185 | 177 |
| 186 | 178 | main(); |
Collapse file Copy file name to clipboardExpand all lines: src/node.cc +19-8Lines changed: 19 additions & 8 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -290,6 +290,8 @@ MaybeLocal<Value> StartExecution(Environment* env, StartExecutionCallback cb) { | 290 | 290 | return scope.EscapeMaybe(StartExecution(env, entry)); | 291 | 291 | } | 292 | 292 |
| | 293 | + CHECK(!env->isolate_data()->is_building_snapshot()); | | 294 | + | 293 | 295 | // TODO(joyeecheung): move these conditions into JS land and let the | 294 | 296 | // deserialize main function take precedence. For workers, we need to | 295 | 297 | // move the pre-execution part into a different file that can be | @@ -311,15 +313,10 @@ MaybeLocal<Value> StartExecution(Environment* env, StartExecutionCallback cb) { | 311 | 313 | return StartExecution(env, "internal/main/inspect"); | 312 | 314 | } | 313 | 315 |
| 314 | | - if (env->isolate_data()->is_building_snapshot()) { | 315 | | - return StartExecution(env, "internal/main/mksnapshot"); | 316 | | - } | 317 | | - | 318 | 316 | if (per_process::cli_options->print_help) { | 319 | 317 | return StartExecution(env, "internal/main/print_help"); | 320 | 318 | } | 321 | 319 |
| 322 | | - | 323 | 320 | if (env->options()->prof_process) { | 324 | 321 | return StartExecution(env, "internal/main/prof_process"); | 325 | 322 | } | @@ -1119,7 +1116,8 @@ ExitCode GenerateAndWriteSnapshotData(const SnapshotData** snapshot_data_ptr, | 1119 | 1116 |
| 1120 | 1117 | // node:embedded_snapshot_main indicates that we are using the | 1121 | 1118 | // 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") { | 1123 | 1121 | *snapshot_data_ptr = SnapshotBuilder::GetEmbeddedSnapshotData(); | 1124 | 1122 | if (*snapshot_data_ptr == nullptr) { | 1125 | 1123 | // The Node.js binary is built without embedded snapshot | @@ -1134,8 +1132,21 @@ ExitCode GenerateAndWriteSnapshotData(const SnapshotData** snapshot_data_ptr, | 1134 | 1132 | // Otherwise, load and run the specified main script. | 1135 | 1133 | std::unique_ptr<SnapshotData> generated_data = | 1136 | 1134 | 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); | 1139 | 1150 | if (exit_code == ExitCode::kNoFailure) { | 1140 | 1151 | *snapshot_data_ptr = generated_data.release(); | 1141 | 1152 | } else { | |
Collapse file Copy file name to clipboardExpand all lines: src/node.h +10Lines changed: 10 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -816,6 +816,8 @@ NODE_EXTERN struct uv_loop_s* GetCurrentEventLoop(v8::Isolate* isolate); | 816 | 816 | // This function only works if `env` has an associated `MultiIsolatePlatform`. | 817 | 817 | NODE_EXTERN v8::Maybe<int> SpinEventLoop(Environment* env); | 818 | 818 |
| | 819 | +NODE_EXTERN std::string GetAnonymousMainPath(); | | 820 | + | 819 | 821 | class NODE_EXTERN CommonEnvironmentSetup { | 820 | 822 | public: | 821 | 823 | ~CommonEnvironmentSetup(); | @@ -848,6 +850,13 @@ class NODE_EXTERN CommonEnvironmentSetup { | 848 | 850 | // no support for native/host objects other than Node.js builtins | 849 | 851 | // in the snapshot. | 850 | 852 | // | | 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 | + // | 851 | 860 | // Snapshots are an *experimental* feature. In particular, the embedder API | 852 | 861 | // exposed through this class is subject to change or removal between Node.js | 853 | 862 | // versions, including possible API and ABI breakage. | @@ -909,6 +918,7 @@ std::unique_ptr<CommonEnvironmentSetup> CommonEnvironmentSetup::Create( | 909 | 918 | if (!errors->empty()) ret.reset(); | 910 | 919 | return ret; | 911 | 920 | } | | 921 | + | 912 | 922 | // Implementation for ::CreateFromSnapshot -- the ::Create() method | 913 | 923 | // could call this with a nullptr snapshot_data in a major version. | 914 | 924 | template <typename... EnvironmentArgs> | |
Collapse file Copy file name to clipboardExpand all lines: src/node_snapshot_builder.h +8-4Lines changed: 8 additions & 4 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 5 | 5 | #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS | 6 | 6 |
| 7 | 7 | #include <cstdint> | | 8 | +#include <optional> | | 9 | +#include <string_view> | 8 | 10 | #include "node_exit_code.h" | 9 | 11 | #include "node_mutex.h" | 10 | 12 | #include "v8.h" | @@ -17,13 +19,15 @@ struct SnapshotData; | 17 | 19 | class NODE_EXTERN_PRIVATE SnapshotBuilder { | 18 | 20 | public: | 19 | 21 | 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); | 22 | 25 |
| 23 | 26 | // Generate the snapshot into out. | 24 | 27 | 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); | 27 | 31 |
| 28 | 32 | // If nullptr is returned, the binary is not built with embedded | 29 | 33 | // snapshot. | |
|