From 93a7aee6bd0d9fce587e5d81e7bd7cd923d98b58 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Fri, 24 Feb 2023 19:30:24 +0100 Subject: [PATCH 1/5] src: share common code paths for SEA and embedder script Since SEA is very similar in principle to embedding functionality, it makes sense to share code paths where possible. This commit does so and addresses a `TODO` while doing so. It also adds a utility to directly run CJS code to the embedder startup callback, which comes in handy for this purpose. Finally, this commit is breaking because it aligns the behavior of `require()`ing internal modules; previously, embedders could use the `require` function that they received to do so. (If this is not considered breaking because accessing internals is not covered by the API, then this would need ABI compatibility patches for becoming fully non-breaking.) --- lib/internal/main/embedding.js | 18 ++++++ lib/internal/main/environment.js | 13 ----- lib/internal/main/mksnapshot.js | 11 +++- .../main/single_executable_application.js | 55 ------------------- lib/internal/util/embedding.js | 47 ++++++++++++++++ src/api/environment.cc | 16 +++--- src/node.cc | 42 +++++--------- src/node.h | 4 +- src/node_main_instance.cc | 11 +++- src/node_sea.cc | 52 ++++-------------- src/node_sea.h | 2 + src/node_snapshotable.cc | 13 ++++- test/embedding/test-embedding.js | 5 ++ 13 files changed, 136 insertions(+), 153 deletions(-) create mode 100644 lib/internal/main/embedding.js delete mode 100644 lib/internal/main/environment.js delete mode 100644 lib/internal/main/single_executable_application.js create mode 100644 lib/internal/util/embedding.js diff --git a/lib/internal/main/embedding.js b/lib/internal/main/embedding.js new file mode 100644 index 00000000000000..a43fb09b3ed1f6 --- /dev/null +++ b/lib/internal/main/embedding.js @@ -0,0 +1,18 @@ +'use strict'; +const { + prepareMainThreadExecution, + markBootstrapComplete, +} = require('internal/process/pre_execution'); +const { isSea } = internalBinding('sea'); +const { emitExperimentalWarning } = require('internal/util'); +const { embedderRequire, embedderRunCjs } = require('internal/util/embedding'); +const { getEmbedderEntryFunction } = internalBinding('mksnapshot'); + +prepareMainThreadExecution(false, true); +markBootstrapComplete(); + +if (isSea) { + emitExperimentalWarning('Single executable application'); +} + +return getEmbedderEntryFunction()(embedderRequire, embedderRunCjs); diff --git a/lib/internal/main/environment.js b/lib/internal/main/environment.js deleted file mode 100644 index 0be982bfb6d25d..00000000000000 --- a/lib/internal/main/environment.js +++ /dev/null @@ -1,13 +0,0 @@ -'use strict'; - -// This runs necessary preparations to prepare a complete Node.js context -// that depends on run time states. -// It is currently only intended for preparing contexts for embedders. - -const { - prepareMainThreadExecution, - markBootstrapComplete -} = require('internal/process/pre_execution'); - -prepareMainThreadExecution(); -markBootstrapComplete(); diff --git a/lib/internal/main/mksnapshot.js b/lib/internal/main/mksnapshot.js index 928b3fd13f91d4..08d483dcff4e76 100644 --- a/lib/internal/main/mksnapshot.js +++ b/lib/internal/main/mksnapshot.js @@ -119,16 +119,25 @@ function main() { const { prepareMainThreadExecution } = require('internal/process/pre_execution'); + const path = require('path'); let serializeMainFunction = getEmbedderEntryFunction(); const serializeMainArgs = [requireForUserSnapshot]; if (serializeMainFunction) { // embedded case prepareMainThreadExecution(false, false); + // TODO(addaleax): Make this `embedderRunCjs` once require('module') + // is supported in snapshots. + const filename = process.execPath; + const dirname = path.dirname(filename); + function minimalRunCjs(source) { + const fn = compileSerializeMain(filename, source); + return fn(requireForUserSnapshot, filename, dirname); + } + serializeMainArgs.push(minimalRunCjs); } else { prepareMainThreadExecution(true, false); const file = process.argv[1]; - const path = require('path'); const filename = path.resolve(file); const dirname = path.dirname(filename); const source = readFileSync(file, 'utf-8'); diff --git a/lib/internal/main/single_executable_application.js b/lib/internal/main/single_executable_application.js deleted file mode 100644 index d9604cff720d2f..00000000000000 --- a/lib/internal/main/single_executable_application.js +++ /dev/null @@ -1,55 +0,0 @@ -'use strict'; -const { - prepareMainThreadExecution, - markBootstrapComplete, -} = require('internal/process/pre_execution'); -const { getSingleExecutableCode } = internalBinding('sea'); -const { emitExperimentalWarning } = require('internal/util'); -const { Module, wrapSafe } = require('internal/modules/cjs/loader'); -const { codes: { ERR_UNKNOWN_BUILTIN_MODULE } } = require('internal/errors'); - -prepareMainThreadExecution(false, true); -markBootstrapComplete(); - -emitExperimentalWarning('Single executable application'); - -// This is roughly the same as: -// -// const mod = new Module(filename); -// mod._compile(contents, filename); -// -// but the code has been duplicated because currently there is no way to set the -// value of require.main to module. -// -// TODO(RaisinTen): Find a way to deduplicate this. - -const filename = process.execPath; -const contents = getSingleExecutableCode(); -const compiledWrapper = wrapSafe(filename, contents); - -const customModule = new Module(filename, null); -customModule.filename = filename; -customModule.paths = Module._nodeModulePaths(customModule.path); - -const customExports = customModule.exports; - -function customRequire(path) { - if (!Module.isBuiltin(path)) { - throw new ERR_UNKNOWN_BUILTIN_MODULE(path); - } - - return require(path); -} - -customRequire.main = customModule; - -const customFilename = customModule.filename; - -const customDirname = customModule.path; - -compiledWrapper( - customExports, - customRequire, - customModule, - customFilename, - customDirname); diff --git a/lib/internal/util/embedding.js b/lib/internal/util/embedding.js new file mode 100644 index 00000000000000..139d4c7a25fb7c --- /dev/null +++ b/lib/internal/util/embedding.js @@ -0,0 +1,47 @@ +'use strict'; +const { codes: { ERR_UNKNOWN_BUILTIN_MODULE } } = require('internal/errors'); +const { Module, wrapSafe } = require('internal/modules/cjs/loader'); + +// This is roughly the same as: +// +// const mod = new Module(filename); +// mod._compile(contents, filename); +// +// but the code has been duplicated because currently there is no way to set the +// value of require.main to module. +// +// TODO(RaisinTen): Find a way to deduplicate this. + +function embedderRunCjs(contents) { + const filename = process.execPath; + const compiledWrapper = wrapSafe(filename, contents); + + const customModule = new Module(filename, null); + customModule.filename = filename; + customModule.paths = Module._nodeModulePaths(customModule.path); + + const customExports = customModule.exports; + + embedderRequire.main = customModule; + + const customFilename = customModule.filename; + + const customDirname = customModule.path; + + return compiledWrapper( + customExports, + embedderRequire, + customModule, + customFilename, + customDirname); +} + +function embedderRequire(path) { + if (!Module.isBuiltin(path)) { + throw new ERR_UNKNOWN_BUILTIN_MODULE(path); + } + + return require(path); +} + +module.exports = { embedderRequire, embedderRunCjs }; diff --git a/src/api/environment.cc b/src/api/environment.cc index 3d3f864d4e956c..11243c70d5e16a 100644 --- a/src/api/environment.cc +++ b/src/api/environment.cc @@ -528,17 +528,15 @@ MaybeLocal LoadEnvironment( return StartExecution(env, cb); } -MaybeLocal LoadEnvironment( - Environment* env, - const char* main_script_source_utf8) { - CHECK_NOT_NULL(main_script_source_utf8); +MaybeLocal LoadEnvironment(Environment* env, + std::string_view main_script_source_utf8) { + CHECK_NOT_NULL(main_script_source_utf8.data()); return LoadEnvironment( env, [&](const StartExecutionCallbackInfo& info) -> MaybeLocal { - std::string name = "embedder_main_" + std::to_string(env->thread_id()); - env->builtin_loader()->Add(name.c_str(), main_script_source_utf8); - Realm* realm = env->principal_realm(); - - return realm->ExecuteBootstrapper(name.c_str()); + Local main_script = + ToV8Value(env->context(), main_script_source_utf8).ToLocalChecked(); + return info.run_cjs->Call( + env->context(), Null(env->isolate()), 1, &main_script); }); } diff --git a/src/node.cc b/src/node.cc index 0d5162dde5da88..29f0ac463acf83 100644 --- a/src/node.cc +++ b/src/node.cc @@ -129,6 +129,8 @@ namespace node { using v8::EscapableHandleScope; +using v8::Function; +using v8::FunctionCallbackInfo; using v8::Isolate; using v8::Local; using v8::MaybeLocal; @@ -277,22 +279,18 @@ MaybeLocal StartExecution(Environment* env, StartExecutionCallback cb) { if (cb != nullptr) { EscapableHandleScope scope(env->isolate()); - - if (env->isolate_data()->options()->build_snapshot) { - // TODO(addaleax): pass the callback to the main script more directly, - // e.g. by making StartExecution(env, builtin) parametrizable - env->set_embedder_mksnapshot_entry_point(std::move(cb)); - auto reset_entry_point = - OnScopeLeave([&]() { env->set_embedder_mksnapshot_entry_point({}); }); - - return StartExecution(env, "internal/main/mksnapshot"); - } - - if (StartExecution(env, "internal/main/environment").IsEmpty()) return {}; - return scope.EscapeMaybe(cb({ - env->process_object(), - env->builtin_module_require(), - })); + Realm* realm = env->principal_realm(); + // TODO(addaleax): pass the callback to the main script more directly, + // e.g. by making StartExecution(env, builtin) parametrizable + env->set_embedder_mksnapshot_entry_point(std::move(cb)); + auto reset_entry_point = + OnScopeLeave([&]() { env->set_embedder_mksnapshot_entry_point({}); }); + + const char* entry = env->isolate_data()->options()->build_snapshot + ? "internal/main/mksnapshot" + : "internal/main/embedding"; + + return scope.EscapeMaybe(StartExecution(env, entry)); } // TODO(joyeecheung): move these conditions into JS land and let the @@ -312,18 +310,6 @@ MaybeLocal StartExecution(Environment* env, StartExecutionCallback cb) { first_argv = env->argv()[1]; } -#ifndef DISABLE_SINGLE_EXECUTABLE_APPLICATION - if (sea::IsSingleExecutable()) { - // TODO(addaleax): Find a way to reuse: - // - // LoadEnvironment(Environment*, const char*) - // - // instead and not add yet another main entry point here because this - // already duplicates existing code. - return StartExecution(env, "internal/main/single_executable_application"); - } -#endif - if (first_argv == "inspect") { return StartExecution(env, "internal/main/inspect"); } diff --git a/src/node.h b/src/node.h index 635e5349f4ee88..c3a81076d54ed6 100644 --- a/src/node.h +++ b/src/node.h @@ -682,6 +682,7 @@ NODE_EXTERN std::unique_ptr GetInspectorParentHandle( struct StartExecutionCallbackInfo { v8::Local process_object; v8::Local native_require; + v8::Local run_cjs; }; using StartExecutionCallback = @@ -691,8 +692,7 @@ NODE_EXTERN v8::MaybeLocal LoadEnvironment( Environment* env, StartExecutionCallback cb); NODE_EXTERN v8::MaybeLocal LoadEnvironment( - Environment* env, - const char* main_script_source_utf8); + Environment* env, std::string_view main_script_source_utf8); NODE_EXTERN void FreeEnvironment(Environment* env); // Set a callback that is called when process.exit() is called from JS, diff --git a/src/node_main_instance.cc b/src/node_main_instance.cc index 5a4d127ffe3e43..1013aafb25ea09 100644 --- a/src/node_main_instance.cc +++ b/src/node_main_instance.cc @@ -9,6 +9,7 @@ #include "node_internals.h" #include "node_options-inl.h" #include "node_realm.h" +#include "node_sea.h" #include "node_snapshot_builder.h" #include "node_snapshotable.h" #include "node_v8_platform-inl.h" @@ -86,7 +87,15 @@ ExitCode NodeMainInstance::Run() { void NodeMainInstance::Run(ExitCode* exit_code, Environment* env) { if (*exit_code == ExitCode::kNoFailure) { - LoadEnvironment(env, StartExecutionCallback{}); + bool is_sea = false; +#ifndef DISABLE_SINGLE_EXECUTABLE_APPLICATION + if (sea::IsSingleExecutable()) { + LoadEnvironment(env, sea::FindSingleExecutableCode()); + } +#endif + if (!is_sea) { + LoadEnvironment(env, StartExecutionCallback{}); + } *exit_code = SpinEventLoopInternal(env).FromMaybe(ExitCode::kGenericUserError); diff --git a/src/node_sea.cc b/src/node_sea.cc index 18b661ce4ff31d..b9207e115dc7a3 100644 --- a/src/node_sea.cc +++ b/src/node_sea.cc @@ -23,15 +23,19 @@ #if !defined(DISABLE_SINGLE_EXECUTABLE_APPLICATION) +using v8::Boolean; using v8::Context; using v8::FunctionCallbackInfo; +using v8::Isolate; using v8::Local; using v8::Object; using v8::Value; -namespace { +namespace node { +namespace sea { -const std::string_view FindSingleExecutableCode() { +std::string_view FindSingleExecutableCode() { + CHECK(IsSingleExecutable()); static const std::string_view sea_code = []() -> std::string_view { size_t size; #ifdef __APPLE__ @@ -49,40 +53,6 @@ const std::string_view FindSingleExecutableCode() { return sea_code; } -void GetSingleExecutableCode(const FunctionCallbackInfo& args) { - node::Environment* env = node::Environment::GetCurrent(args); - - static const std::string_view sea_code = FindSingleExecutableCode(); - - if (sea_code.empty()) { - return; - } - - // TODO(joyeecheung): Use one-byte strings for ASCII-only source to save - // memory/binary size - using UTF16 by default results in twice of the size - // than necessary. - static const node::UnionBytes sea_code_union_bytes = - []() -> node::UnionBytes { - size_t expected_u16_length = - simdutf::utf16_length_from_utf8(sea_code.data(), sea_code.size()); - auto out = std::make_shared>(expected_u16_length); - size_t u16_length = simdutf::convert_utf8_to_utf16( - sea_code.data(), - sea_code.size(), - reinterpret_cast(out->data())); - out->resize(u16_length); - return node::UnionBytes{out}; - }(); - - args.GetReturnValue().Set( - sea_code_union_bytes.ToStringChecked(env->isolate())); -} - -} // namespace - -namespace node { -namespace sea { - bool IsSingleExecutable() { return postject_has_resource(); } @@ -113,13 +83,13 @@ void Initialize(Local target, Local unused, Local context, void* priv) { - SetMethod( - context, target, "getSingleExecutableCode", GetSingleExecutableCode); + Environment* env = Environment::GetCurrent(context); + Isolate* isolate = env->isolate(); + READONLY_PROPERTY( + target, "isSea", Boolean::New(isolate, IsSingleExecutable())); } -void RegisterExternalReferences(ExternalReferenceRegistry* registry) { - registry->Register(GetSingleExecutableCode); -} +void RegisterExternalReferences(ExternalReferenceRegistry* registry) {} } // namespace sea } // namespace node diff --git a/src/node_sea.h b/src/node_sea.h index 97bf0115e0f0d4..aa0f20204743c0 100644 --- a/src/node_sea.h +++ b/src/node_sea.h @@ -5,12 +5,14 @@ #if !defined(DISABLE_SINGLE_EXECUTABLE_APPLICATION) +#include #include namespace node { namespace sea { bool IsSingleExecutable(); +std::string_view FindSingleExecutableCode(); std::tuple FixupArgsForSEA(int argc, char** argv); } // namespace sea diff --git a/src/node_snapshotable.cc b/src/node_snapshotable.cc index d9d4f162e9cfd2..c7bea3ca5a5bcb 100644 --- a/src/node_snapshotable.cc +++ b/src/node_snapshotable.cc @@ -1443,6 +1443,7 @@ void SerializeSnapshotableObjects(Realm* realm, namespace mksnapshot { +// NB: This is also use by the regular embedding codepath. void GetEmbedderEntryFunction(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); Isolate* isolate = env->isolate(); @@ -1452,10 +1453,16 @@ void GetEmbedderEntryFunction(const FunctionCallbackInfo& args) { [](const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); Local require_fn = args[0]; + Local runcjs_fn = args[1]; CHECK(require_fn->IsFunction()); - CHECK(env->embedder_mksnapshot_entry_point()); - env->embedder_mksnapshot_entry_point()( - {env->process_object(), require_fn.As()}); + CHECK(runcjs_fn->IsFunction()); + MaybeLocal retval = + env->embedder_mksnapshot_entry_point()( + {env->process_object(), + require_fn.As(), + runcjs_fn.As()}); + if (!retval.IsEmpty()) + args.GetReturnValue().Set(retval.ToLocalChecked()); }); if (!jsfn.IsEmpty()) args.GetReturnValue().Set(jsfn.ToLocalChecked()); } diff --git a/test/embedding/test-embedding.js b/test/embedding/test-embedding.js index 498c05fdebf377..9dfaad6c2ab27f 100644 --- a/test/embedding/test-embedding.js +++ b/test/embedding/test-embedding.js @@ -40,6 +40,11 @@ assert.strictEqual( child_process.spawnSync(binary, ['throw new Error()']).status, 1); +// Cannot require internals anymore: +assert.strictEqual( + child_process.spawnSync(binary, ['require("lib/internal/test/binding")']).status, + 1); + assert.strictEqual( child_process.spawnSync(binary, ['process.exitCode = 8']).status, 8); From 62056b2e451c9df3ca7503c51413edb8dd3065f6 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Fri, 24 Feb 2023 20:07:59 +0100 Subject: [PATCH 2/5] fixup! src: share common code paths for SEA and embedder script --- src/node.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/node.cc b/src/node.cc index 29f0ac463acf83..916952bf4e4675 100644 --- a/src/node.cc +++ b/src/node.cc @@ -279,7 +279,6 @@ MaybeLocal StartExecution(Environment* env, StartExecutionCallback cb) { if (cb != nullptr) { EscapableHandleScope scope(env->isolate()); - Realm* realm = env->principal_realm(); // TODO(addaleax): pass the callback to the main script more directly, // e.g. by making StartExecution(env, builtin) parametrizable env->set_embedder_mksnapshot_entry_point(std::move(cb)); From eeccbe543a9ddaa45b9232f8a4f424776afb21b2 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Sat, 25 Feb 2023 22:17:51 +0100 Subject: [PATCH 3/5] fixup! fixup! src: share common code paths for SEA and embedder script --- src/node_builtins.cc | 29 +++++++---------------------- src/node_main_instance.cc | 1 + src/node_sea.cc | 3 --- src/node_snapshotable.cc | 2 +- 4 files changed, 9 insertions(+), 26 deletions(-) diff --git a/src/node_builtins.cc b/src/node_builtins.cc index e9bf8a5a0e0b7e..59eff5460704c6 100644 --- a/src/node_builtins.cc +++ b/src/node_builtins.cc @@ -185,17 +185,14 @@ static std::string OnDiskFileName(const char* id) { MaybeLocal BuiltinLoader::LoadBuiltinSource(Isolate* isolate, const char* id) const { auto source = source_.read(); -#ifdef NODE_BUILTIN_MODULES_PATH - if (strncmp(id, "embedder_main_", strlen("embedder_main_")) == 0) { -#endif // NODE_BUILTIN_MODULES_PATH - const auto source_it = source->find(id); - if (UNLIKELY(source_it == source->end())) { - fprintf(stderr, "Cannot find native builtin: \"%s\".\n", id); - ABORT(); - } - return source_it->second.ToStringChecked(isolate); -#ifdef NODE_BUILTIN_MODULES_PATH +#ifndef NODE_BUILTIN_MODULES_PATH + const auto source_it = source->find(id); + if (UNLIKELY(source_it == source->end())) { + fprintf(stderr, "Cannot find native builtin: \"%s\".\n", id); + ABORT(); } + return source_it->second.ToStringChecked(isolate); +#else // !NODE_BUILTIN_MODULES_PATH std::string filename = OnDiskFileName(id); std::string contents; @@ -395,12 +392,6 @@ MaybeLocal BuiltinLoader::LookupAndCompile(Local context, FIXED_ONE_BYTE_STRING(isolate, "internalBinding"), FIXED_ONE_BYTE_STRING(isolate, "primordials"), }; - } else if (strncmp(id, "embedder_main_", strlen("embedder_main_")) == 0) { - // Synthetic embedder main scripts from LoadEnvironment(): process, require - parameters = { - FIXED_ONE_BYTE_STRING(isolate, "process"), - FIXED_ONE_BYTE_STRING(isolate, "require"), - }; } else { // others: exports, require, module, process, internalBinding, primordials parameters = { @@ -457,12 +448,6 @@ MaybeLocal BuiltinLoader::CompileAndCall(Local context, realm->builtin_module_require(), realm->internal_binding_loader(), realm->primordials()}; - } else if (strncmp(id, "embedder_main_", strlen("embedder_main_")) == 0) { - // Synthetic embedder main scripts from LoadEnvironment(): process, require - arguments = { - realm->process_object(), - realm->builtin_module_require(), - }; } else { // This should be invoked with the other CompileAndCall() methods, as // we are unable to generate the arguments. diff --git a/src/node_main_instance.cc b/src/node_main_instance.cc index 1013aafb25ea09..f0dc6ca275b007 100644 --- a/src/node_main_instance.cc +++ b/src/node_main_instance.cc @@ -90,6 +90,7 @@ void NodeMainInstance::Run(ExitCode* exit_code, Environment* env) { bool is_sea = false; #ifndef DISABLE_SINGLE_EXECUTABLE_APPLICATION if (sea::IsSingleExecutable()) { + is_sea = true; LoadEnvironment(env, sea::FindSingleExecutableCode()); } #endif diff --git a/src/node_sea.cc b/src/node_sea.cc index b9207e115dc7a3..28b813dd1ce770 100644 --- a/src/node_sea.cc +++ b/src/node_sea.cc @@ -4,8 +4,6 @@ #include "node_external_reference.h" #include "node_internals.h" #include "node_union_bytes.h" -#include "simdutf.h" -#include "v8.h" // The POSTJECT_SENTINEL_FUSE macro is a string of random characters selected by // the Node.js project that is present only once in the entire binary. It is @@ -19,7 +17,6 @@ #include #include #include -#include #if !defined(DISABLE_SINGLE_EXECUTABLE_APPLICATION) diff --git a/src/node_snapshotable.cc b/src/node_snapshotable.cc index c7bea3ca5a5bcb..833d01368b4c26 100644 --- a/src/node_snapshotable.cc +++ b/src/node_snapshotable.cc @@ -1443,7 +1443,7 @@ void SerializeSnapshotableObjects(Realm* realm, namespace mksnapshot { -// NB: This is also use by the regular embedding codepath. +// NB: This is also used by the regular embedding codepath. void GetEmbedderEntryFunction(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); Isolate* isolate = env->isolate(); From e618affaac2e480e243f4b5990eabff101071a22 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Sun, 26 Feb 2023 01:15:10 +0100 Subject: [PATCH 4/5] fixup! fixup! fixup! src: share common code paths for SEA and embedder script --- src/node.cc | 2 -- src/node_builtins.cc | 2 +- src/node_sea.cc | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/node.cc b/src/node.cc index 916952bf4e4675..edaac855cfb1c0 100644 --- a/src/node.cc +++ b/src/node.cc @@ -129,8 +129,6 @@ namespace node { using v8::EscapableHandleScope; -using v8::Function; -using v8::FunctionCallbackInfo; using v8::Isolate; using v8::Local; using v8::MaybeLocal; diff --git a/src/node_builtins.cc b/src/node_builtins.cc index 59eff5460704c6..0439fff5115bd9 100644 --- a/src/node_builtins.cc +++ b/src/node_builtins.cc @@ -192,7 +192,7 @@ MaybeLocal BuiltinLoader::LoadBuiltinSource(Isolate* isolate, ABORT(); } return source_it->second.ToStringChecked(isolate); -#else // !NODE_BUILTIN_MODULES_PATH +#else // !NODE_BUILTIN_MODULES_PATH std::string filename = OnDiskFileName(id); std::string contents; diff --git a/src/node_sea.cc b/src/node_sea.cc index 28b813dd1ce770..fcab0811770cce 100644 --- a/src/node_sea.cc +++ b/src/node_sea.cc @@ -22,7 +22,6 @@ using v8::Boolean; using v8::Context; -using v8::FunctionCallbackInfo; using v8::Isolate; using v8::Local; using v8::Object; From a0e1149ca86a3259381fbfc3a8186960f431e9a8 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Tue, 28 Feb 2023 18:41:50 +0100 Subject: [PATCH 5/5] fixup! src: share common code paths for SEA and embedder script --- lib/internal/main/embedding.js | 2 +- src/env-inl.h | 10 ++++------ src/env.h | 6 +++--- src/node.cc | 4 ++-- src/node_sea.cc | 16 +++++++++------- src/node_snapshotable.cc | 11 +++++------ 6 files changed, 24 insertions(+), 25 deletions(-) diff --git a/lib/internal/main/embedding.js b/lib/internal/main/embedding.js index a43fb09b3ed1f6..aa3f06cca10f99 100644 --- a/lib/internal/main/embedding.js +++ b/lib/internal/main/embedding.js @@ -11,7 +11,7 @@ const { getEmbedderEntryFunction } = internalBinding('mksnapshot'); prepareMainThreadExecution(false, true); markBootstrapComplete(); -if (isSea) { +if (isSea()) { emitExperimentalWarning('Single executable application'); } diff --git a/src/env-inl.h b/src/env-inl.h index 6b4d63616abe39..8d17a0ae4f6282 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -406,14 +406,12 @@ inline builtins::BuiltinLoader* Environment::builtin_loader() { return &builtin_loader_; } -inline const StartExecutionCallback& -Environment::embedder_mksnapshot_entry_point() const { - return embedder_mksnapshot_entry_point_; +inline const StartExecutionCallback& Environment::embedder_entry_point() const { + return embedder_entry_point_; } -inline void Environment::set_embedder_mksnapshot_entry_point( - StartExecutionCallback&& fn) { - embedder_mksnapshot_entry_point_ = std::move(fn); +inline void Environment::set_embedder_entry_point(StartExecutionCallback&& fn) { + embedder_entry_point_ = std::move(fn); } inline double Environment::new_async_id() { diff --git a/src/env.h b/src/env.h index 629b99a9205069..0f27e105e4af2a 100644 --- a/src/env.h +++ b/src/env.h @@ -946,8 +946,8 @@ class Environment : public MemoryRetainer { #endif // HAVE_INSPECTOR - inline const StartExecutionCallback& embedder_mksnapshot_entry_point() const; - inline void set_embedder_mksnapshot_entry_point(StartExecutionCallback&& fn); + inline const StartExecutionCallback& embedder_entry_point() const; + inline void set_embedder_entry_point(StartExecutionCallback&& fn); inline void set_process_exit_handler( std::function&& handler); @@ -1131,7 +1131,7 @@ class Environment : public MemoryRetainer { std::unique_ptr principal_realm_ = nullptr; builtins::BuiltinLoader builtin_loader_; - StartExecutionCallback embedder_mksnapshot_entry_point_; + StartExecutionCallback embedder_entry_point_; // Used by allocate_managed_buffer() and release_managed_buffer() to keep // track of the BackingStore for a given pointer. diff --git a/src/node.cc b/src/node.cc index edaac855cfb1c0..00fe99aaba165b 100644 --- a/src/node.cc +++ b/src/node.cc @@ -279,9 +279,9 @@ MaybeLocal StartExecution(Environment* env, StartExecutionCallback cb) { EscapableHandleScope scope(env->isolate()); // TODO(addaleax): pass the callback to the main script more directly, // e.g. by making StartExecution(env, builtin) parametrizable - env->set_embedder_mksnapshot_entry_point(std::move(cb)); + env->set_embedder_entry_point(std::move(cb)); auto reset_entry_point = - OnScopeLeave([&]() { env->set_embedder_mksnapshot_entry_point({}); }); + OnScopeLeave([&]() { env->set_embedder_entry_point({}); }); const char* entry = env->isolate_data()->options()->build_snapshot ? "internal/main/mksnapshot" diff --git a/src/node_sea.cc b/src/node_sea.cc index fcab0811770cce..b65620d1ff9684 100644 --- a/src/node_sea.cc +++ b/src/node_sea.cc @@ -20,9 +20,8 @@ #if !defined(DISABLE_SINGLE_EXECUTABLE_APPLICATION) -using v8::Boolean; using v8::Context; -using v8::Isolate; +using v8::FunctionCallbackInfo; using v8::Local; using v8::Object; using v8::Value; @@ -53,6 +52,10 @@ bool IsSingleExecutable() { return postject_has_resource(); } +void IsSingleExecutable(const FunctionCallbackInfo& args) { + args.GetReturnValue().Set(IsSingleExecutable()); +} + std::tuple FixupArgsForSEA(int argc, char** argv) { // Repeats argv[0] at position 1 on argv as a replacement for the missing // entry point file path. @@ -79,13 +82,12 @@ void Initialize(Local target, Local unused, Local context, void* priv) { - Environment* env = Environment::GetCurrent(context); - Isolate* isolate = env->isolate(); - READONLY_PROPERTY( - target, "isSea", Boolean::New(isolate, IsSingleExecutable())); + SetMethod(context, target, "isSea", IsSingleExecutable); } -void RegisterExternalReferences(ExternalReferenceRegistry* registry) {} +void RegisterExternalReferences(ExternalReferenceRegistry* registry) { + registry->Register(IsSingleExecutable); +} } // namespace sea } // namespace node diff --git a/src/node_snapshotable.cc b/src/node_snapshotable.cc index 833d01368b4c26..b4d8174c4f50e0 100644 --- a/src/node_snapshotable.cc +++ b/src/node_snapshotable.cc @@ -1447,7 +1447,7 @@ namespace mksnapshot { void GetEmbedderEntryFunction(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); Isolate* isolate = env->isolate(); - if (!env->embedder_mksnapshot_entry_point()) return; + if (!env->embedder_entry_point()) return; MaybeLocal jsfn = Function::New(isolate->GetCurrentContext(), [](const FunctionCallbackInfo& args) { @@ -1456,11 +1456,10 @@ void GetEmbedderEntryFunction(const FunctionCallbackInfo& args) { Local runcjs_fn = args[1]; CHECK(require_fn->IsFunction()); CHECK(runcjs_fn->IsFunction()); - MaybeLocal retval = - env->embedder_mksnapshot_entry_point()( - {env->process_object(), - require_fn.As(), - runcjs_fn.As()}); + MaybeLocal retval = env->embedder_entry_point()( + {env->process_object(), + require_fn.As(), + runcjs_fn.As()}); if (!retval.IsEmpty()) args.GetReturnValue().Set(retval.ToLocalChecked()); });