mirror of
https://github.com/nodejs/node.git
synced 2026-11-09 15:11:11 -05:00
- 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: https://github.com/nodejs/node/pull/48242 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: James M Snell <jasnell@gmail.com>
198 lines
6.3 KiB
C++
198 lines
6.3 KiB
C++
#ifdef NDEBUG
|
|
#undef NDEBUG
|
|
#endif
|
|
#include "node.h"
|
|
#include "uv.h"
|
|
#include <assert.h>
|
|
|
|
#include <algorithm>
|
|
|
|
// Note: This file is being referred to from doc/api/embedding.md, and excerpts
|
|
// from it are included in the documentation. Try to keep these in sync.
|
|
// Snapshot support is not part of the embedder API docs yet due to its
|
|
// experimental nature, although it is of course documented in node.h.
|
|
|
|
using node::CommonEnvironmentSetup;
|
|
using node::Environment;
|
|
using node::MultiIsolatePlatform;
|
|
using v8::Context;
|
|
using v8::HandleScope;
|
|
using v8::Isolate;
|
|
using v8::Locker;
|
|
using v8::MaybeLocal;
|
|
using v8::V8;
|
|
using v8::Value;
|
|
|
|
static int RunNodeInstance(MultiIsolatePlatform* platform,
|
|
const std::vector<std::string>& args,
|
|
const std::vector<std::string>& exec_args);
|
|
|
|
int main(int argc, char** argv) {
|
|
argv = uv_setup_args(argc, argv);
|
|
std::vector<std::string> args(argv, argv + argc);
|
|
std::unique_ptr<node::InitializationResult> result =
|
|
node::InitializeOncePerProcess(
|
|
args,
|
|
{node::ProcessInitializationFlags::kNoInitializeV8,
|
|
node::ProcessInitializationFlags::kNoInitializeNodeV8Platform});
|
|
|
|
for (const std::string& error : result->errors())
|
|
fprintf(stderr, "%s: %s\n", args[0].c_str(), error.c_str());
|
|
if (result->early_return() != 0) {
|
|
return result->exit_code();
|
|
}
|
|
|
|
std::unique_ptr<MultiIsolatePlatform> platform =
|
|
MultiIsolatePlatform::Create(4);
|
|
V8::InitializePlatform(platform.get());
|
|
V8::Initialize();
|
|
|
|
int ret =
|
|
RunNodeInstance(platform.get(), result->args(), result->exec_args());
|
|
|
|
V8::Dispose();
|
|
V8::DisposePlatform();
|
|
|
|
node::TearDownOncePerProcess();
|
|
return ret;
|
|
}
|
|
|
|
int RunNodeInstance(MultiIsolatePlatform* platform,
|
|
const std::vector<std::string>& args,
|
|
const std::vector<std::string>& exec_args) {
|
|
int exit_code = 0;
|
|
|
|
// Format of the arguments of this binary:
|
|
// Building snapshot:
|
|
// embedtest js_code_to_eval arg1 arg2... \
|
|
// --embedder-snapshot-blob blob-path \
|
|
// --embedder-snapshot-create
|
|
// [--embedder-snapshot-as-file]
|
|
// Running snapshot:
|
|
// embedtest --embedder-snapshot-blob blob-path \
|
|
// [--embedder-snapshot-as-file]
|
|
// arg1 arg2...
|
|
// No snapshot:
|
|
// embedtest arg1 arg2...
|
|
node::EmbedderSnapshotData::Pointer snapshot;
|
|
|
|
std::string binary_path = args[0];
|
|
std::vector<std::string> filtered_args;
|
|
bool is_building_snapshot = false;
|
|
bool snapshot_as_file = false;
|
|
std::string snapshot_blob_path;
|
|
for (size_t i = 0; i < args.size(); ++i) {
|
|
const std::string& arg = args[i];
|
|
if (arg == "--embedder-snapshot-create") {
|
|
is_building_snapshot = true;
|
|
} else if (arg == "--embedder-snapshot-as-file") {
|
|
snapshot_as_file = true;
|
|
} else if (arg == "--embedder-snapshot-blob") {
|
|
assert(i + 1 < args.size());
|
|
snapshot_blob_path = args[i + i];
|
|
i++;
|
|
} else {
|
|
filtered_args.push_back(arg);
|
|
}
|
|
}
|
|
|
|
if (!snapshot_blob_path.empty() && !is_building_snapshot) {
|
|
FILE* fp = fopen(snapshot_blob_path.c_str(), "r");
|
|
assert(fp != nullptr);
|
|
if (snapshot_as_file) {
|
|
snapshot = node::EmbedderSnapshotData::FromFile(fp);
|
|
} else {
|
|
uv_fs_t req = uv_fs_t();
|
|
int statret =
|
|
uv_fs_stat(nullptr, &req, snapshot_blob_path.c_str(), nullptr);
|
|
assert(statret == 0);
|
|
size_t filesize = req.statbuf.st_size;
|
|
uv_fs_req_cleanup(&req);
|
|
|
|
std::vector<char> vec(filesize);
|
|
size_t read = fread(vec.data(), filesize, 1, fp);
|
|
assert(read == 1);
|
|
snapshot = node::EmbedderSnapshotData::FromBlob(vec);
|
|
}
|
|
assert(snapshot);
|
|
int ret = fclose(fp);
|
|
assert(ret == 0);
|
|
}
|
|
|
|
if (is_building_snapshot) {
|
|
// It contains at least the binary path, the code to snapshot,
|
|
// and --embedder-snapshot-create. Insert an anonymous filename
|
|
// as process.argv[1].
|
|
assert(filtered_args.size() >= 3);
|
|
filtered_args.insert(filtered_args.begin() + 1,
|
|
node::GetAnonymousMainPath());
|
|
}
|
|
|
|
std::vector<std::string> errors;
|
|
std::unique_ptr<CommonEnvironmentSetup> setup =
|
|
snapshot
|
|
? CommonEnvironmentSetup::CreateFromSnapshot(
|
|
platform, &errors, snapshot.get(), filtered_args, exec_args)
|
|
: is_building_snapshot ? CommonEnvironmentSetup::CreateForSnapshotting(
|
|
platform, &errors, filtered_args, exec_args)
|
|
: CommonEnvironmentSetup::Create(
|
|
platform, &errors, filtered_args, exec_args);
|
|
if (!setup) {
|
|
for (const std::string& err : errors)
|
|
fprintf(stderr, "%s: %s\n", binary_path.c_str(), err.c_str());
|
|
return 1;
|
|
}
|
|
|
|
Isolate* isolate = setup->isolate();
|
|
Environment* env = setup->env();
|
|
|
|
{
|
|
Locker locker(isolate);
|
|
Isolate::Scope isolate_scope(isolate);
|
|
HandleScope handle_scope(isolate);
|
|
Context::Scope context_scope(setup->context());
|
|
|
|
MaybeLocal<Value> loadenv_ret;
|
|
if (snapshot) {
|
|
loadenv_ret = node::LoadEnvironment(env, node::StartExecutionCallback{});
|
|
} else {
|
|
loadenv_ret = node::LoadEnvironment(
|
|
env,
|
|
// Snapshots do not support userland require()s (yet)
|
|
"if (!require('v8').startupSnapshot.isBuildingSnapshot()) {"
|
|
" const publicRequire ="
|
|
" require('module').createRequire(process.cwd() + '/');"
|
|
" globalThis.require = publicRequire;"
|
|
"} else globalThis.require = require;"
|
|
"globalThis.embedVars = { nön_ascıı: '🏳️🌈' };"
|
|
"require('vm').runInThisContext(process.argv[2]);");
|
|
}
|
|
|
|
if (loadenv_ret.IsEmpty()) // There has been a JS exception.
|
|
return 1;
|
|
|
|
exit_code = node::SpinEventLoop(env).FromMaybe(1);
|
|
}
|
|
|
|
if (!snapshot_blob_path.empty() && is_building_snapshot) {
|
|
snapshot = setup->CreateSnapshot();
|
|
assert(snapshot);
|
|
|
|
FILE* fp = fopen(snapshot_blob_path.c_str(), "w");
|
|
assert(fp != nullptr);
|
|
if (snapshot_as_file) {
|
|
snapshot->ToFile(fp);
|
|
} else {
|
|
const std::vector<char> vec = snapshot->ToBlob();
|
|
size_t written = fwrite(vec.data(), vec.size(), 1, fp);
|
|
assert(written == 1);
|
|
}
|
|
int ret = fclose(fp);
|
|
assert(ret == 0);
|
|
}
|
|
|
|
node::Stop(env);
|
|
|
|
return exit_code;
|
|
}
|