process: split execution into main scripts
This patch splits the execution mode selection from the environment setup in `lib/internal/bootstrap/node.js`, and split the entry point of different execution mode into main scripts under `lib/internal/main`: - `check_syntax.js`: used when `-c`/`--check` which only checks the syntax of the input instead of executing it. - `eval_stdin.js`: used when `-e` is passed without value and stdin is not a TTY (e.g. something is piped). - `eval_string`: used when `-e` is passed along with a string argument - `inspect.js`: for `node inspect`/`node debug` - `print_bash_completion.js`: for `--completion-bash` - `print_help.js`: for `--help` - `prof_process.js`: for `--prof-process` - `repl.js`: for the REPL - `run_main_module.js`: used when a main module is passed - `run_third_party_main.js`: for the legacy `_third_party_main.js` support - `worker_thread.js`: for workers This makes the entry points easier to navigate and paves the way for customized v8 snapshots (that do not need to deserialize execution mode setup) and better embedder APIs. As an example, after this patch, for the most common case where Node.js executes a user module as an entry point, it essentially goes through: - `lib/internal/per_context.js` to setup the v8 Context (which is also run when setting up contexts for the `vm` module) - `lib/internal/bootstrap/loaders.js` to set up internal binding and builtin module loaders (that are separate from the loaders accessible in the user land). - `lib/internal/bootstrap/node.js`: to set up the rest of the environment, including various globals and the process object - `lib/internal/main/run_main_module.js`: which is selected from C++ to prepare execution of the user module. This patch also removes `NativeModuleLoader::CompileAndCall` and exposes `NativeModuleLoader::LookupAndCompile` directly so that we can handle syntax errors and runtime errors of bootstrap scripts differently. PR-URL: https://github.com/nodejs/node/pull/25667 Reviewed-By: Anna Henningsen <anna@addaleax.net>
This commit is contained in:
parent
feebdc5bc5
commit
6967f91368
@ -13,7 +13,7 @@ const { hasTracing, hasInspector } = process.binding('config');
|
||||
|
||||
// Modules with source code compiled in js2c that
|
||||
// cannot be compiled with the code cache.
|
||||
const cannotUseCache = [
|
||||
const cannotBeRequired = [
|
||||
'sys', // Deprecated.
|
||||
'internal/v8_prof_polyfill',
|
||||
'internal/v8_prof_processor',
|
||||
@ -21,8 +21,7 @@ const cannotUseCache = [
|
||||
'internal/per_context',
|
||||
|
||||
'internal/test/binding',
|
||||
// TODO(joyeecheung): update the C++ side so that
|
||||
// the code cache is also used when compiling these two files.
|
||||
|
||||
'internal/bootstrap/loaders',
|
||||
'internal/bootstrap/node'
|
||||
];
|
||||
@ -30,16 +29,16 @@ const cannotUseCache = [
|
||||
// Skip modules that cannot be required when they are not
|
||||
// built into the binary.
|
||||
if (!hasInspector) {
|
||||
cannotUseCache.push(
|
||||
cannotBeRequired.push(
|
||||
'inspector',
|
||||
'internal/util/inspector',
|
||||
);
|
||||
}
|
||||
if (!hasTracing) {
|
||||
cannotUseCache.push('trace_events');
|
||||
cannotBeRequired.push('trace_events');
|
||||
}
|
||||
if (!process.versions.openssl) {
|
||||
cannotUseCache.push(
|
||||
cannotBeRequired.push(
|
||||
'crypto',
|
||||
'https',
|
||||
'http2',
|
||||
@ -67,10 +66,10 @@ if (!process.versions.openssl) {
|
||||
|
||||
const cachableBuiltins = [];
|
||||
for (const id of NativeModule.map.keys()) {
|
||||
if (id.startsWith('internal/deps')) {
|
||||
cannotUseCache.push(id);
|
||||
if (id.startsWith('internal/deps') || id.startsWith('internal/main')) {
|
||||
cannotBeRequired.push(id);
|
||||
}
|
||||
if (!cannotUseCache.includes(id)) {
|
||||
if (!cannotBeRequired.includes(id)) {
|
||||
cachableBuiltins.push(id);
|
||||
}
|
||||
}
|
||||
@ -79,5 +78,5 @@ module.exports = {
|
||||
cachableBuiltins,
|
||||
getCodeCache,
|
||||
compileFunction,
|
||||
cannotUseCache
|
||||
cannotBeRequired
|
||||
};
|
||||
|
@ -160,7 +160,12 @@ internalBinding('module_wrap').callbackMap = new WeakMap();
|
||||
|
||||
// Think of this as module.exports in this file even though it is not
|
||||
// written in CommonJS style.
|
||||
const loaderExports = { internalBinding, NativeModule };
|
||||
const loaderExports = {
|
||||
internalBinding,
|
||||
NativeModule,
|
||||
require: nativeModuleRequire
|
||||
};
|
||||
|
||||
const loaderId = 'internal/bootstrap/loaders';
|
||||
|
||||
// Set up NativeModule.
|
||||
@ -194,7 +199,7 @@ for (var i = 0; i < moduleIds.length; ++i) {
|
||||
NativeModule.map.set(id, mod);
|
||||
}
|
||||
|
||||
NativeModule.require = function(id) {
|
||||
function nativeModuleRequire(id) {
|
||||
if (id === loaderId) {
|
||||
return loaderExports;
|
||||
}
|
||||
@ -218,8 +223,9 @@ NativeModule.require = function(id) {
|
||||
moduleLoadList.push(`NativeModule ${id}`);
|
||||
mod.compile();
|
||||
return mod.exports;
|
||||
};
|
||||
}
|
||||
|
||||
NativeModule.require = nativeModuleRequire;
|
||||
NativeModule.exists = function(id) {
|
||||
return NativeModule.map.has(id);
|
||||
};
|
||||
|
@ -21,546 +21,294 @@ const { internalBinding, NativeModule } = loaderExports;
|
||||
const { getOptionValue } = NativeModule.require('internal/options');
|
||||
const config = internalBinding('config');
|
||||
|
||||
function startup() {
|
||||
setupTraceCategoryState();
|
||||
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;
|
||||
}
|
||||
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 {
|
||||
onWarning,
|
||||
emitWarning
|
||||
} = NativeModule.require('internal/process/warning');
|
||||
if (!process.noProcessWarnings && process.env.NODE_NO_WARNINGS !== '1') {
|
||||
process.on('warning', onWarning);
|
||||
}
|
||||
process.emitWarning = emitWarning;
|
||||
fatalException,
|
||||
setUncaughtExceptionCaptureCallback,
|
||||
hasUncaughtExceptionCaptureCallback
|
||||
} = NativeModule.require('internal/process/execution');
|
||||
|
||||
const {
|
||||
nextTick,
|
||||
runNextTicks
|
||||
} = NativeModule.require('internal/process/next_tick').setup();
|
||||
process._fatalException = fatalException;
|
||||
process.setUncaughtExceptionCaptureCallback =
|
||||
setUncaughtExceptionCaptureCallback;
|
||||
process.hasUncaughtExceptionCaptureCallback =
|
||||
hasUncaughtExceptionCaptureCallback;
|
||||
}
|
||||
|
||||
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;
|
||||
setupGlobalVariables();
|
||||
|
||||
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;
|
||||
// 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'
|
||||
);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
// 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 { 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
|
||||
const experimentalPolicy = getOptionValue('--experimental-policy');
|
||||
if (isMainThread && experimentalPolicy) {
|
||||
process.emitWarning('Policies are experimental.',
|
||||
'ExperimentalWarning');
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
function startWorkerThreadExecution() {
|
||||
// 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,
|
||||
prepareUserCodeExecution));
|
||||
port.start();
|
||||
|
||||
// Overwrite fatalException
|
||||
process._fatalException = createWorkerFatalExeception(port);
|
||||
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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
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();
|
||||
}
|
||||
|
||||
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', undefined, true);
|
||||
process.exit(9);
|
||||
} else if (process._deprecatedDebugBrk) {
|
||||
process.emitWarning(
|
||||
'`node --inspect --debug-brk` is deprecated. ' +
|
||||
'Please use `node --inspect-brk` instead.',
|
||||
'DeprecationWarning', 'DEP0062', undefined, 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
|
||||
});
|
||||
return;
|
||||
},
|
||||
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
|
||||
}
|
||||
});
|
||||
|
||||
// `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();
|
||||
// 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);
|
||||
};
|
||||
}
|
||||
|
||||
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.length) {
|
||||
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);
|
||||
}
|
||||
});
|
||||
if (getOptionValue('--experimental-report')) {
|
||||
NativeModule.require('internal/process/report').setup();
|
||||
}
|
||||
|
||||
function setupTraceCategoryState() {
|
||||
@ -795,22 +543,3 @@ function setupDOMException() {
|
||||
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();
|
||||
|
82
lib/internal/bootstrap/pre_execution.js
Normal file
82
lib/internal/bootstrap/pre_execution.js
Normal file
@ -0,0 +1,82 @@
|
||||
'use strict';
|
||||
|
||||
const { getOptionValue } = require('internal/options');
|
||||
|
||||
function initializeClusterIPC() {
|
||||
// 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 = require('cluster');
|
||||
cluster._setupWorker();
|
||||
// Make sure it's not accidentally inherited by child processes.
|
||||
delete process.env.NODE_UNIQUE_ID;
|
||||
}
|
||||
}
|
||||
|
||||
function initializePolicy() {
|
||||
const experimentalPolicy = getOptionValue('--experimental-policy');
|
||||
if (experimentalPolicy) {
|
||||
process.emitWarning('Policies are experimental.',
|
||||
'ExperimentalWarning');
|
||||
const { pathToFileURL, URL } = require('url');
|
||||
// URL here as it is slightly different parsing
|
||||
// no bare specifiers for now
|
||||
let manifestURL;
|
||||
if (require('path').isAbsolute(experimentalPolicy)) {
|
||||
manifestURL = new URL(`file:///${experimentalPolicy}`);
|
||||
} else {
|
||||
const cwdURL = pathToFileURL(process.cwd());
|
||||
cwdURL.pathname += '/';
|
||||
manifestURL = new URL(experimentalPolicy, cwdURL);
|
||||
}
|
||||
const fs = require('fs');
|
||||
const src = fs.readFileSync(manifestURL, 'utf8');
|
||||
require('internal/process/policy')
|
||||
.setup(src, manifestURL.href);
|
||||
}
|
||||
}
|
||||
|
||||
function initializeESMLoader() {
|
||||
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 = 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);
|
||||
}
|
||||
}
|
||||
|
||||
function loadPreloadModules() {
|
||||
// For user code, we preload modules if `-r` is passed
|
||||
const preloadModules = getOptionValue('--require');
|
||||
if (preloadModules) {
|
||||
const {
|
||||
_preloadModules
|
||||
} = require('internal/modules/cjs/loader');
|
||||
_preloadModules(preloadModules);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
initializeClusterIPC,
|
||||
initializePolicy,
|
||||
initializeESMLoader,
|
||||
loadPreloadModules
|
||||
};
|
2
lib/internal/main/.eslintrc.yaml
Normal file
2
lib/internal/main/.eslintrc.yaml
Normal file
@ -0,0 +1,2 @@
|
||||
globals:
|
||||
markBootstrapComplete: true
|
56
lib/internal/main/check_syntax.js
Normal file
56
lib/internal/main/check_syntax.js
Normal file
@ -0,0 +1,56 @@
|
||||
'use strict';
|
||||
|
||||
// If user passed `-c` or `--check` arguments to Node, check its syntax
|
||||
// instead of actually running the file.
|
||||
|
||||
const {
|
||||
initializeClusterIPC,
|
||||
initializePolicy,
|
||||
initializeESMLoader,
|
||||
loadPreloadModules
|
||||
} = require('internal/bootstrap/pre_execution');
|
||||
|
||||
const {
|
||||
readStdin
|
||||
} = require('internal/process/execution');
|
||||
|
||||
const CJSModule = require('internal/modules/cjs/loader');
|
||||
const vm = require('vm');
|
||||
const {
|
||||
stripShebang, stripBOM
|
||||
} = require('internal/modules/cjs/helpers');
|
||||
|
||||
// TODO(joyeecheung): not every one of these are necessary
|
||||
initializeClusterIPC();
|
||||
initializePolicy();
|
||||
initializeESMLoader();
|
||||
loadPreloadModules();
|
||||
markBootstrapComplete();
|
||||
|
||||
if (process.argv[1] && process.argv[1] !== '-') {
|
||||
// Expand process.argv[1] into a full path.
|
||||
const path = require('path');
|
||||
process.argv[1] = path.resolve(process.argv[1]);
|
||||
// Read the source.
|
||||
const filename = CJSModule._resolveFilename(process.argv[1]);
|
||||
|
||||
const fs = require('fs');
|
||||
const source = fs.readFileSync(filename, 'utf-8');
|
||||
|
||||
checkScriptSyntax(source, filename);
|
||||
} else {
|
||||
readStdin((code) => {
|
||||
checkScriptSyntax(code, '[stdin]');
|
||||
});
|
||||
}
|
||||
|
||||
function checkScriptSyntax(source, filename) {
|
||||
// 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 });
|
||||
}
|
26
lib/internal/main/eval_stdin.js
Normal file
26
lib/internal/main/eval_stdin.js
Normal file
@ -0,0 +1,26 @@
|
||||
'use strict';
|
||||
|
||||
// Stdin is not a TTY, we will read it and execute it.
|
||||
|
||||
const {
|
||||
initializeClusterIPC,
|
||||
initializePolicy,
|
||||
initializeESMLoader,
|
||||
loadPreloadModules
|
||||
} = require('internal/bootstrap/pre_execution');
|
||||
|
||||
const {
|
||||
evalScript,
|
||||
readStdin
|
||||
} = require('internal/process/execution');
|
||||
|
||||
initializeClusterIPC();
|
||||
initializePolicy();
|
||||
initializeESMLoader();
|
||||
loadPreloadModules();
|
||||
markBootstrapComplete();
|
||||
|
||||
readStdin((code) => {
|
||||
process._eval = code;
|
||||
evalScript('[stdin]', process._eval, process._breakFirstLine);
|
||||
});
|
22
lib/internal/main/eval_string.js
Normal file
22
lib/internal/main/eval_string.js
Normal file
@ -0,0 +1,22 @@
|
||||
'use strict';
|
||||
|
||||
// User passed `-e` or `--eval` arguments to Node without `-i` or
|
||||
// `--interactive`.
|
||||
|
||||
const {
|
||||
initializeClusterIPC,
|
||||
initializePolicy,
|
||||
initializeESMLoader,
|
||||
loadPreloadModules
|
||||
} = require('internal/bootstrap/pre_execution');
|
||||
const { evalScript } = require('internal/process/execution');
|
||||
const { addBuiltinLibsToObject } = require('internal/modules/cjs/helpers');
|
||||
|
||||
const source = require('internal/options').getOptionValue('--eval');
|
||||
initializeClusterIPC();
|
||||
initializePolicy();
|
||||
initializeESMLoader();
|
||||
loadPreloadModules();
|
||||
addBuiltinLibsToObject(global);
|
||||
markBootstrapComplete();
|
||||
evalScript('[eval]', source, process._breakFirstLine);
|
16
lib/internal/main/inspect.js
Normal file
16
lib/internal/main/inspect.js
Normal file
@ -0,0 +1,16 @@
|
||||
'use strict';
|
||||
|
||||
// `node inspect ...` or `node debug ...`
|
||||
|
||||
if (process.argv[1] === 'debug') {
|
||||
process.emitWarning(
|
||||
'`node debug` is deprecated. Please use `node inspect` instead.',
|
||||
'DeprecationWarning', 'DEP0068');
|
||||
}
|
||||
|
||||
markBootstrapComplete();
|
||||
|
||||
// Start the debugger agent.
|
||||
process.nextTick(() => {
|
||||
require('internal/deps/node-inspect/lib/_inspect').start();
|
||||
});
|
@ -18,6 +18,6 @@ function print(stream) {
|
||||
complete -F _node_complete node node_g`);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
print
|
||||
};
|
||||
markBootstrapComplete();
|
||||
|
||||
print(process.stdout);
|
@ -172,6 +172,6 @@ function print(stream) {
|
||||
stream.write('\nDocumentation can be found at https://nodejs.org/\n');
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
print
|
||||
};
|
||||
markBootstrapComplete();
|
||||
|
||||
print(process.stdout);
|
4
lib/internal/main/prof_process.js
Normal file
4
lib/internal/main/prof_process.js
Normal file
@ -0,0 +1,4 @@
|
||||
'use strict';
|
||||
|
||||
markBootstrapComplete();
|
||||
require('internal/v8_prof_processor');
|
44
lib/internal/main/repl.js
Normal file
44
lib/internal/main/repl.js
Normal file
@ -0,0 +1,44 @@
|
||||
'use strict';
|
||||
|
||||
// Create the REPL if `-i` or `--interactive` is passed, or if
|
||||
// the main module is not specified and stdin is a TTY.
|
||||
|
||||
const {
|
||||
initializeClusterIPC,
|
||||
initializePolicy,
|
||||
initializeESMLoader,
|
||||
loadPreloadModules
|
||||
} = require('internal/bootstrap/pre_execution');
|
||||
|
||||
const {
|
||||
evalScript
|
||||
} = require('internal/process/execution');
|
||||
|
||||
initializeClusterIPC();
|
||||
initializePolicy();
|
||||
initializeESMLoader();
|
||||
loadPreloadModules();
|
||||
|
||||
const cliRepl = 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();
|
||||
});
|
||||
});
|
||||
|
||||
// If user passed '-e' or '--eval' along with `-i` or `--interactive`,
|
||||
// evaluate the code in the current context.
|
||||
if (process._eval != null) {
|
||||
evalScript('[eval]', process._eval, process._breakFirstLine);
|
||||
}
|
||||
|
||||
markBootstrapComplete();
|
27
lib/internal/main/run_main_module.js
Normal file
27
lib/internal/main/run_main_module.js
Normal file
@ -0,0 +1,27 @@
|
||||
'use strict';
|
||||
|
||||
const {
|
||||
initializeClusterIPC,
|
||||
initializePolicy,
|
||||
initializeESMLoader,
|
||||
loadPreloadModules
|
||||
} = require('internal/bootstrap/pre_execution');
|
||||
|
||||
initializeClusterIPC();
|
||||
initializePolicy();
|
||||
initializeESMLoader();
|
||||
loadPreloadModules();
|
||||
|
||||
// Expand process.argv[1] into a full path.
|
||||
const path = require('path');
|
||||
process.argv[1] = path.resolve(process.argv[1]);
|
||||
|
||||
const CJSModule = require('internal/modules/cjs/loader');
|
||||
|
||||
markBootstrapComplete();
|
||||
|
||||
// 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();
|
9
lib/internal/main/run_third_party_main.js
Normal file
9
lib/internal/main/run_third_party_main.js
Normal file
@ -0,0 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
// Legacy _third_party_main.js support
|
||||
|
||||
markBootstrapComplete();
|
||||
|
||||
process.nextTick(() => {
|
||||
require('_third_party_main');
|
||||
});
|
39
lib/internal/main/worker_thread.js
Normal file
39
lib/internal/main/worker_thread.js
Normal file
@ -0,0 +1,39 @@
|
||||
'use strict';
|
||||
|
||||
// In worker threads, execute the script sent through the
|
||||
// message port.
|
||||
|
||||
const {
|
||||
initializeClusterIPC,
|
||||
initializeESMLoader,
|
||||
loadPreloadModules
|
||||
} = require('internal/bootstrap/pre_execution');
|
||||
|
||||
const {
|
||||
getEnvMessagePort,
|
||||
threadId
|
||||
} = internalBinding('worker');
|
||||
|
||||
const {
|
||||
createMessageHandler,
|
||||
createWorkerFatalExeception
|
||||
} = require('internal/process/worker_thread_only');
|
||||
|
||||
const debug = require('util').debuglog('worker');
|
||||
debug(`[${threadId}] is setting up worker child environment`);
|
||||
|
||||
function prepareUserCodeExecution() {
|
||||
initializeClusterIPC();
|
||||
initializeESMLoader();
|
||||
loadPreloadModules();
|
||||
}
|
||||
|
||||
// Set up the message port and start listening
|
||||
const port = getEnvMessagePort();
|
||||
port.on('message', createMessageHandler(port, prepareUserCodeExecution));
|
||||
port.start();
|
||||
|
||||
// Overwrite fatalException
|
||||
process._fatalException = createWorkerFatalExeception(port);
|
||||
|
||||
markBootstrapComplete();
|
@ -165,7 +165,21 @@ function createFatalException() {
|
||||
};
|
||||
}
|
||||
|
||||
function readStdin(callback) {
|
||||
process.stdin.setEncoding('utf8');
|
||||
|
||||
let code = '';
|
||||
process.stdin.on('data', (d) => {
|
||||
code += d;
|
||||
});
|
||||
|
||||
process.stdin.on('end', () => {
|
||||
callback(code);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
readStdin,
|
||||
tryGetCwd,
|
||||
evalScript,
|
||||
fatalException: createFatalException(),
|
||||
|
16
node.gyp
16
node.gyp
@ -29,6 +29,7 @@
|
||||
'lib/internal/bootstrap/cache.js',
|
||||
'lib/internal/bootstrap/loaders.js',
|
||||
'lib/internal/bootstrap/node.js',
|
||||
'lib/internal/bootstrap/pre_execution.js',
|
||||
'lib/async_hooks.js',
|
||||
'lib/assert.js',
|
||||
'lib/buffer.js',
|
||||
@ -85,7 +86,6 @@
|
||||
'lib/zlib.js',
|
||||
'lib/internal/assert.js',
|
||||
'lib/internal/async_hooks.js',
|
||||
'lib/internal/bash_completion.js',
|
||||
'lib/internal/buffer.js',
|
||||
'lib/internal/cli_table.js',
|
||||
'lib/internal/child_process.js',
|
||||
@ -130,6 +130,17 @@
|
||||
'lib/internal/inspector_async_hook.js',
|
||||
'lib/internal/js_stream_socket.js',
|
||||
'lib/internal/linkedlist.js',
|
||||
'lib/internal/main/check_syntax.js',
|
||||
'lib/internal/main/eval_string.js',
|
||||
'lib/internal/main/eval_stdin.js',
|
||||
'lib/internal/main/inspect.js',
|
||||
'lib/internal/main/print_bash_completion.js',
|
||||
'lib/internal/main/print_help.js',
|
||||
'lib/internal/main/prof_process.js',
|
||||
'lib/internal/main/repl.js',
|
||||
'lib/internal/main/run_main_module.js',
|
||||
'lib/internal/main/run_third_party_main.js',
|
||||
'lib/internal/main/worker_thread.js',
|
||||
'lib/internal/modules/cjs/helpers.js',
|
||||
'lib/internal/modules/cjs/loader.js',
|
||||
'lib/internal/modules/esm/loader.js',
|
||||
@ -141,9 +152,8 @@
|
||||
'lib/internal/safe_globals.js',
|
||||
'lib/internal/net.js',
|
||||
'lib/internal/options.js',
|
||||
'lib/internal/policy/sri.js',
|
||||
'lib/internal/policy/manifest.js',
|
||||
'lib/internal/print_help.js',
|
||||
'lib/internal/policy/sri.js',
|
||||
'lib/internal/priority_queue.js',
|
||||
'lib/internal/process/esm_loader.js',
|
||||
'lib/internal/process/execution.js',
|
||||
|
13
src/env.cc
13
src/env.cc
@ -332,9 +332,20 @@ void Environment::Start(bool start_profiler_idle_notifier) {
|
||||
uv_key_set(&thread_local_env, this);
|
||||
}
|
||||
|
||||
MaybeLocal<Object> Environment::CreateProcessObject(
|
||||
MaybeLocal<Object> Environment::ProcessCliArgs(
|
||||
const std::vector<std::string>& args,
|
||||
const std::vector<std::string>& exec_args) {
|
||||
if (args.size() > 1) {
|
||||
std::string first_arg = args[1];
|
||||
if (first_arg == "inspect") {
|
||||
execution_mode_ = ExecutionMode::kInspect;
|
||||
} else if (first_arg == "debug") {
|
||||
execution_mode_ = ExecutionMode::kDebug;
|
||||
} else if (first_arg != "-") {
|
||||
execution_mode_ = ExecutionMode::kRunMainModule;
|
||||
}
|
||||
}
|
||||
|
||||
if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
|
||||
TRACING_CATEGORY_NODE1(environment)) != 0) {
|
||||
auto traced_value = tracing::TracedValue::Create();
|
||||
|
26
src/env.h
26
src/env.h
@ -315,7 +315,7 @@ constexpr size_t kFsStatsBufferLength = kFsStatsFieldsNumber * 2;
|
||||
V(write_host_object_string, "_writeHostObject") \
|
||||
V(write_queue_size_string, "writeQueueSize") \
|
||||
V(x_forwarded_string, "x-forwarded-for") \
|
||||
V(zero_return_string, "ZERO_RETURN") \
|
||||
V(zero_return_string, "ZERO_RETURN")
|
||||
|
||||
#define ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V) \
|
||||
V(as_external, v8::External) \
|
||||
@ -355,11 +355,13 @@ constexpr size_t kFsStatsBufferLength = kFsStatsFieldsNumber * 2;
|
||||
V(http2session_on_stream_trailers_function, v8::Function) \
|
||||
V(http2settings_constructor_template, v8::ObjectTemplate) \
|
||||
V(http2stream_constructor_template, v8::ObjectTemplate) \
|
||||
V(internal_binding_loader, v8::Function) \
|
||||
V(immediate_callback_function, v8::Function) \
|
||||
V(inspector_console_extension_installer, v8::Function) \
|
||||
V(libuv_stream_wrap_ctor_template, v8::FunctionTemplate) \
|
||||
V(message_port, v8::Object) \
|
||||
V(message_port_constructor_template, v8::FunctionTemplate) \
|
||||
V(native_module_require, v8::Function) \
|
||||
V(performance_entry_callback, v8::Function) \
|
||||
V(performance_entry_template, v8::Function) \
|
||||
V(pipe_constructor_template, v8::FunctionTemplate) \
|
||||
@ -371,7 +373,6 @@ constexpr size_t kFsStatsBufferLength = kFsStatsFieldsNumber * 2;
|
||||
V(script_data_constructor_function, v8::Function) \
|
||||
V(secure_context_constructor_template, v8::FunctionTemplate) \
|
||||
V(shutdown_wrap_template, v8::ObjectTemplate) \
|
||||
V(start_execution_function, v8::Function) \
|
||||
V(tcp_constructor_template, v8::FunctionTemplate) \
|
||||
V(tick_callback_function, v8::Function) \
|
||||
V(timers_callback_function, v8::Function) \
|
||||
@ -611,7 +612,7 @@ class Environment {
|
||||
~Environment();
|
||||
|
||||
void Start(bool start_profiler_idle_notifier);
|
||||
v8::MaybeLocal<v8::Object> CreateProcessObject(
|
||||
v8::MaybeLocal<v8::Object> ProcessCliArgs(
|
||||
const std::vector<std::string>& args,
|
||||
const std::vector<std::string>& exec_args);
|
||||
|
||||
@ -928,6 +929,24 @@ class Environment {
|
||||
inline std::shared_ptr<EnvironmentOptions> options();
|
||||
inline std::shared_ptr<HostPort> inspector_host_port();
|
||||
|
||||
enum class ExecutionMode {
|
||||
kDefault,
|
||||
kInspect, // node inspect
|
||||
kDebug, // node debug
|
||||
kPrintHelp, // node --help
|
||||
kPrintBashCompletion, // node --completion-bash
|
||||
kProfProcess, // node --prof-process
|
||||
kEvalString, // node --eval without --interactive
|
||||
kCheckSyntax, // node --check (incompatible with --eval)
|
||||
kRepl,
|
||||
kEvalStdin,
|
||||
kRunMainModule
|
||||
};
|
||||
|
||||
inline ExecutionMode execution_mode() { return execution_mode_; }
|
||||
|
||||
inline void set_execution_mode(ExecutionMode mode) { execution_mode_ = mode; }
|
||||
|
||||
private:
|
||||
inline void CreateImmediate(native_immediate_callback cb,
|
||||
void* data,
|
||||
@ -937,6 +956,7 @@ class Environment {
|
||||
inline void ThrowError(v8::Local<v8::Value> (*fun)(v8::Local<v8::String>),
|
||||
const char* errmsg);
|
||||
|
||||
ExecutionMode execution_mode_ = ExecutionMode::kDefault;
|
||||
std::list<binding::DLib> loaded_addons_;
|
||||
v8::Isolate* const isolate_;
|
||||
IsolateData* const isolate_data_;
|
||||
|
212
src/node.cc
212
src/node.cc
@ -100,6 +100,7 @@
|
||||
#if defined(_MSC_VER)
|
||||
#include <direct.h>
|
||||
#include <io.h>
|
||||
#define STDIN_FILENO 0
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#include <sys/resource.h> // getrlimit, setrlimit
|
||||
@ -114,6 +115,7 @@ using v8::Array;
|
||||
using v8::Boolean;
|
||||
using v8::Context;
|
||||
using v8::DEFAULT;
|
||||
using v8::EscapableHandleScope;
|
||||
using v8::Exception;
|
||||
using v8::Function;
|
||||
using v8::FunctionCallbackInfo;
|
||||
@ -605,8 +607,20 @@ static MaybeLocal<Value> ExecuteBootstrapper(
|
||||
const char* id,
|
||||
std::vector<Local<String>>* parameters,
|
||||
std::vector<Local<Value>>* arguments) {
|
||||
MaybeLocal<Value> ret = per_process::native_module_loader.CompileAndCall(
|
||||
env->context(), id, parameters, arguments, env);
|
||||
EscapableHandleScope scope(env->isolate());
|
||||
MaybeLocal<Function> maybe_fn =
|
||||
per_process::native_module_loader.LookupAndCompile(
|
||||
env->context(), id, parameters, env);
|
||||
|
||||
if (maybe_fn.IsEmpty()) {
|
||||
return MaybeLocal<Value>();
|
||||
}
|
||||
|
||||
Local<Function> fn = maybe_fn.ToLocalChecked();
|
||||
MaybeLocal<Value> result = fn->Call(env->context(),
|
||||
Undefined(env->isolate()),
|
||||
arguments->size(),
|
||||
arguments->data());
|
||||
|
||||
// If there was an error during bootstrap then it was either handled by the
|
||||
// FatalException handler or it's unrecoverable (e.g. max call stack
|
||||
@ -615,44 +629,17 @@ static MaybeLocal<Value> ExecuteBootstrapper(
|
||||
// There are only two ways to have a stack size > 1: 1) the user manually
|
||||
// called MakeCallback or 2) user awaited during bootstrap, which triggered
|
||||
// _tickCallback().
|
||||
if (ret.IsEmpty()) {
|
||||
if (result.IsEmpty()) {
|
||||
env->async_hooks()->clear_async_id_stack();
|
||||
}
|
||||
|
||||
return ret;
|
||||
return scope.EscapeMaybe(result);
|
||||
}
|
||||
|
||||
void LoadEnvironment(Environment* env) {
|
||||
RunBootstrapping(env);
|
||||
|
||||
// To allow people to extend Node in different ways, this hook allows
|
||||
// one to drop a file lib/_third_party_main.js into the build
|
||||
// directory which will be executed instead of Node's normal loading.
|
||||
if (per_process::native_module_loader.Exists("_third_party_main")) {
|
||||
StartExecution(env, "_third_party_main");
|
||||
} else {
|
||||
// TODO(joyeecheung): create different scripts for different
|
||||
// execution modes:
|
||||
// - `main_thread_main.js` when env->is_main_thread()
|
||||
// - `worker_thread_main.js` when !env->is_main_thread()
|
||||
// - `run_third_party_main.js` for `_third_party_main`
|
||||
// - `inspect_main.js` for `node inspect`
|
||||
// - `mkcodecache_main.js` for the code cache generator
|
||||
// - `print_help_main.js` for --help
|
||||
// - `bash_completion_main.js` for --completion-bash
|
||||
// - `internal/v8_prof_processor` for --prof-process
|
||||
// And leave bootstrap/node.js dedicated to the setup of the environment.
|
||||
// We may want to move this switch out of LoadEnvironment, especially for
|
||||
// the per-process options.
|
||||
StartExecution(env, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void RunBootstrapping(Environment* env) {
|
||||
MaybeLocal<Value> RunBootstrapping(Environment* env) {
|
||||
CHECK(!env->has_run_bootstrapping_code());
|
||||
env->set_has_run_bootstrapping_code(true);
|
||||
|
||||
HandleScope handle_scope(env->isolate());
|
||||
EscapableHandleScope scope(env->isolate());
|
||||
Isolate* isolate = env->isolate();
|
||||
Local<Context> context = env->context();
|
||||
|
||||
@ -702,14 +689,24 @@ void RunBootstrapping(Environment* env) {
|
||||
Boolean::New(isolate,
|
||||
env->options()->expose_internals)};
|
||||
|
||||
MaybeLocal<Value> loader_exports;
|
||||
// Bootstrap internal loaders
|
||||
loader_exports = ExecuteBootstrapper(
|
||||
MaybeLocal<Value> loader_exports = ExecuteBootstrapper(
|
||||
env, "internal/bootstrap/loaders", &loaders_params, &loaders_args);
|
||||
if (loader_exports.IsEmpty()) {
|
||||
return;
|
||||
return MaybeLocal<Value>();
|
||||
}
|
||||
|
||||
Local<Object> loader_exports_obj =
|
||||
loader_exports.ToLocalChecked().As<Object>();
|
||||
Local<Value> internal_binding_loader =
|
||||
loader_exports_obj->Get(context, env->internal_binding_string())
|
||||
.ToLocalChecked();
|
||||
env->set_internal_binding_loader(internal_binding_loader.As<Function>());
|
||||
|
||||
Local<Value> require =
|
||||
loader_exports_obj->Get(context, env->require_string()).ToLocalChecked();
|
||||
env->set_native_module_require(require.As<Function>());
|
||||
|
||||
// process, loaderExports, isMainThread
|
||||
std::vector<Local<String>> node_params = {
|
||||
env->process_string(),
|
||||
@ -717,43 +714,107 @@ void RunBootstrapping(Environment* env) {
|
||||
FIXED_ONE_BYTE_STRING(isolate, "isMainThread")};
|
||||
std::vector<Local<Value>> node_args = {
|
||||
process,
|
||||
loader_exports.ToLocalChecked(),
|
||||
loader_exports_obj,
|
||||
Boolean::New(isolate, env->is_main_thread())};
|
||||
|
||||
Local<Value> start_execution;
|
||||
if (!ExecuteBootstrapper(
|
||||
env, "internal/bootstrap/node", &node_params, &node_args)
|
||||
.ToLocal(&start_execution)) {
|
||||
return;
|
||||
}
|
||||
MaybeLocal<Value> result = ExecuteBootstrapper(
|
||||
env, "internal/bootstrap/node", &node_params, &node_args);
|
||||
|
||||
if (start_execution->IsFunction())
|
||||
env->set_start_execution_function(start_execution.As<Function>());
|
||||
env->set_has_run_bootstrapping_code(true);
|
||||
|
||||
return scope.EscapeMaybe(result);
|
||||
}
|
||||
|
||||
void StartExecution(Environment* env, const char* main_script_id) {
|
||||
HandleScope handle_scope(env->isolate());
|
||||
// We have to use Local<>::New because of the optimized way in which we access
|
||||
// the object in the env->...() getters, which does not play well with
|
||||
// resetting the handle while we're accessing the object through the Local<>.
|
||||
Local<Function> start_execution =
|
||||
Local<Function>::New(env->isolate(), env->start_execution_function());
|
||||
env->set_start_execution_function(Local<Function>());
|
||||
void MarkBootstrapComplete(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
env->performance_state()->Mark(
|
||||
performance::NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE);
|
||||
}
|
||||
|
||||
if (start_execution.IsEmpty()) return;
|
||||
MaybeLocal<Value> StartExecution(Environment* env, const char* main_script_id) {
|
||||
EscapableHandleScope scope(env->isolate());
|
||||
CHECK_NE(main_script_id, nullptr);
|
||||
|
||||
Local<Value> main_script_v;
|
||||
if (main_script_id == nullptr) {
|
||||
// TODO(joyeecheung): make this mandatory - we may also create an overload
|
||||
// for main_script that is a Local<Function>.
|
||||
main_script_v = Undefined(env->isolate());
|
||||
} else {
|
||||
main_script_v = OneByteString(env->isolate(), main_script_id);
|
||||
std::vector<Local<String>> parameters = {
|
||||
env->process_string(),
|
||||
env->require_string(),
|
||||
env->internal_binding_string(),
|
||||
FIXED_ONE_BYTE_STRING(env->isolate(), "markBootstrapComplete")};
|
||||
|
||||
std::vector<Local<Value>> arguments = {
|
||||
env->process_object(),
|
||||
env->native_module_require(),
|
||||
env->internal_binding_loader(),
|
||||
env->NewFunctionTemplate(MarkBootstrapComplete)
|
||||
->GetFunction(env->context())
|
||||
.ToLocalChecked()};
|
||||
|
||||
MaybeLocal<Value> result =
|
||||
ExecuteBootstrapper(env, main_script_id, ¶meters, &arguments);
|
||||
return scope.EscapeMaybe(result);
|
||||
}
|
||||
|
||||
MaybeLocal<Value> StartMainThreadExecution(Environment* env) {
|
||||
// To allow people to extend Node in different ways, this hook allows
|
||||
// one to drop a file lib/_third_party_main.js into the build
|
||||
// directory which will be executed instead of Node's normal loading.
|
||||
if (per_process::native_module_loader.Exists("_third_party_main")) {
|
||||
return StartExecution(env, "internal/main/run_third_party_main");
|
||||
}
|
||||
|
||||
Local<Value> argv[] = {main_script_v};
|
||||
USE(start_execution->Call(
|
||||
env->context(), Undefined(env->isolate()), arraysize(argv), argv));
|
||||
if (env->execution_mode() == Environment::ExecutionMode::kInspect ||
|
||||
env->execution_mode() == Environment::ExecutionMode::kDebug) {
|
||||
return StartExecution(env, "internal/main/inspect");
|
||||
}
|
||||
|
||||
if (per_process::cli_options->print_help) {
|
||||
env->set_execution_mode(Environment::ExecutionMode::kPrintHelp);
|
||||
return StartExecution(env, "internal/main/print_help");
|
||||
}
|
||||
|
||||
if (per_process::cli_options->print_bash_completion) {
|
||||
env->set_execution_mode(Environment::ExecutionMode::kPrintBashCompletion);
|
||||
return StartExecution(env, "internal/main/print_bash_completion");
|
||||
}
|
||||
|
||||
if (env->options()->prof_process) {
|
||||
env->set_execution_mode(Environment::ExecutionMode::kPrintBashCompletion);
|
||||
return StartExecution(env, "internal/main/prof_process");
|
||||
}
|
||||
|
||||
// -e/--eval without -i/--interactive
|
||||
if (env->options()->has_eval_string && !env->options()->force_repl) {
|
||||
env->set_execution_mode(Environment::ExecutionMode::kEvalString);
|
||||
return StartExecution(env, "internal/main/eval_string");
|
||||
}
|
||||
|
||||
if (env->options()->syntax_check_only) {
|
||||
env->set_execution_mode(Environment::ExecutionMode::kCheckSyntax);
|
||||
return StartExecution(env, "internal/main/check_syntax");
|
||||
}
|
||||
|
||||
if (env->execution_mode() == Environment::ExecutionMode::kRunMainModule) {
|
||||
return StartExecution(env, "internal/main/run_main_module");
|
||||
}
|
||||
|
||||
if (env->options()->force_repl || uv_guess_handle(STDIN_FILENO) == UV_TTY) {
|
||||
env->set_execution_mode(Environment::ExecutionMode::kRepl);
|
||||
return StartExecution(env, "internal/main/repl");
|
||||
}
|
||||
|
||||
env->set_execution_mode(Environment::ExecutionMode::kEvalStdin);
|
||||
return StartExecution(env, "internal/main/eval_stdin");
|
||||
}
|
||||
|
||||
void LoadEnvironment(Environment* env) {
|
||||
CHECK(env->is_main_thread());
|
||||
// TODO(joyeecheung): Not all of the execution modes in
|
||||
// StartMainThreadExecution() make sense for embedders. Pick the
|
||||
// useful ones out, and allow embedders to customize the entry
|
||||
// point more directly without using _third_party_main.js
|
||||
if (!RunBootstrapping(env).IsEmpty()) {
|
||||
USE(StartMainThreadExecution(env));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1180,7 +1241,7 @@ Environment* CreateEnvironment(IsolateData* isolate_data,
|
||||
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->CreateProcessObject(args, exec_args);
|
||||
env->ProcessCliArgs(args, exec_args);
|
||||
return env;
|
||||
}
|
||||
|
||||
@ -1220,7 +1281,7 @@ void FreePlatform(MultiIsolatePlatform* platform) {
|
||||
|
||||
Local<Context> NewContext(Isolate* isolate,
|
||||
Local<ObjectTemplate> object_template) {
|
||||
auto context = Context::New(isolate, nullptr, object_template);
|
||||
Local<Context> context = Context::New(isolate, nullptr, object_template);
|
||||
if (context.IsEmpty()) return context;
|
||||
HandleScope handle_scope(isolate);
|
||||
|
||||
@ -1233,12 +1294,19 @@ Local<Context> NewContext(Isolate* isolate,
|
||||
|
||||
std::vector<Local<String>> parameters = {
|
||||
FIXED_ONE_BYTE_STRING(isolate, "global")};
|
||||
std::vector<Local<Value>> arguments = {context->Global()};
|
||||
MaybeLocal<Value> result = per_process::native_module_loader.CompileAndCall(
|
||||
context, "internal/per_context", ¶meters, &arguments, nullptr);
|
||||
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()) {
|
||||
// Execution failed during context creation.
|
||||
// TODO(joyeecheung): deprecate this signature and return a MaybeLocal.
|
||||
return Local<Context>();
|
||||
}
|
||||
}
|
||||
@ -1255,7 +1323,7 @@ inline int Start(Isolate* isolate, IsolateData* isolate_data,
|
||||
Context::Scope context_scope(context);
|
||||
Environment env(isolate_data, context);
|
||||
env.Start(per_process::v8_is_profiling);
|
||||
env.CreateProcessObject(args, exec_args);
|
||||
env.ProcessCliArgs(args, exec_args);
|
||||
|
||||
#if HAVE_INSPECTOR && NODE_USE_V8_PLATFORM
|
||||
CHECK(!env.inspector_agent()->IsListening());
|
||||
|
@ -268,8 +268,9 @@ bool SafeGetenv(const char* key, std::string* text);
|
||||
|
||||
void DefineZlibConstants(v8::Local<v8::Object> target);
|
||||
|
||||
void RunBootstrapping(Environment* env);
|
||||
void StartExecution(Environment* env, const char* main_script_id);
|
||||
v8::MaybeLocal<v8::Value> RunBootstrapping(Environment* env);
|
||||
v8::MaybeLocal<v8::Value> StartExecution(Environment* env,
|
||||
const char* main_script_id);
|
||||
|
||||
} // namespace node
|
||||
|
||||
|
@ -175,26 +175,6 @@ void NativeModuleLoader::CompileFunction(
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(joyeecheung): it should be possible to generate the argument names
|
||||
// from some special comments for the bootstrapper case.
|
||||
MaybeLocal<Value> NativeModuleLoader::CompileAndCall(
|
||||
Local<Context> context,
|
||||
const char* id,
|
||||
std::vector<Local<String>>* parameters,
|
||||
std::vector<Local<Value>>* arguments,
|
||||
Environment* optional_env) {
|
||||
Isolate* isolate = context->GetIsolate();
|
||||
MaybeLocal<Function> compiled =
|
||||
per_process::native_module_loader.LookupAndCompile(
|
||||
context, id, parameters, nullptr);
|
||||
if (compiled.IsEmpty()) {
|
||||
return MaybeLocal<Value>();
|
||||
}
|
||||
Local<Function> fn = compiled.ToLocalChecked().As<Function>();
|
||||
return fn->Call(
|
||||
context, v8::Null(isolate), arguments->size(), arguments->data());
|
||||
}
|
||||
|
||||
MaybeLocal<Function> NativeModuleLoader::CompileAsModule(Environment* env,
|
||||
const char* id) {
|
||||
std::vector<Local<String>> parameters = {env->exports_string(),
|
||||
|
@ -42,20 +42,17 @@ class NativeModuleLoader {
|
||||
// Returns config.gypi as a JSON string
|
||||
v8::Local<v8::String> GetConfigString(v8::Isolate* isolate) const;
|
||||
|
||||
// Run a script with JS source bundled inside the binary as if it's wrapped
|
||||
// in a function called with a null receiver and arguments specified in C++.
|
||||
// The returned value is empty if an exception is encountered.
|
||||
// JS code run with this method can assume that their top-level
|
||||
// declarations won't affect the global scope.
|
||||
v8::MaybeLocal<v8::Value> CompileAndCall(
|
||||
bool Exists(const char* id);
|
||||
|
||||
// For bootstrappers optional_env may be a nullptr.
|
||||
// If an exception is encountered (e.g. source code contains
|
||||
// syntax error), the returned value is empty.
|
||||
v8::MaybeLocal<v8::Function> LookupAndCompile(
|
||||
v8::Local<v8::Context> context,
|
||||
const char* id,
|
||||
std::vector<v8::Local<v8::String>>* parameters,
|
||||
std::vector<v8::Local<v8::Value>>* arguments,
|
||||
Environment* optional_env);
|
||||
|
||||
bool Exists(const char* id);
|
||||
|
||||
private:
|
||||
static void GetCacheUsage(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
// Passing ids of builtin module source code into JS land as
|
||||
@ -87,15 +84,6 @@ class NativeModuleLoader {
|
||||
static v8::MaybeLocal<v8::Function> CompileAsModule(Environment* env,
|
||||
const char* id);
|
||||
|
||||
// For bootstrappers optional_env may be a nullptr.
|
||||
// If an exception is encountered (e.g. source code contains
|
||||
// syntax error), the returned value is empty.
|
||||
v8::MaybeLocal<v8::Function> LookupAndCompile(
|
||||
v8::Local<v8::Context> context,
|
||||
const char* id,
|
||||
std::vector<v8::Local<v8::String>>* parameters,
|
||||
Environment* optional_env);
|
||||
|
||||
NativeModuleRecordMap source_;
|
||||
NativeModuleCacheMap code_cache_;
|
||||
UnionBytes config_;
|
||||
|
@ -133,8 +133,8 @@ Worker::Worker(Environment* env,
|
||||
env_->set_thread_id(thread_id_);
|
||||
|
||||
env_->Start(env->profiler_idle_notifier_started());
|
||||
env_->CreateProcessObject(std::vector<std::string>{},
|
||||
std::vector<std::string>{});
|
||||
env_->ProcessCliArgs(std::vector<std::string>{},
|
||||
std::vector<std::string>{});
|
||||
// Done while on the parent thread
|
||||
AddWorkerInspector(env, env_.get(), thread_id_, url_);
|
||||
}
|
||||
@ -192,10 +192,10 @@ void Worker::Run() {
|
||||
HandleScope handle_scope(isolate_);
|
||||
Environment::AsyncCallbackScope callback_scope(env_.get());
|
||||
env_->async_hooks()->push_async_ids(1, 0);
|
||||
RunBootstrapping(env_.get());
|
||||
// TODO(joyeecheung): create a main script for worker threads
|
||||
// that starts listening on the message port.
|
||||
StartExecution(env_.get(), nullptr);
|
||||
if (!RunBootstrapping(env_.get()).IsEmpty()) {
|
||||
USE(StartExecution(env_.get(), "internal/main/worker_thread"));
|
||||
}
|
||||
|
||||
env_->async_hooks()->pop_async_id(1);
|
||||
|
||||
Debug(this, "Loaded environment for worker %llu", thread_id_);
|
||||
|
@ -9,7 +9,7 @@ const { isMainThread } = require('../common');
|
||||
const assert = require('assert');
|
||||
const {
|
||||
cachableBuiltins,
|
||||
cannotUseCache
|
||||
cannotBeRequired
|
||||
} = require('internal/bootstrap/cache');
|
||||
|
||||
const {
|
||||
@ -60,7 +60,7 @@ if (process.config.variables.node_code_cache_path === undefined) {
|
||||
);
|
||||
|
||||
for (const key of loadedModules) {
|
||||
if (cannotUseCache.includes(key)) {
|
||||
if (cannotBeRequired.includes(key)) {
|
||||
assert(compiledWithoutCache.has(key),
|
||||
`"${key}" should've been compiled without code cache`);
|
||||
} else {
|
||||
|
@ -17,4 +17,3 @@ AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
|
||||
at *
|
||||
at *
|
||||
at *
|
||||
at *
|
||||
|
@ -12,4 +12,4 @@ RangeError: Invalid input
|
||||
at tryModuleLoad (internal/modules/cjs/loader.js:*:*)
|
||||
at Function.Module._load (internal/modules/cjs/loader.js:*:*)
|
||||
at Function.Module.runMain (internal/modules/cjs/loader.js:*:*)
|
||||
at executeUserCode (internal/bootstrap/node.js:*:*)
|
||||
at internal/main/run_main_module.js:*:*
|
||||
|
@ -14,5 +14,4 @@ AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
|
||||
at tryModuleLoad (internal/modules/cjs/loader.js:*:*)
|
||||
at Function.Module._load (internal/modules/cjs/loader.js:*:*)
|
||||
at Function.Module.runMain (internal/modules/cjs/loader.js:*:*)
|
||||
at executeUserCode (internal/bootstrap/node.js:*:*)
|
||||
at startMainThreadExecution (internal/bootstrap/node.js:*:*)
|
||||
at internal/main/run_main_module.js:*:*
|
||||
|
@ -9,8 +9,7 @@ SyntaxError: Strict mode code may not include a with statement
|
||||
at Object.<anonymous> ([eval]-wrapper:*:*)
|
||||
at Module._compile (internal/modules/cjs/loader.js:*:*)
|
||||
at evalScript (internal/process/execution.js:*:*)
|
||||
at executeUserCode (internal/bootstrap/node.js:*:*)
|
||||
at startMainThreadExecution (internal/bootstrap/node.js:*:*)
|
||||
at internal/main/eval_string.js:*:*
|
||||
42
|
||||
42
|
||||
[eval]:1
|
||||
@ -24,8 +23,7 @@ Error: hello
|
||||
at Object.<anonymous> ([eval]-wrapper:*:*)
|
||||
at Module._compile (internal/modules/cjs/loader.js:*:*)
|
||||
at evalScript (internal/process/execution.js:*:*)
|
||||
at executeUserCode (internal/bootstrap/node.js:*:*)
|
||||
at startMainThreadExecution (internal/bootstrap/node.js:*:*)
|
||||
at internal/main/eval_string.js:*:*
|
||||
|
||||
[eval]:1
|
||||
throw new Error("hello")
|
||||
@ -38,8 +36,7 @@ Error: hello
|
||||
at Object.<anonymous> ([eval]-wrapper:*:*)
|
||||
at Module._compile (internal/modules/cjs/loader.js:*:*)
|
||||
at evalScript (internal/process/execution.js:*:*)
|
||||
at executeUserCode (internal/bootstrap/node.js:*:*)
|
||||
at startMainThreadExecution (internal/bootstrap/node.js:*:*)
|
||||
at internal/main/eval_string.js:*:*
|
||||
100
|
||||
[eval]:1
|
||||
var x = 100; y = x;
|
||||
@ -52,8 +49,7 @@ ReferenceError: y is not defined
|
||||
at Object.<anonymous> ([eval]-wrapper:*:*)
|
||||
at Module._compile (internal/modules/cjs/loader.js:*:*)
|
||||
at evalScript (internal/process/execution.js:*:*)
|
||||
at executeUserCode (internal/bootstrap/node.js:*:*)
|
||||
at startMainThreadExecution (internal/bootstrap/node.js:*:*)
|
||||
at internal/main/eval_string.js:*:*
|
||||
|
||||
[eval]:1
|
||||
var ______________________________________________; throw 10
|
||||
|
@ -12,11 +12,10 @@ Error: foo:bar
|
||||
at tryModuleLoad (internal/modules/cjs/loader.js:*:*)
|
||||
at Function.Module._load (internal/modules/cjs/loader.js:*:*)
|
||||
at Function.Module.runMain (internal/modules/cjs/loader.js:*:*)
|
||||
at executeUserCode (internal/bootstrap/node.js:*:*)
|
||||
at internal/main/run_main_module.js:*:*
|
||||
Emitted 'error' event at:
|
||||
at quux (*events_unhandled_error_common_trace.js:*:*)
|
||||
at Object.<anonymous> (*events_unhandled_error_common_trace.js:*:*)
|
||||
at Module._compile (internal/modules/cjs/loader.js:*:*)
|
||||
[... lines matching original stack trace ...]
|
||||
at executeUserCode (internal/bootstrap/node.js:*:*)
|
||||
at startMainThreadExecution (internal/bootstrap/node.js:*:*)
|
||||
at internal/main/run_main_module.js:*:*
|
||||
|
@ -10,12 +10,10 @@ Error
|
||||
at tryModuleLoad (internal/modules/cjs/loader.js:*:*)
|
||||
at Function.Module._load (internal/modules/cjs/loader.js:*:*)
|
||||
at Function.Module.runMain (internal/modules/cjs/loader.js:*:*)
|
||||
at executeUserCode (internal/bootstrap/node.js:*:*)
|
||||
at startMainThreadExecution (internal/bootstrap/node.js:*:*)
|
||||
at internal/main/run_main_module.js:*:*
|
||||
Emitted 'error' event at:
|
||||
at process.nextTick (*events_unhandled_error_nexttick.js:*:*)
|
||||
at processTicksAndRejections (internal/process/next_tick.js:*:*)
|
||||
at process.runNextTicks [as _tickCallback] (internal/process/next_tick.js:*:*)
|
||||
at Function.Module.runMain (internal/modules/cjs/loader.js:*:*)
|
||||
at executeUserCode (internal/bootstrap/node.js:*:*)
|
||||
at startMainThreadExecution (internal/bootstrap/node.js:*:*)
|
||||
at internal/main/run_main_module.js:*:*
|
||||
|
@ -10,10 +10,9 @@ Error
|
||||
at tryModuleLoad (internal/modules/cjs/loader.js:*:*)
|
||||
at Function.Module._load (internal/modules/cjs/loader.js:*:*)
|
||||
at Function.Module.runMain (internal/modules/cjs/loader.js:*:*)
|
||||
at executeUserCode (internal/bootstrap/node.js:*:*)
|
||||
at startMainThreadExecution (internal/bootstrap/node.js:*:*)
|
||||
at internal/main/run_main_module.js:*:*
|
||||
Emitted 'error' event at:
|
||||
at Object.<anonymous> (*events_unhandled_error_sameline.js:*:*)
|
||||
at Module._compile (internal/modules/cjs/loader.js:*:*)
|
||||
[... lines matching original stack trace ...]
|
||||
at startMainThreadExecution (internal/bootstrap/node.js:*:*)
|
||||
at internal/main/run_main_module.js:*:*
|
||||
|
@ -7,5 +7,4 @@ ReferenceError: undefined_reference_error_maker is not defined
|
||||
at processTicksAndRejections (internal/process/next_tick.js:*:*)
|
||||
at process.runNextTicks [as _tickCallback] (internal/process/next_tick.js:*:*)
|
||||
at Function.Module.runMain (internal/modules/cjs/loader.js:*:*)
|
||||
at executeUserCode (internal/bootstrap/node.js:*:*)
|
||||
at startMainThreadExecution (internal/bootstrap/node.js:*:*)
|
||||
at internal/main/run_main_module.js:*:*
|
||||
|
@ -2,6 +2,7 @@
|
||||
[stdin]:1
|
||||
with(this){__filename}
|
||||
^^^^
|
||||
|
||||
SyntaxError: Strict mode code may not include a with statement
|
||||
at new Script (vm.js:*)
|
||||
at createScript (vm.js:*)
|
||||
@ -9,10 +10,10 @@ SyntaxError: Strict mode code may not include a with statement
|
||||
at Object.<anonymous> ([stdin]-wrapper:*:*)
|
||||
at Module._compile (internal/modules/cjs/loader.js:*:*)
|
||||
at evalScript (internal/process/execution.js:*:*)
|
||||
at Socket.process.stdin.on (internal/bootstrap/node.js:*:*)
|
||||
at readStdin (internal/main/eval_stdin.js:*:*)
|
||||
at Socket.process.stdin.on (internal/process/execution.js:*:*)
|
||||
at Socket.emit (events.js:*:*)
|
||||
at endReadableNT (_stream_readable.js:*:*)
|
||||
at processTicksAndRejections (internal/process/next_tick.js:*:*)
|
||||
42
|
||||
42
|
||||
[stdin]:1
|
||||
@ -26,10 +27,10 @@ Error: hello
|
||||
at Object.<anonymous> ([stdin]-wrapper:*:*)
|
||||
at Module._compile (internal/modules/cjs/loader.js:*:*)
|
||||
at evalScript (internal/process/execution.js:*:*)
|
||||
at Socket.process.stdin.on (internal/bootstrap/node.js:*:*)
|
||||
at readStdin (internal/main/eval_stdin.js:*:*)
|
||||
at Socket.process.stdin.on (internal/process/execution.js:*:*)
|
||||
at Socket.emit (events.js:*:*)
|
||||
at endReadableNT (_stream_readable.js:*:*)
|
||||
at processTicksAndRejections (internal/process/next_tick.js:*:*)
|
||||
[stdin]:1
|
||||
throw new Error("hello")
|
||||
^
|
||||
@ -41,10 +42,10 @@ Error: hello
|
||||
at Object.<anonymous> ([stdin]-wrapper:*:*)
|
||||
at Module._compile (internal/modules/cjs/loader.js:*:*)
|
||||
at evalScript (internal/process/execution.js:*:*)
|
||||
at Socket.process.stdin.on (internal/bootstrap/node.js:*:*)
|
||||
at readStdin (internal/main/eval_stdin.js:*:*)
|
||||
at Socket.process.stdin.on (internal/process/execution.js:*:*)
|
||||
at Socket.emit (events.js:*:*)
|
||||
at endReadableNT (_stream_readable.js:*:*)
|
||||
at processTicksAndRejections (internal/process/next_tick.js:*:*)
|
||||
100
|
||||
[stdin]:1
|
||||
var x = 100; y = x;
|
||||
@ -57,10 +58,10 @@ ReferenceError: y is not defined
|
||||
at Object.<anonymous> ([stdin]-wrapper:*:*)
|
||||
at Module._compile (internal/modules/cjs/loader.js:*:*)
|
||||
at evalScript (internal/process/execution.js:*:*)
|
||||
at Socket.process.stdin.on (internal/bootstrap/node.js:*:*)
|
||||
at readStdin (internal/main/eval_stdin.js:*:*)
|
||||
at Socket.process.stdin.on (internal/process/execution.js:*:*)
|
||||
at Socket.emit (events.js:*:*)
|
||||
at endReadableNT (_stream_readable.js:*:*)
|
||||
at processTicksAndRejections (internal/process/next_tick.js:*:*)
|
||||
|
||||
[stdin]:1
|
||||
var ______________________________________________; throw 10
|
||||
|
@ -13,8 +13,6 @@
|
||||
at *
|
||||
at *
|
||||
at *
|
||||
at *
|
||||
at *
|
||||
(node:*) Error: This was rejected
|
||||
at * (*test*message*unhandled_promise_trace_warnings.js:*)
|
||||
at *
|
||||
@ -24,7 +22,6 @@
|
||||
at *
|
||||
at *
|
||||
at *
|
||||
at *
|
||||
(node:*) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
|
||||
at *
|
||||
at *
|
||||
@ -33,7 +30,6 @@
|
||||
at *
|
||||
at *
|
||||
at *
|
||||
at *
|
||||
(node:*) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)
|
||||
at handledRejection (internal/process/promises.js:*)
|
||||
at promiseRejectHandler (internal/process/promises.js:*)
|
||||
|
@ -9,7 +9,6 @@
|
||||
at *
|
||||
at *
|
||||
at *
|
||||
at *
|
||||
nested:
|
||||
{ err:
|
||||
Error: foo
|
||||
@ -22,7 +21,6 @@
|
||||
at *
|
||||
at *
|
||||
at *
|
||||
at * } }
|
||||
{
|
||||
err: Error: foo
|
||||
bar
|
||||
@ -34,7 +32,6 @@
|
||||
at *
|
||||
at *
|
||||
at *
|
||||
at *,
|
||||
nested: {
|
||||
err: Error: foo
|
||||
bar
|
||||
@ -46,7 +43,6 @@
|
||||
at *
|
||||
at *
|
||||
at *
|
||||
at *
|
||||
}
|
||||
}
|
||||
{ Error: foo
|
||||
@ -59,5 +55,4 @@ bar
|
||||
at *
|
||||
at *
|
||||
at *
|
||||
at *
|
||||
foo: 'bar' }
|
||||
|
Loading…
x
Reference in New Issue
Block a user