mirror of
https://github.com/nodejs/node.git
synced 2025-05-01 17:03:34 +00:00

- Instead of creating the console extensions eagerly during bootstrap and storing them on an object, wrap the code into a function to be called during `installAdditionalCommandLineAPI` only when the extensions are actually needed, which may not even happen if the user do not use the console in an inspector session, and does not need to happen during bootstrap unconditionally. - Simplify the console methods wrapping and move the `consoleFromVM` storage to `internal/util/inspector.js` PR-URL: https://github.com/nodejs/node/pull/25450 Reviewed-By: John-David Dalton <john.david.dalton@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
817 lines
26 KiB
JavaScript
817 lines
26 KiB
JavaScript
// Hello, and welcome to hacking node.js!
|
|
//
|
|
// This file is invoked by node::LoadEnvironment in src/node.cc, and is
|
|
// responsible for bootstrapping the node.js core. As special caution is given
|
|
// to the performance of the startup process, many dependencies are invoked
|
|
// lazily.
|
|
//
|
|
// Before this file is run, lib/internal/bootstrap/loaders.js gets run first
|
|
// to bootstrap the internal binding and module loaders, including
|
|
// process.binding(), process._linkedBinding(), internalBinding() and
|
|
// NativeModule. And then { internalBinding, NativeModule } will be passed
|
|
// into this bootstrapper to bootstrap Node.js core.
|
|
'use strict';
|
|
|
|
// This file is compiled as if it's wrapped in a function with arguments
|
|
// passed by node::LoadEnvironment()
|
|
/* global process, loaderExports, isMainThread */
|
|
|
|
const { internalBinding, NativeModule } = loaderExports;
|
|
|
|
const { getOptionValue } = NativeModule.require('internal/options');
|
|
const config = internalBinding('config');
|
|
|
|
function startup() {
|
|
setupTraceCategoryState();
|
|
|
|
setupProcessObject();
|
|
|
|
// TODO(joyeecheung): this does not have to done so early, any fatal errors
|
|
// thrown before user code execution should simply crash the process
|
|
// and we do not care about any clean up at that point. We don't care
|
|
// about emitting any events if the process crash upon bootstrap either.
|
|
{
|
|
const {
|
|
fatalException,
|
|
setUncaughtExceptionCaptureCallback,
|
|
hasUncaughtExceptionCaptureCallback
|
|
} = NativeModule.require('internal/process/execution');
|
|
|
|
process._fatalException = fatalException;
|
|
process.setUncaughtExceptionCaptureCallback =
|
|
setUncaughtExceptionCaptureCallback;
|
|
process.hasUncaughtExceptionCaptureCallback =
|
|
hasUncaughtExceptionCaptureCallback;
|
|
}
|
|
|
|
setupGlobalVariables();
|
|
|
|
// Bootstrappers for all threads, including worker threads and main thread
|
|
const perThreadSetup = NativeModule.require('internal/process/per_thread');
|
|
// Bootstrappers for the main thread only
|
|
let mainThreadSetup;
|
|
// Bootstrappers for the worker threads only
|
|
let workerThreadSetup;
|
|
if (isMainThread) {
|
|
mainThreadSetup = NativeModule.require(
|
|
'internal/process/main_thread_only'
|
|
);
|
|
} else {
|
|
workerThreadSetup = NativeModule.require(
|
|
'internal/process/worker_thread_only'
|
|
);
|
|
}
|
|
|
|
// process.config is serialized config.gypi
|
|
process.config = JSON.parse(internalBinding('native_module').config);
|
|
|
|
const rawMethods = internalBinding('process_methods');
|
|
// Set up methods and events on the process object for the main thread
|
|
if (isMainThread) {
|
|
// This depends on process being an event emitter
|
|
mainThreadSetup.setupSignalHandlers(internalBinding);
|
|
|
|
process.abort = rawMethods.abort;
|
|
const wrapped = mainThreadSetup.wrapProcessMethods(rawMethods);
|
|
process.umask = wrapped.umask;
|
|
process.chdir = wrapped.chdir;
|
|
|
|
// TODO(joyeecheung): deprecate and remove these underscore methods
|
|
process._debugProcess = rawMethods._debugProcess;
|
|
process._debugEnd = rawMethods._debugEnd;
|
|
process._startProfilerIdleNotifier =
|
|
rawMethods._startProfilerIdleNotifier;
|
|
process._stopProfilerIdleNotifier = rawMethods._stopProfilerIdleNotifier;
|
|
} else {
|
|
const wrapped = workerThreadSetup.wrapProcessMethods(rawMethods);
|
|
|
|
process.umask = wrapped.umask;
|
|
}
|
|
|
|
// Set up methods on the process object for all threads
|
|
{
|
|
process.cwd = rawMethods.cwd;
|
|
process.dlopen = rawMethods.dlopen;
|
|
process.uptime = rawMethods.uptime;
|
|
|
|
// TODO(joyeecheung): either remove them or make them public
|
|
process._getActiveRequests = rawMethods._getActiveRequests;
|
|
process._getActiveHandles = rawMethods._getActiveHandles;
|
|
|
|
// TODO(joyeecheung): remove these
|
|
process.reallyExit = rawMethods.reallyExit;
|
|
process._kill = rawMethods._kill;
|
|
|
|
const wrapped = perThreadSetup.wrapProcessMethods(rawMethods);
|
|
process._rawDebug = wrapped._rawDebug;
|
|
process.hrtime = wrapped.hrtime;
|
|
process.hrtime.bigint = wrapped.hrtimeBigInt;
|
|
process.cpuUsage = wrapped.cpuUsage;
|
|
process.memoryUsage = wrapped.memoryUsage;
|
|
process.kill = wrapped.kill;
|
|
process.exit = wrapped.exit;
|
|
}
|
|
|
|
const {
|
|
onWarning,
|
|
emitWarning
|
|
} = NativeModule.require('internal/process/warning');
|
|
if (!process.noProcessWarnings && process.env.NODE_NO_WARNINGS !== '1') {
|
|
process.on('warning', onWarning);
|
|
}
|
|
process.emitWarning = emitWarning;
|
|
|
|
const {
|
|
nextTick,
|
|
runNextTicks
|
|
} = NativeModule.require('internal/process/next_tick').setup();
|
|
|
|
process.nextTick = nextTick;
|
|
// Used to emulate a tick manually in the JS land.
|
|
// A better name for this function would be `runNextTicks` but
|
|
// it has been exposed to the process object so we keep this legacy name
|
|
// TODO(joyeecheung): either remove it or make it public
|
|
process._tickCallback = runNextTicks;
|
|
|
|
const credentials = internalBinding('credentials');
|
|
if (credentials.implementsPosixCredentials) {
|
|
process.getuid = credentials.getuid;
|
|
process.geteuid = credentials.geteuid;
|
|
process.getgid = credentials.getgid;
|
|
process.getegid = credentials.getegid;
|
|
process.getgroups = credentials.getgroups;
|
|
|
|
if (isMainThread) {
|
|
const wrapped = mainThreadSetup.wrapPosixCredentialSetters(credentials);
|
|
process.initgroups = wrapped.initgroups;
|
|
process.setgroups = wrapped.setgroups;
|
|
process.setegid = wrapped.setegid;
|
|
process.seteuid = wrapped.seteuid;
|
|
process.setgid = wrapped.setgid;
|
|
process.setuid = wrapped.setuid;
|
|
}
|
|
}
|
|
|
|
if (isMainThread) {
|
|
const { getStdout, getStdin, getStderr } =
|
|
NativeModule.require('internal/process/stdio').getMainThreadStdio();
|
|
setupProcessStdio(getStdout, getStdin, getStderr);
|
|
} else {
|
|
const { getStdout, getStdin, getStderr } =
|
|
workerThreadSetup.initializeWorkerStdio();
|
|
setupProcessStdio(getStdout, getStdin, getStderr);
|
|
}
|
|
|
|
if (config.hasInspector) {
|
|
const {
|
|
enable,
|
|
disable
|
|
} = NativeModule.require('internal/inspector_async_hook');
|
|
internalBinding('inspector').registerAsyncHook(enable, disable);
|
|
}
|
|
|
|
// If the process is spawned with env NODE_CHANNEL_FD, it's probably
|
|
// spawned by our child_process module, then initialize IPC.
|
|
// This attaches some internal event listeners and creates:
|
|
// process.send(), process.channel, process.connected,
|
|
// process.disconnect()
|
|
if (isMainThread && process.env.NODE_CHANNEL_FD) {
|
|
mainThreadSetup.setupChildProcessIpcChannel();
|
|
}
|
|
|
|
// TODO(joyeecheung): move this down further to get better snapshotting
|
|
if (getOptionValue('[has_experimental_policy]')) {
|
|
process.emitWarning('Policies are experimental.',
|
|
'ExperimentalWarning');
|
|
const experimentalPolicy = getOptionValue('--experimental-policy');
|
|
const { pathToFileURL, URL } = NativeModule.require('url');
|
|
// URL here as it is slightly different parsing
|
|
// no bare specifiers for now
|
|
let manifestURL;
|
|
if (NativeModule.require('path').isAbsolute(experimentalPolicy)) {
|
|
manifestURL = new URL(`file:///${experimentalPolicy}`);
|
|
} else {
|
|
const cwdURL = pathToFileURL(process.cwd());
|
|
cwdURL.pathname += '/';
|
|
manifestURL = new URL(experimentalPolicy, cwdURL);
|
|
}
|
|
const fs = NativeModule.require('fs');
|
|
const src = fs.readFileSync(manifestURL, 'utf8');
|
|
NativeModule.require('internal/process/policy')
|
|
.setup(src, manifestURL.href);
|
|
}
|
|
|
|
const browserGlobals = !process._noBrowserGlobals;
|
|
if (browserGlobals) {
|
|
setupGlobalTimeouts();
|
|
setupGlobalConsole();
|
|
setupGlobalURL();
|
|
setupGlobalEncoding();
|
|
setupQueueMicrotask();
|
|
}
|
|
|
|
setupDOMException();
|
|
|
|
// On OpenBSD process.execPath will be relative unless we
|
|
// get the full path before process.execPath is used.
|
|
if (process.platform === 'openbsd') {
|
|
const { realpathSync } = NativeModule.require('fs');
|
|
process.execPath = realpathSync.native(process.execPath);
|
|
}
|
|
|
|
Object.defineProperty(process, 'argv0', {
|
|
enumerable: true,
|
|
configurable: false,
|
|
value: process.argv[0]
|
|
});
|
|
process.argv[0] = process.execPath;
|
|
|
|
// Handle `--debug*` deprecation and invalidation.
|
|
if (process._invalidDebug) {
|
|
process.emitWarning(
|
|
'`node --debug` and `node --debug-brk` are invalid. ' +
|
|
'Please use `node --inspect` or `node --inspect-brk` instead.',
|
|
'DeprecationWarning', 'DEP0062', startup, true);
|
|
process.exit(9);
|
|
} else if (process._deprecatedDebugBrk) {
|
|
process.emitWarning(
|
|
'`node --inspect --debug-brk` is deprecated. ' +
|
|
'Please use `node --inspect-brk` instead.',
|
|
'DeprecationWarning', 'DEP0062', startup, true);
|
|
}
|
|
|
|
const { deprecate } = NativeModule.require('internal/util');
|
|
{
|
|
// Install legacy getters on the `util` binding for typechecking.
|
|
// TODO(addaleax): Turn into a full runtime deprecation.
|
|
const pendingDeprecation = getOptionValue('--pending-deprecation');
|
|
const utilBinding = internalBinding('util');
|
|
const types = NativeModule.require('internal/util/types');
|
|
for (const name of [
|
|
'isArrayBuffer', 'isArrayBufferView', 'isAsyncFunction',
|
|
'isDataView', 'isDate', 'isExternal', 'isMap', 'isMapIterator',
|
|
'isNativeError', 'isPromise', 'isRegExp', 'isSet', 'isSetIterator',
|
|
'isTypedArray', 'isUint8Array', 'isAnyArrayBuffer'
|
|
]) {
|
|
utilBinding[name] = pendingDeprecation ?
|
|
deprecate(types[name],
|
|
'Accessing native typechecking bindings of Node ' +
|
|
'directly is deprecated. ' +
|
|
`Please use \`util.types.${name}\` instead.`,
|
|
'DEP0103') :
|
|
types[name];
|
|
}
|
|
}
|
|
|
|
// process.allowedNodeEnvironmentFlags
|
|
Object.defineProperty(process, 'allowedNodeEnvironmentFlags', {
|
|
get() {
|
|
const flags = perThreadSetup.buildAllowedFlags();
|
|
process.allowedNodeEnvironmentFlags = flags;
|
|
return process.allowedNodeEnvironmentFlags;
|
|
},
|
|
// If the user tries to set this to another value, override
|
|
// this completely to that value.
|
|
set(value) {
|
|
Object.defineProperty(this, 'allowedNodeEnvironmentFlags', {
|
|
value,
|
|
configurable: true,
|
|
enumerable: true,
|
|
writable: true
|
|
});
|
|
},
|
|
enumerable: true,
|
|
configurable: true
|
|
});
|
|
// process.assert
|
|
process.assert = deprecate(
|
|
perThreadSetup.assert,
|
|
'process.assert() is deprecated. Please use the `assert` module instead.',
|
|
'DEP0100');
|
|
|
|
// TODO(joyeecheung): this property has not been well-maintained, should we
|
|
// deprecate it in favor of a better API?
|
|
const { isDebugBuild, hasOpenSSL } = config;
|
|
Object.defineProperty(process, 'features', {
|
|
enumerable: true,
|
|
writable: false,
|
|
configurable: false,
|
|
value: {
|
|
debug: isDebugBuild,
|
|
uv: true,
|
|
ipv6: true, // TODO(bnoordhuis) ping libuv
|
|
tls_alpn: hasOpenSSL,
|
|
tls_sni: hasOpenSSL,
|
|
tls_ocsp: hasOpenSSL,
|
|
tls: hasOpenSSL
|
|
}
|
|
});
|
|
|
|
// User-facing NODE_V8_COVERAGE environment variable that writes
|
|
// ScriptCoverage to a specified file.
|
|
if (process.env.NODE_V8_COVERAGE) {
|
|
const originalReallyExit = process.reallyExit;
|
|
const cwd = NativeModule.require('internal/process/execution').tryGetCwd();
|
|
const { resolve } = NativeModule.require('path');
|
|
// Resolve the coverage directory to an absolute path, and
|
|
// overwrite process.env so that the original path gets passed
|
|
// to child processes even when they switch cwd.
|
|
const coverageDirectory = resolve(cwd, process.env.NODE_V8_COVERAGE);
|
|
process.env.NODE_V8_COVERAGE = coverageDirectory;
|
|
const {
|
|
writeCoverage,
|
|
setCoverageDirectory
|
|
} = NativeModule.require('internal/coverage-gen/with_profiler');
|
|
setCoverageDirectory(coverageDirectory);
|
|
process.on('exit', writeCoverage);
|
|
process.reallyExit = (code) => {
|
|
writeCoverage();
|
|
originalReallyExit(code);
|
|
};
|
|
}
|
|
|
|
const perf = internalBinding('performance');
|
|
const {
|
|
NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE,
|
|
} = perf.constants;
|
|
perf.markMilestone(NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE);
|
|
|
|
if (getOptionValue('--experimental-report')) {
|
|
NativeModule.require('internal/process/report').setup();
|
|
}
|
|
|
|
if (isMainThread) {
|
|
return startMainThreadExecution;
|
|
} else {
|
|
return startWorkerThreadExecution;
|
|
}
|
|
}
|
|
|
|
function startWorkerThreadExecution() {
|
|
prepareUserCodeExecution();
|
|
|
|
// If we are in a worker thread, execute the script sent through the
|
|
// message port.
|
|
const {
|
|
getEnvMessagePort,
|
|
threadId
|
|
} = internalBinding('worker');
|
|
const {
|
|
createMessageHandler,
|
|
createWorkerFatalExeception
|
|
} = NativeModule.require('internal/process/worker_thread_only');
|
|
|
|
// Set up the message port and start listening
|
|
const debug = NativeModule.require('util').debuglog('worker');
|
|
debug(`[${threadId}] is setting up worker child environment`);
|
|
|
|
const port = getEnvMessagePort();
|
|
port.on('message', createMessageHandler(port));
|
|
port.start();
|
|
|
|
// Overwrite fatalException
|
|
process._fatalException = createWorkerFatalExeception(port);
|
|
}
|
|
|
|
// There are various modes that Node can run in. The most common two
|
|
// are running from a script and running the REPL - but there are a few
|
|
// others like the debugger or running --eval arguments. Here we decide
|
|
// which mode we run in.
|
|
function startMainThreadExecution(mainScript) {
|
|
if (mainScript) {
|
|
process.nextTick(() => {
|
|
NativeModule.require(mainScript);
|
|
});
|
|
return;
|
|
}
|
|
|
|
// `node inspect ...` or `node debug ...`
|
|
if (process.argv[1] === 'inspect' || process.argv[1] === 'debug') {
|
|
if (process.argv[1] === 'debug') {
|
|
process.emitWarning(
|
|
'`node debug` is deprecated. Please use `node inspect` instead.',
|
|
'DeprecationWarning', 'DEP0068');
|
|
}
|
|
|
|
// Start the debugger agent.
|
|
process.nextTick(() => {
|
|
NativeModule.require('internal/deps/node-inspect/lib/_inspect').start();
|
|
});
|
|
return;
|
|
}
|
|
|
|
// node --help
|
|
if (getOptionValue('--help')) {
|
|
NativeModule.require('internal/print_help').print(process.stdout);
|
|
return;
|
|
}
|
|
|
|
// e.g. node --completion-bash >> ~/.bashrc
|
|
if (getOptionValue('--completion-bash')) {
|
|
NativeModule.require('internal/bash_completion').print(process.stdout);
|
|
return;
|
|
}
|
|
|
|
// `node --prof-process`
|
|
if (getOptionValue('--prof-process')) {
|
|
NativeModule.require('internal/v8_prof_processor');
|
|
return;
|
|
}
|
|
|
|
// There is user code to be run.
|
|
prepareUserCodeExecution();
|
|
executeUserCode();
|
|
}
|
|
|
|
function prepareUserCodeExecution() {
|
|
// If this is a worker in cluster mode, start up the communication
|
|
// channel. This needs to be done before any user code gets executed
|
|
// (including preload modules).
|
|
if (process.argv[1] && process.env.NODE_UNIQUE_ID) {
|
|
const cluster = NativeModule.require('cluster');
|
|
cluster._setupWorker();
|
|
// Make sure it's not accidentally inherited by child processes.
|
|
delete process.env.NODE_UNIQUE_ID;
|
|
}
|
|
|
|
const experimentalModules = getOptionValue('--experimental-modules');
|
|
const experimentalVMModules = getOptionValue('--experimental-vm-modules');
|
|
if (experimentalModules || experimentalVMModules) {
|
|
if (experimentalModules) {
|
|
process.emitWarning(
|
|
'The ESM module loader is experimental.',
|
|
'ExperimentalWarning', undefined);
|
|
}
|
|
|
|
const {
|
|
setImportModuleDynamicallyCallback,
|
|
setInitializeImportMetaObjectCallback
|
|
} = internalBinding('module_wrap');
|
|
const esm = NativeModule.require('internal/process/esm_loader');
|
|
// Setup per-isolate callbacks that locate data or callbacks that we keep
|
|
// track of for different ESM modules.
|
|
setInitializeImportMetaObjectCallback(esm.initializeImportMetaObject);
|
|
setImportModuleDynamicallyCallback(esm.importModuleDynamicallyCallback);
|
|
const userLoader = getOptionValue('--loader');
|
|
// If --loader is specified, create a loader with user hooks. Otherwise
|
|
// create the default loader.
|
|
esm.initializeLoader(process.cwd(), userLoader);
|
|
}
|
|
|
|
// For user code, we preload modules if `-r` is passed
|
|
const preloadModules = getOptionValue('--require');
|
|
if (preloadModules) {
|
|
const {
|
|
_preloadModules
|
|
} = NativeModule.require('internal/modules/cjs/loader');
|
|
_preloadModules(preloadModules);
|
|
}
|
|
}
|
|
|
|
function executeUserCode() {
|
|
// User passed `-e` or `--eval` arguments to Node without `-i` or
|
|
// `--interactive`.
|
|
// Note that the name `forceRepl` is merely an alias of `interactive`
|
|
// in code.
|
|
if (getOptionValue('[has_eval_string]') && !getOptionValue('--interactive')) {
|
|
const {
|
|
addBuiltinLibsToObject
|
|
} = NativeModule.require('internal/modules/cjs/helpers');
|
|
addBuiltinLibsToObject(global);
|
|
const source = getOptionValue('--eval');
|
|
const { evalScript } = NativeModule.require('internal/process/execution');
|
|
evalScript('[eval]', source, process._breakFirstLine);
|
|
return;
|
|
}
|
|
|
|
// If the first argument is a file name, run it as a main script
|
|
if (process.argv[1] && process.argv[1] !== '-') {
|
|
// Expand process.argv[1] into a full path.
|
|
const path = NativeModule.require('path');
|
|
process.argv[1] = path.resolve(process.argv[1]);
|
|
|
|
const CJSModule = NativeModule.require('internal/modules/cjs/loader');
|
|
|
|
// If user passed `-c` or `--check` arguments to Node, check its syntax
|
|
// instead of actually running the file.
|
|
if (getOptionValue('--check')) {
|
|
const fs = NativeModule.require('fs');
|
|
// Read the source.
|
|
const filename = CJSModule._resolveFilename(process.argv[1]);
|
|
const source = fs.readFileSync(filename, 'utf-8');
|
|
checkScriptSyntax(source, filename);
|
|
process.exit(0);
|
|
}
|
|
|
|
// Note: this actually tries to run the module as a ESM first if
|
|
// --experimental-modules is on.
|
|
// TODO(joyeecheung): can we move that logic to here? Note that this
|
|
// is an undocumented method available via `require('module').runMain`
|
|
CJSModule.runMain();
|
|
return;
|
|
}
|
|
|
|
// Create the REPL if `-i` or `--interactive` is passed, or if
|
|
// stdin is a TTY.
|
|
// Note that the name `forceRepl` is merely an alias of `interactive`
|
|
// in code.
|
|
if (process._forceRepl || NativeModule.require('tty').isatty(0)) {
|
|
const cliRepl = NativeModule.require('internal/repl');
|
|
cliRepl.createInternalRepl(process.env, (err, repl) => {
|
|
if (err) {
|
|
throw err;
|
|
}
|
|
repl.on('exit', () => {
|
|
if (repl._flushing) {
|
|
repl.pause();
|
|
return repl.once('flushHistory', () => {
|
|
process.exit();
|
|
});
|
|
}
|
|
process.exit();
|
|
});
|
|
});
|
|
|
|
// User passed '-e' or '--eval' along with `-i` or `--interactive`
|
|
if (process._eval != null) {
|
|
const { evalScript } = NativeModule.require('internal/process/execution');
|
|
evalScript('[eval]', process._eval, process._breakFirstLine);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Stdin is not a TTY, we will read it and execute it.
|
|
readAndExecuteStdin();
|
|
}
|
|
|
|
function readAndExecuteStdin() {
|
|
process.stdin.setEncoding('utf8');
|
|
|
|
let code = '';
|
|
process.stdin.on('data', (d) => {
|
|
code += d;
|
|
});
|
|
|
|
process.stdin.on('end', () => {
|
|
if (process._syntax_check_only != null) {
|
|
checkScriptSyntax(code, '[stdin]');
|
|
} else {
|
|
process._eval = code;
|
|
const { evalScript } = NativeModule.require('internal/process/execution');
|
|
evalScript('[stdin]', process._eval, process._breakFirstLine);
|
|
}
|
|
});
|
|
}
|
|
|
|
function setupTraceCategoryState() {
|
|
const {
|
|
traceCategoryState,
|
|
setTraceCategoryStateUpdateHandler
|
|
} = internalBinding('trace_events');
|
|
const kCategoryAsyncHooks = 0;
|
|
let traceEventsAsyncHook;
|
|
|
|
function toggleTraceCategoryState() {
|
|
// Dynamically enable/disable the traceEventsAsyncHook
|
|
const asyncHooksEnabled = !!traceCategoryState[kCategoryAsyncHooks];
|
|
|
|
if (asyncHooksEnabled) {
|
|
// Lazy load internal/trace_events_async_hooks only if the async_hooks
|
|
// trace event category is enabled.
|
|
if (!traceEventsAsyncHook) {
|
|
traceEventsAsyncHook =
|
|
NativeModule.require('internal/trace_events_async_hooks');
|
|
}
|
|
traceEventsAsyncHook.enable();
|
|
} else if (traceEventsAsyncHook) {
|
|
traceEventsAsyncHook.disable();
|
|
}
|
|
}
|
|
|
|
toggleTraceCategoryState();
|
|
setTraceCategoryStateUpdateHandler(toggleTraceCategoryState);
|
|
}
|
|
|
|
function setupProcessObject() {
|
|
const EventEmitter = NativeModule.require('events');
|
|
const origProcProto = Object.getPrototypeOf(process);
|
|
Object.setPrototypeOf(origProcProto, EventEmitter.prototype);
|
|
EventEmitter.call(process);
|
|
}
|
|
|
|
function setupProcessStdio(getStdout, getStdin, getStderr) {
|
|
Object.defineProperty(process, 'stdout', {
|
|
configurable: true,
|
|
enumerable: true,
|
|
get: getStdout
|
|
});
|
|
|
|
Object.defineProperty(process, 'stderr', {
|
|
configurable: true,
|
|
enumerable: true,
|
|
get: getStderr
|
|
});
|
|
|
|
Object.defineProperty(process, 'stdin', {
|
|
configurable: true,
|
|
enumerable: true,
|
|
get: getStdin
|
|
});
|
|
|
|
process.openStdin = function() {
|
|
process.stdin.resume();
|
|
return process.stdin;
|
|
};
|
|
}
|
|
|
|
function setupGlobalVariables() {
|
|
Object.defineProperty(global, Symbol.toStringTag, {
|
|
value: 'global',
|
|
writable: false,
|
|
enumerable: false,
|
|
configurable: true
|
|
});
|
|
Object.defineProperty(global, 'process', {
|
|
value: process,
|
|
enumerable: false,
|
|
writable: true,
|
|
configurable: true
|
|
});
|
|
const util = NativeModule.require('util');
|
|
|
|
function makeGetter(name) {
|
|
return util.deprecate(function() {
|
|
return this;
|
|
}, `'${name}' is deprecated, use 'global'`, 'DEP0016');
|
|
}
|
|
|
|
function makeSetter(name) {
|
|
return util.deprecate(function(value) {
|
|
Object.defineProperty(this, name, {
|
|
configurable: true,
|
|
writable: true,
|
|
enumerable: true,
|
|
value: value
|
|
});
|
|
}, `'${name}' is deprecated, use 'global'`, 'DEP0016');
|
|
}
|
|
|
|
Object.defineProperties(global, {
|
|
GLOBAL: {
|
|
configurable: true,
|
|
get: makeGetter('GLOBAL'),
|
|
set: makeSetter('GLOBAL')
|
|
},
|
|
root: {
|
|
configurable: true,
|
|
get: makeGetter('root'),
|
|
set: makeSetter('root')
|
|
}
|
|
});
|
|
|
|
const { Buffer } = NativeModule.require('buffer');
|
|
const bufferBinding = internalBinding('buffer');
|
|
|
|
// Only after this point can C++ use Buffer::New()
|
|
bufferBinding.setBufferPrototype(Buffer.prototype);
|
|
delete bufferBinding.setBufferPrototype;
|
|
delete bufferBinding.zeroFill;
|
|
|
|
Object.defineProperty(global, 'Buffer', {
|
|
value: Buffer,
|
|
enumerable: false,
|
|
writable: true,
|
|
configurable: true
|
|
});
|
|
|
|
process.domain = null;
|
|
process._exiting = false;
|
|
}
|
|
|
|
function setupGlobalTimeouts() {
|
|
const timers = NativeModule.require('timers');
|
|
global.clearImmediate = timers.clearImmediate;
|
|
global.clearInterval = timers.clearInterval;
|
|
global.clearTimeout = timers.clearTimeout;
|
|
global.setImmediate = timers.setImmediate;
|
|
global.setInterval = timers.setInterval;
|
|
global.setTimeout = timers.setTimeout;
|
|
}
|
|
|
|
function setupGlobalConsole() {
|
|
const consoleFromVM = global.console;
|
|
const consoleFromNode =
|
|
NativeModule.require('internal/console/global');
|
|
// Override global console from the one provided by the VM
|
|
// to the one implemented by Node.js
|
|
Object.defineProperty(global, 'console', {
|
|
configurable: true,
|
|
enumerable: false,
|
|
value: consoleFromNode,
|
|
writable: true
|
|
});
|
|
|
|
if (config.hasInspector) {
|
|
const inspector = NativeModule.require('internal/util/inspector');
|
|
// This will be exposed by `require('inspector').console` later.
|
|
inspector.consoleFromVM = consoleFromVM;
|
|
// TODO(joyeecheung): postpone this until the first time inspector
|
|
// is activated.
|
|
inspector.wrapConsole(consoleFromNode, consoleFromVM);
|
|
const { setConsoleExtensionInstaller } = internalBinding('inspector');
|
|
// Setup inspector command line API.
|
|
setConsoleExtensionInstaller(inspector.installConsoleExtensions);
|
|
}
|
|
}
|
|
|
|
function setupGlobalURL() {
|
|
const { URL, URLSearchParams } = NativeModule.require('internal/url');
|
|
Object.defineProperties(global, {
|
|
URL: {
|
|
value: URL,
|
|
writable: true,
|
|
configurable: true,
|
|
enumerable: false
|
|
},
|
|
URLSearchParams: {
|
|
value: URLSearchParams,
|
|
writable: true,
|
|
configurable: true,
|
|
enumerable: false
|
|
}
|
|
});
|
|
}
|
|
|
|
function setupGlobalEncoding() {
|
|
const { TextEncoder, TextDecoder } = NativeModule.require('util');
|
|
Object.defineProperties(global, {
|
|
TextEncoder: {
|
|
value: TextEncoder,
|
|
writable: true,
|
|
configurable: true,
|
|
enumerable: false
|
|
},
|
|
TextDecoder: {
|
|
value: TextDecoder,
|
|
writable: true,
|
|
configurable: true,
|
|
enumerable: false
|
|
}
|
|
});
|
|
}
|
|
|
|
function setupQueueMicrotask() {
|
|
Object.defineProperty(global, 'queueMicrotask', {
|
|
get() {
|
|
process.emitWarning('queueMicrotask() is experimental.',
|
|
'ExperimentalWarning');
|
|
const { queueMicrotask } =
|
|
NativeModule.require('internal/queue_microtask');
|
|
|
|
Object.defineProperty(global, 'queueMicrotask', {
|
|
value: queueMicrotask,
|
|
writable: true,
|
|
enumerable: false,
|
|
configurable: true,
|
|
});
|
|
return queueMicrotask;
|
|
},
|
|
set(v) {
|
|
Object.defineProperty(global, 'queueMicrotask', {
|
|
value: v,
|
|
writable: true,
|
|
enumerable: false,
|
|
configurable: true,
|
|
});
|
|
},
|
|
enumerable: false,
|
|
configurable: true,
|
|
});
|
|
}
|
|
|
|
function setupDOMException() {
|
|
// Registers the constructor with C++.
|
|
const DOMException = NativeModule.require('internal/domexception');
|
|
const { registerDOMException } = internalBinding('messaging');
|
|
registerDOMException(DOMException);
|
|
}
|
|
|
|
function checkScriptSyntax(source, filename) {
|
|
const CJSModule = NativeModule.require('internal/modules/cjs/loader');
|
|
const vm = NativeModule.require('vm');
|
|
const {
|
|
stripShebang, stripBOM
|
|
} = NativeModule.require('internal/modules/cjs/helpers');
|
|
|
|
// Remove Shebang.
|
|
source = stripShebang(source);
|
|
// Remove BOM.
|
|
source = stripBOM(source);
|
|
// Wrap it.
|
|
source = CJSModule.wrap(source);
|
|
// Compile the script, this will throw if it fails.
|
|
new vm.Script(source, { displayErrors: true, filename });
|
|
}
|
|
|
|
return startup();
|