mirror of
https://github.com/nodejs/node.git
synced 2026-10-28 18:25:13 +08:00
This patch: 1. Refactor the routines used to compile and run an embedder entrypoint. In JS land special handling for SEA is done directly in main/embedding.js instead of clobbering the CJS loader. Add warnings to remind users that currently the require() in SEA bundled scripts only supports loading builtins. 2. Don't use the bundled SEA code cache when compiling CJS loaded from disk, since in that case we are certainly not compiling the code bundled into the SEA. Use a is_sea_main flag in CompileFunctionForCJSLoader() (which replaces an unused argument) to pass this into the C++ land - the code cache is still read directly from C++ to avoid the overhead of ArrayBuffer creation. 3. Move SEA loading code into MaybeLoadSingleExecutableApplication() which calls LoadEnvironment() with its own StartExecutionCallback(). This avoids more hidden switches in StartExecution() and make them explicit. Also add some TODOs about how to support ESM in embedded applications. 4. Add more comments PR-URL: https://github.com/nodejs/node/pull/53573 Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
154 lines
4.6 KiB
C++
154 lines
4.6 KiB
C++
#include "node_main_instance.h"
|
|
#include <memory>
|
|
#if HAVE_OPENSSL
|
|
#include "crypto/crypto_util.h"
|
|
#endif // HAVE_OPENSSL
|
|
#include "debug_utils-inl.h"
|
|
#include "node_builtins.h"
|
|
#include "node_external_reference.h"
|
|
#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"
|
|
#include "util-inl.h"
|
|
#if defined(LEAK_SANITIZER)
|
|
#include <sanitizer/lsan_interface.h>
|
|
#endif
|
|
|
|
#if HAVE_INSPECTOR
|
|
#include "inspector/worker_inspector.h" // ParentInspectorHandle
|
|
#endif
|
|
|
|
namespace node {
|
|
|
|
using v8::Context;
|
|
using v8::HandleScope;
|
|
using v8::Isolate;
|
|
using v8::Local;
|
|
using v8::Locker;
|
|
|
|
NodeMainInstance::NodeMainInstance(const SnapshotData* snapshot_data,
|
|
uv_loop_t* event_loop,
|
|
MultiIsolatePlatform* platform,
|
|
const std::vector<std::string>& args,
|
|
const std::vector<std::string>& exec_args)
|
|
: args_(args),
|
|
exec_args_(exec_args),
|
|
array_buffer_allocator_(ArrayBufferAllocator::Create()),
|
|
isolate_(nullptr),
|
|
platform_(platform),
|
|
isolate_data_(),
|
|
isolate_params_(std::make_unique<Isolate::CreateParams>()),
|
|
snapshot_data_(snapshot_data) {
|
|
isolate_params_->array_buffer_allocator = array_buffer_allocator_.get();
|
|
|
|
isolate_ =
|
|
NewIsolate(isolate_params_.get(), event_loop, platform, snapshot_data);
|
|
CHECK_NOT_NULL(isolate_);
|
|
|
|
// If the indexes are not nullptr, we are not deserializing
|
|
isolate_data_.reset(
|
|
CreateIsolateData(isolate_,
|
|
event_loop,
|
|
platform,
|
|
array_buffer_allocator_.get(),
|
|
snapshot_data->AsEmbedderWrapper().get()));
|
|
|
|
isolate_data_->max_young_gen_size =
|
|
isolate_params_->constraints.max_young_generation_size_in_bytes();
|
|
}
|
|
|
|
NodeMainInstance::~NodeMainInstance() {
|
|
if (isolate_params_ == nullptr) {
|
|
return;
|
|
}
|
|
|
|
{
|
|
#ifdef DEBUG
|
|
// node::Environment has been disposed and no JavaScript Execution is
|
|
// allowed at this point.
|
|
// Create a scope to check that no JavaScript is executed in debug build
|
|
// and proactively crash the process in the case JavaScript is being
|
|
// executed.
|
|
// Isolate::Dispose() must be invoked outside of this scope to avoid
|
|
// use-after-free.
|
|
Isolate::DisallowJavascriptExecutionScope disallow_js(
|
|
isolate_, Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
|
|
#endif
|
|
// This should only be done on a main instance that owns its isolate.
|
|
// IsolateData must be freed before UnregisterIsolate() is called.
|
|
isolate_data_.reset();
|
|
platform_->UnregisterIsolate(isolate_);
|
|
}
|
|
isolate_->Dispose();
|
|
}
|
|
|
|
ExitCode NodeMainInstance::Run() {
|
|
Locker locker(isolate_);
|
|
Isolate::Scope isolate_scope(isolate_);
|
|
HandleScope handle_scope(isolate_);
|
|
|
|
ExitCode exit_code = ExitCode::kNoFailure;
|
|
DeleteFnPtr<Environment, FreeEnvironment> env =
|
|
CreateMainEnvironment(&exit_code);
|
|
CHECK_NOT_NULL(env);
|
|
|
|
Context::Scope context_scope(env->context());
|
|
Run(&exit_code, env.get());
|
|
return exit_code;
|
|
}
|
|
|
|
void NodeMainInstance::Run(ExitCode* exit_code, Environment* env) {
|
|
if (*exit_code == ExitCode::kNoFailure) {
|
|
if (!sea::MaybeLoadSingleExecutableApplication(env)) {
|
|
LoadEnvironment(env, StartExecutionCallback{});
|
|
}
|
|
|
|
*exit_code =
|
|
SpinEventLoopInternal(env).FromMaybe(ExitCode::kGenericUserError);
|
|
}
|
|
|
|
#if defined(LEAK_SANITIZER)
|
|
__lsan_do_leak_check();
|
|
#endif
|
|
}
|
|
|
|
DeleteFnPtr<Environment, FreeEnvironment>
|
|
NodeMainInstance::CreateMainEnvironment(ExitCode* exit_code) {
|
|
*exit_code = ExitCode::kNoFailure; // Reset the exit code to 0
|
|
|
|
HandleScope handle_scope(isolate_);
|
|
|
|
// TODO(addaleax): This should load a real per-Isolate option, currently
|
|
// this is still effectively per-process.
|
|
if (isolate_data_->options()->track_heap_objects) {
|
|
isolate_->GetHeapProfiler()->StartTrackingHeapObjects(true);
|
|
}
|
|
|
|
Local<Context> context;
|
|
DeleteFnPtr<Environment, FreeEnvironment> env;
|
|
|
|
if (snapshot_data_ != nullptr) {
|
|
env.reset(CreateEnvironment(isolate_data_.get(),
|
|
Local<Context>(), // read from snapshot
|
|
args_,
|
|
exec_args_));
|
|
#if HAVE_OPENSSL
|
|
crypto::InitCryptoOnce(isolate_);
|
|
#endif // HAVE_OPENSSL
|
|
} else {
|
|
context = NewContext(isolate_);
|
|
CHECK(!context.IsEmpty());
|
|
Context::Scope context_scope(context);
|
|
env.reset(
|
|
CreateEnvironment(isolate_data_.get(), context, args_, exec_args_));
|
|
}
|
|
|
|
return env;
|
|
}
|
|
|
|
} // namespace node
|