src: move public C++ APIs into src/api/*.cc
This patch moves most of the public C++ APIs into src/api/*.cc so that it's easier to tell that we need to be careful about the compatibility of these code. Some APIs, like `node::LoadEnvironmet()`, `node::Start()` and `node::Init()` still stay in `node.cc` because they are still very specific to our use cases and do not work quite well yet for embedders anyway - we could not even manage to write cctest for them at the moment. PR-URL: https://github.com/nodejs/node/pull/25541 Reviewed-By: Gus Caplan <me@gus.host>
This commit is contained in:
parent
99c3243b22
commit
ca9e24e8b4
10
node.gyp
10
node.gyp
@ -363,14 +363,19 @@
|
||||
],
|
||||
|
||||
'sources': [
|
||||
'src/api/callback.cc',
|
||||
'src/api/encoding.cc',
|
||||
'src/api/environment.cc',
|
||||
'src/api/exceptions.cc',
|
||||
'src/api/hooks.cc',
|
||||
'src/api/utils.cc',
|
||||
|
||||
'src/async_wrap.cc',
|
||||
'src/callback_scope.cc',
|
||||
'src/cares_wrap.cc',
|
||||
'src/connect_wrap.cc',
|
||||
'src/connection_wrap.cc',
|
||||
'src/debug_utils.cc',
|
||||
'src/env.cc',
|
||||
'src/exceptions.cc',
|
||||
'src/fs_event_wrap.cc',
|
||||
'src/handle_wrap.cc',
|
||||
'src/heap_utils.cc',
|
||||
@ -390,7 +395,6 @@
|
||||
'src/node_contextify.cc',
|
||||
'src/node_credentials.cc',
|
||||
'src/node_domain.cc',
|
||||
'src/node_encoding.cc',
|
||||
'src/node_env_var.cc',
|
||||
'src/node_errors.cc',
|
||||
'src/node_file.cc',
|
||||
|
214
src/api/environment.cc
Normal file
214
src/api/environment.cc
Normal file
@ -0,0 +1,214 @@
|
||||
#include "env.h"
|
||||
#include "node.h"
|
||||
#include "node_context_data.h"
|
||||
#include "node_errors.h"
|
||||
#include "node_internals.h"
|
||||
#include "node_native_module.h"
|
||||
#include "node_platform.h"
|
||||
#include "node_process.h"
|
||||
#include "node_v8_platform-inl.h"
|
||||
#include "uv.h"
|
||||
|
||||
namespace node {
|
||||
using v8::Context;
|
||||
using v8::Function;
|
||||
using v8::HandleScope;
|
||||
using v8::Isolate;
|
||||
using v8::Local;
|
||||
using v8::MaybeLocal;
|
||||
using v8::Message;
|
||||
using v8::MicrotasksPolicy;
|
||||
using v8::ObjectTemplate;
|
||||
using v8::String;
|
||||
using v8::Value;
|
||||
|
||||
static bool AllowWasmCodeGenerationCallback(Local<Context> context,
|
||||
Local<String>) {
|
||||
Local<Value> wasm_code_gen =
|
||||
context->GetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration);
|
||||
return wasm_code_gen->IsUndefined() || wasm_code_gen->IsTrue();
|
||||
}
|
||||
|
||||
static bool ShouldAbortOnUncaughtException(Isolate* isolate) {
|
||||
HandleScope scope(isolate);
|
||||
Environment* env = Environment::GetCurrent(isolate);
|
||||
return env != nullptr && env->should_abort_on_uncaught_toggle()[0] &&
|
||||
!env->inside_should_not_abort_on_uncaught_scope();
|
||||
}
|
||||
|
||||
static void OnMessage(Local<Message> message, Local<Value> error) {
|
||||
Isolate* isolate = message->GetIsolate();
|
||||
switch (message->ErrorLevel()) {
|
||||
case Isolate::MessageErrorLevel::kMessageWarning: {
|
||||
Environment* env = Environment::GetCurrent(isolate);
|
||||
if (!env) {
|
||||
break;
|
||||
}
|
||||
Utf8Value filename(isolate, message->GetScriptOrigin().ResourceName());
|
||||
// (filename):(line) (message)
|
||||
std::stringstream warning;
|
||||
warning << *filename;
|
||||
warning << ":";
|
||||
warning << message->GetLineNumber(env->context()).FromMaybe(-1);
|
||||
warning << " ";
|
||||
v8::String::Utf8Value msg(isolate, message->Get());
|
||||
warning << *msg;
|
||||
USE(ProcessEmitWarningGeneric(env, warning.str().c_str(), "V8"));
|
||||
break;
|
||||
}
|
||||
case Isolate::MessageErrorLevel::kMessageError:
|
||||
FatalException(isolate, error, message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void* ArrayBufferAllocator::Allocate(size_t size) {
|
||||
if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers)
|
||||
return UncheckedCalloc(size);
|
||||
else
|
||||
return UncheckedMalloc(size);
|
||||
}
|
||||
|
||||
ArrayBufferAllocator* CreateArrayBufferAllocator() {
|
||||
return new ArrayBufferAllocator();
|
||||
}
|
||||
|
||||
void FreeArrayBufferAllocator(ArrayBufferAllocator* allocator) {
|
||||
delete allocator;
|
||||
}
|
||||
|
||||
Isolate* NewIsolate(ArrayBufferAllocator* allocator, uv_loop_t* event_loop) {
|
||||
Isolate::CreateParams params;
|
||||
params.array_buffer_allocator = allocator;
|
||||
#ifdef NODE_ENABLE_VTUNE_PROFILING
|
||||
params.code_event_handler = vTune::GetVtuneCodeEventHandler();
|
||||
#endif
|
||||
|
||||
Isolate* isolate = Isolate::Allocate();
|
||||
if (isolate == nullptr) return nullptr;
|
||||
|
||||
// Register the isolate on the platform before the isolate gets initialized,
|
||||
// so that the isolate can access the platform during initialization.
|
||||
per_process::v8_platform.Platform()->RegisterIsolate(isolate, event_loop);
|
||||
Isolate::Initialize(isolate, params);
|
||||
|
||||
isolate->AddMessageListenerWithErrorLevel(
|
||||
OnMessage,
|
||||
Isolate::MessageErrorLevel::kMessageError |
|
||||
Isolate::MessageErrorLevel::kMessageWarning);
|
||||
isolate->SetAbortOnUncaughtExceptionCallback(ShouldAbortOnUncaughtException);
|
||||
isolate->SetMicrotasksPolicy(MicrotasksPolicy::kExplicit);
|
||||
isolate->SetFatalErrorHandler(OnFatalError);
|
||||
isolate->SetAllowWasmCodeGenerationCallback(AllowWasmCodeGenerationCallback);
|
||||
v8::CpuProfiler::UseDetailedSourcePositionsForProfiling(isolate);
|
||||
|
||||
return isolate;
|
||||
}
|
||||
|
||||
IsolateData* CreateIsolateData(Isolate* isolate,
|
||||
uv_loop_t* loop,
|
||||
MultiIsolatePlatform* platform,
|
||||
ArrayBufferAllocator* allocator) {
|
||||
return new IsolateData(
|
||||
isolate,
|
||||
loop,
|
||||
platform,
|
||||
allocator != nullptr ? allocator->zero_fill_field() : nullptr);
|
||||
}
|
||||
|
||||
void FreeIsolateData(IsolateData* isolate_data) {
|
||||
delete isolate_data;
|
||||
}
|
||||
|
||||
Environment* CreateEnvironment(IsolateData* isolate_data,
|
||||
Local<Context> context,
|
||||
int argc,
|
||||
const char* const* argv,
|
||||
int exec_argc,
|
||||
const char* const* exec_argv) {
|
||||
Isolate* isolate = context->GetIsolate();
|
||||
HandleScope handle_scope(isolate);
|
||||
Context::Scope context_scope(context);
|
||||
// TODO(addaleax): This is a much better place for parsing per-Environment
|
||||
// options than the global parse call.
|
||||
std::vector<std::string> args(argv, argv + argc);
|
||||
std::vector<std::string> exec_args(exec_argv, exec_argv + exec_argc);
|
||||
Environment* env = new Environment(isolate_data, context);
|
||||
env->Start(per_process::v8_is_profiling);
|
||||
env->ProcessCliArgs(args, exec_args);
|
||||
return env;
|
||||
}
|
||||
|
||||
void FreeEnvironment(Environment* env) {
|
||||
env->RunCleanup();
|
||||
delete env;
|
||||
}
|
||||
|
||||
Environment* GetCurrentEnvironment(Local<Context> context) {
|
||||
return Environment::GetCurrent(context);
|
||||
}
|
||||
|
||||
MultiIsolatePlatform* GetMainThreadMultiIsolatePlatform() {
|
||||
return per_process::v8_platform.Platform();
|
||||
}
|
||||
|
||||
MultiIsolatePlatform* CreatePlatform(
|
||||
int thread_pool_size,
|
||||
node::tracing::TracingController* tracing_controller) {
|
||||
return new NodePlatform(thread_pool_size, tracing_controller);
|
||||
}
|
||||
|
||||
MultiIsolatePlatform* InitializeV8Platform(int thread_pool_size) {
|
||||
per_process::v8_platform.Initialize(thread_pool_size);
|
||||
return per_process::v8_platform.Platform();
|
||||
}
|
||||
|
||||
void FreePlatform(MultiIsolatePlatform* platform) {
|
||||
delete platform;
|
||||
}
|
||||
|
||||
Local<Context> NewContext(Isolate* isolate,
|
||||
Local<ObjectTemplate> object_template) {
|
||||
auto context = Context::New(isolate, nullptr, object_template);
|
||||
if (context.IsEmpty()) return context;
|
||||
HandleScope handle_scope(isolate);
|
||||
|
||||
context->SetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration,
|
||||
True(isolate));
|
||||
|
||||
{
|
||||
// Run lib/internal/per_context.js
|
||||
Context::Scope context_scope(context);
|
||||
|
||||
std::vector<Local<String>> parameters = {
|
||||
FIXED_ONE_BYTE_STRING(isolate, "global")};
|
||||
Local<Value> arguments[] = {context->Global()};
|
||||
MaybeLocal<Function> maybe_fn =
|
||||
per_process::native_module_loader.LookupAndCompile(
|
||||
context, "internal/per_context", ¶meters, nullptr);
|
||||
if (maybe_fn.IsEmpty()) {
|
||||
return Local<Context>();
|
||||
}
|
||||
Local<Function> fn = maybe_fn.ToLocalChecked();
|
||||
MaybeLocal<Value> result =
|
||||
fn->Call(context, Undefined(isolate), arraysize(arguments), arguments);
|
||||
// Execution failed during context creation.
|
||||
// TODO(joyeecheung): deprecate this signature and return a MaybeLocal.
|
||||
if (result.IsEmpty()) {
|
||||
return Local<Context>();
|
||||
}
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
uv_loop_t* GetCurrentEventLoop(Isolate* isolate) {
|
||||
HandleScope handle_scope(isolate);
|
||||
Local<Context> context = isolate->GetCurrentContext();
|
||||
if (context.IsEmpty()) return nullptr;
|
||||
Environment* env = Environment::GetCurrent(context);
|
||||
if (env == nullptr) return nullptr;
|
||||
return env->event_loop();
|
||||
}
|
||||
|
||||
} // namespace node
|
@ -12,6 +12,7 @@
|
||||
namespace node {
|
||||
|
||||
using v8::Exception;
|
||||
using v8::HandleScope;
|
||||
using v8::Integer;
|
||||
using v8::Isolate;
|
||||
using v8::Local;
|
||||
@ -228,4 +229,17 @@ Local<Value> WinapiErrnoException(Isolate* isolate,
|
||||
}
|
||||
#endif
|
||||
|
||||
void FatalException(Isolate* isolate, const v8::TryCatch& try_catch) {
|
||||
// If we try to print out a termination exception, we'd just get 'null',
|
||||
// so just crashing here with that information seems like a better idea,
|
||||
// and in particular it seems like we should handle terminations at the call
|
||||
// site for this function rather than by printing them out somewhere.
|
||||
CHECK(!try_catch.HasTerminated());
|
||||
|
||||
HandleScope scope(isolate);
|
||||
if (!try_catch.IsVerbose()) {
|
||||
FatalException(isolate, try_catch.Exception(), try_catch.Message());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace node
|
149
src/api/hooks.cc
Normal file
149
src/api/hooks.cc
Normal file
@ -0,0 +1,149 @@
|
||||
#include "env-inl.h"
|
||||
#include "node.h"
|
||||
#include "node_process.h"
|
||||
#include "async_wrap.h"
|
||||
|
||||
namespace node {
|
||||
|
||||
using v8::Context;
|
||||
using v8::HandleScope;
|
||||
using v8::Integer;
|
||||
using v8::Isolate;
|
||||
using v8::Local;
|
||||
using v8::Object;
|
||||
using v8::String;
|
||||
using v8::Value;
|
||||
using v8::NewStringType;
|
||||
|
||||
void RunAtExit(Environment* env) {
|
||||
env->RunAtExitCallbacks();
|
||||
}
|
||||
|
||||
void AtExit(void (*cb)(void* arg), void* arg) {
|
||||
auto env = Environment::GetThreadLocalEnv();
|
||||
AtExit(env, cb, arg);
|
||||
}
|
||||
|
||||
void AtExit(Environment* env, void (*cb)(void* arg), void* arg) {
|
||||
CHECK_NOT_NULL(env);
|
||||
env->AtExit(cb, arg);
|
||||
}
|
||||
|
||||
void EmitBeforeExit(Environment* env) {
|
||||
HandleScope handle_scope(env->isolate());
|
||||
Context::Scope context_scope(env->context());
|
||||
Local<Value> exit_code = env->process_object()
|
||||
->Get(env->context(), env->exit_code_string())
|
||||
.ToLocalChecked()
|
||||
->ToInteger(env->context())
|
||||
.ToLocalChecked();
|
||||
ProcessEmit(env, "beforeExit", exit_code).ToLocalChecked();
|
||||
}
|
||||
|
||||
int EmitExit(Environment* env) {
|
||||
// process.emit('exit')
|
||||
HandleScope handle_scope(env->isolate());
|
||||
Context::Scope context_scope(env->context());
|
||||
Local<Object> process_object = env->process_object();
|
||||
process_object
|
||||
->Set(env->context(),
|
||||
FIXED_ONE_BYTE_STRING(env->isolate(), "_exiting"),
|
||||
True(env->isolate()))
|
||||
.FromJust();
|
||||
|
||||
Local<String> exit_code = env->exit_code_string();
|
||||
int code = process_object->Get(env->context(), exit_code)
|
||||
.ToLocalChecked()
|
||||
->Int32Value(env->context())
|
||||
.ToChecked();
|
||||
ProcessEmit(env, "exit", Integer::New(env->isolate(), code));
|
||||
|
||||
// Reload exit code, it may be changed by `emit('exit')`
|
||||
return process_object->Get(env->context(), exit_code)
|
||||
.ToLocalChecked()
|
||||
->Int32Value(env->context())
|
||||
.ToChecked();
|
||||
}
|
||||
|
||||
void AddPromiseHook(Isolate* isolate, promise_hook_func fn, void* arg) {
|
||||
Environment* env = Environment::GetCurrent(isolate);
|
||||
CHECK_NOT_NULL(env);
|
||||
env->AddPromiseHook(fn, arg);
|
||||
}
|
||||
|
||||
void AddEnvironmentCleanupHook(Isolate* isolate,
|
||||
void (*fun)(void* arg),
|
||||
void* arg) {
|
||||
Environment* env = Environment::GetCurrent(isolate);
|
||||
CHECK_NOT_NULL(env);
|
||||
env->AddCleanupHook(fun, arg);
|
||||
}
|
||||
|
||||
void RemoveEnvironmentCleanupHook(Isolate* isolate,
|
||||
void (*fun)(void* arg),
|
||||
void* arg) {
|
||||
Environment* env = Environment::GetCurrent(isolate);
|
||||
CHECK_NOT_NULL(env);
|
||||
env->RemoveCleanupHook(fun, arg);
|
||||
}
|
||||
|
||||
async_id AsyncHooksGetExecutionAsyncId(Isolate* isolate) {
|
||||
// Environment::GetCurrent() allocates a Local<> handle.
|
||||
HandleScope handle_scope(isolate);
|
||||
Environment* env = Environment::GetCurrent(isolate);
|
||||
if (env == nullptr) return -1;
|
||||
return env->execution_async_id();
|
||||
}
|
||||
|
||||
async_id AsyncHooksGetTriggerAsyncId(Isolate* isolate) {
|
||||
// Environment::GetCurrent() allocates a Local<> handle.
|
||||
HandleScope handle_scope(isolate);
|
||||
Environment* env = Environment::GetCurrent(isolate);
|
||||
if (env == nullptr) return -1;
|
||||
return env->trigger_async_id();
|
||||
}
|
||||
|
||||
|
||||
async_context EmitAsyncInit(Isolate* isolate,
|
||||
Local<Object> resource,
|
||||
const char* name,
|
||||
async_id trigger_async_id) {
|
||||
HandleScope handle_scope(isolate);
|
||||
Local<String> type =
|
||||
String::NewFromUtf8(isolate, name, NewStringType::kInternalized)
|
||||
.ToLocalChecked();
|
||||
return EmitAsyncInit(isolate, resource, type, trigger_async_id);
|
||||
}
|
||||
|
||||
async_context EmitAsyncInit(Isolate* isolate,
|
||||
Local<Object> resource,
|
||||
Local<String> name,
|
||||
async_id trigger_async_id) {
|
||||
HandleScope handle_scope(isolate);
|
||||
Environment* env = Environment::GetCurrent(isolate);
|
||||
CHECK_NOT_NULL(env);
|
||||
|
||||
// Initialize async context struct
|
||||
if (trigger_async_id == -1)
|
||||
trigger_async_id = env->get_default_trigger_async_id();
|
||||
|
||||
async_context context = {
|
||||
env->new_async_id(), // async_id_
|
||||
trigger_async_id // trigger_async_id_
|
||||
};
|
||||
|
||||
// Run init hooks
|
||||
AsyncWrap::EmitAsyncInit(env, resource, name, context.async_id,
|
||||
context.trigger_async_id);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
void EmitAsyncDestroy(Isolate* isolate, async_context asyncContext) {
|
||||
// Environment::GetCurrent() allocates a Local<> handle.
|
||||
HandleScope handle_scope(isolate);
|
||||
AsyncWrap::EmitDestroy(
|
||||
Environment::GetCurrent(isolate), asyncContext.async_id);
|
||||
}
|
||||
|
||||
} // namespace node
|
170
src/api/utils.cc
Normal file
170
src/api/utils.cc
Normal file
@ -0,0 +1,170 @@
|
||||
#include "node.h"
|
||||
#include "node_internals.h"
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
namespace node {
|
||||
|
||||
const char* signo_string(int signo) {
|
||||
#define SIGNO_CASE(e) \
|
||||
case e: \
|
||||
return #e;
|
||||
switch (signo) {
|
||||
#ifdef SIGHUP
|
||||
SIGNO_CASE(SIGHUP);
|
||||
#endif
|
||||
|
||||
#ifdef SIGINT
|
||||
SIGNO_CASE(SIGINT);
|
||||
#endif
|
||||
|
||||
#ifdef SIGQUIT
|
||||
SIGNO_CASE(SIGQUIT);
|
||||
#endif
|
||||
|
||||
#ifdef SIGILL
|
||||
SIGNO_CASE(SIGILL);
|
||||
#endif
|
||||
|
||||
#ifdef SIGTRAP
|
||||
SIGNO_CASE(SIGTRAP);
|
||||
#endif
|
||||
|
||||
#ifdef SIGABRT
|
||||
SIGNO_CASE(SIGABRT);
|
||||
#endif
|
||||
|
||||
#ifdef SIGIOT
|
||||
#if SIGABRT != SIGIOT
|
||||
SIGNO_CASE(SIGIOT);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef SIGBUS
|
||||
SIGNO_CASE(SIGBUS);
|
||||
#endif
|
||||
|
||||
#ifdef SIGFPE
|
||||
SIGNO_CASE(SIGFPE);
|
||||
#endif
|
||||
|
||||
#ifdef SIGKILL
|
||||
SIGNO_CASE(SIGKILL);
|
||||
#endif
|
||||
|
||||
#ifdef SIGUSR1
|
||||
SIGNO_CASE(SIGUSR1);
|
||||
#endif
|
||||
|
||||
#ifdef SIGSEGV
|
||||
SIGNO_CASE(SIGSEGV);
|
||||
#endif
|
||||
|
||||
#ifdef SIGUSR2
|
||||
SIGNO_CASE(SIGUSR2);
|
||||
#endif
|
||||
|
||||
#ifdef SIGPIPE
|
||||
SIGNO_CASE(SIGPIPE);
|
||||
#endif
|
||||
|
||||
#ifdef SIGALRM
|
||||
SIGNO_CASE(SIGALRM);
|
||||
#endif
|
||||
|
||||
SIGNO_CASE(SIGTERM);
|
||||
|
||||
#ifdef SIGCHLD
|
||||
SIGNO_CASE(SIGCHLD);
|
||||
#endif
|
||||
|
||||
#ifdef SIGSTKFLT
|
||||
SIGNO_CASE(SIGSTKFLT);
|
||||
#endif
|
||||
|
||||
#ifdef SIGCONT
|
||||
SIGNO_CASE(SIGCONT);
|
||||
#endif
|
||||
|
||||
#ifdef SIGSTOP
|
||||
SIGNO_CASE(SIGSTOP);
|
||||
#endif
|
||||
|
||||
#ifdef SIGTSTP
|
||||
SIGNO_CASE(SIGTSTP);
|
||||
#endif
|
||||
|
||||
#ifdef SIGBREAK
|
||||
SIGNO_CASE(SIGBREAK);
|
||||
#endif
|
||||
|
||||
#ifdef SIGTTIN
|
||||
SIGNO_CASE(SIGTTIN);
|
||||
#endif
|
||||
|
||||
#ifdef SIGTTOU
|
||||
SIGNO_CASE(SIGTTOU);
|
||||
#endif
|
||||
|
||||
#ifdef SIGURG
|
||||
SIGNO_CASE(SIGURG);
|
||||
#endif
|
||||
|
||||
#ifdef SIGXCPU
|
||||
SIGNO_CASE(SIGXCPU);
|
||||
#endif
|
||||
|
||||
#ifdef SIGXFSZ
|
||||
SIGNO_CASE(SIGXFSZ);
|
||||
#endif
|
||||
|
||||
#ifdef SIGVTALRM
|
||||
SIGNO_CASE(SIGVTALRM);
|
||||
#endif
|
||||
|
||||
#ifdef SIGPROF
|
||||
SIGNO_CASE(SIGPROF);
|
||||
#endif
|
||||
|
||||
#ifdef SIGWINCH
|
||||
SIGNO_CASE(SIGWINCH);
|
||||
#endif
|
||||
|
||||
#ifdef SIGIO
|
||||
SIGNO_CASE(SIGIO);
|
||||
#endif
|
||||
|
||||
#ifdef SIGPOLL
|
||||
#if SIGPOLL != SIGIO
|
||||
SIGNO_CASE(SIGPOLL);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef SIGLOST
|
||||
#if SIGLOST != SIGABRT
|
||||
SIGNO_CASE(SIGLOST);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef SIGPWR
|
||||
#if SIGPWR != SIGLOST
|
||||
SIGNO_CASE(SIGPWR);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef SIGINFO
|
||||
#if !defined(SIGPWR) || SIGINFO != SIGPWR
|
||||
SIGNO_CASE(SIGINFO);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef SIGSYS
|
||||
SIGNO_CASE(SIGSYS);
|
||||
#endif
|
||||
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace node
|
@ -39,7 +39,6 @@ using v8::Integer;
|
||||
using v8::Isolate;
|
||||
using v8::Local;
|
||||
using v8::MaybeLocal;
|
||||
using v8::NewStringType;
|
||||
using v8::Number;
|
||||
using v8::Object;
|
||||
using v8::ObjectTemplate;
|
||||
@ -688,70 +687,6 @@ MaybeLocal<Value> AsyncWrap::MakeCallback(const Local<Function> cb,
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Public C++ embedder API */
|
||||
|
||||
|
||||
async_id AsyncHooksGetExecutionAsyncId(Isolate* isolate) {
|
||||
// Environment::GetCurrent() allocates a Local<> handle.
|
||||
HandleScope handle_scope(isolate);
|
||||
Environment* env = Environment::GetCurrent(isolate);
|
||||
if (env == nullptr) return -1;
|
||||
return env->execution_async_id();
|
||||
}
|
||||
|
||||
|
||||
async_id AsyncHooksGetTriggerAsyncId(Isolate* isolate) {
|
||||
// Environment::GetCurrent() allocates a Local<> handle.
|
||||
HandleScope handle_scope(isolate);
|
||||
Environment* env = Environment::GetCurrent(isolate);
|
||||
if (env == nullptr) return -1;
|
||||
return env->trigger_async_id();
|
||||
}
|
||||
|
||||
|
||||
async_context EmitAsyncInit(Isolate* isolate,
|
||||
Local<Object> resource,
|
||||
const char* name,
|
||||
async_id trigger_async_id) {
|
||||
HandleScope handle_scope(isolate);
|
||||
Local<String> type =
|
||||
String::NewFromUtf8(isolate, name, NewStringType::kInternalized)
|
||||
.ToLocalChecked();
|
||||
return EmitAsyncInit(isolate, resource, type, trigger_async_id);
|
||||
}
|
||||
|
||||
async_context EmitAsyncInit(Isolate* isolate,
|
||||
Local<Object> resource,
|
||||
Local<String> name,
|
||||
async_id trigger_async_id) {
|
||||
HandleScope handle_scope(isolate);
|
||||
Environment* env = Environment::GetCurrent(isolate);
|
||||
CHECK_NOT_NULL(env);
|
||||
|
||||
// Initialize async context struct
|
||||
if (trigger_async_id == -1)
|
||||
trigger_async_id = env->get_default_trigger_async_id();
|
||||
|
||||
async_context context = {
|
||||
env->new_async_id(), // async_id_
|
||||
trigger_async_id // trigger_async_id_
|
||||
};
|
||||
|
||||
// Run init hooks
|
||||
AsyncWrap::EmitAsyncInit(env, resource, name, context.async_id,
|
||||
context.trigger_async_id);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
void EmitAsyncDestroy(Isolate* isolate, async_context asyncContext) {
|
||||
// Environment::GetCurrent() allocates a Local<> handle.
|
||||
HandleScope handle_scope(isolate);
|
||||
AsyncWrap::EmitDestroy(
|
||||
Environment::GetCurrent(isolate), asyncContext.async_id);
|
||||
}
|
||||
|
||||
std::string AsyncWrap::MemoryInfoName() const {
|
||||
return provider_names[provider_type()];
|
||||
}
|
||||
|
456
src/node.cc
456
src/node.cc
@ -119,32 +119,21 @@ using v8::Function;
|
||||
using v8::FunctionCallbackInfo;
|
||||
using v8::HandleScope;
|
||||
using v8::Int32;
|
||||
using v8::Integer;
|
||||
using v8::Isolate;
|
||||
using v8::Just;
|
||||
using v8::Local;
|
||||
using v8::Locker;
|
||||
using v8::Maybe;
|
||||
using v8::MaybeLocal;
|
||||
using v8::Message;
|
||||
using v8::MicrotasksPolicy;
|
||||
using v8::Object;
|
||||
using v8::ObjectTemplate;
|
||||
using v8::Script;
|
||||
using v8::ScriptOrigin;
|
||||
using v8::SealHandleScope;
|
||||
using v8::String;
|
||||
using v8::TracingController;
|
||||
using v8::Undefined;
|
||||
using v8::V8;
|
||||
using v8::Value;
|
||||
|
||||
namespace per_process {
|
||||
// Tells whether --prof is passed.
|
||||
// TODO(joyeecheung): move env->options()->prof_process to
|
||||
// per_process::cli_options.prof_process and use that instead.
|
||||
static bool v8_is_profiling = false;
|
||||
|
||||
// TODO(joyeecheung): these are no longer necessary. Remove them.
|
||||
// See: https://github.com/nodejs/node/pull/25302#discussion_r244924196
|
||||
// Isolate on the main thread
|
||||
@ -163,6 +152,8 @@ bool v8_initialized = false;
|
||||
// node_internals.h
|
||||
// process-relative uptime base, initialized at start-up
|
||||
double prog_start_time;
|
||||
// Tells whether --prof is passed.
|
||||
bool v8_is_profiling = false;
|
||||
|
||||
// node_v8_platform-inl.h
|
||||
struct V8Platform v8_platform;
|
||||
@ -172,209 +163,6 @@ struct V8Platform v8_platform;
|
||||
static const unsigned kMaxSignal = 32;
|
||||
#endif
|
||||
|
||||
const char* signo_string(int signo) {
|
||||
#define SIGNO_CASE(e) case e: return #e;
|
||||
switch (signo) {
|
||||
#ifdef SIGHUP
|
||||
SIGNO_CASE(SIGHUP);
|
||||
#endif
|
||||
|
||||
#ifdef SIGINT
|
||||
SIGNO_CASE(SIGINT);
|
||||
#endif
|
||||
|
||||
#ifdef SIGQUIT
|
||||
SIGNO_CASE(SIGQUIT);
|
||||
#endif
|
||||
|
||||
#ifdef SIGILL
|
||||
SIGNO_CASE(SIGILL);
|
||||
#endif
|
||||
|
||||
#ifdef SIGTRAP
|
||||
SIGNO_CASE(SIGTRAP);
|
||||
#endif
|
||||
|
||||
#ifdef SIGABRT
|
||||
SIGNO_CASE(SIGABRT);
|
||||
#endif
|
||||
|
||||
#ifdef SIGIOT
|
||||
# if SIGABRT != SIGIOT
|
||||
SIGNO_CASE(SIGIOT);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef SIGBUS
|
||||
SIGNO_CASE(SIGBUS);
|
||||
#endif
|
||||
|
||||
#ifdef SIGFPE
|
||||
SIGNO_CASE(SIGFPE);
|
||||
#endif
|
||||
|
||||
#ifdef SIGKILL
|
||||
SIGNO_CASE(SIGKILL);
|
||||
#endif
|
||||
|
||||
#ifdef SIGUSR1
|
||||
SIGNO_CASE(SIGUSR1);
|
||||
#endif
|
||||
|
||||
#ifdef SIGSEGV
|
||||
SIGNO_CASE(SIGSEGV);
|
||||
#endif
|
||||
|
||||
#ifdef SIGUSR2
|
||||
SIGNO_CASE(SIGUSR2);
|
||||
#endif
|
||||
|
||||
#ifdef SIGPIPE
|
||||
SIGNO_CASE(SIGPIPE);
|
||||
#endif
|
||||
|
||||
#ifdef SIGALRM
|
||||
SIGNO_CASE(SIGALRM);
|
||||
#endif
|
||||
|
||||
SIGNO_CASE(SIGTERM);
|
||||
|
||||
#ifdef SIGCHLD
|
||||
SIGNO_CASE(SIGCHLD);
|
||||
#endif
|
||||
|
||||
#ifdef SIGSTKFLT
|
||||
SIGNO_CASE(SIGSTKFLT);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef SIGCONT
|
||||
SIGNO_CASE(SIGCONT);
|
||||
#endif
|
||||
|
||||
#ifdef SIGSTOP
|
||||
SIGNO_CASE(SIGSTOP);
|
||||
#endif
|
||||
|
||||
#ifdef SIGTSTP
|
||||
SIGNO_CASE(SIGTSTP);
|
||||
#endif
|
||||
|
||||
#ifdef SIGBREAK
|
||||
SIGNO_CASE(SIGBREAK);
|
||||
#endif
|
||||
|
||||
#ifdef SIGTTIN
|
||||
SIGNO_CASE(SIGTTIN);
|
||||
#endif
|
||||
|
||||
#ifdef SIGTTOU
|
||||
SIGNO_CASE(SIGTTOU);
|
||||
#endif
|
||||
|
||||
#ifdef SIGURG
|
||||
SIGNO_CASE(SIGURG);
|
||||
#endif
|
||||
|
||||
#ifdef SIGXCPU
|
||||
SIGNO_CASE(SIGXCPU);
|
||||
#endif
|
||||
|
||||
#ifdef SIGXFSZ
|
||||
SIGNO_CASE(SIGXFSZ);
|
||||
#endif
|
||||
|
||||
#ifdef SIGVTALRM
|
||||
SIGNO_CASE(SIGVTALRM);
|
||||
#endif
|
||||
|
||||
#ifdef SIGPROF
|
||||
SIGNO_CASE(SIGPROF);
|
||||
#endif
|
||||
|
||||
#ifdef SIGWINCH
|
||||
SIGNO_CASE(SIGWINCH);
|
||||
#endif
|
||||
|
||||
#ifdef SIGIO
|
||||
SIGNO_CASE(SIGIO);
|
||||
#endif
|
||||
|
||||
#ifdef SIGPOLL
|
||||
# if SIGPOLL != SIGIO
|
||||
SIGNO_CASE(SIGPOLL);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef SIGLOST
|
||||
# if SIGLOST != SIGABRT
|
||||
SIGNO_CASE(SIGLOST);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef SIGPWR
|
||||
# if SIGPWR != SIGLOST
|
||||
SIGNO_CASE(SIGPWR);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef SIGINFO
|
||||
# if !defined(SIGPWR) || SIGINFO != SIGPWR
|
||||
SIGNO_CASE(SIGINFO);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef SIGSYS
|
||||
SIGNO_CASE(SIGSYS);
|
||||
#endif
|
||||
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
|
||||
void* ArrayBufferAllocator::Allocate(size_t size) {
|
||||
if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers)
|
||||
return UncheckedCalloc(size);
|
||||
else
|
||||
return UncheckedMalloc(size);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool ShouldAbortOnUncaughtException(Isolate* isolate) {
|
||||
HandleScope scope(isolate);
|
||||
Environment* env = Environment::GetCurrent(isolate);
|
||||
return env != nullptr &&
|
||||
env->should_abort_on_uncaught_toggle()[0] &&
|
||||
!env->inside_should_not_abort_on_uncaught_scope();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
void AddPromiseHook(Isolate* isolate, promise_hook_func fn, void* arg) {
|
||||
Environment* env = Environment::GetCurrent(isolate);
|
||||
CHECK_NOT_NULL(env);
|
||||
env->AddPromiseHook(fn, arg);
|
||||
}
|
||||
|
||||
void AddEnvironmentCleanupHook(Isolate* isolate,
|
||||
void (*fun)(void* arg),
|
||||
void* arg) {
|
||||
Environment* env = Environment::GetCurrent(isolate);
|
||||
CHECK_NOT_NULL(env);
|
||||
env->AddCleanupHook(fun, arg);
|
||||
}
|
||||
|
||||
|
||||
void RemoveEnvironmentCleanupHook(Isolate* isolate,
|
||||
void (*fun)(void* arg),
|
||||
void* arg) {
|
||||
Environment* env = Environment::GetCurrent(isolate);
|
||||
CHECK_NOT_NULL(env);
|
||||
env->RemoveCleanupHook(fun, arg);
|
||||
}
|
||||
|
||||
static void WaitForInspectorDisconnect(Environment* env) {
|
||||
#if HAVE_INSPECTOR
|
||||
if (env->inspector_agent()->IsActive()) {
|
||||
@ -402,33 +190,6 @@ void Exit(const FunctionCallbackInfo<Value>& args) {
|
||||
env->Exit(code);
|
||||
}
|
||||
|
||||
static void OnMessage(Local<Message> message, Local<Value> error) {
|
||||
Isolate* isolate = message->GetIsolate();
|
||||
switch (message->ErrorLevel()) {
|
||||
case Isolate::MessageErrorLevel::kMessageWarning: {
|
||||
Environment* env = Environment::GetCurrent(isolate);
|
||||
if (!env) {
|
||||
break;
|
||||
}
|
||||
Utf8Value filename(isolate,
|
||||
message->GetScriptOrigin().ResourceName());
|
||||
// (filename):(line) (message)
|
||||
std::stringstream warning;
|
||||
warning << *filename;
|
||||
warning << ":";
|
||||
warning << message->GetLineNumber(env->context()).FromMaybe(-1);
|
||||
warning << " ";
|
||||
v8::String::Utf8Value msg(isolate, message->Get());
|
||||
warning << *msg;
|
||||
USE(ProcessEmitWarningGeneric(env, warning.str().c_str(), "V8"));
|
||||
break;
|
||||
}
|
||||
case Isolate::MessageErrorLevel::kMessageError:
|
||||
FatalException(isolate, error, message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SignalExit(int signo) {
|
||||
uv_tty_reset_mode();
|
||||
#ifdef __FreeBSD__
|
||||
@ -969,35 +730,6 @@ void Init(int* argc,
|
||||
argv[i] = strdup(argv_[i].c_str());
|
||||
}
|
||||
|
||||
void RunAtExit(Environment* env) {
|
||||
env->RunAtExitCallbacks();
|
||||
}
|
||||
|
||||
|
||||
uv_loop_t* GetCurrentEventLoop(Isolate* isolate) {
|
||||
HandleScope handle_scope(isolate);
|
||||
Local<Context> context = isolate->GetCurrentContext();
|
||||
if (context.IsEmpty())
|
||||
return nullptr;
|
||||
Environment* env = Environment::GetCurrent(context);
|
||||
if (env == nullptr)
|
||||
return nullptr;
|
||||
return env->event_loop();
|
||||
}
|
||||
|
||||
|
||||
void AtExit(void (*cb)(void* arg), void* arg) {
|
||||
auto env = Environment::GetThreadLocalEnv();
|
||||
AtExit(env, cb, arg);
|
||||
}
|
||||
|
||||
|
||||
void AtExit(Environment* env, void (*cb)(void* arg), void* arg) {
|
||||
CHECK_NOT_NULL(env);
|
||||
env->AtExit(cb, arg);
|
||||
}
|
||||
|
||||
|
||||
void RunBeforeExit(Environment* env) {
|
||||
env->RunBeforeExitCallbacks();
|
||||
|
||||
@ -1005,155 +737,6 @@ void RunBeforeExit(Environment* env) {
|
||||
EmitBeforeExit(env);
|
||||
}
|
||||
|
||||
|
||||
void EmitBeforeExit(Environment* env) {
|
||||
HandleScope handle_scope(env->isolate());
|
||||
Context::Scope context_scope(env->context());
|
||||
Local<Value> exit_code = env->process_object()
|
||||
->Get(env->context(), env->exit_code_string())
|
||||
.ToLocalChecked()
|
||||
->ToInteger(env->context())
|
||||
.ToLocalChecked();
|
||||
ProcessEmit(env, "beforeExit", exit_code).ToLocalChecked();
|
||||
}
|
||||
|
||||
int EmitExit(Environment* env) {
|
||||
// process.emit('exit')
|
||||
HandleScope handle_scope(env->isolate());
|
||||
Context::Scope context_scope(env->context());
|
||||
Local<Object> process_object = env->process_object();
|
||||
process_object->Set(env->context(),
|
||||
FIXED_ONE_BYTE_STRING(env->isolate(), "_exiting"),
|
||||
True(env->isolate())).FromJust();
|
||||
|
||||
Local<String> exit_code = env->exit_code_string();
|
||||
int code = process_object->Get(env->context(), exit_code).ToLocalChecked()
|
||||
->Int32Value(env->context()).ToChecked();
|
||||
ProcessEmit(env, "exit", Integer::New(env->isolate(), code));
|
||||
|
||||
// Reload exit code, it may be changed by `emit('exit')`
|
||||
return process_object->Get(env->context(), exit_code).ToLocalChecked()
|
||||
->Int32Value(env->context()).ToChecked();
|
||||
}
|
||||
|
||||
|
||||
ArrayBufferAllocator* CreateArrayBufferAllocator() {
|
||||
return new ArrayBufferAllocator();
|
||||
}
|
||||
|
||||
|
||||
void FreeArrayBufferAllocator(ArrayBufferAllocator* allocator) {
|
||||
delete allocator;
|
||||
}
|
||||
|
||||
|
||||
IsolateData* CreateIsolateData(
|
||||
Isolate* isolate,
|
||||
uv_loop_t* loop,
|
||||
MultiIsolatePlatform* platform,
|
||||
ArrayBufferAllocator* allocator) {
|
||||
return new IsolateData(
|
||||
isolate,
|
||||
loop,
|
||||
platform,
|
||||
allocator != nullptr ? allocator->zero_fill_field() : nullptr);
|
||||
}
|
||||
|
||||
|
||||
void FreeIsolateData(IsolateData* isolate_data) {
|
||||
delete isolate_data;
|
||||
}
|
||||
|
||||
|
||||
Environment* CreateEnvironment(IsolateData* isolate_data,
|
||||
Local<Context> context,
|
||||
int argc,
|
||||
const char* const* argv,
|
||||
int exec_argc,
|
||||
const char* const* exec_argv) {
|
||||
Isolate* isolate = context->GetIsolate();
|
||||
HandleScope handle_scope(isolate);
|
||||
Context::Scope context_scope(context);
|
||||
// TODO(addaleax): This is a much better place for parsing per-Environment
|
||||
// options than the global parse call.
|
||||
std::vector<std::string> args(argv, argv + argc);
|
||||
std::vector<std::string> exec_args(exec_argv, exec_argv + exec_argc);
|
||||
Environment* env = new Environment(isolate_data, context);
|
||||
env->Start(per_process::v8_is_profiling);
|
||||
env->ProcessCliArgs(args, exec_args);
|
||||
return env;
|
||||
}
|
||||
|
||||
|
||||
void FreeEnvironment(Environment* env) {
|
||||
env->RunCleanup();
|
||||
delete env;
|
||||
}
|
||||
|
||||
|
||||
Environment* GetCurrentEnvironment(Local<Context> context) {
|
||||
return Environment::GetCurrent(context);
|
||||
}
|
||||
|
||||
|
||||
MultiIsolatePlatform* GetMainThreadMultiIsolatePlatform() {
|
||||
return per_process::v8_platform.Platform();
|
||||
}
|
||||
|
||||
|
||||
MultiIsolatePlatform* CreatePlatform(
|
||||
int thread_pool_size,
|
||||
node::tracing::TracingController* tracing_controller) {
|
||||
return new NodePlatform(thread_pool_size, tracing_controller);
|
||||
}
|
||||
|
||||
|
||||
MultiIsolatePlatform* InitializeV8Platform(int thread_pool_size) {
|
||||
per_process::v8_platform.Initialize(thread_pool_size);
|
||||
return per_process::v8_platform.Platform();
|
||||
}
|
||||
|
||||
|
||||
void FreePlatform(MultiIsolatePlatform* platform) {
|
||||
delete platform;
|
||||
}
|
||||
|
||||
Local<Context> NewContext(Isolate* isolate,
|
||||
Local<ObjectTemplate> object_template) {
|
||||
Local<Context> context = Context::New(isolate, nullptr, object_template);
|
||||
if (context.IsEmpty()) return context;
|
||||
HandleScope handle_scope(isolate);
|
||||
|
||||
context->SetEmbedderData(
|
||||
ContextEmbedderIndex::kAllowWasmCodeGeneration, True(isolate));
|
||||
|
||||
{
|
||||
// Run lib/internal/per_context.js
|
||||
Context::Scope context_scope(context);
|
||||
|
||||
std::vector<Local<String>> parameters = {
|
||||
FIXED_ONE_BYTE_STRING(isolate, "global")};
|
||||
Local<Value> arguments[] = {context->Global()};
|
||||
MaybeLocal<Function> maybe_fn =
|
||||
per_process::native_module_loader.LookupAndCompile(
|
||||
context, "internal/per_context", ¶meters, nullptr);
|
||||
if (maybe_fn.IsEmpty()) {
|
||||
return Local<Context>();
|
||||
}
|
||||
Local<Function> fn = maybe_fn.ToLocalChecked();
|
||||
MaybeLocal<Value> result =
|
||||
fn->Call(context, Undefined(isolate), arraysize(arguments), arguments);
|
||||
// Execution failed during context creation.
|
||||
// TODO(joyeecheung): deprecate this signature and return a MaybeLocal.
|
||||
if (result.IsEmpty()) {
|
||||
return Local<Context>();
|
||||
}
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
inline int Start(Isolate* isolate, IsolateData* isolate_data,
|
||||
const std::vector<std::string>& args,
|
||||
const std::vector<std::string>& exec_args) {
|
||||
@ -1235,41 +818,6 @@ inline int Start(Isolate* isolate, IsolateData* isolate_data,
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
bool AllowWasmCodeGenerationCallback(
|
||||
Local<Context> context, Local<String>) {
|
||||
Local<Value> wasm_code_gen =
|
||||
context->GetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration);
|
||||
return wasm_code_gen->IsUndefined() || wasm_code_gen->IsTrue();
|
||||
}
|
||||
|
||||
Isolate* NewIsolate(ArrayBufferAllocator* allocator, uv_loop_t* event_loop) {
|
||||
Isolate::CreateParams params;
|
||||
params.array_buffer_allocator = allocator;
|
||||
#ifdef NODE_ENABLE_VTUNE_PROFILING
|
||||
params.code_event_handler = vTune::GetVtuneCodeEventHandler();
|
||||
#endif
|
||||
|
||||
Isolate* isolate = Isolate::Allocate();
|
||||
if (isolate == nullptr)
|
||||
return nullptr;
|
||||
|
||||
// Register the isolate on the platform before the isolate gets initialized,
|
||||
// so that the isolate can access the platform during initialization.
|
||||
per_process::v8_platform.Platform()->RegisterIsolate(isolate, event_loop);
|
||||
Isolate::Initialize(isolate, params);
|
||||
|
||||
isolate->AddMessageListenerWithErrorLevel(OnMessage,
|
||||
Isolate::MessageErrorLevel::kMessageError |
|
||||
Isolate::MessageErrorLevel::kMessageWarning);
|
||||
isolate->SetAbortOnUncaughtExceptionCallback(ShouldAbortOnUncaughtException);
|
||||
isolate->SetMicrotasksPolicy(MicrotasksPolicy::kExplicit);
|
||||
isolate->SetFatalErrorHandler(OnFatalError);
|
||||
isolate->SetAllowWasmCodeGenerationCallback(AllowWasmCodeGenerationCallback);
|
||||
v8::CpuProfiler::UseDetailedSourcePositionsForProfiling(isolate);
|
||||
|
||||
return isolate;
|
||||
}
|
||||
|
||||
inline int Start(uv_loop_t* event_loop,
|
||||
const std::vector<std::string>& args,
|
||||
const std::vector<std::string>& exec_args) {
|
||||
|
@ -763,19 +763,6 @@ void FatalException(Isolate* isolate,
|
||||
}
|
||||
}
|
||||
|
||||
void FatalException(Isolate* isolate, const v8::TryCatch& try_catch) {
|
||||
// If we try to print out a termination exception, we'd just get 'null',
|
||||
// so just crashing here with that information seems like a better idea,
|
||||
// and in particular it seems like we should handle terminations at the call
|
||||
// site for this function rather than by printing them out somewhere.
|
||||
CHECK(!try_catch.HasTerminated());
|
||||
|
||||
HandleScope scope(isolate);
|
||||
if (!try_catch.IsVerbose()) {
|
||||
FatalException(isolate, try_catch.Exception(), try_catch.Message());
|
||||
}
|
||||
}
|
||||
|
||||
void FatalException(const FunctionCallbackInfo<Value>& args) {
|
||||
Isolate* isolate = args.GetIsolate();
|
||||
Environment* env = Environment::GetCurrent(isolate);
|
||||
|
@ -56,6 +56,7 @@ class NativeModuleLoader;
|
||||
namespace per_process {
|
||||
extern Mutex env_var_mutex;
|
||||
extern double prog_start_time;
|
||||
extern bool v8_is_profiling;
|
||||
} // namespace per_process
|
||||
|
||||
// Forward declaration
|
||||
|
Loading…
x
Reference in New Issue
Block a user