Files
node/src/node_main_instance.cc
T
Anna Henningsen 3803b028dd 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.)

PR-URL: https://github.com/nodejs/node/pull/46825
Reviewed-By: Darshan Sen <raisinten@gmail.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Minwoo Jung <nodecorelab@gmail.com>
2023-03-02 14:31:08 +00:00

145 lines
4.2 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;
}
// This should only be done on a main instance that owns its isolate.
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) {
bool is_sea = false;
#ifndef DISABLE_SINGLE_EXECUTABLE_APPLICATION
if (sea::IsSingleExecutable()) {
is_sea = true;
LoadEnvironment(env, sea::FindSingleExecutableCode());
}
#endif
if (!is_sea) {
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